mirror of
https://github.com/OpenMW/openmw.git
synced 2025-01-30 09:15:38 +00:00
Merge remote-tracking branch 'upstream/master' into multiple_esm_esp
Conflicts: apps/openmw/engine.cpp apps/openmw/mwworld/cellstore.cpp apps/openmw/mwworld/store.hpp apps/openmw/mwworld/worldimp.cpp apps/openmw/mwworld/worldimp.hpp components/esm/esmreader.hpp - Quick hack: OMW::Engine::prepareEngine only loads translation data for the first master file.
This commit is contained in:
commit
dca8dc4fdb
290 changed files with 12827 additions and 3319 deletions
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -15,3 +15,5 @@ makefile
|
|||
data
|
||||
*.kdev4
|
||||
CMakeLists.txt.user
|
||||
*.swp
|
||||
*.swo
|
||||
|
|
1
.gitmodules
vendored
1
.gitmodules
vendored
|
@ -1 +0,0 @@
|
|||
|
|
@ -1,123 +0,0 @@
|
|||
Bitstream Vera Fonts Copyright
|
||||
|
||||
The fonts have a generous copyright, allowing derivative works (as
|
||||
long as "Bitstream" or "Vera" are not in the names), and full
|
||||
redistribution (so long as they are not *sold* by themselves). They
|
||||
can be be bundled, redistributed and sold with any software.
|
||||
|
||||
The fonts are distributed under the following copyright:
|
||||
|
||||
Copyright
|
||||
=========
|
||||
|
||||
Copyright (c) 2003 by Bitstream, Inc. All Rights Reserved. Bitstream
|
||||
Vera is a trademark of Bitstream, Inc.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of the fonts accompanying this license ("Fonts") and associated
|
||||
documentation files (the "Font Software"), to reproduce and distribute
|
||||
the Font Software, including without limitation the rights to use,
|
||||
copy, merge, publish, distribute, and/or sell copies of the Font
|
||||
Software, and to permit persons to whom the Font Software is furnished
|
||||
to do so, subject to the following conditions:
|
||||
|
||||
The above copyright and trademark notices and this permission notice
|
||||
shall be included in all copies of one or more of the Font Software
|
||||
typefaces.
|
||||
|
||||
The Font Software may be modified, altered, or added to, and in
|
||||
particular the designs of glyphs or characters in the Fonts may be
|
||||
modified and additional glyphs or characters may be added to the
|
||||
Fonts, only if the fonts are renamed to names not containing either
|
||||
the words "Bitstream" or the word "Vera".
|
||||
|
||||
This License becomes null and void to the extent applicable to Fonts
|
||||
or Font Software that has been modified and is distributed under the
|
||||
"Bitstream Vera" names.
|
||||
|
||||
The Font Software may be sold as part of a larger software package but
|
||||
no copy of one or more of the Font Software typefaces may be sold by
|
||||
itself.
|
||||
|
||||
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
|
||||
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL
|
||||
BITSTREAM OR THE GNOME FOUNDATION BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
OTHER LIABILITY, INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL,
|
||||
OR CONSEQUENTIAL DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
||||
OTHERWISE, ARISING FROM, OUT OF THE USE OR INABILITY TO USE THE FONT
|
||||
SOFTWARE OR FROM OTHER DEALINGS IN THE FONT SOFTWARE.
|
||||
|
||||
Except as contained in this notice, the names of Gnome, the Gnome
|
||||
Foundation, and Bitstream Inc., shall not be used in advertising or
|
||||
otherwise to promote the sale, use or other dealings in this Font
|
||||
Software without prior written authorization from the Gnome Foundation
|
||||
or Bitstream Inc., respectively. For further information, contact:
|
||||
fonts at gnome dot org.
|
||||
|
||||
Copyright FAQ
|
||||
=============
|
||||
|
||||
1. I don't understand the resale restriction... What gives?
|
||||
|
||||
Bitstream is giving away these fonts, but wishes to ensure its
|
||||
competitors can't just drop the fonts as is into a font sale system
|
||||
and sell them as is. It seems fair that if Bitstream can't make money
|
||||
from the Bitstream Vera fonts, their competitors should not be able to
|
||||
do so either. You can sell the fonts as part of any software package,
|
||||
however.
|
||||
|
||||
2. I want to package these fonts separately for distribution and
|
||||
sale as part of a larger software package or system. Can I do so?
|
||||
|
||||
Yes. A RPM or Debian package is a "larger software package" to begin
|
||||
with, and you aren't selling them independently by themselves.
|
||||
See 1. above.
|
||||
|
||||
3. Are derivative works allowed?
|
||||
Yes!
|
||||
|
||||
4. Can I change or add to the font(s)?
|
||||
Yes, but you must change the name(s) of the font(s).
|
||||
|
||||
5. Under what terms are derivative works allowed?
|
||||
|
||||
You must change the name(s) of the fonts. This is to ensure the
|
||||
quality of the fonts, both to protect Bitstream and Gnome. We want to
|
||||
ensure that if an application has opened a font specifically of these
|
||||
names, it gets what it expects (though of course, using fontconfig,
|
||||
substitutions could still could have occurred during font
|
||||
opening). You must include the Bitstream copyright. Additional
|
||||
copyrights can be added, as per copyright law. Happy Font Hacking!
|
||||
|
||||
6. If I have improvements for Bitstream Vera, is it possible they might get
|
||||
adopted in future versions?
|
||||
|
||||
Yes. The contract between the Gnome Foundation and Bitstream has
|
||||
provisions for working with Bitstream to ensure quality additions to
|
||||
the Bitstream Vera font family. Please contact us if you have such
|
||||
additions. Note, that in general, we will want such additions for the
|
||||
entire family, not just a single font, and that you'll have to keep
|
||||
both Gnome and Jim Lyles, Vera's designer, happy! To make sense to add
|
||||
glyphs to the font, they must be stylistically in keeping with Vera's
|
||||
design. Vera cannot become a "ransom note" font. Jim Lyles will be
|
||||
providing a document describing the design elements used in Vera, as a
|
||||
guide and aid for people interested in contributing to Vera.
|
||||
|
||||
7. I want to sell a software package that uses these fonts: Can I do so?
|
||||
|
||||
Sure. Bundle the fonts with your software and sell your software
|
||||
with the fonts. That is the intent of the copyright.
|
||||
|
||||
8. If applications have built the names "Bitstream Vera" into them,
|
||||
can I override this somehow to use fonts of my choosing?
|
||||
|
||||
This depends on exact details of the software. Most open source
|
||||
systems and software (e.g., Gnome, KDE, etc.) are now converting to
|
||||
use fontconfig (see www.fontconfig.org) to handle font configuration,
|
||||
selection and substitution; it has provisions for overriding font
|
||||
names and subsituting alternatives. An example is provided by the
|
||||
supplied local.conf file, which chooses the family Bitstream Vera for
|
||||
"sans", "serif" and "monospace". Other software (e.g., the XFree86
|
||||
core server) has other mechanisms for font substitution.
|
118
CMakeLists.txt
118
CMakeLists.txt
|
@ -15,7 +15,7 @@ include (OpenMWMacros)
|
|||
# Version
|
||||
|
||||
set (OPENMW_VERSION_MAJOR 0)
|
||||
set (OPENMW_VERSION_MINOR 19)
|
||||
set (OPENMW_VERSION_MINOR 20)
|
||||
set (OPENMW_VERSION_RELEASE 0)
|
||||
|
||||
set (OPENMW_VERSION "${OPENMW_VERSION_MAJOR}.${OPENMW_VERSION_MINOR}.${OPENMW_VERSION_RELEASE}")
|
||||
|
@ -25,18 +25,20 @@ set (OPENMW_VERSION "${OPENMW_VERSION_MAJOR}.${OPENMW_VERSION_MINOR}.${OPENMW_VE
|
|||
configure_file ("${OpenMW_SOURCE_DIR}/Docs/mainpage.hpp.cmake" "${OpenMW_SOURCE_DIR}/Docs/mainpage.hpp")
|
||||
|
||||
option(MYGUI_STATIC "Link static build of Mygui into the binaries" FALSE)
|
||||
option(OGRE_STATIC "Link static build of Ogre and Ogre Plugins into the binaries" FALSE)
|
||||
option(OGRE_STATIC "Link static build of Ogre and Ogre Plugins into the binaries" FALSE)
|
||||
option(BOOST_STATIC "Link static build of Boost into the binaries" FALSE)
|
||||
|
||||
# Apps and tools
|
||||
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" OFF)
|
||||
option(USE_AUDIERE "use audiere for sound" OFF)
|
||||
option(USE_FFMPEG "use ffmpeg for sound" ON)
|
||||
option(USE_AUDIERE "use audiere for sound" ON)
|
||||
option(USE_MPG123 "use mpg123 + libsndfile for sound" ON)
|
||||
|
||||
# OS X deployment
|
||||
|
@ -65,35 +67,6 @@ endif()
|
|||
# We probably support older versions than this.
|
||||
cmake_minimum_required(VERSION 2.6)
|
||||
|
||||
#
|
||||
# Pre-built binaries being used?
|
||||
#
|
||||
IF(EXISTS "${CMAKE_SOURCE_DIR}/prebuilt/vc100-mt-gd/ogre_1_7_1")
|
||||
set(PREBUILT_DIR "${CMAKE_SOURCE_DIR}/prebuilt/vc100-mt-gd")
|
||||
message (STATUS "OpenMW pre-built binaries found at ${PREBUILT_DIR}.")
|
||||
|
||||
SET(ENV{OGRE_HOME} "${PREBUILT_DIR}/ogre_1_7_1")
|
||||
|
||||
SET(ENV{BOOST_ROOT} "${PREBUILT_DIR}/boost_1_42_0")
|
||||
set(Boost_USE_STATIC_LIBS ON)
|
||||
set(Boost_USE_MULTITHREADED ON)
|
||||
set(ENV{BOOST_INCLUDEDIR} "${BOOST_ROOT}/include")
|
||||
set(ENV{BOOST_LIBRARYDIR} "${BOOST_ROOT}/lib")
|
||||
|
||||
set(ENV{FREETYPE_DIR} "${PREBUILT_DIR}/freetype-2.3.5-1")
|
||||
|
||||
set(USE_MPG123 OFF)
|
||||
set(USE_AUDIERE ON)
|
||||
set(AUDIERE_INCLUDE_DIR "${PREBUILT_DIR}/audiere-1.9.4/include")
|
||||
set(AUDIERE_LIBRARY "${PREBUILT_DIR}/audiere-1.9.4/lib/audiere.lib")
|
||||
|
||||
set(ENV{OPENALDIR} "${PREBUILT_DIR}/OpenAL 1.1 SDK")
|
||||
|
||||
set(BULLET_ROOT "${PREBUILT_DIR}/bullet")
|
||||
ELSE()
|
||||
message (STATUS "OpenMW pre-built binaries not found. Using standard locations.")
|
||||
ENDIF()
|
||||
|
||||
# source directory: libs
|
||||
|
||||
set(LIBDIR ${CMAKE_SOURCE_DIR}/libs)
|
||||
|
@ -102,7 +75,6 @@ set(OENGINE_OGRE
|
|||
${LIBDIR}/openengine/ogre/renderer.cpp
|
||||
${LIBDIR}/openengine/ogre/fader.cpp
|
||||
${LIBDIR}/openengine/ogre/imagerotate.cpp
|
||||
${LIBDIR}/openengine/ogre/atlas.cpp
|
||||
${LIBDIR}/openengine/ogre/selectionbuffer.cpp
|
||||
)
|
||||
set(OENGINE_GUI
|
||||
|
@ -136,30 +108,54 @@ 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)
|
||||
find_package(FFMPEG REQUIRED)
|
||||
set(SOUND_INPUT_INCLUDES ${SOUND_INPUT_INCLUDES} ${FFMPEG_INCLUDE_DIR})
|
||||
set(SOUND_INPUT_LIBRARY ${SOUND_INPUT_LIBRARY} ${FFMPEG_LIBRARIES})
|
||||
set(SOUND_DEFINE ${SOUND_DEFINE} -DOPENMW_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 (USE_AUDIERE)
|
||||
find_package(Audiere REQUIRED)
|
||||
set(SOUND_INPUT_INCLUDES ${SOUND_INPUT_INCLUDES} ${AUDIERE_INCLUDE_DIR})
|
||||
set(SOUND_INPUT_LIBRARY ${SOUND_INPUT_LIBRARY} ${AUDIERE_LIBRARY})
|
||||
set(SOUND_DEFINE ${SOUND_DEFINE} -DOPENMW_USE_AUDIERE)
|
||||
endif (USE_AUDIERE)
|
||||
if (USE_AUDIERE AND NOT GOT_SOUND_INPUT)
|
||||
find_package(Audiere)
|
||||
if (AUDIERE_FOUND)
|
||||
set(SOUND_INPUT_INCLUDES ${SOUND_INPUT_INCLUDES} ${AUDIERE_INCLUDE_DIR})
|
||||
set(SOUND_INPUT_LIBRARY ${SOUND_INPUT_LIBRARY} ${AUDIERE_LIBRARY})
|
||||
set(SOUND_DEFINE ${SOUND_DEFINE} -DOPENMW_USE_AUDIERE)
|
||||
set(GOT_SOUND_INPUT 1)
|
||||
endif (AUDIERE_FOUND)
|
||||
endif (USE_AUDIERE AND NOT GOT_SOUND_INPUT)
|
||||
|
||||
if (USE_MPG123)
|
||||
if (USE_MPG123 AND NOT GOT_SOUND_INPUT)
|
||||
find_package(MPG123 REQUIRED)
|
||||
find_package(SNDFILE REQUIRED)
|
||||
set(SOUND_INPUT_INCLUDES ${SOUND_INPUT_INCLUDES} ${MPG123_INCLUDE_DIR} ${SNDFILE_INCLUDE_DIR})
|
||||
set(SOUND_INPUT_LIBRARY ${SOUND_INPUT_LIBRARY} ${MPG123_LIBRARY} ${SNDFILE_LIBRARY})
|
||||
set(SOUND_DEFINE ${SOUND_DEFINE} -DOPENMW_USE_MPG123)
|
||||
endif (USE_MPG123)
|
||||
if (MPG123_FOUND AND SNDFILE_FOUND)
|
||||
set(SOUND_INPUT_INCLUDES ${SOUND_INPUT_INCLUDES} ${MPG123_INCLUDE_DIR} ${SNDFILE_INCLUDE_DIR})
|
||||
set(SOUND_INPUT_LIBRARY ${SOUND_INPUT_LIBRARY} ${MPG123_LIBRARY} ${SNDFILE_LIBRARY})
|
||||
set(SOUND_DEFINE ${SOUND_DEFINE} -DOPENMW_USE_MPG123)
|
||||
set(GOT_SOUND_INPUT 1)
|
||||
endif (MPG123_FOUND AND SNDFILE_FOUND)
|
||||
endif (USE_MPG123 AND NOT GOT_SOUND_INPUT)
|
||||
|
||||
if (NOT GOT_SOUND_INPUT)
|
||||
message(WARNING "--------------------")
|
||||
message(WARNING "Failed to find any sound input packages")
|
||||
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)
|
||||
|
||||
|
||||
# Platform specific
|
||||
if (WIN32)
|
||||
|
@ -167,9 +163,9 @@ if (WIN32)
|
|||
set(PLATFORM_INCLUDE_DIR "platform")
|
||||
add_definitions(-DBOOST_ALL_NO_LIB)
|
||||
else (WIN32)
|
||||
set(PLATFORM_INCLUDE_DIR "")
|
||||
find_path (UUID_INCLUDE_DIR uuid/uuid.h)
|
||||
include_directories(${UUID_INCLUDE_DIR})
|
||||
set(PLATFORM_INCLUDE_DIR "")
|
||||
find_path (UUID_INCLUDE_DIR uuid/uuid.h)
|
||||
include_directories(${UUID_INCLUDE_DIR})
|
||||
endif (WIN32)
|
||||
if (MSVC10)
|
||||
set(PLATFORM_INCLUDE_DIR "")
|
||||
|
@ -183,7 +179,7 @@ endif (APPLE)
|
|||
|
||||
# Fix for not visible pthreads functions for linker with glibc 2.15
|
||||
if (UNIX AND NOT APPLE)
|
||||
find_package (Threads)
|
||||
find_package (Threads)
|
||||
endif()
|
||||
|
||||
# find boost without components so we can use Boost_VERSION
|
||||
|
@ -196,6 +192,10 @@ if (Boost_VERSION LESS 104900)
|
|||
set(BOOST_COMPONENTS ${BOOST_COMPONENTS} wave)
|
||||
endif()
|
||||
|
||||
IF(BOOST_STATIC)
|
||||
set(Boost_USE_STATIC_LIBS ON)
|
||||
endif()
|
||||
|
||||
find_package(OGRE REQUIRED)
|
||||
find_package(MyGUI REQUIRED)
|
||||
find_package(Boost REQUIRED COMPONENTS ${BOOST_COMPONENTS})
|
||||
|
@ -244,7 +244,7 @@ if (APPLE)
|
|||
else ()
|
||||
set(OGRE_PLUGIN_DIR ${OGRE_PLUGIN_DIR_DBG})
|
||||
endif ()
|
||||
|
||||
|
||||
#set(OGRE_PLUGIN_DIR "${OGRE_PLUGIN_DIR}/")
|
||||
|
||||
configure_file(${OpenMW_SOURCE_DIR}/files/mac/Info.plist
|
||||
|
@ -356,7 +356,7 @@ if(DPKG_PROGRAM)
|
|||
SET(CPACK_DEBIAN_PACKAGE_NAME "openmw")
|
||||
SET(CPACK_DEBIAN_PACKAGE_VERSION "${VERSION_STRING}")
|
||||
SET(CPACK_PACKAGE_EXECUTABLES "openmw;OpenMW esmtool;Esmtool omwlauncher;OMWLauncher mwiniimporter;MWiniImporter")
|
||||
SET(CPACK_DEBIAN_PACKAGE_DEPENDS "libboost-filesystem1.46.1 (>= 1.46.1), libboost-program-options1.46.1 (>= 1.46.1), libboost-system1.46.1 (>= 1.46.1), libboost-thread1.46.1 (>= 1.46.1), libc6 (>= 2.11.2), libfreetype6 (>= 2.2.1), libgcc1 (>= 1:4.1.1), libmpg123-0 (>= 1.12.1), libois-1.3.0 (>= 1.3.0), libopenal1 (>= 1:1.12.854), libsndfile1 (>= 1.0.23), libstdc++6 (>= 4.4.5), libuuid1 (>= 2.17.2), libqtgui4 (>= 4.7.0)")
|
||||
SET(CPACK_DEBIAN_PACKAGE_DEPENDS "libc6 (>= 2.11.2), libfreetype6 (>= 2.2.1), libgcc1 (>= 1:4.1.1), libmpg123-0 (>= 1.12.1), libois-1.3.0 (>= 1.3.0), libopenal1 (>= 1:1.12.854), libsndfile1 (>= 1.0.23), libstdc++6 (>= 4.4.5), libuuid1 (>= 2.17.2), libqtgui4 (>= 4.7.0)")
|
||||
|
||||
SET(CPACK_DEBIAN_PACKAGE_SECTION "Games")
|
||||
|
||||
|
@ -462,6 +462,10 @@ if (BUILD_MWINIIMPORTER)
|
|||
add_subdirectory( apps/mwiniimporter )
|
||||
endif()
|
||||
|
||||
if (BUILD_OPENCS)
|
||||
add_subdirectory (apps/opencs)
|
||||
endif()
|
||||
|
||||
# UnitTests
|
||||
if (BUILD_UNITTESTS)
|
||||
add_subdirectory( apps/openmw_test_suite )
|
||||
|
@ -525,7 +529,9 @@ if (WIN32)
|
|||
set_target_properties(omwlauncher PROPERTIES COMPILE_FLAGS ${WARNINGS})
|
||||
endif (BUILD_LAUNCHER)
|
||||
set_target_properties(openmw PROPERTIES COMPILE_FLAGS ${WARNINGS})
|
||||
set_target_properties(esmtool PROPERTIES COMPILE_FLAGS ${WARNINGS})
|
||||
if (BUILD_ESMTOOL)
|
||||
set_target_properties(esmtool PROPERTIES COMPILE_FLAGS ${WARNINGS})
|
||||
endif (BUILD_ESMTOOL)
|
||||
endif(MSVC)
|
||||
|
||||
# Same for MinGW
|
||||
|
|
99
DejaVu Font License.txt
Normal file
99
DejaVu Font License.txt
Normal file
|
@ -0,0 +1,99 @@
|
|||
Fonts are (c) Bitstream (see below). DejaVu changes are in public domain.
|
||||
Glyphs imported from Arev fonts are (c) Tavmjong Bah (see below)
|
||||
|
||||
Bitstream Vera Fonts Copyright
|
||||
------------------------------
|
||||
|
||||
Copyright (c) 2003 by Bitstream, Inc. All Rights Reserved. Bitstream Vera is
|
||||
a trademark of Bitstream, Inc.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of the fonts accompanying this license ("Fonts") and associated
|
||||
documentation files (the "Font Software"), to reproduce and distribute the
|
||||
Font Software, including without limitation the rights to use, copy, merge,
|
||||
publish, distribute, and/or sell copies of the Font Software, and to permit
|
||||
persons to whom the Font Software is furnished to do so, subject to the
|
||||
following conditions:
|
||||
|
||||
The above copyright and trademark notices and this permission notice shall
|
||||
be included in all copies of one or more of the Font Software typefaces.
|
||||
|
||||
The Font Software may be modified, altered, or added to, and in particular
|
||||
the designs of glyphs or characters in the Fonts may be modified and
|
||||
additional glyphs or characters may be added to the Fonts, only if the fonts
|
||||
are renamed to names not containing either the words "Bitstream" or the word
|
||||
"Vera".
|
||||
|
||||
This License becomes null and void to the extent applicable to Fonts or Font
|
||||
Software that has been modified and is distributed under the "Bitstream
|
||||
Vera" names.
|
||||
|
||||
The Font Software may be sold as part of a larger software package but no
|
||||
copy of one or more of the Font Software typefaces may be sold by itself.
|
||||
|
||||
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF COPYRIGHT, PATENT,
|
||||
TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL BITSTREAM OR THE GNOME
|
||||
FOUNDATION BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, INCLUDING
|
||||
ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES,
|
||||
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
|
||||
THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM OTHER DEALINGS IN THE
|
||||
FONT SOFTWARE.
|
||||
|
||||
Except as contained in this notice, the names of Gnome, the Gnome
|
||||
Foundation, and Bitstream Inc., shall not be used in advertising or
|
||||
otherwise to promote the sale, use or other dealings in this Font Software
|
||||
without prior written authorization from the Gnome Foundation or Bitstream
|
||||
Inc., respectively. For further information, contact: fonts at gnome dot
|
||||
org.
|
||||
|
||||
Arev Fonts Copyright
|
||||
------------------------------
|
||||
|
||||
Copyright (c) 2006 by Tavmjong Bah. All Rights Reserved.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of the fonts accompanying this license ("Fonts") and
|
||||
associated documentation files (the "Font Software"), to reproduce
|
||||
and distribute the modifications to the Bitstream Vera Font Software,
|
||||
including without limitation the rights to use, copy, merge, publish,
|
||||
distribute, and/or sell copies of the Font Software, and to permit
|
||||
persons to whom the Font Software is furnished to do so, subject to
|
||||
the following conditions:
|
||||
|
||||
The above copyright and trademark notices and this permission notice
|
||||
shall be included in all copies of one or more of the Font Software
|
||||
typefaces.
|
||||
|
||||
The Font Software may be modified, altered, or added to, and in
|
||||
particular the designs of glyphs or characters in the Fonts may be
|
||||
modified and additional glyphs or characters may be added to the
|
||||
Fonts, only if the fonts are renamed to names not containing either
|
||||
the words "Tavmjong Bah" or the word "Arev".
|
||||
|
||||
This License becomes null and void to the extent applicable to Fonts
|
||||
or Font Software that has been modified and is distributed under the
|
||||
"Tavmjong Bah Arev" names.
|
||||
|
||||
The Font Software may be sold as part of a larger software package but
|
||||
no copy of one or more of the Font Software typefaces may be sold by
|
||||
itself.
|
||||
|
||||
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
|
||||
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL
|
||||
TAVMJONG BAH BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
|
||||
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
|
||||
OTHER DEALINGS IN THE FONT SOFTWARE.
|
||||
|
||||
Except as contained in this notice, the name of Tavmjong Bah shall not
|
||||
be used in advertising or otherwise to promote the sale, use or other
|
||||
dealings in this Font Software without prior written authorization
|
||||
from Tavmjong Bah. For further information, contact: tavmjong @ free
|
||||
. fr.
|
||||
|
||||
$Id: LICENSE 2133 2007-11-28 02:46:28Z lechimp $
|
|
@ -59,7 +59,7 @@ struct Arguments
|
|||
std::string outname;
|
||||
|
||||
std::vector<std::string> types;
|
||||
|
||||
|
||||
ESMData data;
|
||||
ESM::ESMReader reader;
|
||||
ESM::ESMWriter writer;
|
||||
|
@ -74,7 +74,7 @@ bool parseOptions (int argc, char** argv, Arguments &info)
|
|||
("version,v", "print version information and quit.")
|
||||
("raw,r", "Show an unformatted list of all records and subrecords.")
|
||||
// The intention is that this option would interact better
|
||||
// with other modes including clone, dump, and raw.
|
||||
// with other modes including clone, dump, and raw.
|
||||
("type,t", bpo::value< std::vector<std::string> >(),
|
||||
"Show only records of this type (four character record code). May "
|
||||
"be specified multiple times. Only affects dump mode.")
|
||||
|
@ -165,23 +165,12 @@ bool parseOptions (int argc, char** argv, Arguments &info)
|
|||
|
||||
// Font encoding settings
|
||||
info.encoding = variables["encoding"].as<std::string>();
|
||||
if (info.encoding == "win1250")
|
||||
if(info.encoding != "win1250" && info.encoding != "win1251" && info.encoding != "win1252")
|
||||
{
|
||||
std::cout << "Using Central and Eastern European font encoding." << std::endl;
|
||||
}
|
||||
else if (info.encoding == "win1251")
|
||||
{
|
||||
std::cout << "Using Cyrillic font encoding." << std::endl;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(info.encoding != "win1252")
|
||||
{
|
||||
std::cout << info.encoding << " is not a valid encoding option." << std::endl;
|
||||
info.encoding = "win1252";
|
||||
}
|
||||
std::cout << "Using default (English) font encoding." << std::endl;
|
||||
std::cout << info.encoding << " is not a valid encoding option." << std::endl;
|
||||
info.encoding = "win1252";
|
||||
}
|
||||
std::cout << ToUTF8::encodingUsingMessage(info.encoding) << std::endl;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -265,7 +254,8 @@ void printRaw(ESM::ESMReader &esm)
|
|||
int load(Arguments& info)
|
||||
{
|
||||
ESM::ESMReader& esm = info.reader;
|
||||
esm.setEncoding(info.encoding);
|
||||
ToUTF8::Utf8Encoder encoder (ToUTF8::calculateEncoding(info.encoding));
|
||||
esm.setEncoder(&encoder);
|
||||
|
||||
std::string filename = info.filename;
|
||||
std::cout << "Loading file: " << filename << std::endl;
|
||||
|
@ -324,7 +314,7 @@ int load(Arguments& info)
|
|||
if (info.types.size() > 0)
|
||||
{
|
||||
std::vector<std::string>::iterator match;
|
||||
match = std::find(info.types.begin(), info.types.end(),
|
||||
match = std::find(info.types.begin(), info.types.end(),
|
||||
n.toString());
|
||||
if (match == info.types.end()) interested = false;
|
||||
}
|
||||
|
@ -428,14 +418,15 @@ int clone(Arguments& info)
|
|||
if (++i % 3 == 0)
|
||||
std::cout << std::endl;
|
||||
}
|
||||
|
||||
|
||||
if (i % 3 != 0)
|
||||
std::cout << std::endl;
|
||||
|
||||
std::cout << std::endl << "Saving records to: " << info.outname << "..." << std::endl;
|
||||
|
||||
ESM::ESMWriter& esm = info.writer;
|
||||
esm.setEncoding(info.encoding);
|
||||
ToUTF8::Utf8Encoder encoder (ToUTF8::calculateEncoding(info.encoding));
|
||||
esm.setEncoder(&encoder);
|
||||
esm.setAuthor(info.data.author);
|
||||
esm.setDescription(info.data.description);
|
||||
esm.setVersion(info.data.version);
|
||||
|
@ -453,7 +444,7 @@ int clone(Arguments& info)
|
|||
for (Records::iterator it = records.begin(); it != records.end() && i > 0; ++it)
|
||||
{
|
||||
EsmTool::RecordBase *record = *it;
|
||||
|
||||
|
||||
name.val = record->getType().val;
|
||||
|
||||
esm.startRecord(name.toString(), record->getFlags());
|
||||
|
@ -488,7 +479,7 @@ int clone(Arguments& info)
|
|||
std::cerr << "\r" << perc << "%";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
std::cout << "\rDone!" << std::endl;
|
||||
|
||||
esm.close();
|
||||
|
@ -516,7 +507,7 @@ int comp(Arguments& info)
|
|||
|
||||
fileOne.encoding = info.encoding;
|
||||
fileTwo.encoding = info.encoding;
|
||||
|
||||
|
||||
fileOne.filename = info.filename;
|
||||
fileTwo.filename = info.outname;
|
||||
|
||||
|
@ -537,9 +528,9 @@ int comp(Arguments& info)
|
|||
std::cout << "Not equal, different amount of records." << std::endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -738,7 +738,6 @@ void Record<ESM::GameSetting>::print()
|
|||
default:
|
||||
std::cout << "unknown type";
|
||||
}
|
||||
std::cout << "\n Dirty: " << mData.mDirty << std::endl;
|
||||
}
|
||||
|
||||
template<>
|
||||
|
|
|
@ -272,7 +272,8 @@ void DataFilesModel::addMasters(const QString &path)
|
|||
foreach (const QString &path, dir.entryList()) {
|
||||
try {
|
||||
ESM::ESMReader fileReader;
|
||||
fileReader.setEncoding(mEncoding.toStdString());
|
||||
ToUTF8::Utf8Encoder encoder (ToUTF8::calculateEncoding(mEncoding.toStdString()));
|
||||
fileReader.setEncoder(&encoder);
|
||||
fileReader.open(dir.absoluteFilePath(path).toStdString());
|
||||
|
||||
ESM::ESMReader::MasterList mlist = fileReader.getMasters();
|
||||
|
@ -335,7 +336,8 @@ void DataFilesModel::addPlugins(const QString &path)
|
|||
|
||||
try {
|
||||
ESM::ESMReader fileReader;
|
||||
fileReader.setEncoding(mEncoding.toStdString());
|
||||
ToUTF8::Utf8Encoder encoder (ToUTF8::calculateEncoding(mEncoding.toStdString()));
|
||||
fileReader.setEncoder(&encoder);
|
||||
fileReader.open(dir.absoluteFilePath(path).toStdString());
|
||||
|
||||
ESM::ESMReader::MasterList mlist = fileReader.getMasters();
|
||||
|
|
|
@ -7,6 +7,8 @@
|
|||
#include <vector>
|
||||
#include <algorithm>
|
||||
#include <sstream>
|
||||
#include <components/misc/stringops.hpp>
|
||||
|
||||
|
||||
MwIniImporter::MwIniImporter()
|
||||
: mVerbose(false)
|
||||
|
@ -18,8 +20,609 @@ MwIniImporter::MwIniImporter()
|
|||
{ 0, 0 }
|
||||
};
|
||||
const char *fallback[] = {
|
||||
|
||||
// light
|
||||
"LightAttenuation:UseConstant",
|
||||
"LightAttenuation:ConstantValue",
|
||||
"LightAttenuation:UseLinear",
|
||||
"LightAttenuation:LinearMethod",
|
||||
"LightAttenuation:LinearValue",
|
||||
"LightAttenuation:LinearRadiusMult",
|
||||
"LightAttenuation:UseQuadratic",
|
||||
"LightAttenuation:QuadraticMethod",
|
||||
"LightAttenuation:QuadraticValue",
|
||||
"LightAttenuation:QuadraticRadiusMult",
|
||||
"LightAttenuation:OutQuadInLin",
|
||||
|
||||
// inventory
|
||||
"Inventory:DirectionalDiffuseR",
|
||||
"Inventory:DirectionalDiffuseG",
|
||||
"Inventory:DirectionalDiffuseB",
|
||||
"Inventory:DirectionalAmbientR",
|
||||
"Inventory:DirectionalAmbientG",
|
||||
"Inventory:DirectionalAmbientB",
|
||||
"Inventory:DirectionalRotationX",
|
||||
"Inventory:DirectionalRotationY",
|
||||
"Inventory:UniformScaling",
|
||||
|
||||
// map
|
||||
"Map:Travel Siltstrider Red",
|
||||
"Map:Travel Siltstrider Green",
|
||||
"Map:Travel Siltstrider Blue",
|
||||
"Map:Travel Boat Red",
|
||||
"Map:Travel Boat Green",
|
||||
"Map:Travel Boat Blue",
|
||||
"Map:Travel Magic Red",
|
||||
"Map:Travel Magic Green",
|
||||
"Map:Travel Magic Blue",
|
||||
"Map:Show Travel Lines",
|
||||
|
||||
// water
|
||||
"Water:Map Alpha",
|
||||
"Water:World Alpha",
|
||||
"Water:SurfaceTextureSize",
|
||||
"Water:SurfaceTileCount",
|
||||
"Water:SurfaceFPS",
|
||||
"Water:SurfaceTexture",
|
||||
"Water:SurfaceFrameCount",
|
||||
"Water:TileTextureDivisor",
|
||||
"Water:RippleTexture",
|
||||
"Water:RippleFrameCount",
|
||||
"Water:RippleLifetime",
|
||||
"Water:MaxNumberRipples",
|
||||
"Water:RippleScale",
|
||||
"Water:RippleRotSpeed",
|
||||
"Water:RippleAlphas",
|
||||
"Water:PSWaterReflectTerrain",
|
||||
"Water:PSWaterReflectUpdate",
|
||||
"Water:NearWaterRadius",
|
||||
"Water:NearWaterPoints",
|
||||
"Water:NearWaterUnderwaterFreq",
|
||||
"Water:NearWaterUnderwaterVolume",
|
||||
"Water:NearWaterIndoorTolerance",
|
||||
"Water:NearWaterOutdoorTolerance",
|
||||
"Water:NearWaterIndoorID",
|
||||
"Water:NearWaterOutdoorID",
|
||||
"Water:UnderwaterSunriseFog",
|
||||
"Water:UnderwaterDayFog",
|
||||
"Water:UnderwaterSunsetFog",
|
||||
"Water:UnderwaterNightFog",
|
||||
"Water:UnderwaterIndoorFog",
|
||||
"Water:UnderwaterColor",
|
||||
"Water:UnderwaterColorWeight",
|
||||
|
||||
// pixelwater
|
||||
"PixelWater:SurfaceFPS",
|
||||
"PixelWater:TileCount",
|
||||
"PixelWater:Resolution",
|
||||
|
||||
// fonts
|
||||
"Fonts:Font 0",
|
||||
"Fonts:Font 1",
|
||||
"Fonts:Font 2",
|
||||
|
||||
// UI colors
|
||||
"FontColor:color_normal",
|
||||
"FontColor:color_normal_over",
|
||||
"FontColor:color_normal_pressed",
|
||||
"FontColor:color_active",
|
||||
"FontColor:color_active_over",
|
||||
"FontColor:color_active_pressed",
|
||||
"FontColor:color_disabled",
|
||||
"FontColor:color_disabled_over",
|
||||
"FontColor:color_disabled_pressed",
|
||||
"FontColor:color_link",
|
||||
"FontColor:color_link_over",
|
||||
"FontColor:color_link_pressed",
|
||||
"FontColor:color_journal_link",
|
||||
"FontColor:color_journal_link_over",
|
||||
"FontColor:color_journal_link_pressed",
|
||||
"FontColor:color_journal_topic",
|
||||
"FontColor:color_journal_topic_over",
|
||||
"FontColor:color_journal_topic_pressed",
|
||||
"FontColor:color_answer",
|
||||
"FontColor:color_answer_over",
|
||||
"FontColor:color_answer_pressed",
|
||||
"FontColor:color_header",
|
||||
"FontColor:color_notify",
|
||||
"FontColor:color_big_normal",
|
||||
"FontColor:color_big_normal_over",
|
||||
"FontColor:color_big_normal_pressed",
|
||||
"FontColor:color_big_link",
|
||||
"FontColor:color_big_link_over",
|
||||
"FontColor:color_big_link_pressed",
|
||||
"FontColor:color_big_answer",
|
||||
"FontColor:color_big_answer_over",
|
||||
"FontColor:color_big_answer_pressed",
|
||||
"FontColor:color_big_header",
|
||||
"FontColor:color_big_notify",
|
||||
"FontColor:color_background",
|
||||
"FontColor:color_focus",
|
||||
"FontColor:color_health",
|
||||
"FontColor:color_magic",
|
||||
"FontColor:color_fatigue",
|
||||
"FontColor:color_misc",
|
||||
"FontColor:color_weapon_fill",
|
||||
"FontColor:color_magic_fill",
|
||||
"FontColor:color_positive",
|
||||
"FontColor:color_negative",
|
||||
"FontColor:color_count",
|
||||
|
||||
// level up messages
|
||||
"Level Up:Level2",
|
||||
"Level Up:Level3",
|
||||
"Level Up:Level4",
|
||||
"Level Up:Level5",
|
||||
"Level Up:Level6",
|
||||
"Level Up:Level7",
|
||||
"Level Up:Level8",
|
||||
"Level Up:Level9",
|
||||
"Level Up:Level10",
|
||||
"Level Up:Level11",
|
||||
"Level Up:Level12",
|
||||
"Level Up:Level13",
|
||||
"Level Up:Level14",
|
||||
"Level Up:Level15",
|
||||
"Level Up:Level16",
|
||||
"Level Up:Level17",
|
||||
"Level Up:Level18",
|
||||
"Level Up:Level19",
|
||||
"Level Up:Level20",
|
||||
"Level Up:Default",
|
||||
|
||||
// character creation multiple choice test
|
||||
"Question 1:Question",
|
||||
"Question 1:AnswerOne",
|
||||
"Question 1:AnswerTwo",
|
||||
"Question 1:AnswerThree",
|
||||
"Question 1:Sound",
|
||||
"Question 2:Question",
|
||||
"Question 2:AnswerOne",
|
||||
"Question 2:AnswerTwo",
|
||||
"Question 2:AnswerThree",
|
||||
"Question 2:Sound",
|
||||
"Question 3:Question",
|
||||
"Question 3:AnswerOne",
|
||||
"Question 3:AnswerTwo",
|
||||
"Question 3:AnswerThree",
|
||||
"Question 3:Sound",
|
||||
"Question 4:Question",
|
||||
"Question 4:AnswerOne",
|
||||
"Question 4:AnswerTwo",
|
||||
"Question 4:AnswerThree",
|
||||
"Question 4:Sound",
|
||||
"Question 5:Question",
|
||||
"Question 5:AnswerOne",
|
||||
"Question 5:AnswerTwo",
|
||||
"Question 5:AnswerThree",
|
||||
"Question 5:Sound",
|
||||
"Question 6:Question",
|
||||
"Question 6:AnswerOne",
|
||||
"Question 6:AnswerTwo",
|
||||
"Question 6:AnswerThree",
|
||||
"Question 6:Sound",
|
||||
"Question 7:Question",
|
||||
"Question 7:AnswerOne",
|
||||
"Question 7:AnswerTwo",
|
||||
"Question 7:AnswerThree",
|
||||
"Question 7:Sound",
|
||||
"Question 8:Question",
|
||||
"Question 8:AnswerOne",
|
||||
"Question 8:AnswerTwo",
|
||||
"Question 8:AnswerThree",
|
||||
"Question 8:Sound",
|
||||
"Question 9:Question",
|
||||
"Question 9:AnswerOne",
|
||||
"Question 9:AnswerTwo",
|
||||
"Question 9:AnswerThree",
|
||||
"Question 9:Sound",
|
||||
"Question 10:Question",
|
||||
"Question 10:AnswerOne",
|
||||
"Question 10:AnswerTwo",
|
||||
"Question 10:AnswerThree",
|
||||
"Question 10:Sound",
|
||||
|
||||
// blood textures and models
|
||||
"Blood:Model 0",
|
||||
"Blood:Model 1",
|
||||
"Blood:Model 2",
|
||||
"Blood:Texture 0",
|
||||
"Blood:Texture 1",
|
||||
"Blood:Texture 2",
|
||||
"Blood:Texture Name 0",
|
||||
"Blood:Texture Name 1",
|
||||
"Blood:Texture Name 2",
|
||||
|
||||
// movies
|
||||
"Movies:Company Logo",
|
||||
"Movies:Morrowind Logo",
|
||||
"Movies:New Game",
|
||||
"Movies:Loading",
|
||||
"Movies:Options Menu",
|
||||
|
||||
// weather related values
|
||||
|
||||
"Weather Thunderstorm:Thunder Sound ID 0",
|
||||
"Weather Thunderstorm:Thunder Sound ID 1",
|
||||
"Weather Thunderstorm:Thunder Sound ID 2",
|
||||
"Weather Thunderstorm:Thunder Sound ID 3",
|
||||
"Weather:Sunrise Time",
|
||||
"Weather:Sunset Time",
|
||||
"Weather:Sunrise Duration",
|
||||
"Weather:Sunset Duration",
|
||||
"Weather:Hours Between Weather Changes", // AKA weather update time
|
||||
"Weather Thunderstorm:Thunder Frequency",
|
||||
"Weather Thunderstorm:Thunder Threshold",
|
||||
|
||||
"Weather:EnvReduceColor",
|
||||
"Weather:LerpCloseColor",
|
||||
"Weather:BumpFadeColor",
|
||||
"Weather:AlphaReduce",
|
||||
"Weather:Minimum Time Between Environmental Sounds",
|
||||
"Weather:Maximum Time Between Environmental Sounds",
|
||||
"Weather:Sun Glare Fader Max",
|
||||
"Weather:Sun Glare Fader Angle Max",
|
||||
"Weather:Sun Glare Fader Color",
|
||||
"Weather:Timescale Clouds",
|
||||
"Weather:Precip Gravity",
|
||||
"Weather:Rain Ripples",
|
||||
"Weather:Rain Ripple Radius",
|
||||
"Weather:Rain Ripples Per Drop",
|
||||
"Weather:Rain Ripple Scale",
|
||||
"Weather:Rain Ripple Speed",
|
||||
"Weather:Fog Depth Change Speed",
|
||||
"Weather:Sky Pre-Sunrise Time",
|
||||
"Weather:Sky Post-Sunrise Time",
|
||||
"Weather:Sky Pre-Sunset Time",
|
||||
"Weather:Sky Post-Sunset Time",
|
||||
"Weather:Ambient Pre-Sunrise Time",
|
||||
"Weather:Ambient Post-Sunrise Time",
|
||||
"Weather:Ambient Pre-Sunset Time",
|
||||
"Weather:Ambient Post-Sunset Time",
|
||||
"Weather:Fog Pre-Sunrise Time",
|
||||
"Weather:Fog Post-Sunrise Time",
|
||||
"Weather:Fog Pre-Sunset Time",
|
||||
"Weather:Fog Post-Sunset Time",
|
||||
"Weather:Sun Pre-Sunrise Time",
|
||||
"Weather:Sun Post-Sunrise Time",
|
||||
"Weather:Sun Pre-Sunset Time",
|
||||
"Weather:Sun Post-Sunset Time",
|
||||
"Weather:Stars Post-Sunset Start",
|
||||
"Weather:Stars Pre-Sunrise Finish",
|
||||
"Weather:Stars Fading Duration",
|
||||
"Weather:Snow Ripples",
|
||||
"Weather:Snow Ripple Radius",
|
||||
"Weather:Snow Ripples Per Flake",
|
||||
"Weather:Snow Ripple Scale",
|
||||
"Weather:Snow Ripple Speed",
|
||||
"Weather:Snow Gravity Scale",
|
||||
"Weather:Snow High Kill",
|
||||
"Weather:Snow Low Kill",
|
||||
|
||||
"Weather Clear:Cloud Texture",
|
||||
"Weather Clear:Clouds Maximum Percent",
|
||||
"Weather Clear:Transition Delta",
|
||||
"Weather Clear:Sky Sunrise Color",
|
||||
"Weather Clear:Sky Day Color",
|
||||
"Weather Clear:Sky Sunset Color",
|
||||
"Weather Clear:Sky Night Color",
|
||||
"Weather Clear:Fog Sunrise Color",
|
||||
"Weather Clear:Fog Day Color",
|
||||
"Weather Clear:Fog Sunset Color",
|
||||
"Weather Clear:Fog Night Color",
|
||||
"Weather Clear:Ambient Sunrise Color",
|
||||
"Weather Clear:Ambient Day Color",
|
||||
"Weather Clear:Ambient Sunset Color",
|
||||
"Weather Clear:Ambient Night Color",
|
||||
"Weather Clear:Sun Sunrise Color",
|
||||
"Weather Clear:Sun Day Color",
|
||||
"Weather Clear:Sun Sunset Color",
|
||||
"Weather Clear:Sun Night Color",
|
||||
"Weather Clear:Sun Disc Sunset Color",
|
||||
"Weather Clear:Land Fog Day Depth",
|
||||
"Weather Clear:Land Fog Night Depth",
|
||||
"Weather Clear:Wind Speed",
|
||||
"Weather Clear:Cloud Speed",
|
||||
"Weather Clear:Glare View",
|
||||
"Weather Clear:Ambient Loop Sound ID",
|
||||
|
||||
"Weather Cloudy:Cloud Texture",
|
||||
"Weather Cloudy:Clouds Maximum Percent",
|
||||
"Weather Cloudy:Transition Delta",
|
||||
"Weather Cloudy:Sky Sunrise Color",
|
||||
"Weather Cloudy:Sky Day Color",
|
||||
"Weather Cloudy:Sky Sunset Color",
|
||||
"Weather Cloudy:Sky Night Color",
|
||||
"Weather Cloudy:Fog Sunrise Color",
|
||||
"Weather Cloudy:Fog Day Color",
|
||||
"Weather Cloudy:Fog Sunset Color",
|
||||
"Weather Cloudy:Fog Night Color",
|
||||
"Weather Cloudy:Ambient Sunrise Color",
|
||||
"Weather Cloudy:Ambient Day Color",
|
||||
"Weather Cloudy:Ambient Sunset Color",
|
||||
"Weather Cloudy:Ambient Night Color",
|
||||
"Weather Cloudy:Sun Sunrise Color",
|
||||
"Weather Cloudy:Sun Day Color",
|
||||
"Weather Cloudy:Sun Sunset Color",
|
||||
"Weather Cloudy:Sun Night Color",
|
||||
"Weather Cloudy:Sun Disc Sunset Color",
|
||||
"Weather Cloudy:Land Fog Day Depth",
|
||||
"Weather Cloudy:Land Fog Night Depth",
|
||||
"Weather Cloudy:Wind Speed",
|
||||
"Weather Cloudy:Cloud Speed",
|
||||
"Weather Cloudy:Glare View",
|
||||
"Weather Cloudy:Ambient Loop Sound ID",
|
||||
|
||||
"Weather Foggy:Cloud Texture",
|
||||
"Weather Foggy:Clouds Maximum Percent",
|
||||
"Weather Foggy:Transition Delta",
|
||||
"Weather Foggy:Sky Sunrise Color",
|
||||
"Weather Foggy:Sky Day Color",
|
||||
"Weather Foggy:Sky Sunset Color",
|
||||
"Weather Foggy:Sky Night Color",
|
||||
"Weather Foggy:Fog Sunrise Color",
|
||||
"Weather Foggy:Fog Day Color",
|
||||
"Weather Foggy:Fog Sunset Color",
|
||||
"Weather Foggy:Fog Night Color",
|
||||
"Weather Foggy:Ambient Sunrise Color",
|
||||
"Weather Foggy:Ambient Day Color",
|
||||
"Weather Foggy:Ambient Sunset Color",
|
||||
"Weather Foggy:Ambient Night Color",
|
||||
"Weather Foggy:Sun Sunrise Color",
|
||||
"Weather Foggy:Sun Day Color",
|
||||
"Weather Foggy:Sun Sunset Color",
|
||||
"Weather Foggy:Sun Night Color",
|
||||
"Weather Foggy:Sun Disc Sunset Color",
|
||||
"Weather Foggy:Land Fog Day Depth",
|
||||
"Weather Foggy:Land Fog Night Depth",
|
||||
"Weather Foggy:Wind Speed",
|
||||
"Weather Foggy:Cloud Speed",
|
||||
"Weather Foggy:Glare View",
|
||||
"Weather Foggy:Ambient Loop Sound ID",
|
||||
|
||||
"Weather Thunderstorm:Cloud Texture",
|
||||
"Weather Thunderstorm:Clouds Maximum Percent",
|
||||
"Weather Thunderstorm:Transition Delta",
|
||||
"Weather Thunderstorm:Sky Sunrise Color",
|
||||
"Weather Thunderstorm:Sky Day Color",
|
||||
"Weather Thunderstorm:Sky Sunset Color",
|
||||
"Weather Thunderstorm:Sky Night Color",
|
||||
"Weather Thunderstorm:Fog Sunrise Color",
|
||||
"Weather Thunderstorm:Fog Day Color",
|
||||
"Weather Thunderstorm:Fog Sunset Color",
|
||||
"Weather Thunderstorm:Fog Night Color",
|
||||
"Weather Thunderstorm:Ambient Sunrise Color",
|
||||
"Weather Thunderstorm:Ambient Day Color",
|
||||
"Weather Thunderstorm:Ambient Sunset Color",
|
||||
"Weather Thunderstorm:Ambient Night Color",
|
||||
"Weather Thunderstorm:Sun Sunrise Color",
|
||||
"Weather Thunderstorm:Sun Day Color",
|
||||
"Weather Thunderstorm:Sun Sunset Color",
|
||||
"Weather Thunderstorm:Sun Night Color",
|
||||
"Weather Thunderstorm:Sun Disc Sunset Color",
|
||||
"Weather Thunderstorm:Land Fog Day Depth",
|
||||
"Weather Thunderstorm:Land Fog Night Depth",
|
||||
"Weather Thunderstorm:Wind Speed",
|
||||
"Weather Thunderstorm:Cloud Speed",
|
||||
"Weather Thunderstorm:Glare View",
|
||||
"Weather Thunderstorm:Rain Loop Sound ID",
|
||||
"Weather Thunderstorm:Using Precip",
|
||||
"Weather Thunderstorm:Rain Diameter",
|
||||
"Weather Thunderstorm:Rain Height Min",
|
||||
"Weather Thunderstorm:Rain Height Max",
|
||||
"Weather Thunderstorm:Rain Threshold",
|
||||
"Weather Thunderstorm:Max Raindrops",
|
||||
"Weather Thunderstorm:Rain Entrance Speed",
|
||||
"Weather Thunderstorm:Ambient Loop Sound ID",
|
||||
"Weather Thunderstorm:Flash Decrement",
|
||||
|
||||
"Weather Rain:Cloud Texture",
|
||||
"Weather Rain:Clouds Maximum Percent",
|
||||
"Weather Rain:Transition Delta",
|
||||
"Weather Rain:Sky Sunrise Color",
|
||||
"Weather Rain:Sky Day Color",
|
||||
"Weather Rain:Sky Sunset Color",
|
||||
"Weather Rain:Sky Night Color",
|
||||
"Weather Rain:Fog Sunrise Color",
|
||||
"Weather Rain:Fog Day Color",
|
||||
"Weather Rain:Fog Sunset Color",
|
||||
"Weather Rain:Fog Night Color",
|
||||
"Weather Rain:Ambient Sunrise Color",
|
||||
"Weather Rain:Ambient Day Color",
|
||||
"Weather Rain:Ambient Sunset Color",
|
||||
"Weather Rain:Ambient Night Color",
|
||||
"Weather Rain:Sun Sunrise Color",
|
||||
"Weather Rain:Sun Day Color",
|
||||
"Weather Rain:Sun Sunset Color",
|
||||
"Weather Rain:Sun Night Color",
|
||||
"Weather Rain:Sun Disc Sunset Color",
|
||||
"Weather Rain:Land Fog Day Depth",
|
||||
"Weather Rain:Land Fog Night Depth",
|
||||
"Weather Rain:Wind Speed",
|
||||
"Weather Rain:Cloud Speed",
|
||||
"Weather Rain:Glare View",
|
||||
"Weather Rain:Rain Loop Sound ID",
|
||||
"Weather Rain:Using Precip",
|
||||
"Weather Rain:Rain Diameter",
|
||||
"Weather Rain:Rain Height Min",
|
||||
"Weather Rain:Rain Height Max",
|
||||
"Weather Rain:Rain Threshold",
|
||||
"Weather Rain:Rain Entrance Speed",
|
||||
"Weather Rain:Ambient Loop Sound ID",
|
||||
"Weather Rain:Max Raindrops",
|
||||
|
||||
"Weather Overcast:Cloud Texture",
|
||||
"Weather Overcast:Clouds Maximum Percent",
|
||||
"Weather Overcast:Transition Delta",
|
||||
"Weather Overcast:Sky Sunrise Color",
|
||||
"Weather Overcast:Sky Day Color",
|
||||
"Weather Overcast:Sky Sunset Color",
|
||||
"Weather Overcast:Sky Night Color",
|
||||
"Weather Overcast:Fog Sunrise Color",
|
||||
"Weather Overcast:Fog Day Color",
|
||||
"Weather Overcast:Fog Sunset Color",
|
||||
"Weather Overcast:Fog Night Color",
|
||||
"Weather Overcast:Ambient Sunrise Color",
|
||||
"Weather Overcast:Ambient Day Color",
|
||||
"Weather Overcast:Ambient Sunset Color",
|
||||
"Weather Overcast:Ambient Night Color",
|
||||
"Weather Overcast:Sun Sunrise Color",
|
||||
"Weather Overcast:Sun Day Color",
|
||||
"Weather Overcast:Sun Sunset Color",
|
||||
"Weather Overcast:Sun Night Color",
|
||||
"Weather Overcast:Sun Disc Sunset Color",
|
||||
"Weather Overcast:Land Fog Day Depth",
|
||||
"Weather Overcast:Land Fog Night Depth",
|
||||
"Weather Overcast:Wind Speed",
|
||||
"Weather Overcast:Cloud Speed",
|
||||
"Weather Overcast:Glare View",
|
||||
"Weather Overcast:Ambient Loop Sound ID",
|
||||
|
||||
"Weather Ashstorm:Cloud Texture",
|
||||
"Weather Ashstorm:Clouds Maximum Percent",
|
||||
"Weather Ashstorm:Transition Delta",
|
||||
"Weather Ashstorm:Sky Sunrise Color",
|
||||
"Weather Ashstorm:Sky Day Color",
|
||||
"Weather Ashstorm:Sky Sunset Color",
|
||||
"Weather Ashstorm:Sky Night Color",
|
||||
"Weather Ashstorm:Fog Sunrise Color",
|
||||
"Weather Ashstorm:Fog Day Color",
|
||||
"Weather Ashstorm:Fog Sunset Color",
|
||||
"Weather Ashstorm:Fog Night Color",
|
||||
"Weather Ashstorm:Ambient Sunrise Color",
|
||||
"Weather Ashstorm:Ambient Day Color",
|
||||
"Weather Ashstorm:Ambient Sunset Color",
|
||||
"Weather Ashstorm:Ambient Night Color",
|
||||
"Weather Ashstorm:Sun Sunrise Color",
|
||||
"Weather Ashstorm:Sun Day Color",
|
||||
"Weather Ashstorm:Sun Sunset Color",
|
||||
"Weather Ashstorm:Sun Night Color",
|
||||
"Weather Ashstorm:Sun Disc Sunset Color",
|
||||
"Weather Ashstorm:Land Fog Day Depth",
|
||||
"Weather Ashstorm:Land Fog Night Depth",
|
||||
"Weather Ashstorm:Wind Speed",
|
||||
"Weather Ashstorm:Cloud Speed",
|
||||
"Weather Ashstorm:Glare View",
|
||||
"Weather Ashstorm:Ambient Loop Sound ID",
|
||||
"Weather Ashstorm:Storm Threshold",
|
||||
|
||||
"Weather Blight:Cloud Texture",
|
||||
"Weather Blight:Clouds Maximum Percent",
|
||||
"Weather Blight:Transition Delta",
|
||||
"Weather Blight:Sky Sunrise Color",
|
||||
"Weather Blight:Sky Day Color",
|
||||
"Weather Blight:Sky Sunset Color",
|
||||
"Weather Blight:Sky Night Color",
|
||||
"Weather Blight:Fog Sunrise Color",
|
||||
"Weather Blight:Fog Day Color",
|
||||
"Weather Blight:Fog Sunset Color",
|
||||
"Weather Blight:Fog Night Color",
|
||||
"Weather Blight:Ambient Sunrise Color",
|
||||
"Weather Blight:Ambient Day Color",
|
||||
"Weather Blight:Ambient Sunset Color",
|
||||
"Weather Blight:Ambient Night Color",
|
||||
"Weather Blight:Sun Sunrise Color",
|
||||
"Weather Blight:Sun Day Color",
|
||||
"Weather Blight:Sun Sunset Color",
|
||||
"Weather Blight:Sun Night Color",
|
||||
"Weather Blight:Sun Disc Sunset Color",
|
||||
"Weather Blight:Land Fog Day Depth",
|
||||
"Weather Blight:Land Fog Night Depth",
|
||||
"Weather Blight:Wind Speed",
|
||||
"Weather Blight:Cloud Speed",
|
||||
"Weather Blight:Glare View",
|
||||
"Weather Blight:Ambient Loop Sound ID",
|
||||
"Weather Blight:Storm Threshold",
|
||||
"Weather Blight:Disease Chance",
|
||||
|
||||
// for Bloodmoon
|
||||
"Weather Snow:Cloud Texture",
|
||||
"Weather Snow:Clouds Maximum Percent",
|
||||
"Weather Snow:Transition Delta",
|
||||
"Weather Snow:Sky Sunrise Color",
|
||||
"Weather Snow:Sky Day Color",
|
||||
"Weather Snow:Sky Sunset Color",
|
||||
"Weather Snow:Sky Night Color",
|
||||
"Weather Snow:Fog Sunrise Color",
|
||||
"Weather Snow:Fog Day Color",
|
||||
"Weather Snow:Fog Sunset Color",
|
||||
"Weather Snow:Fog Night Color",
|
||||
"Weather Snow:Ambient Sunrise Color",
|
||||
"Weather Snow:Ambient Day Color",
|
||||
"Weather Snow:Ambient Sunset Color",
|
||||
"Weather Snow:Ambient Night Color",
|
||||
"Weather Snow:Sun Sunrise Color",
|
||||
"Weather Snow:Sun Day Color",
|
||||
"Weather Snow:Sun Sunset Color",
|
||||
"Weather Snow:Sun Night Color",
|
||||
"Weather Snow:Sun Disc Sunset Color",
|
||||
"Weather Snow:Land Fog Day Depth",
|
||||
"Weather Snow:Land Fog Night Depth",
|
||||
"Weather Snow:Wind Speed",
|
||||
"Weather Snow:Cloud Speed",
|
||||
"Weather Snow:Glare View",
|
||||
"Weather Snow:Snow Diameter",
|
||||
"Weather Snow:Snow Height Min",
|
||||
"Weather Snow:Snow Height Max",
|
||||
"Weather Snow:Snow Entrance Speed",
|
||||
"Weather Snow:Max Snowflakes",
|
||||
"Weather Snow:Ambient Loop Sound ID",
|
||||
"Weather Snow:Snow Threshold",
|
||||
|
||||
// for Bloodmoon
|
||||
"Weather Blizzard:Cloud Texture",
|
||||
"Weather Blizzard:Clouds Maximum Percent",
|
||||
"Weather Blizzard:Transition Delta",
|
||||
"Weather Blizzard:Sky Sunrise Color",
|
||||
"Weather Blizzard:Sky Day Color",
|
||||
"Weather Blizzard:Sky Sunset Color",
|
||||
"Weather Blizzard:Sky Night Color",
|
||||
"Weather Blizzard:Fog Sunrise Color",
|
||||
"Weather Blizzard:Fog Day Color",
|
||||
"Weather Blizzard:Fog Sunset Color",
|
||||
"Weather Blizzard:Fog Night Color",
|
||||
"Weather Blizzard:Ambient Sunrise Color",
|
||||
"Weather Blizzard:Ambient Day Color",
|
||||
"Weather Blizzard:Ambient Sunset Color",
|
||||
"Weather Blizzard:Ambient Night Color",
|
||||
"Weather Blizzard:Sun Sunrise Color",
|
||||
"Weather Blizzard:Sun Day Color",
|
||||
"Weather Blizzard:Sun Sunset Color",
|
||||
"Weather Blizzard:Sun Night Color",
|
||||
"Weather Blizzard:Sun Disc Sunset Color",
|
||||
"Weather Blizzard:Land Fog Day Depth",
|
||||
"Weather Blizzard:Land Fog Night Depth",
|
||||
"Weather Blizzard:Wind Speed",
|
||||
"Weather Blizzard:Cloud Speed",
|
||||
"Weather Blizzard:Glare View",
|
||||
"Weather Blizzard:Ambient Loop Sound ID",
|
||||
"Weather Blizzard:Storm Threshold",
|
||||
|
||||
// moons
|
||||
"Moons:Secunda Size",
|
||||
"Moons:Secunda Axis Offset",
|
||||
"Moons:Secunda Speed",
|
||||
"Moons:Secunda Daily Increment",
|
||||
"Moons:Secunda Moon Shadow Early Fade Angle",
|
||||
"Moons:Secunda Fade Start Angle",
|
||||
"Moons:Secunda Fade End Angle",
|
||||
"Moons:Secunda Fade In Start",
|
||||
"Moons:Secunda Fade In Finish",
|
||||
"Moons:Secunda Fade Out Start",
|
||||
"Moons:Secunda Fade Out Finish",
|
||||
"Moons:Masser Size",
|
||||
"Moons:Masser Axis Offset",
|
||||
"Moons:Masser Speed",
|
||||
"Moons:Masser Daily Increment",
|
||||
"Moons:Masser Moon Shadow Early Fade Angle",
|
||||
"Moons:Masser Fade Start Angle",
|
||||
"Moons:Masser Fade End Angle",
|
||||
"Moons:Masser Fade In Start",
|
||||
"Moons:Masser Fade In Finish",
|
||||
"Moons:Masser Fade Out Start",
|
||||
"Moons:Masser Fade Out Finish",
|
||||
"Moons:Script Color",
|
||||
|
||||
0
|
||||
};
|
||||
|
||||
|
@ -48,14 +651,26 @@ MwIniImporter::multistrmap MwIniImporter::loadIniFile(std::string filename) {
|
|||
std::string section("");
|
||||
MwIniImporter::multistrmap map;
|
||||
boost::iostreams::stream<boost::iostreams::file_source>file(filename.c_str());
|
||||
ToUTF8::Utf8Encoder encoder(mEncoding);
|
||||
|
||||
std::string line;
|
||||
while (std::getline(file, line)) {
|
||||
|
||||
line = encoder.getUtf8(line);
|
||||
|
||||
// unify Unix-style and Windows file ending
|
||||
if (!(line.empty()) && (line[line.length()-1]) == '\r') {
|
||||
line = line.substr(0, line.length()-1);
|
||||
}
|
||||
|
||||
if(line[0] == '[') {
|
||||
if(line.length() > 2) {
|
||||
section = line.substr(1, line.length()-3);
|
||||
int pos = line.find(']');
|
||||
if(pos < 2) {
|
||||
std::cout << "Warning: ini file wrongly formatted (" << line << "). Line ignored." << std::endl;
|
||||
continue;
|
||||
}
|
||||
|
||||
section = line.substr(1, line.find(']')-1);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -147,7 +762,7 @@ void MwIniImporter::mergeFallback(multistrmap &cfg, multistrmap &ini) {
|
|||
std::string value(*it);
|
||||
std::replace( value.begin(), value.end(), ' ', '_' );
|
||||
std::replace( value.begin(), value.end(), ':', '_' );
|
||||
value.append(",").append(vc->substr(0,vc->length()-1));
|
||||
value.append(",").append(vc->substr(0,vc->length()));
|
||||
insertMultistrmap(cfg, "fallback", value);
|
||||
}
|
||||
}
|
||||
|
@ -180,7 +795,7 @@ void MwIniImporter::importGameFiles(multistrmap &cfg, multistrmap &ini) {
|
|||
|
||||
for(std::vector<std::string>::iterator entry = it->second.begin(); entry!=it->second.end(); ++entry) {
|
||||
std::string filetype(entry->substr(entry->length()-4, 3));
|
||||
std::transform(filetype.begin(), filetype.end(), filetype.begin(), ::tolower);
|
||||
Misc::StringUtils::toLower(filetype);
|
||||
|
||||
if(filetype.compare("esm") == 0) {
|
||||
esmFiles.push_back(*entry);
|
||||
|
@ -216,3 +831,8 @@ void MwIniImporter::writeToFile(boost::iostreams::stream<boost::iostreams::file_
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MwIniImporter::setInputEncoding(const ToUTF8::FromType &encoding)
|
||||
{
|
||||
mEncoding = encoding;
|
||||
}
|
||||
|
|
|
@ -8,12 +8,15 @@
|
|||
#include <vector>
|
||||
#include <exception>
|
||||
|
||||
#include <components/to_utf8/to_utf8.hpp>
|
||||
|
||||
class MwIniImporter {
|
||||
public:
|
||||
typedef std::map<std::string, std::string> strmap;
|
||||
typedef std::map<std::string, std::vector<std::string> > multistrmap;
|
||||
|
||||
MwIniImporter();
|
||||
void setInputEncoding(const ToUTF8::FromType& encoding);
|
||||
void setVerbose(bool verbose);
|
||||
multistrmap loadIniFile(std::string filename);
|
||||
multistrmap loadCfgFile(std::string filename);
|
||||
|
@ -25,9 +28,11 @@ class MwIniImporter {
|
|||
private:
|
||||
void insertMultistrmap(multistrmap &cfg, std::string key, std::string value);
|
||||
std::string numberToString(int n);
|
||||
std::string toUTF8(const std::string &str);
|
||||
bool mVerbose;
|
||||
strmap mMergeMap;
|
||||
std::vector<std::string> mMergeFallback;
|
||||
ToUTF8::FromType mEncoding;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -18,6 +18,11 @@ int main(int argc, char *argv[]) {
|
|||
("cfg,c", bpo::value<std::string>(), "openmw.cfg file")
|
||||
("output,o", bpo::value<std::string>()->default_value(""), "openmw.cfg file")
|
||||
("game-files,g", "import esm and esp files")
|
||||
("encoding,e", bpo::value<std::string>()-> default_value("win1252"),
|
||||
"Character encoding used in OpenMW game messages:\n"
|
||||
"\n\twin1250 - Central and Eastern European such as Polish, Czech, Slovak, Hungarian, Slovene, Bosnian, Croatian, Serbian (Latin script), Romanian and Albanian languages\n"
|
||||
"\n\twin1251 - Cyrillic alphabet such as Russian, Bulgarian, Serbian Cyrillic and other languages\n"
|
||||
"\n\twin1252 - Western European (Latin) alphabet, used by default")
|
||||
;
|
||||
p_desc.add("ini", 1).add("cfg", 1);
|
||||
|
||||
|
@ -57,6 +62,10 @@ int main(int argc, char *argv[]) {
|
|||
MwIniImporter importer;
|
||||
importer.setVerbose(vm.count("verbose"));
|
||||
|
||||
// Font encoding settings
|
||||
std::string encoding(vm["encoding"].as<std::string>());
|
||||
importer.setInputEncoding(ToUTF8::calculateEncoding(encoding));
|
||||
|
||||
MwIniImporter::multistrmap ini = importer.loadIniFile(iniFile);
|
||||
MwIniImporter::multistrmap cfg = importer.loadCfgFile(cfgFile);
|
||||
|
||||
|
|
76
apps/opencs/CMakeLists.txt
Normal file
76
apps/opencs/CMakeLists.txt
Normal file
|
@ -0,0 +1,76 @@
|
|||
|
||||
set (OPENCS_SRC
|
||||
main.cpp editor.cpp
|
||||
|
||||
model/doc/documentmanager.cpp model/doc/document.cpp
|
||||
|
||||
model/world/universalid.cpp model/world/idcollection.cpp model/world/data.cpp model/world/idtable.cpp
|
||||
model/world/commands.cpp model/world/idtableproxymodel.cpp model/world/record.cpp
|
||||
model/world/columnbase.cpp
|
||||
|
||||
model/tools/tools.cpp model/tools/operation.cpp model/tools/stage.cpp model/tools/verifier.cpp
|
||||
model/tools/mandatoryid.cpp model/tools/reportmodel.cpp
|
||||
|
||||
view/doc/viewmanager.cpp view/doc/view.cpp view/doc/operations.cpp view/doc/operation.cpp view/doc/subviewfactory.cpp
|
||||
view/doc/subview.cpp
|
||||
|
||||
view/world/table.cpp view/world/tablesubview.cpp view/world/subviews.cpp view/world/util.cpp
|
||||
view/world/dialoguesubview.cpp
|
||||
|
||||
view/tools/reportsubview.cpp view/tools/subviews.cpp
|
||||
)
|
||||
|
||||
set (OPENCS_HDR
|
||||
editor.hpp
|
||||
|
||||
model/doc/documentmanager.hpp model/doc/document.hpp model/doc/state.hpp
|
||||
|
||||
model/world/universalid.hpp model/world/record.hpp model/world/idcollection.hpp model/world/data.hpp
|
||||
model/world/idtable.hpp model/world/columns.hpp model/world/idtableproxymodel.hpp
|
||||
model/world/commands.hpp model/world/columnbase.hpp
|
||||
|
||||
model/tools/tools.hpp model/tools/operation.hpp model/tools/stage.hpp model/tools/verifier.hpp
|
||||
model/tools/mandatoryid.hpp model/tools/reportmodel.hpp
|
||||
|
||||
view/doc/viewmanager.hpp view/doc/view.hpp view/doc/operations.hpp view/doc/operation.hpp view/doc/subviewfactory.hpp
|
||||
view/doc/subview.hpp view/doc/subviewfactoryimp.hpp
|
||||
|
||||
view/world/table.hpp view/world/tablesubview.hpp view/world/subviews.hpp view/world/util.hpp
|
||||
view/world/dialoguesubview.hpp
|
||||
|
||||
view/tools/reportsubview.hpp view/tools/subviews.hpp
|
||||
)
|
||||
|
||||
set (OPENCS_US
|
||||
)
|
||||
|
||||
set (OPENCS_RES
|
||||
)
|
||||
|
||||
source_group (opencs FILES ${OPENCS_SRC} ${OPENCS_HDR})
|
||||
|
||||
if(WIN32)
|
||||
set(QT_USE_QTMAIN TRUE)
|
||||
endif(WIN32)
|
||||
|
||||
find_package(Qt4 COMPONENTS QtCore QtGui QtXml QtXmlPatterns REQUIRED)
|
||||
include(${QT_USE_FILE})
|
||||
|
||||
qt4_wrap_ui(OPENCS_UI_HDR ${OPENCS_UI})
|
||||
qt4_wrap_cpp(OPENCS_MOC_SRC ${OPENCS_HDR})
|
||||
qt4_add_resources(OPENCS_RES_SRC ${OPENCS_RES})
|
||||
|
||||
include_directories(${CMAKE_CURRENT_BINARY_DIR})
|
||||
|
||||
add_executable(opencs
|
||||
${OPENCS_SRC}
|
||||
${OPENCS_UI_HDR}
|
||||
${OPENCS_MOC_SRC}
|
||||
${OPENCS_RES_SRC}
|
||||
)
|
||||
|
||||
target_link_libraries(opencs
|
||||
${Boost_LIBRARIES}
|
||||
${QT_LIBRARIES}
|
||||
components
|
||||
)
|
49
apps/opencs/editor.cpp
Normal file
49
apps/opencs/editor.cpp
Normal file
|
@ -0,0 +1,49 @@
|
|||
|
||||
#include "editor.hpp"
|
||||
|
||||
#include <sstream>
|
||||
|
||||
#include <QtGui/QApplication>
|
||||
|
||||
#include "model/doc/document.hpp"
|
||||
#include "model/world/data.hpp"
|
||||
|
||||
CS::Editor::Editor() : mViewManager (mDocumentManager), mNewDocumentIndex (0)
|
||||
{
|
||||
connect (&mViewManager, SIGNAL (newDocumentRequest ()), this, SLOT (createDocument ()));
|
||||
}
|
||||
|
||||
void CS::Editor::createDocument()
|
||||
{
|
||||
std::ostringstream stream;
|
||||
|
||||
stream << "NewDocument" << (++mNewDocumentIndex);
|
||||
|
||||
CSMDoc::Document *document = mDocumentManager.addDocument (stream.str());
|
||||
|
||||
static const char *sGlobals[] =
|
||||
{
|
||||
"Day", "DaysPassed", "GameHour", "Month", "PCRace", "PCVampire", "PCWerewolf", "PCYear", 0
|
||||
};
|
||||
|
||||
for (int i=0; sGlobals[i]; ++i)
|
||||
{
|
||||
ESM::Global record;
|
||||
record.mId = sGlobals[i];
|
||||
record.mValue = i==0 ? 1 : 0;
|
||||
record.mType = ESM::VT_Float;
|
||||
document->getData().getGlobals().add (record);
|
||||
}
|
||||
|
||||
document->getData().merge(); /// \todo remove once proper ESX loading is implemented
|
||||
|
||||
mViewManager.addView (document);
|
||||
}
|
||||
|
||||
int CS::Editor::run()
|
||||
{
|
||||
/// \todo Instead of creating an empty document, open a small welcome dialogue window with buttons for new/load/recent projects
|
||||
createDocument();
|
||||
|
||||
return QApplication::exec();
|
||||
}
|
37
apps/opencs/editor.hpp
Normal file
37
apps/opencs/editor.hpp
Normal file
|
@ -0,0 +1,37 @@
|
|||
#ifndef CS_EDITOR_H
|
||||
#define CS_EDITOR_H
|
||||
|
||||
#include <QObject>
|
||||
|
||||
#include "model/doc/documentmanager.hpp"
|
||||
#include "view/doc/viewmanager.hpp"
|
||||
|
||||
namespace CS
|
||||
{
|
||||
class Editor : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
int mNewDocumentIndex; ///< \todo remove when the proper new document dialogue is implemented.
|
||||
|
||||
CSMDoc::DocumentManager mDocumentManager;
|
||||
CSVDoc::ViewManager mViewManager;
|
||||
|
||||
// not implemented
|
||||
Editor (const Editor&);
|
||||
Editor& operator= (const Editor&);
|
||||
|
||||
public:
|
||||
|
||||
Editor();
|
||||
|
||||
int run();
|
||||
///< \return error status
|
||||
|
||||
public slots:
|
||||
|
||||
void createDocument();
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
39
apps/opencs/main.cpp
Normal file
39
apps/opencs/main.cpp
Normal file
|
@ -0,0 +1,39 @@
|
|||
|
||||
#include "editor.hpp"
|
||||
|
||||
#include <exception>
|
||||
#include <iostream>
|
||||
|
||||
#include <QtGui/QApplication>
|
||||
|
||||
class Application : public QApplication
|
||||
{
|
||||
private:
|
||||
|
||||
bool notify (QObject *receiver, QEvent *event)
|
||||
{
|
||||
try
|
||||
{
|
||||
return QApplication::notify (receiver, event);
|
||||
}
|
||||
catch (const std::exception& exception)
|
||||
{
|
||||
std::cerr << "An exception has been caught: " << exception.what() << std::endl;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
Application (int& argc, char *argv[]) : QApplication (argc, argv) {}
|
||||
};
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
Application mApplication (argc, argv);
|
||||
|
||||
CS::Editor editor;
|
||||
|
||||
return editor.run();
|
||||
}
|
114
apps/opencs/model/doc/document.cpp
Normal file
114
apps/opencs/model/doc/document.cpp
Normal file
|
@ -0,0 +1,114 @@
|
|||
|
||||
#include "document.hpp"
|
||||
|
||||
CSMDoc::Document::Document (const std::string& name)
|
||||
: mTools (mData)
|
||||
{
|
||||
mName = name; ///< \todo replace with ESX list
|
||||
|
||||
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)));
|
||||
|
||||
// dummy implementation -> remove when proper save is implemented.
|
||||
mSaveCount = 0;
|
||||
connect (&mSaveTimer, SIGNAL(timeout()), this, SLOT (saving()));
|
||||
}
|
||||
|
||||
QUndoStack& CSMDoc::Document::getUndoStack()
|
||||
{
|
||||
return mUndoStack;
|
||||
}
|
||||
|
||||
int CSMDoc::Document::getState() const
|
||||
{
|
||||
int state = 0;
|
||||
|
||||
if (!mUndoStack.isClean())
|
||||
state |= State_Modified;
|
||||
|
||||
if (mSaveCount)
|
||||
state |= State_Locked | State_Saving | State_Operation;
|
||||
|
||||
if (int operations = mTools.getRunningOperations())
|
||||
state |= State_Locked | State_Operation | operations;
|
||||
|
||||
return state;
|
||||
}
|
||||
|
||||
const std::string& CSMDoc::Document::getName() const
|
||||
{
|
||||
return mName;
|
||||
}
|
||||
|
||||
void CSMDoc::Document::save()
|
||||
{
|
||||
mSaveCount = 1;
|
||||
mSaveTimer.start (500);
|
||||
emit stateChanged (getState(), this);
|
||||
emit progress (1, 16, State_Saving, 1, this);
|
||||
}
|
||||
|
||||
CSMWorld::UniversalId CSMDoc::Document::verify()
|
||||
{
|
||||
CSMWorld::UniversalId id = mTools.runVerifier();
|
||||
emit stateChanged (getState(), this);
|
||||
return id;
|
||||
}
|
||||
|
||||
void CSMDoc::Document::abortOperation (int type)
|
||||
{
|
||||
mTools.abortOperation (type);
|
||||
|
||||
if (type==State_Saving)
|
||||
{
|
||||
mSaveTimer.stop();
|
||||
emit stateChanged (getState(), this);
|
||||
}
|
||||
}
|
||||
|
||||
void CSMDoc::Document::modificationStateChanged (bool clean)
|
||||
{
|
||||
emit stateChanged (getState(), this);
|
||||
}
|
||||
|
||||
void CSMDoc::Document::operationDone (int type)
|
||||
{
|
||||
emit stateChanged (getState(), this);
|
||||
}
|
||||
|
||||
void CSMDoc::Document::saving()
|
||||
{
|
||||
++mSaveCount;
|
||||
|
||||
emit progress (mSaveCount, 16, State_Saving, 1, this);
|
||||
|
||||
if (mSaveCount>15)
|
||||
{
|
||||
mSaveCount = 0;
|
||||
mSaveTimer.stop();
|
||||
mUndoStack.setClean();
|
||||
emit stateChanged (getState(), this);
|
||||
}
|
||||
}
|
||||
|
||||
const CSMWorld::Data& CSMDoc::Document::getData() const
|
||||
{
|
||||
return mData;
|
||||
}
|
||||
|
||||
CSMWorld::Data& CSMDoc::Document::getData()
|
||||
{
|
||||
return mData;
|
||||
}
|
||||
|
||||
CSMTools::ReportModel *CSMDoc::Document::getReport (const CSMWorld::UniversalId& id)
|
||||
{
|
||||
return mTools.getReport (id);
|
||||
}
|
||||
|
||||
void CSMDoc::Document::progress (int current, int max, int type)
|
||||
{
|
||||
emit progress (current, max, type, 1, this);
|
||||
}
|
87
apps/opencs/model/doc/document.hpp
Normal file
87
apps/opencs/model/doc/document.hpp
Normal file
|
@ -0,0 +1,87 @@
|
|||
#ifndef CSM_DOC_DOCUMENT_H
|
||||
#define CSM_DOC_DOCUMENT_H
|
||||
|
||||
#include <string>
|
||||
|
||||
#include <QUndoStack>
|
||||
#include <QObject>
|
||||
#include <QTimer>
|
||||
|
||||
#include "../world/data.hpp"
|
||||
|
||||
#include "../tools/tools.hpp"
|
||||
|
||||
#include "state.hpp"
|
||||
|
||||
class QAbstractItemModel;
|
||||
|
||||
namespace CSMDoc
|
||||
{
|
||||
class Document : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
private:
|
||||
|
||||
std::string mName; ///< \todo replace name with ESX list
|
||||
CSMWorld::Data mData;
|
||||
CSMTools::Tools mTools;
|
||||
|
||||
// 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.
|
||||
QUndoStack mUndoStack;
|
||||
|
||||
int mSaveCount; ///< dummy implementation -> remove when proper save is implemented.
|
||||
QTimer mSaveTimer; ///< dummy implementation -> remove when proper save is implemented.
|
||||
|
||||
// not implemented
|
||||
Document (const Document&);
|
||||
Document& operator= (const Document&);
|
||||
|
||||
public:
|
||||
|
||||
Document (const std::string& name);
|
||||
///< \todo replace name with ESX list
|
||||
|
||||
QUndoStack& getUndoStack();
|
||||
|
||||
int getState() const;
|
||||
|
||||
const std::string& getName() const;
|
||||
///< \todo replace with ESX list
|
||||
|
||||
void save();
|
||||
|
||||
CSMWorld::UniversalId verify();
|
||||
|
||||
void abortOperation (int type);
|
||||
|
||||
const CSMWorld::Data& getData() const;
|
||||
|
||||
CSMWorld::Data& getData();
|
||||
|
||||
CSMTools::ReportModel *getReport (const CSMWorld::UniversalId& id);
|
||||
///< The ownership of the returned report is not transferred.
|
||||
|
||||
signals:
|
||||
|
||||
void stateChanged (int state, CSMDoc::Document *document);
|
||||
|
||||
void progress (int current, int max, int type, int threads, CSMDoc::Document *document);
|
||||
|
||||
private slots:
|
||||
|
||||
void modificationStateChanged (bool clean);
|
||||
|
||||
void operationDone (int type);
|
||||
|
||||
void saving();
|
||||
///< dummy implementation -> remove when proper save is implemented.
|
||||
|
||||
public slots:
|
||||
|
||||
void progress (int current, int max, int type);
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
37
apps/opencs/model/doc/documentmanager.cpp
Normal file
37
apps/opencs/model/doc/documentmanager.cpp
Normal file
|
@ -0,0 +1,37 @@
|
|||
|
||||
#include "documentmanager.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
#include <stdexcept>
|
||||
|
||||
#include "document.hpp"
|
||||
|
||||
CSMDoc::DocumentManager::DocumentManager() {}
|
||||
|
||||
CSMDoc::DocumentManager::~DocumentManager()
|
||||
{
|
||||
for (std::vector<Document *>::iterator iter (mDocuments.begin()); iter!=mDocuments.end(); ++iter)
|
||||
delete *iter;
|
||||
}
|
||||
|
||||
CSMDoc::Document *CSMDoc::DocumentManager::addDocument (const std::string& name)
|
||||
{
|
||||
Document *document = new Document (name);
|
||||
|
||||
mDocuments.push_back (document);
|
||||
|
||||
return document;
|
||||
}
|
||||
|
||||
bool CSMDoc::DocumentManager::removeDocument (Document *document)
|
||||
{
|
||||
std::vector<Document *>::iterator iter = std::find (mDocuments.begin(), mDocuments.end(), document);
|
||||
|
||||
if (iter==mDocuments.end())
|
||||
throw std::runtime_error ("removing invalid document");
|
||||
|
||||
mDocuments.erase (iter);
|
||||
delete document;
|
||||
|
||||
return mDocuments.empty();
|
||||
}
|
32
apps/opencs/model/doc/documentmanager.hpp
Normal file
32
apps/opencs/model/doc/documentmanager.hpp
Normal file
|
@ -0,0 +1,32 @@
|
|||
#ifndef CSM_DOC_DOCUMENTMGR_H
|
||||
#define CSM_DOC_DOCUMENTMGR_H
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
namespace CSMDoc
|
||||
{
|
||||
class Document;
|
||||
|
||||
class DocumentManager
|
||||
{
|
||||
std::vector<Document *> mDocuments;
|
||||
|
||||
DocumentManager (const DocumentManager&);
|
||||
DocumentManager& operator= (const DocumentManager&);
|
||||
|
||||
public:
|
||||
|
||||
DocumentManager();
|
||||
|
||||
~DocumentManager();
|
||||
|
||||
Document *addDocument (const std::string& name);
|
||||
///< The ownership of the returned document is not transferred to the caller.
|
||||
|
||||
bool removeDocument (Document *document);
|
||||
///< \return last document removed?
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
19
apps/opencs/model/doc/state.hpp
Normal file
19
apps/opencs/model/doc/state.hpp
Normal file
|
@ -0,0 +1,19 @@
|
|||
#ifndef CSM_DOC_STATE_H
|
||||
#define CSM_DOC_STATE_H
|
||||
|
||||
namespace CSMDoc
|
||||
{
|
||||
enum State
|
||||
{
|
||||
State_Modified = 1,
|
||||
State_Locked = 2,
|
||||
State_Operation = 4,
|
||||
|
||||
State_Saving = 8,
|
||||
State_Verifying = 16,
|
||||
State_Compiling = 32, // not implemented yet
|
||||
State_Searching = 64 // not implemented yet
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
21
apps/opencs/model/tools/mandatoryid.cpp
Normal file
21
apps/opencs/model/tools/mandatoryid.cpp
Normal file
|
@ -0,0 +1,21 @@
|
|||
|
||||
#include "mandatoryid.hpp"
|
||||
|
||||
#include "../world/idcollection.hpp"
|
||||
|
||||
CSMTools::MandatoryIdStage::MandatoryIdStage (const CSMWorld::IdCollectionBase& idCollection,
|
||||
const CSMWorld::UniversalId& collectionId, const std::vector<std::string>& ids)
|
||||
: mIdCollection (idCollection), mCollectionId (collectionId), mIds (ids)
|
||||
{}
|
||||
|
||||
int CSMTools::MandatoryIdStage::setup()
|
||||
{
|
||||
return mIds.size();
|
||||
}
|
||||
|
||||
void CSMTools::MandatoryIdStage::perform (int stage, std::vector<std::string>& messages)
|
||||
{
|
||||
if (mIdCollection.searchId (mIds.at (stage))==-1 ||
|
||||
mIdCollection.getRecord (mIds.at (stage)).isDeleted())
|
||||
messages.push_back (mCollectionId.toString() + "|Missing mandatory record: " + mIds.at (stage));
|
||||
}
|
38
apps/opencs/model/tools/mandatoryid.hpp
Normal file
38
apps/opencs/model/tools/mandatoryid.hpp
Normal file
|
@ -0,0 +1,38 @@
|
|||
#ifndef CSM_TOOLS_MANDATORYID_H
|
||||
#define CSM_TOOLS_MANDATORYID_H
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "../world/universalid.hpp"
|
||||
|
||||
#include "stage.hpp"
|
||||
|
||||
namespace CSMWorld
|
||||
{
|
||||
class IdCollectionBase;
|
||||
}
|
||||
|
||||
namespace CSMTools
|
||||
{
|
||||
/// \brief Verify stage: make sure that records with specific IDs exist.
|
||||
class MandatoryIdStage : public Stage
|
||||
{
|
||||
const CSMWorld::IdCollectionBase& mIdCollection;
|
||||
CSMWorld::UniversalId mCollectionId;
|
||||
std::vector<std::string> mIds;
|
||||
|
||||
public:
|
||||
|
||||
MandatoryIdStage (const CSMWorld::IdCollectionBase& idCollection, const CSMWorld::UniversalId& collectionId,
|
||||
const std::vector<std::string>& ids);
|
||||
|
||||
virtual int setup();
|
||||
///< \return number of steps
|
||||
|
||||
virtual void perform (int stage, std::vector<std::string>& messages);
|
||||
///< Messages resulting from this tage will be appended to \a messages.
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
84
apps/opencs/model/tools/operation.cpp
Normal file
84
apps/opencs/model/tools/operation.cpp
Normal file
|
@ -0,0 +1,84 @@
|
|||
|
||||
#include "operation.hpp"
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <QTimer>
|
||||
|
||||
#include "../doc/state.hpp"
|
||||
|
||||
#include "stage.hpp"
|
||||
|
||||
void CSMTools::Operation::prepareStages()
|
||||
{
|
||||
mCurrentStage = mStages.begin();
|
||||
mCurrentStep = 0;
|
||||
mCurrentStepTotal = 0;
|
||||
mTotalSteps = 0;
|
||||
|
||||
for (std::vector<std::pair<Stage *, int> >::iterator iter (mStages.begin()); iter!=mStages.end(); ++iter)
|
||||
{
|
||||
iter->second = iter->first->setup();
|
||||
mTotalSteps += iter->second;
|
||||
}
|
||||
}
|
||||
|
||||
CSMTools::Operation::Operation (int type) : mType (type) {}
|
||||
|
||||
CSMTools::Operation::~Operation()
|
||||
{
|
||||
for (std::vector<std::pair<Stage *, int> >::iterator iter (mStages.begin()); iter!=mStages.end(); ++iter)
|
||||
delete iter->first;
|
||||
}
|
||||
|
||||
void CSMTools::Operation::run()
|
||||
{
|
||||
prepareStages();
|
||||
|
||||
QTimer timer;
|
||||
|
||||
timer.connect (&timer, SIGNAL (timeout()), this, SLOT (verify()));
|
||||
|
||||
timer.start (0);
|
||||
|
||||
exec();
|
||||
}
|
||||
|
||||
void CSMTools::Operation::appendStage (Stage *stage)
|
||||
{
|
||||
mStages.push_back (std::make_pair (stage, 0));
|
||||
}
|
||||
|
||||
void CSMTools::Operation::abort()
|
||||
{
|
||||
exit();
|
||||
}
|
||||
|
||||
void CSMTools::Operation::verify()
|
||||
{
|
||||
std::vector<std::string> messages;
|
||||
|
||||
while (mCurrentStage!=mStages.end())
|
||||
{
|
||||
if (mCurrentStep>=mCurrentStage->second)
|
||||
{
|
||||
mCurrentStep = 0;
|
||||
++mCurrentStage;
|
||||
}
|
||||
else
|
||||
{
|
||||
mCurrentStage->first->perform (mCurrentStep++, messages);
|
||||
++mCurrentStepTotal;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
emit progress (mCurrentStepTotal, mTotalSteps ? mTotalSteps : 1, mType);
|
||||
|
||||
for (std::vector<std::string>::const_iterator iter (messages.begin()); iter!=messages.end(); ++iter)
|
||||
emit reportMessage (iter->c_str(), mType);
|
||||
|
||||
if (mCurrentStage==mStages.end())
|
||||
exit();
|
||||
}
|
54
apps/opencs/model/tools/operation.hpp
Normal file
54
apps/opencs/model/tools/operation.hpp
Normal file
|
@ -0,0 +1,54 @@
|
|||
#ifndef CSM_TOOLS_OPERATION_H
|
||||
#define CSM_TOOLS_OPERATION_H
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include <QThread>
|
||||
|
||||
namespace CSMTools
|
||||
{
|
||||
class Stage;
|
||||
|
||||
class Operation : public QThread
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
int mType;
|
||||
std::vector<std::pair<Stage *, int> > mStages; // stage, number of steps
|
||||
std::vector<std::pair<Stage *, int> >::iterator mCurrentStage;
|
||||
int mCurrentStep;
|
||||
int mCurrentStepTotal;
|
||||
int mTotalSteps;
|
||||
|
||||
void prepareStages();
|
||||
|
||||
public:
|
||||
|
||||
Operation (int type);
|
||||
|
||||
virtual ~Operation();
|
||||
|
||||
virtual void run();
|
||||
|
||||
void appendStage (Stage *stage);
|
||||
///< The ownership of \a stage is transferred to *this.
|
||||
///
|
||||
/// \attention Do no call this function while this Operation is running.
|
||||
|
||||
signals:
|
||||
|
||||
void progress (int current, int max, int type);
|
||||
|
||||
void reportMessage (const QString& message, int type);
|
||||
|
||||
public slots:
|
||||
|
||||
void abort();
|
||||
|
||||
private slots:
|
||||
|
||||
void verify();
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
71
apps/opencs/model/tools/reportmodel.cpp
Normal file
71
apps/opencs/model/tools/reportmodel.cpp
Normal file
|
@ -0,0 +1,71 @@
|
|||
|
||||
#include "reportmodel.hpp"
|
||||
|
||||
#include <stdexcept>
|
||||
|
||||
int CSMTools::ReportModel::rowCount (const QModelIndex & parent) const
|
||||
{
|
||||
if (parent.isValid())
|
||||
return 0;
|
||||
|
||||
return mRows.size();
|
||||
}
|
||||
|
||||
int CSMTools::ReportModel::columnCount (const QModelIndex & parent) const
|
||||
{
|
||||
if (parent.isValid())
|
||||
return 0;
|
||||
|
||||
return 2;
|
||||
}
|
||||
|
||||
QVariant CSMTools::ReportModel::data (const QModelIndex & index, int role) const
|
||||
{
|
||||
if (role!=Qt::DisplayRole)
|
||||
return QVariant();
|
||||
|
||||
if (index.column()==0)
|
||||
return static_cast<int> (mRows.at (index.row()).first.getType());
|
||||
else
|
||||
return mRows.at (index.row()).second.c_str();
|
||||
}
|
||||
|
||||
QVariant CSMTools::ReportModel::headerData (int section, Qt::Orientation orientation, int role) const
|
||||
{
|
||||
if (role!=Qt::DisplayRole)
|
||||
return QVariant();
|
||||
|
||||
if (orientation==Qt::Vertical)
|
||||
return QVariant();
|
||||
|
||||
return tr (section==0 ? "Type" : "Description");
|
||||
}
|
||||
|
||||
bool CSMTools::ReportModel::removeRows (int row, int count, const QModelIndex& parent)
|
||||
{
|
||||
if (parent.isValid())
|
||||
return false;
|
||||
|
||||
mRows.erase (mRows.begin()+row, mRows.begin()+row+count);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void CSMTools::ReportModel::add (const std::string& row)
|
||||
{
|
||||
std::string::size_type index = row.find ('|');
|
||||
|
||||
if (index==std::string::npos)
|
||||
throw std::logic_error ("invalid report message");
|
||||
|
||||
beginInsertRows (QModelIndex(), mRows.size(), mRows.size());
|
||||
|
||||
mRows.push_back (std::make_pair (row.substr (0, index), row.substr (index+1)));
|
||||
|
||||
endInsertRows();
|
||||
}
|
||||
|
||||
const CSMWorld::UniversalId& CSMTools::ReportModel::getUniversalId (int row) const
|
||||
{
|
||||
return mRows.at (row).first;
|
||||
}
|
37
apps/opencs/model/tools/reportmodel.hpp
Normal file
37
apps/opencs/model/tools/reportmodel.hpp
Normal file
|
@ -0,0 +1,37 @@
|
|||
#ifndef CSM_TOOLS_REPORTMODEL_H
|
||||
#define CSM_TOOLS_REPORTMODEL_H
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
#include <QAbstractTableModel>
|
||||
|
||||
#include "../world/universalid.hpp"
|
||||
|
||||
namespace CSMTools
|
||||
{
|
||||
class ReportModel : public QAbstractTableModel
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
std::vector<std::pair<CSMWorld::UniversalId, std::string> > mRows;
|
||||
|
||||
public:
|
||||
|
||||
virtual int rowCount (const QModelIndex & parent = QModelIndex()) const;
|
||||
|
||||
virtual int columnCount (const QModelIndex & parent = QModelIndex()) const;
|
||||
|
||||
virtual QVariant data (const QModelIndex & index, int role = Qt::DisplayRole) const;
|
||||
|
||||
virtual QVariant headerData (int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const;
|
||||
|
||||
virtual bool removeRows (int row, int count, const QModelIndex& parent = QModelIndex());
|
||||
|
||||
void add (const std::string& row);
|
||||
|
||||
const CSMWorld::UniversalId& getUniversalId (int row) const;
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
4
apps/opencs/model/tools/stage.cpp
Normal file
4
apps/opencs/model/tools/stage.cpp
Normal file
|
@ -0,0 +1,4 @@
|
|||
|
||||
#include "stage.hpp"
|
||||
|
||||
CSMTools::Stage::~Stage() {}
|
24
apps/opencs/model/tools/stage.hpp
Normal file
24
apps/opencs/model/tools/stage.hpp
Normal file
|
@ -0,0 +1,24 @@
|
|||
#ifndef CSM_TOOLS_STAGE_H
|
||||
#define CSM_TOOLS_STAGE_H
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
namespace CSMTools
|
||||
{
|
||||
class Stage
|
||||
{
|
||||
public:
|
||||
|
||||
virtual ~Stage();
|
||||
|
||||
virtual int setup() = 0;
|
||||
///< \return number of steps
|
||||
|
||||
virtual void perform (int stage, std::vector<std::string>& messages) = 0;
|
||||
///< Messages resulting from this tage will be appended to \a messages.
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
|
123
apps/opencs/model/tools/tools.cpp
Normal file
123
apps/opencs/model/tools/tools.cpp
Normal file
|
@ -0,0 +1,123 @@
|
|||
|
||||
#include "tools.hpp"
|
||||
|
||||
#include <QThreadPool>
|
||||
|
||||
#include "verifier.hpp"
|
||||
|
||||
#include "../doc/state.hpp"
|
||||
|
||||
#include "../world/data.hpp"
|
||||
#include "../world/universalid.hpp"
|
||||
|
||||
#include "reportmodel.hpp"
|
||||
#include "mandatoryid.hpp"
|
||||
|
||||
CSMTools::Operation *CSMTools::Tools::get (int type)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case CSMDoc::State_Verifying: return mVerifier;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
const CSMTools::Operation *CSMTools::Tools::get (int type) const
|
||||
{
|
||||
return const_cast<Tools *> (this)->get (type);
|
||||
}
|
||||
|
||||
CSMTools::Verifier *CSMTools::Tools::getVerifier()
|
||||
{
|
||||
if (!mVerifier)
|
||||
{
|
||||
mVerifier = new Verifier;
|
||||
|
||||
connect (mVerifier, SIGNAL (progress (int, int, int)), this, SIGNAL (progress (int, int, int)));
|
||||
connect (mVerifier, SIGNAL (finished()), this, SLOT (verifierDone()));
|
||||
connect (mVerifier, SIGNAL (reportMessage (const QString&, int)),
|
||||
this, SLOT (verifierMessage (const QString&, int)));
|
||||
|
||||
std::vector<std::string> mandatoryIds; // I want C++11, damn it!
|
||||
mandatoryIds.push_back ("Day");
|
||||
mandatoryIds.push_back ("DaysPassed");
|
||||
mandatoryIds.push_back ("GameHour");
|
||||
mandatoryIds.push_back ("Month");
|
||||
mandatoryIds.push_back ("PCRace");
|
||||
mandatoryIds.push_back ("PCVampire");
|
||||
mandatoryIds.push_back ("PCWerewolf");
|
||||
mandatoryIds.push_back ("PCYear");
|
||||
|
||||
mVerifier->appendStage (new MandatoryIdStage (mData.getGlobals(),
|
||||
CSMWorld::UniversalId (CSMWorld::UniversalId::Type_Globals), mandatoryIds));
|
||||
}
|
||||
|
||||
return mVerifier;
|
||||
}
|
||||
|
||||
CSMTools::Tools::Tools (CSMWorld::Data& data) : mData (data), mVerifier (0), mNextReportNumber (0)
|
||||
{
|
||||
for (std::map<int, ReportModel *>::iterator iter (mReports.begin()); iter!=mReports.end(); ++iter)
|
||||
delete iter->second;
|
||||
}
|
||||
|
||||
CSMTools::Tools::~Tools()
|
||||
{
|
||||
delete mVerifier;
|
||||
}
|
||||
|
||||
CSMWorld::UniversalId CSMTools::Tools::runVerifier()
|
||||
{
|
||||
mReports.insert (std::make_pair (mNextReportNumber++, new ReportModel));
|
||||
mActiveReports[CSMDoc::State_Verifying] = mNextReportNumber-1;
|
||||
|
||||
getVerifier()->start();
|
||||
|
||||
return CSMWorld::UniversalId (CSMWorld::UniversalId::Type_VerificationResults, mNextReportNumber-1);
|
||||
}
|
||||
|
||||
void CSMTools::Tools::abortOperation (int type)
|
||||
{
|
||||
if (Operation *operation = get (type))
|
||||
operation->abort();
|
||||
}
|
||||
|
||||
int CSMTools::Tools::getRunningOperations() const
|
||||
{
|
||||
static const int sOperations[] =
|
||||
{
|
||||
CSMDoc::State_Verifying,
|
||||
-1
|
||||
};
|
||||
|
||||
int result = 0;
|
||||
|
||||
for (int i=0; sOperations[i]!=-1; ++i)
|
||||
if (const Operation *operation = get (sOperations[i]))
|
||||
if (operation->isRunning())
|
||||
result |= sOperations[i];
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
CSMTools::ReportModel *CSMTools::Tools::getReport (const CSMWorld::UniversalId& id)
|
||||
{
|
||||
if (id.getType()!=CSMWorld::UniversalId::Type_VerificationResults)
|
||||
throw std::logic_error ("invalid request for report model: " + id.toString());
|
||||
|
||||
return mReports.at (id.getIndex());
|
||||
}
|
||||
|
||||
void CSMTools::Tools::verifierDone()
|
||||
{
|
||||
emit done (CSMDoc::State_Verifying);
|
||||
}
|
||||
|
||||
void CSMTools::Tools::verifierMessage (const QString& message, int type)
|
||||
{
|
||||
std::map<int, int>::iterator iter = mActiveReports.find (type);
|
||||
|
||||
if (iter!=mActiveReports.end())
|
||||
mReports[iter->second]->add (message.toStdString());
|
||||
}
|
73
apps/opencs/model/tools/tools.hpp
Normal file
73
apps/opencs/model/tools/tools.hpp
Normal file
|
@ -0,0 +1,73 @@
|
|||
#ifndef CSM_TOOLS_TOOLS_H
|
||||
#define CSM_TOOLS_TOOLS_H
|
||||
|
||||
#include <QObject>
|
||||
|
||||
#include <map>
|
||||
|
||||
namespace CSMWorld
|
||||
{
|
||||
class Data;
|
||||
class UniversalId;
|
||||
}
|
||||
|
||||
namespace CSMTools
|
||||
{
|
||||
class Verifier;
|
||||
class Operation;
|
||||
class ReportModel;
|
||||
|
||||
class Tools : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
CSMWorld::Data& mData;
|
||||
Verifier *mVerifier;
|
||||
std::map<int, ReportModel *> mReports;
|
||||
int mNextReportNumber;
|
||||
std::map<int, int> mActiveReports; // type, report number
|
||||
|
||||
// not implemented
|
||||
Tools (const Tools&);
|
||||
Tools& operator= (const Tools&);
|
||||
|
||||
Verifier *getVerifier();
|
||||
|
||||
Operation *get (int type);
|
||||
///< Returns a 0-pointer, if operation hasn't been used yet.
|
||||
|
||||
const Operation *get (int type) const;
|
||||
///< Returns a 0-pointer, if operation hasn't been used yet.
|
||||
|
||||
public:
|
||||
|
||||
Tools (CSMWorld::Data& data);
|
||||
|
||||
virtual ~Tools();
|
||||
|
||||
CSMWorld::UniversalId runVerifier();
|
||||
///< \return ID of the report for this verification run
|
||||
|
||||
void abortOperation (int type);
|
||||
///< \attention The operation is not aborted immediately.
|
||||
|
||||
int getRunningOperations() const;
|
||||
|
||||
ReportModel *getReport (const CSMWorld::UniversalId& id);
|
||||
///< The ownership of the returned report is not transferred.
|
||||
|
||||
private slots:
|
||||
|
||||
void verifierDone();
|
||||
|
||||
void verifierMessage (const QString& message, int type);
|
||||
|
||||
signals:
|
||||
|
||||
void progress (int current, int max, int type);
|
||||
|
||||
void done (int type);
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
7
apps/opencs/model/tools/verifier.cpp
Normal file
7
apps/opencs/model/tools/verifier.cpp
Normal file
|
@ -0,0 +1,7 @@
|
|||
|
||||
#include "verifier.hpp"
|
||||
|
||||
#include "../doc/state.hpp"
|
||||
|
||||
CSMTools::Verifier::Verifier() : Operation (CSMDoc::State_Verifying)
|
||||
{}
|
17
apps/opencs/model/tools/verifier.hpp
Normal file
17
apps/opencs/model/tools/verifier.hpp
Normal file
|
@ -0,0 +1,17 @@
|
|||
#ifndef CSM_TOOLS_VERIFIER_H
|
||||
#define CSM_TOOLS_VERIFIER_H
|
||||
|
||||
#include "operation.hpp"
|
||||
|
||||
namespace CSMTools
|
||||
{
|
||||
class Verifier : public Operation
|
||||
{
|
||||
public:
|
||||
|
||||
Verifier();
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
13
apps/opencs/model/world/columnbase.cpp
Normal file
13
apps/opencs/model/world/columnbase.cpp
Normal file
|
@ -0,0 +1,13 @@
|
|||
|
||||
#include "columnbase.hpp"
|
||||
|
||||
CSMWorld::ColumnBase::ColumnBase (const std::string& title, Display displayType, int flags)
|
||||
: mTitle (title), mDisplayType (displayType), mFlags (flags)
|
||||
{}
|
||||
|
||||
CSMWorld::ColumnBase::~ColumnBase() {}
|
||||
|
||||
bool CSMWorld::ColumnBase::isUserEditable() const
|
||||
{
|
||||
return isEditable();
|
||||
}
|
67
apps/opencs/model/world/columnbase.hpp
Normal file
67
apps/opencs/model/world/columnbase.hpp
Normal file
|
@ -0,0 +1,67 @@
|
|||
#ifndef CSM_WOLRD_COLUMNBASE_H
|
||||
#define CSM_WOLRD_COLUMNBASE_H
|
||||
|
||||
#include <string>
|
||||
|
||||
#include <Qt>
|
||||
#include <QVariant>
|
||||
|
||||
#include "record.hpp"
|
||||
|
||||
namespace CSMWorld
|
||||
{
|
||||
struct ColumnBase
|
||||
{
|
||||
enum Roles
|
||||
{
|
||||
Role_Flags = Qt::UserRole,
|
||||
Role_Display = Qt::UserRole+1
|
||||
};
|
||||
|
||||
enum Flags
|
||||
{
|
||||
Flag_Table = 1, // column should be displayed in table view
|
||||
Flag_Dialogue = 2 // column should be displayed in dialogue view
|
||||
};
|
||||
|
||||
enum Display
|
||||
{
|
||||
Display_String,
|
||||
Display_Integer,
|
||||
Display_Float
|
||||
};
|
||||
|
||||
std::string mTitle;
|
||||
int mFlags;
|
||||
Display mDisplayType;
|
||||
|
||||
ColumnBase (const std::string& title, Display displayType, int flag);
|
||||
|
||||
virtual ~ColumnBase();
|
||||
|
||||
virtual bool isEditable() const = 0;
|
||||
|
||||
virtual bool isUserEditable() const;
|
||||
///< Can this column be edited directly by the user?
|
||||
|
||||
};
|
||||
|
||||
template<typename ESXRecordT>
|
||||
struct Column : public ColumnBase
|
||||
{
|
||||
std::string mTitle;
|
||||
int mFlags;
|
||||
|
||||
Column (const std::string& title, Display displayType, int flags = Flag_Table | Flag_Dialogue)
|
||||
: ColumnBase (title, displayType, flags) {}
|
||||
|
||||
virtual QVariant get (const Record<ESXRecordT>& record) const = 0;
|
||||
|
||||
virtual void set (Record<ESXRecordT>& record, const QVariant& data)
|
||||
{
|
||||
throw std::logic_error ("Column " + mTitle + " is not editable");
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
96
apps/opencs/model/world/columns.hpp
Normal file
96
apps/opencs/model/world/columns.hpp
Normal file
|
@ -0,0 +1,96 @@
|
|||
#ifndef CSM_WOLRD_COLUMNS_H
|
||||
#define CSM_WOLRD_COLUMNS_H
|
||||
|
||||
#include "columnbase.hpp"
|
||||
|
||||
namespace CSMWorld
|
||||
{
|
||||
template<typename ESXRecordT>
|
||||
struct FloatValueColumn : public Column<ESXRecordT>
|
||||
{
|
||||
FloatValueColumn() : Column<ESXRecordT> ("Value", ColumnBase::Display_Float) {}
|
||||
|
||||
virtual QVariant get (const Record<ESXRecordT>& record) const
|
||||
{
|
||||
return record.get().mValue;
|
||||
}
|
||||
|
||||
virtual void set (Record<ESXRecordT>& record, const QVariant& data)
|
||||
{
|
||||
ESXRecordT base = record.getBase();
|
||||
base.mValue = data.toFloat();
|
||||
record.setModified (base);
|
||||
}
|
||||
|
||||
virtual bool isEditable() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
template<typename ESXRecordT>
|
||||
struct StringIdColumn : public Column<ESXRecordT>
|
||||
{
|
||||
StringIdColumn() : Column<ESXRecordT> ("ID", ColumnBase::Display_String) {}
|
||||
|
||||
virtual QVariant get (const Record<ESXRecordT>& record) const
|
||||
{
|
||||
return record.get().mId.c_str();
|
||||
}
|
||||
|
||||
virtual bool isEditable() const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
template<typename ESXRecordT>
|
||||
struct RecordStateColumn : public Column<ESXRecordT>
|
||||
{
|
||||
RecordStateColumn() : Column<ESXRecordT> ("*", ColumnBase::Display_Integer) {}
|
||||
|
||||
virtual QVariant get (const Record<ESXRecordT>& record) const
|
||||
{
|
||||
if (record.mState==Record<ESXRecordT>::State_Erased)
|
||||
return static_cast<int> (Record<ESXRecordT>::State_Deleted);
|
||||
|
||||
return static_cast<int> (record.mState);
|
||||
}
|
||||
|
||||
virtual void set (Record<ESXRecordT>& record, const QVariant& data)
|
||||
{
|
||||
record.mState = static_cast<RecordBase::State> (data.toInt());
|
||||
}
|
||||
|
||||
virtual bool isEditable() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual bool isUserEditable() const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
template<typename ESXRecordT>
|
||||
struct FixedRecordTypeColumn : public Column<ESXRecordT>
|
||||
{
|
||||
int mType;
|
||||
|
||||
FixedRecordTypeColumn (int type)
|
||||
: Column<ESXRecordT> ("Type", ColumnBase::Display_Integer, 0), mType (type) {}
|
||||
|
||||
virtual QVariant get (const Record<ESXRecordT>& record) const
|
||||
{
|
||||
return mType;
|
||||
}
|
||||
|
||||
virtual bool isEditable() const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
108
apps/opencs/model/world/commands.cpp
Normal file
108
apps/opencs/model/world/commands.cpp
Normal file
|
@ -0,0 +1,108 @@
|
|||
|
||||
#include "commands.hpp"
|
||||
|
||||
#include <QAbstractTableModel>
|
||||
|
||||
#include "idtableproxymodel.hpp"
|
||||
#include "idtable.hpp"
|
||||
|
||||
CSMWorld::ModifyCommand::ModifyCommand (QAbstractItemModel& model, const QModelIndex& index,
|
||||
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()
|
||||
{
|
||||
mModel.setData (mIndex, mNew);
|
||||
}
|
||||
|
||||
void CSMWorld::ModifyCommand::undo()
|
||||
{
|
||||
mModel.setData (mIndex, mOld);
|
||||
}
|
||||
|
||||
CSMWorld::CreateCommand::CreateCommand (IdTableProxyModel& model, const std::string& id, QUndoCommand *parent)
|
||||
: QUndoCommand (parent), mModel (model), mId (id)
|
||||
{
|
||||
setText (("Create record " + id).c_str());
|
||||
}
|
||||
|
||||
void CSMWorld::CreateCommand::redo()
|
||||
{
|
||||
mModel.addRecord (mId);
|
||||
}
|
||||
|
||||
void CSMWorld::CreateCommand::undo()
|
||||
{
|
||||
mModel.removeRow (mModel.getModelIndex (mId, 0).row());
|
||||
}
|
||||
|
||||
CSMWorld::RevertCommand::RevertCommand (IdTable& model, const std::string& id, QUndoCommand *parent)
|
||||
: QUndoCommand (parent), mModel (model), mId (id), mOld (0)
|
||||
{
|
||||
setText (("Revert record " + id).c_str());
|
||||
|
||||
mOld = model.getRecord (id).clone();
|
||||
}
|
||||
|
||||
CSMWorld::RevertCommand::~RevertCommand()
|
||||
{
|
||||
delete mOld;
|
||||
}
|
||||
|
||||
void CSMWorld::RevertCommand::redo()
|
||||
{
|
||||
QModelIndex index = mModel.getModelIndex (mId, 1);
|
||||
RecordBase::State state = static_cast<RecordBase::State> (mModel.data (index).toInt());
|
||||
|
||||
if (state==RecordBase::State_ModifiedOnly)
|
||||
{
|
||||
mModel.removeRows (index.row(), 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
mModel.setData (index, static_cast<int> (RecordBase::State_BaseOnly));
|
||||
}
|
||||
}
|
||||
|
||||
void CSMWorld::RevertCommand::undo()
|
||||
{
|
||||
mModel.setRecord (*mOld);
|
||||
}
|
||||
|
||||
CSMWorld::DeleteCommand::DeleteCommand (IdTable& model, const std::string& id, QUndoCommand *parent)
|
||||
: QUndoCommand (parent), mModel (model), mId (id), mOld (0)
|
||||
{
|
||||
setText (("Delete record " + id).c_str());
|
||||
|
||||
mOld = model.getRecord (id).clone();
|
||||
}
|
||||
|
||||
CSMWorld::DeleteCommand::~DeleteCommand()
|
||||
{
|
||||
delete mOld;
|
||||
}
|
||||
|
||||
void CSMWorld::DeleteCommand::redo()
|
||||
{
|
||||
QModelIndex index = mModel.getModelIndex (mId, 1);
|
||||
RecordBase::State state = static_cast<RecordBase::State> (mModel.data (index).toInt());
|
||||
|
||||
if (state==RecordBase::State_ModifiedOnly)
|
||||
{
|
||||
mModel.removeRows (index.row(), 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
mModel.setData (index, static_cast<int> (RecordBase::State_Deleted));
|
||||
}
|
||||
}
|
||||
|
||||
void CSMWorld::DeleteCommand::undo()
|
||||
{
|
||||
mModel.setRecord (*mOld);
|
||||
}
|
95
apps/opencs/model/world/commands.hpp
Normal file
95
apps/opencs/model/world/commands.hpp
Normal file
|
@ -0,0 +1,95 @@
|
|||
#ifndef CSM_WOLRD_COMMANDS_H
|
||||
#define CSM_WOLRD_COMMANDS_H
|
||||
|
||||
#include "record.hpp"
|
||||
|
||||
#include <string>
|
||||
|
||||
#include <QVariant>
|
||||
#include <QUndoCommand>
|
||||
#include <QModelIndex>
|
||||
|
||||
class QModelIndex;
|
||||
class QAbstractItemModel;
|
||||
|
||||
namespace CSMWorld
|
||||
{
|
||||
class IdTableProxyModel;
|
||||
class IdTable;
|
||||
class RecordBase;
|
||||
|
||||
class ModifyCommand : public QUndoCommand
|
||||
{
|
||||
QAbstractItemModel& mModel;
|
||||
QModelIndex mIndex;
|
||||
QVariant mNew;
|
||||
QVariant mOld;
|
||||
|
||||
public:
|
||||
|
||||
ModifyCommand (QAbstractItemModel& model, const QModelIndex& index, const QVariant& new_,
|
||||
QUndoCommand *parent = 0);
|
||||
|
||||
virtual void redo();
|
||||
|
||||
virtual void undo();
|
||||
};
|
||||
|
||||
class CreateCommand : public QUndoCommand
|
||||
{
|
||||
IdTableProxyModel& mModel;
|
||||
std::string mId;
|
||||
|
||||
public:
|
||||
|
||||
CreateCommand (IdTableProxyModel& model, const std::string& id, QUndoCommand *parent = 0);
|
||||
|
||||
virtual void redo();
|
||||
|
||||
virtual void undo();
|
||||
};
|
||||
|
||||
class RevertCommand : public QUndoCommand
|
||||
{
|
||||
IdTable& mModel;
|
||||
std::string mId;
|
||||
RecordBase *mOld;
|
||||
|
||||
// not implemented
|
||||
RevertCommand (const RevertCommand&);
|
||||
RevertCommand& operator= (const RevertCommand&);
|
||||
|
||||
public:
|
||||
|
||||
RevertCommand (IdTable& model, const std::string& id, QUndoCommand *parent = 0);
|
||||
|
||||
virtual ~RevertCommand();
|
||||
|
||||
virtual void redo();
|
||||
|
||||
virtual void undo();
|
||||
};
|
||||
|
||||
class DeleteCommand : public QUndoCommand
|
||||
{
|
||||
IdTable& mModel;
|
||||
std::string mId;
|
||||
RecordBase *mOld;
|
||||
|
||||
// not implemented
|
||||
DeleteCommand (const DeleteCommand&);
|
||||
DeleteCommand& operator= (const DeleteCommand&);
|
||||
|
||||
public:
|
||||
|
||||
DeleteCommand (IdTable& model, const std::string& id, QUndoCommand *parent = 0);
|
||||
|
||||
virtual ~DeleteCommand();
|
||||
|
||||
virtual void redo();
|
||||
|
||||
virtual void undo();
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
62
apps/opencs/model/world/data.cpp
Normal file
62
apps/opencs/model/world/data.cpp
Normal file
|
@ -0,0 +1,62 @@
|
|||
|
||||
#include "data.hpp"
|
||||
|
||||
#include <stdexcept>
|
||||
|
||||
#include <QAbstractTableModel>
|
||||
|
||||
#include <components/esm/loadglob.hpp>
|
||||
|
||||
#include "idtable.hpp"
|
||||
#include "columns.hpp"
|
||||
|
||||
void CSMWorld::Data::addModel (QAbstractTableModel *model, UniversalId::Type type1,
|
||||
UniversalId::Type type2)
|
||||
{
|
||||
mModels.push_back (model);
|
||||
mModelIndex.insert (std::make_pair (type1, model));
|
||||
|
||||
if (type2!=UniversalId::Type_None)
|
||||
mModelIndex.insert (std::make_pair (type2, model));
|
||||
}
|
||||
|
||||
CSMWorld::Data::Data()
|
||||
{
|
||||
mGlobals.addColumn (new StringIdColumn<ESM::Global>);
|
||||
mGlobals.addColumn (new RecordStateColumn<ESM::Global>);
|
||||
mGlobals.addColumn (new FixedRecordTypeColumn<ESM::Global> (UniversalId::Type_Global));
|
||||
mGlobals.addColumn (new FloatValueColumn<ESM::Global>);
|
||||
|
||||
addModel (new IdTable (&mGlobals), UniversalId::Type_Globals, UniversalId::Type_Global);
|
||||
}
|
||||
|
||||
CSMWorld::Data::~Data()
|
||||
{
|
||||
for (std::vector<QAbstractTableModel *>::iterator iter (mModels.begin()); iter!=mModels.end(); ++iter)
|
||||
delete *iter;
|
||||
}
|
||||
|
||||
const CSMWorld::IdCollection<ESM::Global>& CSMWorld::Data::getGlobals() const
|
||||
{
|
||||
return mGlobals;
|
||||
}
|
||||
|
||||
CSMWorld::IdCollection<ESM::Global>& CSMWorld::Data::getGlobals()
|
||||
{
|
||||
return mGlobals;
|
||||
}
|
||||
|
||||
QAbstractTableModel *CSMWorld::Data::getTableModel (const UniversalId& id)
|
||||
{
|
||||
std::map<UniversalId::Type, QAbstractTableModel *>::iterator iter = mModelIndex.find (id.getType());
|
||||
|
||||
if (iter==mModelIndex.end())
|
||||
throw std::logic_error ("No table model available for " + id.toString());
|
||||
|
||||
return iter->second;
|
||||
}
|
||||
|
||||
void CSMWorld::Data::merge()
|
||||
{
|
||||
mGlobals.merge();
|
||||
}
|
50
apps/opencs/model/world/data.hpp
Normal file
50
apps/opencs/model/world/data.hpp
Normal file
|
@ -0,0 +1,50 @@
|
|||
#ifndef CSM_WOLRD_DATA_H
|
||||
#define CSM_WOLRD_DATA_H
|
||||
|
||||
#include <map>
|
||||
#include <vector>
|
||||
|
||||
#include <components/esm/loadglob.hpp>
|
||||
|
||||
#include "idcollection.hpp"
|
||||
#include "universalid.hpp"
|
||||
|
||||
class QAbstractTableModel;
|
||||
|
||||
namespace CSMWorld
|
||||
{
|
||||
class Data
|
||||
{
|
||||
IdCollection<ESM::Global> mGlobals;
|
||||
std::vector<QAbstractTableModel *> mModels;
|
||||
std::map<UniversalId::Type, QAbstractTableModel *> mModelIndex;
|
||||
|
||||
// not implemented
|
||||
Data (const Data&);
|
||||
Data& operator= (const Data&);
|
||||
|
||||
void addModel (QAbstractTableModel *model, UniversalId::Type type1,
|
||||
UniversalId::Type type2 = UniversalId::Type_None);
|
||||
|
||||
public:
|
||||
|
||||
Data();
|
||||
|
||||
~Data();
|
||||
|
||||
const IdCollection<ESM::Global>& getGlobals() const;
|
||||
|
||||
IdCollection<ESM::Global>& getGlobals();
|
||||
|
||||
QAbstractTableModel *getTableModel (const UniversalId& id);
|
||||
///< If no table model is available for \a id, an exception is thrown.
|
||||
///
|
||||
/// \note The returned table may either be the model for the ID itself or the model that
|
||||
/// contains the record specified by the ID.
|
||||
|
||||
void merge();
|
||||
///< Merge modified into base.
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
6
apps/opencs/model/world/idcollection.cpp
Normal file
6
apps/opencs/model/world/idcollection.cpp
Normal file
|
@ -0,0 +1,6 @@
|
|||
|
||||
#include "idcollection.hpp"
|
||||
|
||||
CSMWorld::IdCollectionBase::IdCollectionBase() {}
|
||||
|
||||
CSMWorld::IdCollectionBase::~IdCollectionBase() {}
|
320
apps/opencs/model/world/idcollection.hpp
Normal file
320
apps/opencs/model/world/idcollection.hpp
Normal file
|
@ -0,0 +1,320 @@
|
|||
#ifndef CSM_WOLRD_IDCOLLECTION_H
|
||||
#define CSM_WOLRD_IDCOLLECTION_H
|
||||
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <algorithm>
|
||||
#include <cctype>
|
||||
#include <stdexcept>
|
||||
#include <functional>
|
||||
|
||||
#include <QVariant>
|
||||
|
||||
#include "columnbase.hpp"
|
||||
#include <components/misc/stringops.hpp>
|
||||
|
||||
namespace CSMWorld
|
||||
{
|
||||
class IdCollectionBase
|
||||
{
|
||||
// not implemented
|
||||
IdCollectionBase (const IdCollectionBase&);
|
||||
IdCollectionBase& operator= (const IdCollectionBase&);
|
||||
|
||||
public:
|
||||
|
||||
IdCollectionBase();
|
||||
|
||||
virtual ~IdCollectionBase();
|
||||
|
||||
virtual int getSize() const = 0;
|
||||
|
||||
virtual std::string getId (int index) const = 0;
|
||||
|
||||
virtual int getIndex (const std::string& id) const = 0;
|
||||
|
||||
virtual int getColumns() const = 0;
|
||||
|
||||
virtual const ColumnBase& getColumn (int column) const = 0;
|
||||
|
||||
virtual QVariant getData (int index, int column) const = 0;
|
||||
|
||||
virtual void setData (int index, int column, const QVariant& data) = 0;
|
||||
|
||||
virtual void merge() = 0;
|
||||
///< Merge modified into base.
|
||||
|
||||
virtual void purge() = 0;
|
||||
///< Remove records that are flagged as erased.
|
||||
|
||||
virtual void removeRows (int index, int count) = 0;
|
||||
|
||||
virtual void appendBlankRecord (const std::string& id) = 0;
|
||||
|
||||
virtual int searchId (const std::string& id) const = 0;
|
||||
////< Search record with \a id.
|
||||
/// \return index of record (if found) or -1 (not found)
|
||||
|
||||
virtual void replace (int index, const RecordBase& record) = 0;
|
||||
///< If the record type does not match, an exception is thrown.
|
||||
///
|
||||
/// \attention \a record must not change the ID.
|
||||
|
||||
virtual void appendRecord (const RecordBase& record) = 0;
|
||||
///< If the record type does not match, an exception is thrown.
|
||||
|
||||
virtual std::string getId (const RecordBase& record) const = 0;
|
||||
///< Return ID for \a record.
|
||||
///
|
||||
/// \attention Throw san exception, if the type of \a record does not match.
|
||||
|
||||
virtual const RecordBase& getRecord (const std::string& id) const = 0;
|
||||
};
|
||||
|
||||
///< \brief Collection of ID-based records
|
||||
template<typename ESXRecordT>
|
||||
class IdCollection : public IdCollectionBase
|
||||
{
|
||||
std::vector<Record<ESXRecordT> > mRecords;
|
||||
std::map<std::string, int> mIndex;
|
||||
std::vector<Column<ESXRecordT> *> mColumns;
|
||||
|
||||
// not implemented
|
||||
IdCollection (const IdCollection&);
|
||||
IdCollection& operator= (const IdCollection&);
|
||||
|
||||
public:
|
||||
|
||||
IdCollection();
|
||||
|
||||
virtual ~IdCollection();
|
||||
|
||||
void add (const ESXRecordT& record);
|
||||
///< Add a new record (modified)
|
||||
|
||||
virtual int getSize() const;
|
||||
|
||||
virtual std::string getId (int index) const;
|
||||
|
||||
virtual int getIndex (const std::string& id) const;
|
||||
|
||||
virtual int getColumns() const;
|
||||
|
||||
virtual QVariant getData (int index, int column) const;
|
||||
|
||||
virtual void setData (int index, int column, const QVariant& data);
|
||||
|
||||
virtual const ColumnBase& getColumn (int column) const;
|
||||
|
||||
virtual void merge();
|
||||
///< Merge modified into base.
|
||||
|
||||
virtual void purge();
|
||||
///< Remove records that are flagged as erased.
|
||||
|
||||
virtual void removeRows (int index, int count) ;
|
||||
|
||||
virtual void appendBlankRecord (const std::string& id);
|
||||
|
||||
virtual int searchId (const std::string& id) const;
|
||||
////< Search record with \a id.
|
||||
/// \return index of record (if found) or -1 (not found)
|
||||
|
||||
virtual void replace (int index, const RecordBase& record);
|
||||
///< If the record type does not match, an exception is thrown.
|
||||
///
|
||||
/// \attention \a record must not change the ID.
|
||||
|
||||
virtual void appendRecord (const RecordBase& record);
|
||||
///< If the record type does not match, an exception is thrown.
|
||||
|
||||
virtual std::string getId (const RecordBase& record) const;
|
||||
///< Return ID for \a record.
|
||||
///
|
||||
/// \attention Throw san exception, if the type of \a record does not match.
|
||||
|
||||
virtual const RecordBase& getRecord (const std::string& id) const;
|
||||
|
||||
void addColumn (Column<ESXRecordT> *column);
|
||||
};
|
||||
|
||||
template<typename ESXRecordT>
|
||||
IdCollection<ESXRecordT>::IdCollection()
|
||||
{}
|
||||
|
||||
template<typename ESXRecordT>
|
||||
IdCollection<ESXRecordT>::~IdCollection()
|
||||
{
|
||||
for (typename std::vector<Column<ESXRecordT> *>::iterator iter (mColumns.begin()); iter!=mColumns.end(); ++iter)
|
||||
delete *iter;
|
||||
}
|
||||
|
||||
template<typename ESXRecordT>
|
||||
void IdCollection<ESXRecordT>::add (const ESXRecordT& record)
|
||||
{
|
||||
std::string id = Misc::StringUtils::lowerCase(record.mId);
|
||||
|
||||
std::map<std::string, int>::iterator iter = mIndex.find (id);
|
||||
|
||||
if (iter==mIndex.end())
|
||||
{
|
||||
Record<ESXRecordT> record2;
|
||||
record2.mState = Record<ESXRecordT>::State_ModifiedOnly;
|
||||
record2.mModified = record;
|
||||
|
||||
mRecords.push_back (record2);
|
||||
mIndex.insert (std::make_pair (id, mRecords.size()-1));
|
||||
}
|
||||
else
|
||||
{
|
||||
mRecords[iter->second].setModified (record);
|
||||
}
|
||||
}
|
||||
|
||||
template<typename ESXRecordT>
|
||||
int IdCollection<ESXRecordT>::getSize() const
|
||||
{
|
||||
return mRecords.size();
|
||||
}
|
||||
|
||||
template<typename ESXRecordT>
|
||||
std::string IdCollection<ESXRecordT>::getId (int index) const
|
||||
{
|
||||
return mRecords.at (index).get().mId;
|
||||
}
|
||||
|
||||
template<typename ESXRecordT>
|
||||
int IdCollection<ESXRecordT>::getIndex (const std::string& id) const
|
||||
{
|
||||
int index = searchId (id);
|
||||
|
||||
if (index==-1)
|
||||
throw std::runtime_error ("invalid ID: " + id);
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
template<typename ESXRecordT>
|
||||
int IdCollection<ESXRecordT>::getColumns() const
|
||||
{
|
||||
return mColumns.size();
|
||||
}
|
||||
|
||||
template<typename ESXRecordT>
|
||||
QVariant IdCollection<ESXRecordT>::getData (int index, int column) const
|
||||
{
|
||||
return mColumns.at (column)->get (mRecords.at (index));
|
||||
}
|
||||
|
||||
template<typename ESXRecordT>
|
||||
void IdCollection<ESXRecordT>::setData (int index, int column, const QVariant& data)
|
||||
{
|
||||
return mColumns.at (column)->set (mRecords.at (index), data);
|
||||
}
|
||||
|
||||
template<typename ESXRecordT>
|
||||
const ColumnBase& IdCollection<ESXRecordT>::getColumn (int column) const
|
||||
{
|
||||
return *mColumns.at (column);
|
||||
}
|
||||
|
||||
template<typename ESXRecordT>
|
||||
void IdCollection<ESXRecordT>::addColumn (Column<ESXRecordT> *column)
|
||||
{
|
||||
mColumns.push_back (column);
|
||||
}
|
||||
|
||||
template<typename ESXRecordT>
|
||||
void IdCollection<ESXRecordT>::merge()
|
||||
{
|
||||
for (typename std::vector<Record<ESXRecordT> >::iterator iter (mRecords.begin()); iter!=mRecords.end(); ++iter)
|
||||
iter->merge();
|
||||
|
||||
purge();
|
||||
}
|
||||
|
||||
template<typename ESXRecordT>
|
||||
void IdCollection<ESXRecordT>::purge()
|
||||
{
|
||||
mRecords.erase (std::remove_if (mRecords.begin(), mRecords.end(),
|
||||
std::mem_fun_ref (&Record<ESXRecordT>::isErased) // I want lambda :(
|
||||
), mRecords.end());
|
||||
}
|
||||
|
||||
template<typename ESXRecordT>
|
||||
void IdCollection<ESXRecordT>::removeRows (int index, int count)
|
||||
{
|
||||
mRecords.erase (mRecords.begin()+index, mRecords.begin()+index+count);
|
||||
|
||||
typename std::map<std::string, int>::iterator iter = mIndex.begin();
|
||||
|
||||
while (iter!=mIndex.end())
|
||||
{
|
||||
if (iter->second>=index)
|
||||
{
|
||||
if (iter->second>=index+count)
|
||||
{
|
||||
iter->second -= count;
|
||||
}
|
||||
else
|
||||
{
|
||||
mIndex.erase (iter++);
|
||||
}
|
||||
}
|
||||
|
||||
++iter;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename ESXRecordT>
|
||||
void IdCollection<ESXRecordT>::appendBlankRecord (const std::string& id)
|
||||
{
|
||||
ESXRecordT record;
|
||||
record.mId = id;
|
||||
record.blank();
|
||||
add (record);
|
||||
}
|
||||
|
||||
template<typename ESXRecordT>
|
||||
int IdCollection<ESXRecordT>::searchId (const std::string& id) const
|
||||
{
|
||||
std::string id2 = Misc::StringUtils::lowerCase(id);
|
||||
|
||||
std::map<std::string, int>::const_iterator iter = mIndex.find (id2);
|
||||
|
||||
if (iter==mIndex.end())
|
||||
return -1;
|
||||
|
||||
return iter->second;
|
||||
}
|
||||
|
||||
template<typename ESXRecordT>
|
||||
void IdCollection<ESXRecordT>::replace (int index, const RecordBase& record)
|
||||
{
|
||||
mRecords.at (index) = dynamic_cast<const Record<ESXRecordT>&> (record);
|
||||
}
|
||||
|
||||
template<typename ESXRecordT>
|
||||
void IdCollection<ESXRecordT>::appendRecord (const RecordBase& record)
|
||||
{
|
||||
mRecords.push_back (dynamic_cast<const Record<ESXRecordT>&> (record));
|
||||
mIndex.insert (std::make_pair (getId (record), mRecords.size()-1));
|
||||
}
|
||||
|
||||
template<typename ESXRecordT>
|
||||
std::string IdCollection<ESXRecordT>::getId (const RecordBase& record) const
|
||||
{
|
||||
const Record<ESXRecordT>& record2 = dynamic_cast<const Record<ESXRecordT>&> (record);
|
||||
return (record2.isModified() ? record2.mModified : record2.mBase).mId;
|
||||
}
|
||||
|
||||
template<typename ESXRecordT>
|
||||
const RecordBase& IdCollection<ESXRecordT>::getRecord (const std::string& id) const
|
||||
{
|
||||
int index = getIndex (id);
|
||||
return mRecords.at (index);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
140
apps/opencs/model/world/idtable.cpp
Normal file
140
apps/opencs/model/world/idtable.cpp
Normal file
|
@ -0,0 +1,140 @@
|
|||
|
||||
#include "idtable.hpp"
|
||||
|
||||
#include "idcollection.hpp"
|
||||
|
||||
CSMWorld::IdTable::IdTable (IdCollectionBase *idCollection) : mIdCollection (idCollection)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
CSMWorld::IdTable::~IdTable()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
int CSMWorld::IdTable::rowCount (const QModelIndex & parent) const
|
||||
{
|
||||
if (parent.isValid())
|
||||
return 0;
|
||||
|
||||
return mIdCollection->getSize();
|
||||
}
|
||||
|
||||
int CSMWorld::IdTable::columnCount (const QModelIndex & parent) const
|
||||
{
|
||||
if (parent.isValid())
|
||||
return 0;
|
||||
|
||||
return mIdCollection->getColumns();
|
||||
}
|
||||
|
||||
QVariant CSMWorld::IdTable::data (const QModelIndex & index, int role) const
|
||||
{
|
||||
if (role!=Qt::DisplayRole && role!=Qt::EditRole)
|
||||
return QVariant();
|
||||
|
||||
if (role==Qt::EditRole && !mIdCollection->getColumn (index.column()).isEditable())
|
||||
return QVariant();
|
||||
|
||||
return mIdCollection->getData (index.row(), index.column());
|
||||
}
|
||||
|
||||
QVariant CSMWorld::IdTable::headerData (int section, Qt::Orientation orientation, int role) const
|
||||
{
|
||||
if (orientation==Qt::Vertical)
|
||||
return QVariant();
|
||||
|
||||
if (role==Qt::DisplayRole)
|
||||
return tr (mIdCollection->getColumn (section).mTitle.c_str());
|
||||
|
||||
if (role==ColumnBase::Role_Flags)
|
||||
return mIdCollection->getColumn (section).mFlags;
|
||||
|
||||
if (role==ColumnBase::Role_Display)
|
||||
return mIdCollection->getColumn (section).mDisplayType;
|
||||
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
bool CSMWorld::IdTable::setData ( const QModelIndex &index, const QVariant &value, int role)
|
||||
{
|
||||
if (mIdCollection->getColumn (index.column()).isEditable() && role==Qt::EditRole)
|
||||
{
|
||||
mIdCollection->setData (index.row(), index.column(), value);
|
||||
|
||||
emit dataChanged (CSMWorld::IdTable::index (index.row(), 0),
|
||||
CSMWorld::IdTable::index (index.row(), mIdCollection->getColumns()-1));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
Qt::ItemFlags CSMWorld::IdTable::flags (const QModelIndex & index) const
|
||||
{
|
||||
Qt::ItemFlags flags = Qt::ItemIsSelectable | Qt::ItemIsEnabled;
|
||||
|
||||
if (mIdCollection->getColumn (index.column()).isUserEditable())
|
||||
flags |= Qt::ItemIsEditable;
|
||||
|
||||
return flags;
|
||||
}
|
||||
|
||||
bool CSMWorld::IdTable::removeRows (int row, int count, const QModelIndex& parent)
|
||||
{
|
||||
if (parent.isValid())
|
||||
return false;
|
||||
|
||||
beginRemoveRows (parent, row, row+count-1);
|
||||
|
||||
mIdCollection->removeRows (row, count);
|
||||
|
||||
endRemoveRows();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void CSMWorld::IdTable::addRecord (const std::string& id)
|
||||
{
|
||||
int index = mIdCollection->getSize();
|
||||
|
||||
beginInsertRows (QModelIndex(), index, index);
|
||||
|
||||
mIdCollection->appendBlankRecord (id);
|
||||
|
||||
endInsertRows();
|
||||
}
|
||||
|
||||
QModelIndex CSMWorld::IdTable::getModelIndex (const std::string& id, int column) const
|
||||
{
|
||||
return index (mIdCollection->getIndex (id), column);
|
||||
}
|
||||
|
||||
void CSMWorld::IdTable::setRecord (const RecordBase& record)
|
||||
{
|
||||
int index = mIdCollection->searchId (mIdCollection->getId (record));
|
||||
|
||||
if (index==-1)
|
||||
{
|
||||
int index = mIdCollection->getSize();
|
||||
|
||||
beginInsertRows (QModelIndex(), index, index);
|
||||
|
||||
mIdCollection->appendRecord (record);
|
||||
|
||||
endInsertRows();
|
||||
}
|
||||
else
|
||||
{
|
||||
mIdCollection->replace (index, record);
|
||||
emit dataChanged (CSMWorld::IdTable::index (index, 0),
|
||||
CSMWorld::IdTable::index (index, mIdCollection->getColumns()-1));
|
||||
}
|
||||
}
|
||||
|
||||
const CSMWorld::RecordBase& CSMWorld::IdTable::getRecord (const std::string& id) const
|
||||
{
|
||||
return mIdCollection->getRecord (id);
|
||||
}
|
53
apps/opencs/model/world/idtable.hpp
Normal file
53
apps/opencs/model/world/idtable.hpp
Normal file
|
@ -0,0 +1,53 @@
|
|||
#ifndef CSM_WOLRD_IDTABLE_H
|
||||
#define CSM_WOLRD_IDTABLE_H
|
||||
|
||||
#include <QAbstractTableModel>
|
||||
|
||||
namespace CSMWorld
|
||||
{
|
||||
class IdCollectionBase;
|
||||
class RecordBase;
|
||||
|
||||
class IdTable : public QAbstractTableModel
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
IdCollectionBase *mIdCollection;
|
||||
|
||||
// not implemented
|
||||
IdTable (const IdTable&);
|
||||
IdTable& operator= (const IdTable&);
|
||||
|
||||
public:
|
||||
|
||||
IdTable (IdCollectionBase *idCollection);
|
||||
///< The ownership of \a idCollection is not transferred.
|
||||
|
||||
virtual ~IdTable();
|
||||
|
||||
virtual int rowCount (const QModelIndex & parent = QModelIndex()) const;
|
||||
|
||||
virtual int columnCount (const QModelIndex & parent = QModelIndex()) const;
|
||||
|
||||
virtual QVariant data (const QModelIndex & index, int role = Qt::DisplayRole) const;
|
||||
|
||||
virtual QVariant headerData (int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const;
|
||||
|
||||
virtual bool setData ( const QModelIndex &index, const QVariant &value, int role = Qt::EditRole);
|
||||
|
||||
virtual Qt::ItemFlags flags (const QModelIndex & index) const;
|
||||
|
||||
virtual bool removeRows (int row, int count, const QModelIndex& parent = QModelIndex());
|
||||
|
||||
void addRecord (const std::string& id);
|
||||
|
||||
QModelIndex getModelIndex (const std::string& id, int column) const;
|
||||
|
||||
void setRecord (const RecordBase& record);
|
||||
///< Add record or overwrite existing recrod.
|
||||
|
||||
const RecordBase& getRecord (const std::string& id) const;
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
18
apps/opencs/model/world/idtableproxymodel.cpp
Normal file
18
apps/opencs/model/world/idtableproxymodel.cpp
Normal file
|
@ -0,0 +1,18 @@
|
|||
|
||||
#include "idtableproxymodel.hpp"
|
||||
|
||||
#include "idtable.hpp"
|
||||
|
||||
CSMWorld::IdTableProxyModel::IdTableProxyModel (QObject *parent)
|
||||
: QSortFilterProxyModel (parent)
|
||||
{}
|
||||
|
||||
void CSMWorld::IdTableProxyModel::addRecord (const std::string& id)
|
||||
{
|
||||
dynamic_cast<IdTable&> (*sourceModel()).addRecord (id);
|
||||
}
|
||||
|
||||
QModelIndex CSMWorld::IdTableProxyModel::getModelIndex (const std::string& id, int column) const
|
||||
{
|
||||
return mapFromSource (dynamic_cast<IdTable&> (*sourceModel()).getModelIndex (id, column));
|
||||
}
|
24
apps/opencs/model/world/idtableproxymodel.hpp
Normal file
24
apps/opencs/model/world/idtableproxymodel.hpp
Normal file
|
@ -0,0 +1,24 @@
|
|||
#ifndef CSM_WOLRD_IDTABLEPROXYMODEL_H
|
||||
#define CSM_WOLRD_IDTABLEPROXYMODEL_H
|
||||
|
||||
#include <QSortFilterProxyModel>
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace CSMWorld
|
||||
{
|
||||
class IdTableProxyModel : public QSortFilterProxyModel
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
IdTableProxyModel (QObject *parent = 0);
|
||||
|
||||
virtual void addRecord (const std::string& id);
|
||||
|
||||
virtual QModelIndex getModelIndex (const std::string& id, int column) const;
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
21
apps/opencs/model/world/record.cpp
Normal file
21
apps/opencs/model/world/record.cpp
Normal file
|
@ -0,0 +1,21 @@
|
|||
|
||||
#include "record.hpp"
|
||||
|
||||
CSMWorld::RecordBase::~RecordBase() {}
|
||||
|
||||
bool CSMWorld::RecordBase::RecordBase::isDeleted() const
|
||||
{
|
||||
return mState==State_Deleted || mState==State_Erased;
|
||||
}
|
||||
|
||||
|
||||
bool CSMWorld::RecordBase::RecordBase::isErased() const
|
||||
{
|
||||
return mState==State_Erased;
|
||||
}
|
||||
|
||||
|
||||
bool CSMWorld::RecordBase::RecordBase::isModified() const
|
||||
{
|
||||
return mState==State_Modified || mState==State_ModifiedOnly;
|
||||
}
|
104
apps/opencs/model/world/record.hpp
Normal file
104
apps/opencs/model/world/record.hpp
Normal file
|
@ -0,0 +1,104 @@
|
|||
#ifndef CSM_WOLRD_RECORD_H
|
||||
#define CSM_WOLRD_RECORD_H
|
||||
|
||||
#include <stdexcept>
|
||||
|
||||
namespace CSMWorld
|
||||
{
|
||||
struct RecordBase
|
||||
{
|
||||
enum State
|
||||
{
|
||||
State_BaseOnly = 0, // defined in base only
|
||||
State_Modified = 1, // exists in base, but has been modified
|
||||
State_ModifiedOnly = 2, // newly created in modified
|
||||
State_Deleted = 3, // exists in base, but has been deleted
|
||||
State_Erased = 4 // does not exist at all (we mostly treat that the same way as deleted)
|
||||
};
|
||||
|
||||
State mState;
|
||||
|
||||
virtual ~RecordBase();
|
||||
|
||||
virtual RecordBase *clone() const = 0;
|
||||
|
||||
bool isDeleted() const;
|
||||
|
||||
bool isErased() const;
|
||||
|
||||
bool isModified() const;
|
||||
};
|
||||
|
||||
template <typename ESXRecordT>
|
||||
struct Record : public RecordBase
|
||||
{
|
||||
ESXRecordT mBase;
|
||||
ESXRecordT mModified;
|
||||
|
||||
virtual RecordBase *clone() const;
|
||||
|
||||
const ESXRecordT& get() const;
|
||||
///< Throws an exception, if the record is deleted.
|
||||
|
||||
const ESXRecordT& getBase() const;
|
||||
///< Throws an exception, if the record is deleted. Returns modified, if there is no base.
|
||||
|
||||
void setModified (const ESXRecordT& modified);
|
||||
///< Throws an exception, if the record is deleted.
|
||||
|
||||
void merge();
|
||||
///< Merge modified into base.
|
||||
};
|
||||
|
||||
template <typename ESXRecordT>
|
||||
RecordBase *Record<ESXRecordT>::clone() const
|
||||
{
|
||||
return new Record<ESXRecordT> (*this);
|
||||
}
|
||||
|
||||
template <typename ESXRecordT>
|
||||
const ESXRecordT& Record<ESXRecordT>::get() const
|
||||
{
|
||||
if (mState==State_Erased)
|
||||
throw std::logic_error ("attempt to access a deleted record");
|
||||
|
||||
return mState==State_BaseOnly ? mBase : mModified;
|
||||
}
|
||||
|
||||
template <typename ESXRecordT>
|
||||
const ESXRecordT& Record<ESXRecordT>::getBase() const
|
||||
{
|
||||
if (mState==State_Erased)
|
||||
throw std::logic_error ("attempt to access a deleted record");
|
||||
|
||||
return mState==State_ModifiedOnly ? mModified : mBase;
|
||||
}
|
||||
|
||||
template <typename ESXRecordT>
|
||||
void Record<ESXRecordT>::setModified (const ESXRecordT& modified)
|
||||
{
|
||||
if (mState==State_Erased)
|
||||
throw std::logic_error ("attempt to modify a deleted record");
|
||||
|
||||
mModified = modified;
|
||||
|
||||
if (mState!=State_ModifiedOnly)
|
||||
mState = mBase==mModified ? State_BaseOnly : State_Modified;
|
||||
}
|
||||
|
||||
template <typename ESXRecordT>
|
||||
void Record<ESXRecordT>::merge()
|
||||
{
|
||||
if (isModified())
|
||||
{
|
||||
mBase = mModified;
|
||||
mState = State_BaseOnly;
|
||||
}
|
||||
else if (mState==State_Deleted)
|
||||
{
|
||||
mState = State_Erased;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
237
apps/opencs/model/world/universalid.cpp
Normal file
237
apps/opencs/model/world/universalid.cpp
Normal file
|
@ -0,0 +1,237 @@
|
|||
|
||||
#include "universalid.hpp"
|
||||
|
||||
#include <ostream>
|
||||
#include <stdexcept>
|
||||
#include <sstream>
|
||||
|
||||
namespace
|
||||
{
|
||||
struct TypeData
|
||||
{
|
||||
CSMWorld::UniversalId::Class mClass;
|
||||
CSMWorld::UniversalId::Type mType;
|
||||
const char *mName;
|
||||
};
|
||||
|
||||
static const TypeData sNoArg[] =
|
||||
{
|
||||
{ CSMWorld::UniversalId::Class_None, CSMWorld::UniversalId::Type_None, "empty" },
|
||||
{ CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Globals, "Global Variables" },
|
||||
|
||||
{ CSMWorld::UniversalId::Class_None, CSMWorld::UniversalId::Type_None, 0 } // end marker
|
||||
};
|
||||
|
||||
static const TypeData sIdArg[] =
|
||||
{
|
||||
{ CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Global, "Global Variable" },
|
||||
|
||||
{ CSMWorld::UniversalId::Class_None, CSMWorld::UniversalId::Type_None, 0 } // end marker
|
||||
};
|
||||
|
||||
static const TypeData sIndexArg[] =
|
||||
{
|
||||
{ CSMWorld::UniversalId::Class_Transient, CSMWorld::UniversalId::Type_VerificationResults, "Verification Results" },
|
||||
|
||||
{ CSMWorld::UniversalId::Class_None, CSMWorld::UniversalId::Type_None, 0 } // end marker
|
||||
};
|
||||
}
|
||||
|
||||
CSMWorld::UniversalId::UniversalId (const std::string& universalId)
|
||||
{
|
||||
std::string::size_type index = universalId.find (':');
|
||||
|
||||
if (index==std::string::npos)
|
||||
{
|
||||
std::string type = universalId.substr (0, index);
|
||||
|
||||
if (index==std::string::npos)
|
||||
{
|
||||
for (int i=0; sNoArg[i].mName; ++i)
|
||||
if (type==sNoArg[i].mName)
|
||||
{
|
||||
mArgumentType = ArgumentType_None;
|
||||
mType = sNoArg[i].mType;
|
||||
mClass = sNoArg[i].mClass;
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i=0; sIdArg[i].mName; ++i)
|
||||
if (type==sIdArg[i].mName)
|
||||
{
|
||||
mArgumentType = ArgumentType_Id;
|
||||
mType = sIdArg[i].mType;
|
||||
mClass = sIdArg[i].mClass;
|
||||
mId = universalId.substr (0, index);
|
||||
return;
|
||||
}
|
||||
|
||||
for (int i=0; sIndexArg[i].mName; ++i)
|
||||
if (type==sIndexArg[i].mName)
|
||||
{
|
||||
mArgumentType = ArgumentType_Index;
|
||||
mType = sIndexArg[i].mType;
|
||||
mClass = sIndexArg[i].mClass;
|
||||
|
||||
std::istringstream stream (universalId.substr (0, index));
|
||||
|
||||
if (stream >> mIndex)
|
||||
return;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
throw std::runtime_error ("invalid UniversalId: " + universalId);
|
||||
}
|
||||
|
||||
CSMWorld::UniversalId::UniversalId (Type type) : mArgumentType (ArgumentType_None), mType (type), mIndex (0)
|
||||
{
|
||||
for (int i=0; sNoArg[i].mName; ++i)
|
||||
if (type==sNoArg[i].mType)
|
||||
{
|
||||
mClass = sNoArg[i].mClass;
|
||||
return;
|
||||
}
|
||||
|
||||
throw std::logic_error ("invalid argument-less UniversalId type");
|
||||
}
|
||||
|
||||
CSMWorld::UniversalId::UniversalId (Type type, const std::string& id)
|
||||
: mArgumentType (ArgumentType_Id), mType (type), mId (id), mIndex (0)
|
||||
{
|
||||
for (int i=0; sIdArg[i].mName; ++i)
|
||||
if (type==sIdArg[i].mType)
|
||||
{
|
||||
mClass = sIdArg[i].mClass;
|
||||
return;
|
||||
}
|
||||
|
||||
throw std::logic_error ("invalid ID argument UniversalId type");
|
||||
}
|
||||
|
||||
CSMWorld::UniversalId::UniversalId (Type type, int index)
|
||||
: mArgumentType (ArgumentType_Index), mType (type), mIndex (index)
|
||||
{
|
||||
for (int i=0; sIndexArg[i].mName; ++i)
|
||||
if (type==sIndexArg[i].mType)
|
||||
{
|
||||
mClass = sIndexArg[i].mClass;
|
||||
return;
|
||||
}
|
||||
|
||||
throw std::logic_error ("invalid index argument UniversalId type");
|
||||
}
|
||||
|
||||
CSMWorld::UniversalId::Class CSMWorld::UniversalId::getClass() const
|
||||
{
|
||||
return mClass;
|
||||
}
|
||||
|
||||
CSMWorld::UniversalId::ArgumentType CSMWorld::UniversalId::getArgumentType() const
|
||||
{
|
||||
return mArgumentType;
|
||||
}
|
||||
|
||||
CSMWorld::UniversalId::Type CSMWorld::UniversalId::getType() const
|
||||
{
|
||||
return mType;
|
||||
}
|
||||
|
||||
const std::string& CSMWorld::UniversalId::getId() const
|
||||
{
|
||||
if (mArgumentType!=ArgumentType_Id)
|
||||
throw std::logic_error ("invalid access to ID of non-ID UniversalId");
|
||||
|
||||
return mId;
|
||||
}
|
||||
|
||||
int CSMWorld::UniversalId::getIndex() const
|
||||
{
|
||||
if (mArgumentType!=ArgumentType_Index)
|
||||
throw std::logic_error ("invalid access to index of non-index UniversalId");
|
||||
|
||||
return mIndex;
|
||||
}
|
||||
|
||||
bool CSMWorld::UniversalId::isEqual (const UniversalId& universalId) const
|
||||
{
|
||||
if (mClass!=universalId.mClass || mArgumentType!=universalId.mArgumentType || mType!=universalId.mType)
|
||||
return false;
|
||||
|
||||
switch (mArgumentType)
|
||||
{
|
||||
case ArgumentType_Id: return mId==universalId.mId;
|
||||
case ArgumentType_Index: return mIndex==universalId.mIndex;
|
||||
|
||||
default: return true;
|
||||
}
|
||||
}
|
||||
|
||||
bool CSMWorld::UniversalId::isLess (const UniversalId& universalId) const
|
||||
{
|
||||
if (mType<universalId.mType)
|
||||
return true;
|
||||
|
||||
if (mType>universalId.mType)
|
||||
return false;
|
||||
|
||||
switch (mArgumentType)
|
||||
{
|
||||
case ArgumentType_Id: return mId<universalId.mId;
|
||||
case ArgumentType_Index: return mIndex<universalId.mIndex;
|
||||
|
||||
default: return false;
|
||||
}
|
||||
}
|
||||
|
||||
std::string CSMWorld::UniversalId::getTypeName() const
|
||||
{
|
||||
const TypeData *typeData = mArgumentType==ArgumentType_None ? sNoArg :
|
||||
(mArgumentType==ArgumentType_Id ? sIdArg : sIndexArg);
|
||||
|
||||
for (int i=0; typeData[i].mName; ++i)
|
||||
if (typeData[i].mType==mType)
|
||||
return typeData[i].mName;
|
||||
|
||||
throw std::logic_error ("failed to retrieve UniversalId type name");
|
||||
}
|
||||
|
||||
std::string CSMWorld::UniversalId::toString() const
|
||||
{
|
||||
std::ostringstream stream;
|
||||
|
||||
stream << getTypeName();
|
||||
|
||||
switch (mArgumentType)
|
||||
{
|
||||
case ArgumentType_None: break;
|
||||
case ArgumentType_Id: stream << ": " << mId; break;
|
||||
case ArgumentType_Index: stream << ": " << mIndex; break;
|
||||
}
|
||||
|
||||
return stream.str();
|
||||
}
|
||||
|
||||
bool CSMWorld::operator== (const CSMWorld::UniversalId& left, const CSMWorld::UniversalId& right)
|
||||
{
|
||||
return left.isEqual (right);
|
||||
}
|
||||
|
||||
bool CSMWorld::operator!= (const CSMWorld::UniversalId& left, const CSMWorld::UniversalId& right)
|
||||
{
|
||||
return !left.isEqual (right);
|
||||
}
|
||||
|
||||
bool CSMWorld::operator< (const UniversalId& left, const UniversalId& right)
|
||||
{
|
||||
return left.isLess (right);
|
||||
}
|
||||
|
||||
std::ostream& CSMWorld::operator< (std::ostream& stream, const CSMWorld::UniversalId& universalId)
|
||||
{
|
||||
return stream << universalId.toString();
|
||||
}
|
96
apps/opencs/model/world/universalid.hpp
Normal file
96
apps/opencs/model/world/universalid.hpp
Normal file
|
@ -0,0 +1,96 @@
|
|||
#ifndef CSM_WOLRD_UNIVERSALID_H
|
||||
#define CSM_WOLRD_UNIVERSALID_H
|
||||
|
||||
#include <string>
|
||||
#include <iosfwd>
|
||||
|
||||
#include <QMetaType>
|
||||
|
||||
namespace CSMWorld
|
||||
{
|
||||
class UniversalId
|
||||
{
|
||||
public:
|
||||
|
||||
enum Class
|
||||
{
|
||||
Class_None = 0,
|
||||
Class_Record,
|
||||
Class_SubRecord,
|
||||
Class_RecordList,
|
||||
Class_Collection, // multiple types of records combined
|
||||
Class_Transient, // not part of the world data or the project data
|
||||
Class_NonRecord // record like data that is not part of the world
|
||||
};
|
||||
|
||||
enum ArgumentType
|
||||
{
|
||||
ArgumentType_None,
|
||||
ArgumentType_Id,
|
||||
ArgumentType_Index
|
||||
};
|
||||
|
||||
enum Type
|
||||
{
|
||||
Type_None,
|
||||
|
||||
Type_Globals,
|
||||
|
||||
Type_Global,
|
||||
|
||||
Type_VerificationResults
|
||||
};
|
||||
|
||||
private:
|
||||
|
||||
Class mClass;
|
||||
ArgumentType mArgumentType;
|
||||
Type mType;
|
||||
std::string mId;
|
||||
int mIndex;
|
||||
|
||||
public:
|
||||
|
||||
UniversalId (const std::string& universalId);
|
||||
|
||||
UniversalId (Type type = Type_None);
|
||||
///< Using a type for a non-argument-less UniversalId will throw an exception.
|
||||
|
||||
UniversalId (Type type, const std::string& id);
|
||||
///< Using a type for a non-ID-argument UniversalId will throw an exception.
|
||||
|
||||
UniversalId (Type type, int index);
|
||||
///< Using a type for a non-index-argument UniversalId will throw an exception.
|
||||
|
||||
Class getClass() const;
|
||||
|
||||
ArgumentType getArgumentType() const;
|
||||
|
||||
Type getType() const;
|
||||
|
||||
const std::string& getId() const;
|
||||
///< Calling this function for a non-ID type will throw an exception.
|
||||
|
||||
int getIndex() const;
|
||||
///< Calling this function for a non-index type will throw an exception.
|
||||
|
||||
bool isEqual (const UniversalId& universalId) const;
|
||||
|
||||
bool isLess (const UniversalId& universalId) const;
|
||||
|
||||
std::string getTypeName() const;
|
||||
|
||||
std::string toString() const;
|
||||
};
|
||||
|
||||
bool operator== (const UniversalId& left, const UniversalId& right);
|
||||
bool operator!= (const UniversalId& left, const UniversalId& right);
|
||||
|
||||
bool operator< (const UniversalId& left, const UniversalId& right);
|
||||
|
||||
std::ostream& operator< (std::ostream& stream, const UniversalId& universalId);
|
||||
}
|
||||
|
||||
Q_DECLARE_METATYPE (CSMWorld::UniversalId)
|
||||
|
||||
#endif
|
54
apps/opencs/view/doc/operation.cpp
Normal file
54
apps/opencs/view/doc/operation.cpp
Normal file
|
@ -0,0 +1,54 @@
|
|||
|
||||
#include "operation.hpp"
|
||||
|
||||
#include <sstream>
|
||||
|
||||
#include "../../model/doc/document.hpp"
|
||||
|
||||
void CSVDoc::Operation::updateLabel (int threads)
|
||||
{
|
||||
if (threads==-1 || ((threads==0)!=mStalling))
|
||||
{
|
||||
std::string name ("unknown operation");
|
||||
|
||||
switch (mType)
|
||||
{
|
||||
case CSMDoc::State_Saving: name = "saving"; break;
|
||||
case CSMDoc::State_Verifying: name = "verifying"; break;
|
||||
}
|
||||
|
||||
std::ostringstream stream;
|
||||
|
||||
if ((mStalling = (threads<=0)))
|
||||
{
|
||||
stream << name << " (waiting for a free worker thread)";
|
||||
}
|
||||
else
|
||||
{
|
||||
stream << name << " (%p%)";
|
||||
}
|
||||
|
||||
setFormat (stream.str().c_str());
|
||||
}
|
||||
}
|
||||
|
||||
CSVDoc::Operation::Operation (int type) : mType (type), mStalling (false)
|
||||
{
|
||||
/// \todo Add a cancel button or a pop up menu with a cancel item
|
||||
|
||||
updateLabel();
|
||||
|
||||
/// \todo assign different progress bar colours to allow the user to distinguish easily between operation types
|
||||
}
|
||||
|
||||
void CSVDoc::Operation::setProgress (int current, int max, int threads)
|
||||
{
|
||||
updateLabel (threads);
|
||||
setRange (0, max);
|
||||
setValue (current);
|
||||
}
|
||||
|
||||
int CSVDoc::Operation::getType() const
|
||||
{
|
||||
return mType;
|
||||
}
|
31
apps/opencs/view/doc/operation.hpp
Normal file
31
apps/opencs/view/doc/operation.hpp
Normal file
|
@ -0,0 +1,31 @@
|
|||
#ifndef CSV_DOC_OPERATION_H
|
||||
#define CSV_DOC_OPERATION_H
|
||||
|
||||
#include <QProgressBar>
|
||||
|
||||
namespace CSVDoc
|
||||
{
|
||||
class Operation : public QProgressBar
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
int mType;
|
||||
bool mStalling;
|
||||
|
||||
// not implemented
|
||||
Operation (const Operation&);
|
||||
Operation& operator= (const Operation&);
|
||||
|
||||
void updateLabel (int threads = -1);
|
||||
|
||||
public:
|
||||
|
||||
Operation (int type);
|
||||
|
||||
void setProgress (int current, int max, int threads);
|
||||
|
||||
int getType() const;
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
47
apps/opencs/view/doc/operations.cpp
Normal file
47
apps/opencs/view/doc/operations.cpp
Normal file
|
@ -0,0 +1,47 @@
|
|||
|
||||
#include "operations.hpp"
|
||||
|
||||
#include <QVBoxLayout>
|
||||
|
||||
#include "operation.hpp"
|
||||
|
||||
CSVDoc::Operations::Operations()
|
||||
{
|
||||
/// \todo make widget height fixed (exactly the height required to display all operations)
|
||||
|
||||
setFeatures (QDockWidget::NoDockWidgetFeatures);
|
||||
|
||||
QWidget *widget = new QWidget;
|
||||
setWidget (widget);
|
||||
|
||||
mLayout = new QVBoxLayout;
|
||||
|
||||
widget->setLayout (mLayout);
|
||||
}
|
||||
|
||||
void CSVDoc::Operations::setProgress (int current, int max, int type, int threads)
|
||||
{
|
||||
for (std::vector<Operation *>::iterator iter (mOperations.begin()); iter!=mOperations.end(); ++iter)
|
||||
if ((*iter)->getType()==type)
|
||||
{
|
||||
(*iter)->setProgress (current, max, threads);
|
||||
return;
|
||||
}
|
||||
|
||||
Operation *operation = new Operation (type);
|
||||
|
||||
mLayout->addWidget (operation);
|
||||
mOperations.push_back (operation);
|
||||
operation->setProgress (current, max, threads);
|
||||
}
|
||||
|
||||
void CSVDoc::Operations::quitOperation (int type)
|
||||
{
|
||||
for (std::vector<Operation *>::iterator iter (mOperations.begin()); iter!=mOperations.end(); ++iter)
|
||||
if ((*iter)->getType()==type)
|
||||
{
|
||||
delete *iter;
|
||||
mOperations.erase (iter);
|
||||
break;
|
||||
}
|
||||
}
|
37
apps/opencs/view/doc/operations.hpp
Normal file
37
apps/opencs/view/doc/operations.hpp
Normal file
|
@ -0,0 +1,37 @@
|
|||
#ifndef CSV_DOC_OPERATIONS_H
|
||||
#define CSV_DOC_OPERATIONS_H
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include <QDockWidget>
|
||||
|
||||
class QVBoxLayout;
|
||||
|
||||
namespace CSVDoc
|
||||
{
|
||||
class Operation;
|
||||
|
||||
class Operations : public QDockWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
QVBoxLayout *mLayout;
|
||||
std::vector<Operation *> mOperations;
|
||||
|
||||
// not implemented
|
||||
Operations (const Operations&);
|
||||
Operations& operator= (const Operations&);
|
||||
|
||||
public:
|
||||
|
||||
Operations();
|
||||
|
||||
void setProgress (int current, int max, int type, int threads);
|
||||
///< Implicitly starts the operation, if it is not running already.
|
||||
|
||||
void quitOperation (int type);
|
||||
///< Calling this function for an operation that is not running is a no-op.
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
18
apps/opencs/view/doc/subview.cpp
Normal file
18
apps/opencs/view/doc/subview.cpp
Normal file
|
@ -0,0 +1,18 @@
|
|||
|
||||
#include "subview.hpp"
|
||||
|
||||
CSVDoc::SubView::SubView (const CSMWorld::UniversalId& id) : mUniversalId (id)
|
||||
{
|
||||
/// \todo add a button to the title bar that clones this sub view
|
||||
|
||||
setWindowTitle (mUniversalId.toString().c_str());
|
||||
|
||||
/// \todo remove (for testing only)
|
||||
setMinimumWidth (100);
|
||||
setMinimumHeight (60);
|
||||
}
|
||||
|
||||
CSMWorld::UniversalId CSVDoc::SubView::getUniversalId() const
|
||||
{
|
||||
return mUniversalId;
|
||||
}
|
45
apps/opencs/view/doc/subview.hpp
Normal file
45
apps/opencs/view/doc/subview.hpp
Normal file
|
@ -0,0 +1,45 @@
|
|||
#ifndef CSV_DOC_SUBVIEW_H
|
||||
#define CSV_DOC_SUBVIEW_H
|
||||
|
||||
#include "../../model/doc/document.hpp"
|
||||
|
||||
#include "../../model/world/universalid.hpp"
|
||||
|
||||
#include "subviewfactory.hpp"
|
||||
|
||||
#include <QDockWidget>
|
||||
|
||||
class QUndoStack;
|
||||
|
||||
namespace CSMWorld
|
||||
{
|
||||
class Data;
|
||||
}
|
||||
|
||||
namespace CSVDoc
|
||||
{
|
||||
class SubView : public QDockWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
CSMWorld::UniversalId mUniversalId;
|
||||
|
||||
// not implemented
|
||||
SubView (const SubView&);
|
||||
SubView& operator= (SubView&);
|
||||
|
||||
public:
|
||||
|
||||
SubView (const CSMWorld::UniversalId& id);
|
||||
|
||||
CSMWorld::UniversalId getUniversalId() const;
|
||||
|
||||
virtual void setEditLock (bool locked) = 0;
|
||||
|
||||
signals:
|
||||
|
||||
void focusId (const CSMWorld::UniversalId& universalId);
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
38
apps/opencs/view/doc/subviewfactory.cpp
Normal file
38
apps/opencs/view/doc/subviewfactory.cpp
Normal file
|
@ -0,0 +1,38 @@
|
|||
|
||||
#include "subviewfactory.hpp"
|
||||
|
||||
#include <cassert>
|
||||
|
||||
#include <stdexcept>
|
||||
|
||||
CSVDoc::SubViewFactoryBase::SubViewFactoryBase() {}
|
||||
|
||||
CSVDoc::SubViewFactoryBase::~SubViewFactoryBase() {}
|
||||
|
||||
|
||||
CSVDoc::SubViewFactoryManager::SubViewFactoryManager() {}
|
||||
|
||||
CSVDoc::SubViewFactoryManager::~SubViewFactoryManager()
|
||||
{
|
||||
for (std::map<CSMWorld::UniversalId::Type, SubViewFactoryBase *>::iterator iter (mSubViewFactories.begin());
|
||||
iter!=mSubViewFactories.end(); ++iter)
|
||||
delete iter->second;
|
||||
}
|
||||
|
||||
void CSVDoc::SubViewFactoryManager::add (const CSMWorld::UniversalId::Type& id, SubViewFactoryBase *factory)
|
||||
{
|
||||
assert (mSubViewFactories.find (id)==mSubViewFactories.end());
|
||||
|
||||
mSubViewFactories.insert (std::make_pair (id, factory));
|
||||
}
|
||||
|
||||
CSVDoc::SubView *CSVDoc::SubViewFactoryManager::makeSubView (const CSMWorld::UniversalId& id,
|
||||
CSMDoc::Document& document)
|
||||
{
|
||||
std::map<CSMWorld::UniversalId::Type, SubViewFactoryBase *>::iterator iter = mSubViewFactories.find (id.getType());
|
||||
|
||||
if (iter==mSubViewFactories.end())
|
||||
throw std::runtime_error ("Failed to create a sub view for: " + id.toString());
|
||||
|
||||
return iter->second->makeSubView (id, document);
|
||||
}
|
55
apps/opencs/view/doc/subviewfactory.hpp
Normal file
55
apps/opencs/view/doc/subviewfactory.hpp
Normal file
|
@ -0,0 +1,55 @@
|
|||
#ifndef CSV_DOC_SUBVIEWFACTORY_H
|
||||
#define CSV_DOC_SUBVIEWFACTORY_H
|
||||
|
||||
#include <map>
|
||||
|
||||
#include "../../model/world/universalid.hpp"
|
||||
|
||||
namespace CSMDoc
|
||||
{
|
||||
class Document;
|
||||
}
|
||||
|
||||
namespace CSVDoc
|
||||
{
|
||||
class SubView;
|
||||
|
||||
class SubViewFactoryBase
|
||||
{
|
||||
// not implemented
|
||||
SubViewFactoryBase (const SubViewFactoryBase&);
|
||||
SubViewFactoryBase& operator= (const SubViewFactoryBase&);
|
||||
|
||||
public:
|
||||
|
||||
SubViewFactoryBase();
|
||||
|
||||
virtual ~SubViewFactoryBase();
|
||||
|
||||
virtual SubView *makeSubView (const CSMWorld::UniversalId& id, CSMDoc::Document& document) = 0;
|
||||
///< The ownership of the returned sub view is not transferred.
|
||||
};
|
||||
|
||||
class SubViewFactoryManager
|
||||
{
|
||||
std::map<CSMWorld::UniversalId::Type, SubViewFactoryBase *> mSubViewFactories;
|
||||
|
||||
// not implemented
|
||||
SubViewFactoryManager (const SubViewFactoryManager&);
|
||||
SubViewFactoryManager& operator= (const SubViewFactoryManager&);
|
||||
|
||||
public:
|
||||
|
||||
SubViewFactoryManager();
|
||||
|
||||
~SubViewFactoryManager();
|
||||
|
||||
void add (const CSMWorld::UniversalId::Type& id, SubViewFactoryBase *factory);
|
||||
///< The ownership of \a factory is transferred to this.
|
||||
|
||||
SubView *makeSubView (const CSMWorld::UniversalId& id, CSMDoc::Document& document);
|
||||
///< The ownership of the returned sub view is not transferred.
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
50
apps/opencs/view/doc/subviewfactoryimp.hpp
Normal file
50
apps/opencs/view/doc/subviewfactoryimp.hpp
Normal file
|
@ -0,0 +1,50 @@
|
|||
#ifndef CSV_DOC_SUBVIEWFACTORYIMP_H
|
||||
#define CSV_DOC_SUBVIEWFACTORYIMP_H
|
||||
|
||||
#include "../../model/doc/document.hpp"
|
||||
|
||||
#include "subviewfactory.hpp"
|
||||
|
||||
namespace CSVDoc
|
||||
{
|
||||
template<class SubViewT>
|
||||
class SubViewFactory : public SubViewFactoryBase
|
||||
{
|
||||
public:
|
||||
|
||||
virtual CSVDoc::SubView *makeSubView (const CSMWorld::UniversalId& id, CSMDoc::Document& document);
|
||||
};
|
||||
|
||||
template<class SubViewT>
|
||||
CSVDoc::SubView *SubViewFactory<SubViewT>::makeSubView (const CSMWorld::UniversalId& id,
|
||||
CSMDoc::Document& document)
|
||||
{
|
||||
return new SubViewT (id, document);
|
||||
}
|
||||
|
||||
template<class SubViewT>
|
||||
class SubViewFactoryWithCreateFlag : public SubViewFactoryBase
|
||||
{
|
||||
bool mCreateAndDelete;
|
||||
|
||||
public:
|
||||
|
||||
SubViewFactoryWithCreateFlag (bool createAndDelete);
|
||||
|
||||
virtual CSVDoc::SubView *makeSubView (const CSMWorld::UniversalId& id, CSMDoc::Document& document);
|
||||
};
|
||||
|
||||
template<class SubViewT>
|
||||
SubViewFactoryWithCreateFlag<SubViewT>::SubViewFactoryWithCreateFlag (bool createAndDelete)
|
||||
: mCreateAndDelete (createAndDelete)
|
||||
{}
|
||||
|
||||
template<class SubViewT>
|
||||
CSVDoc::SubView *SubViewFactoryWithCreateFlag<SubViewT>::makeSubView (const CSMWorld::UniversalId& id,
|
||||
CSMDoc::Document& document)
|
||||
{
|
||||
return new SubViewT (id, document, mCreateAndDelete);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
216
apps/opencs/view/doc/view.cpp
Normal file
216
apps/opencs/view/doc/view.cpp
Normal file
|
@ -0,0 +1,216 @@
|
|||
|
||||
#include "view.hpp"
|
||||
|
||||
#include <sstream>
|
||||
#include <stdexcept>
|
||||
|
||||
#include <QCloseEvent>
|
||||
#include <QMenuBar>
|
||||
#include <QMdiArea>
|
||||
|
||||
#include "../../model/doc/document.hpp"
|
||||
|
||||
#include "../world/subviews.hpp"
|
||||
|
||||
#include "../tools/subviews.hpp"
|
||||
|
||||
#include "viewmanager.hpp"
|
||||
#include "operations.hpp"
|
||||
#include "subview.hpp"
|
||||
|
||||
void CSVDoc::View::closeEvent (QCloseEvent *event)
|
||||
{
|
||||
if (!mViewManager.closeRequest (this))
|
||||
event->ignore();
|
||||
}
|
||||
|
||||
void CSVDoc::View::setupFileMenu()
|
||||
{
|
||||
QMenu *file = menuBar()->addMenu (tr ("&File"));
|
||||
|
||||
QAction *new_ = new QAction (tr ("New"), this);
|
||||
connect (new_, SIGNAL (triggered()), this, SIGNAL (newDocumentRequest()));
|
||||
file->addAction (new_);
|
||||
|
||||
mSave = new QAction (tr ("&Save"), this);
|
||||
connect (mSave, SIGNAL (triggered()), this, SLOT (save()));
|
||||
file->addAction (mSave);
|
||||
}
|
||||
|
||||
void CSVDoc::View::setupEditMenu()
|
||||
{
|
||||
QMenu *edit = menuBar()->addMenu (tr ("&Edit"));
|
||||
|
||||
mUndo = mDocument->getUndoStack().createUndoAction (this, tr("&Undo"));
|
||||
mUndo->setShortcuts (QKeySequence::Undo);
|
||||
edit->addAction (mUndo);
|
||||
|
||||
mRedo= mDocument->getUndoStack().createRedoAction (this, tr("&Redo"));
|
||||
mRedo->setShortcuts (QKeySequence::Redo);
|
||||
edit->addAction (mRedo);
|
||||
}
|
||||
|
||||
void CSVDoc::View::setupViewMenu()
|
||||
{
|
||||
QMenu *view = menuBar()->addMenu (tr ("&View"));
|
||||
|
||||
QAction *newWindow = new QAction (tr ("&New View"), this);
|
||||
connect (newWindow, SIGNAL (triggered()), this, SLOT (newView()));
|
||||
view->addAction (newWindow);
|
||||
}
|
||||
|
||||
void CSVDoc::View::setupWorldMenu()
|
||||
{
|
||||
QMenu *world = menuBar()->addMenu (tr ("&World"));
|
||||
|
||||
QAction *globals = new QAction (tr ("Globals"), this);
|
||||
connect (globals, SIGNAL (triggered()), this, SLOT (addGlobalsSubView()));
|
||||
world->addAction (globals);
|
||||
|
||||
mVerify = new QAction (tr ("&Verify"), this);
|
||||
connect (mVerify, SIGNAL (triggered()), this, SLOT (verify()));
|
||||
world->addAction (mVerify);
|
||||
}
|
||||
|
||||
void CSVDoc::View::setupUi()
|
||||
{
|
||||
setupFileMenu();
|
||||
setupEditMenu();
|
||||
setupViewMenu();
|
||||
setupWorldMenu();
|
||||
}
|
||||
|
||||
void CSVDoc::View::updateTitle()
|
||||
{
|
||||
std::ostringstream stream;
|
||||
|
||||
stream << mDocument->getName();
|
||||
|
||||
if (mDocument->getState() & CSMDoc::State_Modified)
|
||||
stream << " *";
|
||||
|
||||
if (mViewTotal>1)
|
||||
stream << " [" << (mViewIndex+1) << "/" << mViewTotal << "]";
|
||||
|
||||
setWindowTitle (stream.str().c_str());
|
||||
}
|
||||
|
||||
void CSVDoc::View::updateActions()
|
||||
{
|
||||
bool editing = !(mDocument->getState() & CSMDoc::State_Locked);
|
||||
|
||||
for (std::vector<QAction *>::iterator iter (mEditingActions.begin()); iter!=mEditingActions.end(); ++iter)
|
||||
(*iter)->setEnabled (editing);
|
||||
|
||||
mUndo->setEnabled (editing & mDocument->getUndoStack().canUndo());
|
||||
mRedo->setEnabled (editing & mDocument->getUndoStack().canRedo());
|
||||
|
||||
mSave->setEnabled (!(mDocument->getState() & CSMDoc::State_Saving));
|
||||
mVerify->setEnabled (!(mDocument->getState() & CSMDoc::State_Verifying));
|
||||
}
|
||||
|
||||
CSVDoc::View::View (ViewManager& viewManager, CSMDoc::Document *document, int totalViews)
|
||||
: mViewManager (viewManager), mDocument (document), mViewIndex (totalViews-1), mViewTotal (totalViews)
|
||||
{
|
||||
setDockOptions (QMainWindow::AllowNestedDocks);
|
||||
|
||||
resize (300, 300); /// \todo get default size from settings and set reasonable minimal size
|
||||
|
||||
mOperations = new Operations;
|
||||
addDockWidget (Qt::BottomDockWidgetArea, mOperations);
|
||||
|
||||
updateTitle();
|
||||
|
||||
setupUi();
|
||||
|
||||
CSVWorld::addSubViewFactories (mSubViewFactory);
|
||||
CSVTools::addSubViewFactories (mSubViewFactory);
|
||||
}
|
||||
|
||||
CSVDoc::View::~View()
|
||||
{
|
||||
}
|
||||
|
||||
const CSMDoc::Document *CSVDoc::View::getDocument() const
|
||||
{
|
||||
return mDocument;
|
||||
}
|
||||
|
||||
CSMDoc::Document *CSVDoc::View::getDocument()
|
||||
{
|
||||
return mDocument;
|
||||
}
|
||||
|
||||
void CSVDoc::View::setIndex (int viewIndex, int totalViews)
|
||||
{
|
||||
mViewIndex = viewIndex;
|
||||
mViewTotal = totalViews;
|
||||
updateTitle();
|
||||
}
|
||||
|
||||
void CSVDoc::View::updateDocumentState()
|
||||
{
|
||||
updateTitle();
|
||||
updateActions();
|
||||
|
||||
static const int operations[] =
|
||||
{
|
||||
CSMDoc::State_Saving, CSMDoc::State_Verifying,
|
||||
-1 // end marker
|
||||
};
|
||||
|
||||
int state = mDocument->getState() ;
|
||||
|
||||
for (int i=0; operations[i]!=-1; ++i)
|
||||
if (!(state & operations[i]))
|
||||
mOperations->quitOperation (operations[i]);
|
||||
|
||||
QList<CSVDoc::SubView *> subViews = findChildren<CSVDoc::SubView *>();
|
||||
|
||||
for (QList<CSVDoc::SubView *>::iterator iter (subViews.begin()); iter!=subViews.end(); ++iter)
|
||||
(*iter)->setEditLock (state & CSMDoc::State_Locked);
|
||||
}
|
||||
|
||||
void CSVDoc::View::updateProgress (int current, int max, int type, int threads)
|
||||
{
|
||||
mOperations->setProgress (current, max, type, threads);
|
||||
}
|
||||
|
||||
void CSVDoc::View::addSubView (const CSMWorld::UniversalId& id)
|
||||
{
|
||||
/// \todo add an user setting for limiting the number of sub views per top level view. Automatically open a new top level view if this
|
||||
/// number is exceeded
|
||||
|
||||
/// \todo if the sub view limit setting is one, the sub view title bar should be hidden and the text in the main title bar adjusted
|
||||
/// accordingly
|
||||
|
||||
/// \todo add an user setting to reuse sub views (on a per document basis or on a per top level view basis)
|
||||
|
||||
SubView *view = mSubViewFactory.makeSubView (id, *mDocument);
|
||||
addDockWidget (Qt::TopDockWidgetArea, view);
|
||||
|
||||
connect (view, SIGNAL (focusId (const CSMWorld::UniversalId&)), this,
|
||||
SLOT (addSubView (const CSMWorld::UniversalId&)));
|
||||
|
||||
view->show();
|
||||
}
|
||||
|
||||
void CSVDoc::View::newView()
|
||||
{
|
||||
mViewManager.addView (mDocument);
|
||||
}
|
||||
|
||||
void CSVDoc::View::save()
|
||||
{
|
||||
mDocument->save();
|
||||
}
|
||||
|
||||
void CSVDoc::View::verify()
|
||||
{
|
||||
addSubView (mDocument->verify());
|
||||
}
|
||||
|
||||
void CSVDoc::View::addGlobalsSubView()
|
||||
{
|
||||
addSubView (CSMWorld::UniversalId::Type_Globals);
|
||||
}
|
103
apps/opencs/view/doc/view.hpp
Normal file
103
apps/opencs/view/doc/view.hpp
Normal file
|
@ -0,0 +1,103 @@
|
|||
#ifndef CSV_DOC_VIEW_H
|
||||
#define CSV_DOC_VIEW_H
|
||||
|
||||
#include <vector>
|
||||
#include <map>
|
||||
|
||||
#include <QMainWindow>
|
||||
|
||||
#include "subviewfactory.hpp"
|
||||
|
||||
class QAction;
|
||||
|
||||
namespace CSMDoc
|
||||
{
|
||||
class Document;
|
||||
}
|
||||
|
||||
namespace CSMWorld
|
||||
{
|
||||
class UniversalId;
|
||||
}
|
||||
|
||||
namespace CSVDoc
|
||||
{
|
||||
class ViewManager;
|
||||
class Operations;
|
||||
|
||||
class View : public QMainWindow
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
ViewManager& mViewManager;
|
||||
CSMDoc::Document *mDocument;
|
||||
int mViewIndex;
|
||||
int mViewTotal;
|
||||
QAction *mUndo;
|
||||
QAction *mRedo;
|
||||
QAction *mSave;
|
||||
QAction *mVerify;
|
||||
std::vector<QAction *> mEditingActions;
|
||||
Operations *mOperations;
|
||||
SubViewFactoryManager mSubViewFactory;
|
||||
|
||||
// not implemented
|
||||
View (const View&);
|
||||
View& operator= (const View&);
|
||||
|
||||
private:
|
||||
|
||||
void closeEvent (QCloseEvent *event);
|
||||
|
||||
void setupFileMenu();
|
||||
|
||||
void setupEditMenu();
|
||||
|
||||
void setupViewMenu();
|
||||
|
||||
void setupWorldMenu();
|
||||
|
||||
void setupUi();
|
||||
|
||||
void updateTitle();
|
||||
|
||||
void updateActions();
|
||||
|
||||
public:
|
||||
|
||||
View (ViewManager& viewManager, CSMDoc::Document *document, int totalViews);
|
||||
///< The ownership of \a document is not transferred to *this.
|
||||
|
||||
virtual ~View();
|
||||
|
||||
const CSMDoc::Document *getDocument() const;
|
||||
|
||||
CSMDoc::Document *getDocument();
|
||||
|
||||
void setIndex (int viewIndex, int totalViews);
|
||||
|
||||
void updateDocumentState();
|
||||
|
||||
void updateProgress (int current, int max, int type, int threads);
|
||||
|
||||
signals:
|
||||
|
||||
void newDocumentRequest();
|
||||
|
||||
public slots:
|
||||
|
||||
void addSubView (const CSMWorld::UniversalId& id);
|
||||
|
||||
private slots:
|
||||
|
||||
void newView();
|
||||
|
||||
void save();
|
||||
|
||||
void verify();
|
||||
|
||||
void addGlobalsSubView();
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
112
apps/opencs/view/doc/viewmanager.cpp
Normal file
112
apps/opencs/view/doc/viewmanager.cpp
Normal file
|
@ -0,0 +1,112 @@
|
|||
|
||||
#include "viewmanager.hpp"
|
||||
|
||||
#include <map>
|
||||
|
||||
#include "../../model/doc/documentmanager.hpp"
|
||||
#include "../../model/doc/document.hpp"
|
||||
|
||||
#include "view.hpp"
|
||||
|
||||
void CSVDoc::ViewManager::updateIndices()
|
||||
{
|
||||
std::map<CSMDoc::Document *, std::pair<int, int> > documents;
|
||||
|
||||
for (std::vector<View *>::const_iterator iter (mViews.begin()); iter!=mViews.end(); ++iter)
|
||||
{
|
||||
std::map<CSMDoc::Document *, std::pair<int, int> >::iterator document = documents.find ((*iter)->getDocument());
|
||||
|
||||
if (document==documents.end())
|
||||
document =
|
||||
documents.insert (
|
||||
std::make_pair ((*iter)->getDocument(), std::make_pair (0, countViews ((*iter)->getDocument())))).
|
||||
first;
|
||||
|
||||
(*iter)->setIndex (document->second.first++, document->second.second);
|
||||
}
|
||||
}
|
||||
|
||||
CSVDoc::ViewManager::ViewManager (CSMDoc::DocumentManager& documentManager)
|
||||
: mDocumentManager (documentManager)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
CSVDoc::ViewManager::~ViewManager()
|
||||
{
|
||||
for (std::vector<View *>::iterator iter (mViews.begin()); iter!=mViews.end(); ++iter)
|
||||
delete *iter;
|
||||
}
|
||||
|
||||
CSVDoc::View *CSVDoc::ViewManager::addView (CSMDoc::Document *document)
|
||||
{
|
||||
if (countViews (document)==0)
|
||||
{
|
||||
// new document
|
||||
connect (document, SIGNAL (stateChanged (int, CSMDoc::Document *)),
|
||||
this, SLOT (documentStateChanged (int, CSMDoc::Document *)));
|
||||
|
||||
connect (document, SIGNAL (progress (int, int, int, int, CSMDoc::Document *)),
|
||||
this, SLOT (progress (int, int, int, int, CSMDoc::Document *)));
|
||||
}
|
||||
|
||||
View *view = new View (*this, document, countViews (document)+1);
|
||||
|
||||
mViews.push_back (view);
|
||||
|
||||
view->show();
|
||||
|
||||
connect (view, SIGNAL (newDocumentRequest ()), this, SIGNAL (newDocumentRequest()));
|
||||
|
||||
updateIndices();
|
||||
|
||||
return view;
|
||||
}
|
||||
|
||||
int CSVDoc::ViewManager::countViews (const CSMDoc::Document *document) const
|
||||
{
|
||||
int count = 0;
|
||||
|
||||
for (std::vector<View *>::const_iterator iter (mViews.begin()); iter!=mViews.end(); ++iter)
|
||||
if ((*iter)->getDocument()==document)
|
||||
++count;
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
bool CSVDoc::ViewManager::closeRequest (View *view)
|
||||
{
|
||||
std::vector<View *>::iterator iter = std::find (mViews.begin(), mViews.end(), view);
|
||||
|
||||
if (iter!=mViews.end())
|
||||
{
|
||||
bool last = countViews (view->getDocument())<=1;
|
||||
|
||||
/// \todo check if save is in progress -> warn user about possible data loss
|
||||
/// \todo check if document has not been saved -> return false and start close dialogue
|
||||
|
||||
mViews.erase (iter);
|
||||
view->deleteLater();
|
||||
|
||||
if (last)
|
||||
mDocumentManager.removeDocument (view->getDocument());
|
||||
else
|
||||
updateIndices();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void CSVDoc::ViewManager::documentStateChanged (int state, CSMDoc::Document *document)
|
||||
{
|
||||
for (std::vector<View *>::const_iterator iter (mViews.begin()); iter!=mViews.end(); ++iter)
|
||||
if ((*iter)->getDocument()==document)
|
||||
(*iter)->updateDocumentState();
|
||||
}
|
||||
|
||||
void CSVDoc::ViewManager::progress (int current, int max, int type, int threads, CSMDoc::Document *document)
|
||||
{
|
||||
for (std::vector<View *>::const_iterator iter (mViews.begin()); iter!=mViews.end(); ++iter)
|
||||
if ((*iter)->getDocument()==document)
|
||||
(*iter)->updateProgress (current, max, type, threads);
|
||||
}
|
58
apps/opencs/view/doc/viewmanager.hpp
Normal file
58
apps/opencs/view/doc/viewmanager.hpp
Normal file
|
@ -0,0 +1,58 @@
|
|||
#ifndef CSV_DOC_VIEWMANAGER_H
|
||||
#define CSV_DOC_VIEWMANAGER_H
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include <QObject>
|
||||
|
||||
namespace CSMDoc
|
||||
{
|
||||
class Document;
|
||||
class DocumentManager;
|
||||
}
|
||||
|
||||
namespace CSVDoc
|
||||
{
|
||||
class View;
|
||||
|
||||
class ViewManager : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
CSMDoc::DocumentManager& mDocumentManager;
|
||||
std::vector<View *> mViews;
|
||||
|
||||
// not implemented
|
||||
ViewManager (const ViewManager&);
|
||||
ViewManager& operator= (const ViewManager&);
|
||||
|
||||
void updateIndices();
|
||||
|
||||
public:
|
||||
|
||||
ViewManager (CSMDoc::DocumentManager& documentManager);
|
||||
|
||||
virtual ~ViewManager();
|
||||
|
||||
View *addView (CSMDoc::Document *document);
|
||||
///< The ownership of the returned view is not transferred.
|
||||
|
||||
int countViews (const CSMDoc::Document *document) const;
|
||||
///< Return number of views for \a document.
|
||||
|
||||
bool closeRequest (View *view);
|
||||
|
||||
signals:
|
||||
|
||||
void newDocumentRequest();
|
||||
|
||||
private slots:
|
||||
|
||||
void documentStateChanged (int state, CSMDoc::Document *document);
|
||||
|
||||
void progress (int current, int max, int type, int threads, CSMDoc::Document *document);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
32
apps/opencs/view/tools/reportsubview.cpp
Normal file
32
apps/opencs/view/tools/reportsubview.cpp
Normal file
|
@ -0,0 +1,32 @@
|
|||
|
||||
#include "reportsubview.hpp"
|
||||
|
||||
#include <QTableView>
|
||||
#include <QHeaderView>
|
||||
|
||||
#include "../../model/tools/reportmodel.hpp"
|
||||
|
||||
CSVTools::ReportSubView::ReportSubView (const CSMWorld::UniversalId& id, CSMDoc::Document& document)
|
||||
: CSVDoc::SubView (id), mModel (document.getReport (id))
|
||||
{
|
||||
setWidget (mTable = new QTableView (this));
|
||||
mTable->setModel (mModel);
|
||||
|
||||
mTable->horizontalHeader()->setResizeMode (QHeaderView::Interactive);
|
||||
mTable->verticalHeader()->hide();
|
||||
mTable->setSortingEnabled (true);
|
||||
mTable->setSelectionBehavior (QAbstractItemView::SelectRows);
|
||||
mTable->setSelectionMode (QAbstractItemView::ExtendedSelection);
|
||||
|
||||
connect (mTable, SIGNAL (doubleClicked (const QModelIndex&)), this, SLOT (show (const QModelIndex&)));
|
||||
}
|
||||
|
||||
void CSVTools::ReportSubView::setEditLock (bool locked)
|
||||
{
|
||||
// ignored. We don't change document state anyway.
|
||||
}
|
||||
|
||||
void CSVTools::ReportSubView::show (const QModelIndex& index)
|
||||
{
|
||||
focusId (mModel->getUniversalId (index.row()));
|
||||
}
|
42
apps/opencs/view/tools/reportsubview.hpp
Normal file
42
apps/opencs/view/tools/reportsubview.hpp
Normal file
|
@ -0,0 +1,42 @@
|
|||
#ifndef CSV_TOOLS_REPORTSUBVIEW_H
|
||||
#define CSV_TOOLS_REPORTSUBVIEW_H
|
||||
|
||||
#include "../doc/subview.hpp"
|
||||
|
||||
class QTableView;
|
||||
class QModelIndex;
|
||||
|
||||
namespace CSMDoc
|
||||
{
|
||||
class Document;
|
||||
}
|
||||
|
||||
namespace CSMTools
|
||||
{
|
||||
class ReportModel;
|
||||
}
|
||||
|
||||
namespace CSVTools
|
||||
{
|
||||
class Table;
|
||||
|
||||
class ReportSubView : public CSVDoc::SubView
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
CSMTools::ReportModel *mModel;
|
||||
QTableView *mTable;
|
||||
|
||||
public:
|
||||
|
||||
ReportSubView (const CSMWorld::UniversalId& id, CSMDoc::Document& document);
|
||||
|
||||
virtual void setEditLock (bool locked);
|
||||
|
||||
private slots:
|
||||
|
||||
void show (const QModelIndex& index);
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
12
apps/opencs/view/tools/subviews.cpp
Normal file
12
apps/opencs/view/tools/subviews.cpp
Normal file
|
@ -0,0 +1,12 @@
|
|||
|
||||
#include "subviews.hpp"
|
||||
|
||||
#include "../doc/subviewfactoryimp.hpp"
|
||||
|
||||
#include "reportsubview.hpp"
|
||||
|
||||
void CSVTools::addSubViewFactories (CSVDoc::SubViewFactoryManager& manager)
|
||||
{
|
||||
manager.add (CSMWorld::UniversalId::Type_VerificationResults,
|
||||
new CSVDoc::SubViewFactory<ReportSubView>);
|
||||
}
|
14
apps/opencs/view/tools/subviews.hpp
Normal file
14
apps/opencs/view/tools/subviews.hpp
Normal file
|
@ -0,0 +1,14 @@
|
|||
#ifndef CSV_TOOLS_SUBVIEWS_H
|
||||
#define CSV_TOOLS_SUBVIEWS_H
|
||||
|
||||
namespace CSVDoc
|
||||
{
|
||||
class SubViewFactoryManager;
|
||||
}
|
||||
|
||||
namespace CSVTools
|
||||
{
|
||||
void addSubViewFactories (CSVDoc::SubViewFactoryManager& manager);
|
||||
}
|
||||
|
||||
#endif
|
94
apps/opencs/view/world/dialoguesubview.cpp
Normal file
94
apps/opencs/view/world/dialoguesubview.cpp
Normal file
|
@ -0,0 +1,94 @@
|
|||
|
||||
#include "dialoguesubview.hpp"
|
||||
|
||||
#include <QGridLayout>
|
||||
#include <QLabel>
|
||||
#include <QAbstractTableModel>
|
||||
#include <QDoubleSpinBox>
|
||||
#include <QSpinBox>
|
||||
#include <QLineEdit>
|
||||
#include <QDataWidgetMapper>
|
||||
|
||||
#include "../../model/world/columnbase.hpp"
|
||||
#include "../../model/world/idtable.hpp"
|
||||
|
||||
CSVWorld::DialogueSubView::DialogueSubView (const CSMWorld::UniversalId& id, CSMDoc::Document& document,
|
||||
bool createAndDelete)
|
||||
: SubView (id)
|
||||
{
|
||||
QWidget *widget = new QWidget (this);
|
||||
|
||||
setWidget (widget);
|
||||
|
||||
QGridLayout *layout = new QGridLayout;
|
||||
|
||||
widget->setLayout (layout);
|
||||
|
||||
QAbstractTableModel *model = document.getData().getTableModel (id);
|
||||
|
||||
int columns = model->columnCount();
|
||||
|
||||
mWidgetMapper = new QDataWidgetMapper (this);
|
||||
mWidgetMapper->setModel (model);
|
||||
|
||||
for (int i=0; i<columns; ++i)
|
||||
{
|
||||
int flags = model->headerData (i, Qt::Horizontal, CSMWorld::ColumnBase::Role_Flags).toInt();
|
||||
|
||||
if (flags & CSMWorld::ColumnBase::Flag_Dialogue)
|
||||
{
|
||||
layout->addWidget (new QLabel (model->headerData (i, Qt::Horizontal).toString()), i, 0);
|
||||
|
||||
CSMWorld::ColumnBase::Display display = static_cast<CSMWorld::ColumnBase::Display>
|
||||
(model->headerData (i, Qt::Horizontal, CSMWorld::ColumnBase::Role_Display).toInt());
|
||||
|
||||
QWidget *widget = 0;
|
||||
|
||||
if (model->flags (model->index (0, i)) & Qt::ItemIsEditable)
|
||||
{
|
||||
switch (display)
|
||||
{
|
||||
case CSMWorld::ColumnBase::Display_String:
|
||||
|
||||
layout->addWidget (widget = new QLineEdit, i, 1);
|
||||
break;
|
||||
|
||||
case CSMWorld::ColumnBase::Display_Integer:
|
||||
|
||||
/// \todo configure widget properly (range)
|
||||
layout->addWidget (widget = new QSpinBox, i, 1);
|
||||
break;
|
||||
|
||||
case CSMWorld::ColumnBase::Display_Float:
|
||||
|
||||
/// \todo configure widget properly (range, format?)
|
||||
layout->addWidget (widget = new QDoubleSpinBox, i, 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (display)
|
||||
{
|
||||
case CSMWorld::ColumnBase::Display_String:
|
||||
case CSMWorld::ColumnBase::Display_Integer:
|
||||
case CSMWorld::ColumnBase::Display_Float:
|
||||
|
||||
layout->addWidget (widget = new QLabel, i, 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (widget)
|
||||
mWidgetMapper->addMapping (widget, i);
|
||||
}
|
||||
}
|
||||
|
||||
mWidgetMapper->setCurrentModelIndex (
|
||||
dynamic_cast<CSMWorld::IdTable&> (*model).getModelIndex (id.getId(), 0));
|
||||
}
|
||||
|
||||
void CSVWorld::DialogueSubView::setEditLock (bool locked)
|
||||
{
|
||||
|
||||
}
|
27
apps/opencs/view/world/dialoguesubview.hpp
Normal file
27
apps/opencs/view/world/dialoguesubview.hpp
Normal file
|
@ -0,0 +1,27 @@
|
|||
#ifndef CSV_WORLD_DIALOGUESUBVIEW_H
|
||||
#define CSV_WORLD_DIALOGUESUBVIEW_H
|
||||
|
||||
#include "../doc/subview.hpp"
|
||||
|
||||
class QDataWidgetMapper;
|
||||
|
||||
namespace CSMDoc
|
||||
{
|
||||
class Document;
|
||||
}
|
||||
|
||||
namespace CSVWorld
|
||||
{
|
||||
class DialogueSubView : public CSVDoc::SubView
|
||||
{
|
||||
QDataWidgetMapper *mWidgetMapper;
|
||||
|
||||
public:
|
||||
|
||||
DialogueSubView (const CSMWorld::UniversalId& id, CSMDoc::Document& document, bool createAndDelete);
|
||||
|
||||
virtual void setEditLock (bool locked);
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
16
apps/opencs/view/world/subviews.cpp
Normal file
16
apps/opencs/view/world/subviews.cpp
Normal file
|
@ -0,0 +1,16 @@
|
|||
|
||||
#include "subviews.hpp"
|
||||
|
||||
#include "../doc/subviewfactoryimp.hpp"
|
||||
|
||||
#include "tablesubview.hpp"
|
||||
#include "dialoguesubview.hpp"
|
||||
|
||||
void CSVWorld::addSubViewFactories (CSVDoc::SubViewFactoryManager& manager)
|
||||
{
|
||||
manager.add (CSMWorld::UniversalId::Type_Globals,
|
||||
new CSVDoc::SubViewFactoryWithCreateFlag<TableSubView> (true));
|
||||
|
||||
manager.add (CSMWorld::UniversalId::Type_Global,
|
||||
new CSVDoc::SubViewFactoryWithCreateFlag<DialogueSubView> (true));
|
||||
}
|
14
apps/opencs/view/world/subviews.hpp
Normal file
14
apps/opencs/view/world/subviews.hpp
Normal file
|
@ -0,0 +1,14 @@
|
|||
#ifndef CSV_WORLD_SUBVIEWS_H
|
||||
#define CSV_WORLD_SUBVIEWS_H
|
||||
|
||||
namespace CSVDoc
|
||||
{
|
||||
class SubViewFactoryManager;
|
||||
}
|
||||
|
||||
namespace CSVWorld
|
||||
{
|
||||
void addSubViewFactories (CSVDoc::SubViewFactoryManager& manager);
|
||||
}
|
||||
|
||||
#endif
|
199
apps/opencs/view/world/table.cpp
Normal file
199
apps/opencs/view/world/table.cpp
Normal file
|
@ -0,0 +1,199 @@
|
|||
|
||||
#include "table.hpp"
|
||||
|
||||
#include <QHeaderView>
|
||||
|
||||
#include <QAction>
|
||||
#include <QMenu>
|
||||
#include <QContextMenuEvent>
|
||||
|
||||
#include "../../model/world/data.hpp"
|
||||
#include "../../model/world/commands.hpp"
|
||||
#include "../../model/world/idtableproxymodel.hpp"
|
||||
#include "../../model/world/idtable.hpp"
|
||||
#include "../../model/world/record.hpp"
|
||||
|
||||
#include "util.hpp"
|
||||
|
||||
void CSVWorld::Table::contextMenuEvent (QContextMenuEvent *event)
|
||||
{
|
||||
QModelIndexList selectedRows = selectionModel()->selectedRows();
|
||||
|
||||
QMenu menu (this);
|
||||
|
||||
/// \todo add menu items for select all and clear selection
|
||||
|
||||
if (!mEditLock)
|
||||
{
|
||||
if (mCreateAction)
|
||||
menu.addAction (mCreateAction);
|
||||
|
||||
if (listRevertableSelectedIds().size()>0)
|
||||
menu.addAction (mRevertAction);
|
||||
|
||||
if (listDeletableSelectedIds().size()>0)
|
||||
menu.addAction (mDeleteAction);
|
||||
}
|
||||
|
||||
menu.exec (event->globalPos());
|
||||
}
|
||||
|
||||
std::vector<std::string> CSVWorld::Table::listRevertableSelectedIds() const
|
||||
{
|
||||
QModelIndexList selectedRows = selectionModel()->selectedRows();
|
||||
|
||||
std::vector<std::string> revertableIds;
|
||||
|
||||
for (QModelIndexList::const_iterator iter (selectedRows.begin()); iter!=selectedRows.end(); ++iter)
|
||||
{
|
||||
std::string id = mProxyModel->data (*iter).toString().toStdString();
|
||||
|
||||
CSMWorld::RecordBase::State state =
|
||||
static_cast<CSMWorld::RecordBase::State> (mModel->data (mModel->getModelIndex (id, 1)).toInt());
|
||||
|
||||
if (state!=CSMWorld::RecordBase::State_BaseOnly)
|
||||
revertableIds.push_back (id);
|
||||
}
|
||||
|
||||
return revertableIds;
|
||||
}
|
||||
|
||||
std::vector<std::string> CSVWorld::Table::listDeletableSelectedIds() const
|
||||
{
|
||||
QModelIndexList selectedRows = selectionModel()->selectedRows();
|
||||
|
||||
std::vector<std::string> deletableIds;
|
||||
|
||||
for (QModelIndexList::const_iterator iter (selectedRows.begin()); iter!=selectedRows.end(); ++iter)
|
||||
{
|
||||
std::string id = mProxyModel->data (*iter).toString().toStdString();
|
||||
|
||||
CSMWorld::RecordBase::State state =
|
||||
static_cast<CSMWorld::RecordBase::State> (mModel->data (mModel->getModelIndex (id, 1)).toInt());
|
||||
|
||||
if (state!=CSMWorld::RecordBase::State_Deleted)
|
||||
deletableIds.push_back (id);
|
||||
}
|
||||
|
||||
return deletableIds;
|
||||
}
|
||||
|
||||
CSVWorld::Table::Table (const CSMWorld::UniversalId& id, CSMWorld::Data& data, QUndoStack& undoStack,
|
||||
bool createAndDelete)
|
||||
: mUndoStack (undoStack), mCreateAction (0), mEditLock (false)
|
||||
{
|
||||
mModel = &dynamic_cast<CSMWorld::IdTable&> (*data.getTableModel (id));
|
||||
|
||||
mProxyModel = new CSMWorld::IdTableProxyModel (this);
|
||||
mProxyModel->setSourceModel (mModel);
|
||||
|
||||
setModel (mProxyModel);
|
||||
horizontalHeader()->setResizeMode (QHeaderView::Interactive);
|
||||
verticalHeader()->hide();
|
||||
setSortingEnabled (true);
|
||||
setSelectionBehavior (QAbstractItemView::SelectRows);
|
||||
setSelectionMode (QAbstractItemView::ExtendedSelection);
|
||||
|
||||
int columns = mModel->columnCount();
|
||||
|
||||
for (int i=0; i<columns; ++i)
|
||||
{
|
||||
int flags = mModel->headerData (i, Qt::Horizontal, CSMWorld::ColumnBase::Role_Flags).toInt();
|
||||
|
||||
if (flags & CSMWorld::ColumnBase::Flag_Table)
|
||||
{
|
||||
CommandDelegate *delegate = new CommandDelegate (undoStack, this);
|
||||
mDelegates.push_back (delegate);
|
||||
setItemDelegateForColumn (i, delegate);
|
||||
}
|
||||
else
|
||||
hideColumn (i);
|
||||
}
|
||||
|
||||
/// \todo make initial layout fill the whole width of the table
|
||||
|
||||
if (createAndDelete)
|
||||
{
|
||||
mCreateAction = new QAction (tr ("Add Record"), this);
|
||||
connect (mCreateAction, SIGNAL (triggered()), this, SLOT (createRecord()));
|
||||
addAction (mCreateAction);
|
||||
}
|
||||
|
||||
mRevertAction = new QAction (tr ("Revert Record"), this);
|
||||
connect (mRevertAction, SIGNAL (triggered()), this, SLOT (revertRecord()));
|
||||
addAction (mRevertAction);
|
||||
|
||||
mDeleteAction = new QAction (tr ("Delete Record"), this);
|
||||
connect (mDeleteAction, SIGNAL (triggered()), this, SLOT (deleteRecord()));
|
||||
addAction (mDeleteAction);
|
||||
}
|
||||
|
||||
void CSVWorld::Table::setEditLock (bool locked)
|
||||
{
|
||||
for (std::vector<CommandDelegate *>::iterator iter (mDelegates.begin()); iter!=mDelegates.end(); ++iter)
|
||||
(*iter)->setEditLock (locked);
|
||||
|
||||
mEditLock = locked;
|
||||
}
|
||||
|
||||
CSMWorld::UniversalId CSVWorld::Table::getUniversalId (int row) const
|
||||
{
|
||||
return CSMWorld::UniversalId (
|
||||
static_cast<CSMWorld::UniversalId::Type> (mProxyModel->data (mProxyModel->index (row, 2)).toInt()),
|
||||
mProxyModel->data (mProxyModel->index (row, 0)).toString().toStdString());
|
||||
}
|
||||
|
||||
#include <sstream> /// \todo remove
|
||||
void CSVWorld::Table::createRecord()
|
||||
{
|
||||
if (!mEditLock)
|
||||
{
|
||||
/// \todo ask the user for an ID instead.
|
||||
static int index = 0;
|
||||
|
||||
std::ostringstream stream;
|
||||
stream << "id" << index++;
|
||||
|
||||
mUndoStack.push (new CSMWorld::CreateCommand (*mProxyModel, stream.str()));
|
||||
}
|
||||
}
|
||||
|
||||
void CSVWorld::Table::revertRecord()
|
||||
{
|
||||
if (!mEditLock)
|
||||
{
|
||||
std::vector<std::string> revertableIds = listRevertableSelectedIds();
|
||||
|
||||
if (revertableIds.size()>0)
|
||||
{
|
||||
if (revertableIds.size()>1)
|
||||
mUndoStack.beginMacro (tr ("Revert multiple records"));
|
||||
|
||||
for (std::vector<std::string>::const_iterator iter (revertableIds.begin()); iter!=revertableIds.end(); ++iter)
|
||||
mUndoStack.push (new CSMWorld::RevertCommand (*mModel, *iter));
|
||||
|
||||
if (revertableIds.size()>1)
|
||||
mUndoStack.endMacro();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CSVWorld::Table::deleteRecord()
|
||||
{
|
||||
if (!mEditLock)
|
||||
{
|
||||
std::vector<std::string> deletableIds = listDeletableSelectedIds();
|
||||
|
||||
if (deletableIds.size()>0)
|
||||
{
|
||||
if (deletableIds.size()>1)
|
||||
mUndoStack.beginMacro (tr ("Delete multiple records"));
|
||||
|
||||
for (std::vector<std::string>::const_iterator iter (deletableIds.begin()); iter!=deletableIds.end(); ++iter)
|
||||
mUndoStack.push (new CSMWorld::DeleteCommand (*mModel, *iter));
|
||||
|
||||
if (deletableIds.size()>1)
|
||||
mUndoStack.endMacro();
|
||||
}
|
||||
}
|
||||
}
|
65
apps/opencs/view/world/table.hpp
Normal file
65
apps/opencs/view/world/table.hpp
Normal file
|
@ -0,0 +1,65 @@
|
|||
#ifndef CSV_WORLD_TABLE_H
|
||||
#define CSV_WORLD_TABLE_H
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
#include <QTableView>
|
||||
|
||||
class QUndoStack;
|
||||
class QAction;
|
||||
|
||||
namespace CSMWorld
|
||||
{
|
||||
class Data;
|
||||
class UniversalId;
|
||||
class IdTableProxyModel;
|
||||
class IdTable;
|
||||
}
|
||||
|
||||
namespace CSVWorld
|
||||
{
|
||||
class CommandDelegate;
|
||||
|
||||
///< Table widget
|
||||
class Table : public QTableView
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
std::vector<CommandDelegate *> mDelegates;
|
||||
QUndoStack& mUndoStack;
|
||||
QAction *mCreateAction;
|
||||
QAction *mRevertAction;
|
||||
QAction *mDeleteAction;
|
||||
CSMWorld::IdTableProxyModel *mProxyModel;
|
||||
CSMWorld::IdTable *mModel;
|
||||
bool mEditLock;
|
||||
|
||||
private:
|
||||
|
||||
void contextMenuEvent (QContextMenuEvent *event);
|
||||
|
||||
std::vector<std::string> listRevertableSelectedIds() const;
|
||||
|
||||
std::vector<std::string> listDeletableSelectedIds() const;
|
||||
|
||||
public:
|
||||
|
||||
Table (const CSMWorld::UniversalId& id, CSMWorld::Data& data, QUndoStack& undoStack, bool createAndDelete);
|
||||
///< \param createAndDelete Allow creation and deletion of records.
|
||||
|
||||
void setEditLock (bool locked);
|
||||
|
||||
CSMWorld::UniversalId getUniversalId (int row) const;
|
||||
|
||||
private slots:
|
||||
|
||||
void createRecord();
|
||||
|
||||
void revertRecord();
|
||||
|
||||
void deleteRecord();
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
26
apps/opencs/view/world/tablesubview.cpp
Normal file
26
apps/opencs/view/world/tablesubview.cpp
Normal file
|
@ -0,0 +1,26 @@
|
|||
|
||||
#include "tablesubview.hpp"
|
||||
|
||||
#include "../../model/doc/document.hpp"
|
||||
|
||||
#include "table.hpp"
|
||||
|
||||
CSVWorld::TableSubView::TableSubView (const CSMWorld::UniversalId& id, CSMDoc::Document& document,
|
||||
bool createAndDelete)
|
||||
: SubView (id)
|
||||
{
|
||||
setWidget (mTable = new Table (id, document.getData(), document.getUndoStack(), createAndDelete));
|
||||
|
||||
connect (mTable, SIGNAL (doubleClicked (const QModelIndex&)), this, SLOT (rowActivated (const QModelIndex&)));
|
||||
}
|
||||
|
||||
void CSVWorld::TableSubView::setEditLock (bool locked)
|
||||
{
|
||||
mTable->setEditLock (locked);
|
||||
}
|
||||
|
||||
void CSVWorld::TableSubView::rowActivated (const QModelIndex& index)
|
||||
{
|
||||
/// \todo re-enable, after dialogue sub views have been fixed up
|
||||
// focusId (mTable->getUniversalId (index.row()));
|
||||
}
|
35
apps/opencs/view/world/tablesubview.hpp
Normal file
35
apps/opencs/view/world/tablesubview.hpp
Normal file
|
@ -0,0 +1,35 @@
|
|||
#ifndef CSV_WORLD_TABLESUBVIEW_H
|
||||
#define CSV_WORLD_TABLESUBVIEW_H
|
||||
|
||||
#include "../doc/subview.hpp"
|
||||
|
||||
class QModelIndex;
|
||||
|
||||
namespace CSMDoc
|
||||
{
|
||||
class Document;
|
||||
}
|
||||
|
||||
namespace CSVWorld
|
||||
{
|
||||
class Table;
|
||||
|
||||
class TableSubView : public CSVDoc::SubView
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
Table *mTable;
|
||||
|
||||
public:
|
||||
|
||||
TableSubView (const CSMWorld::UniversalId& id, CSMDoc::Document& document, bool createAndDelete);
|
||||
|
||||
virtual void setEditLock (bool locked);
|
||||
|
||||
private slots:
|
||||
|
||||
void rowActivated (const QModelIndex& index);
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
57
apps/opencs/view/world/util.cpp
Normal file
57
apps/opencs/view/world/util.cpp
Normal file
|
@ -0,0 +1,57 @@
|
|||
|
||||
#include "util.hpp"
|
||||
|
||||
#include <QUndoStack>
|
||||
|
||||
#include "../../model/world/commands.hpp"
|
||||
|
||||
CSVWorld::NastyTableModelHack::NastyTableModelHack (QAbstractItemModel& model)
|
||||
: mModel (model)
|
||||
{}
|
||||
|
||||
int CSVWorld::NastyTableModelHack::rowCount (const QModelIndex & parent) const
|
||||
{
|
||||
return mModel.rowCount (parent);
|
||||
}
|
||||
|
||||
int CSVWorld::NastyTableModelHack::columnCount (const QModelIndex & parent) const
|
||||
{
|
||||
return mModel.columnCount (parent);
|
||||
}
|
||||
|
||||
QVariant CSVWorld::NastyTableModelHack::data (const QModelIndex & index, int role) const
|
||||
{
|
||||
return mModel.data (index, role);
|
||||
}
|
||||
|
||||
bool CSVWorld::NastyTableModelHack::setData ( const QModelIndex &index, const QVariant &value, int role)
|
||||
{
|
||||
mData = value;
|
||||
return true;
|
||||
}
|
||||
|
||||
QVariant CSVWorld::NastyTableModelHack::getData() const
|
||||
{
|
||||
return mData;
|
||||
}
|
||||
|
||||
CSVWorld::CommandDelegate::CommandDelegate (QUndoStack& undoStack, QObject *parent)
|
||||
: QStyledItemDelegate (parent), mUndoStack (undoStack), mEditLock (false)
|
||||
{}
|
||||
|
||||
void CSVWorld::CommandDelegate::setModelData (QWidget *editor, QAbstractItemModel *model,
|
||||
const QModelIndex& index) const
|
||||
{
|
||||
if (!mEditLock)
|
||||
{
|
||||
NastyTableModelHack hack (*model);
|
||||
QStyledItemDelegate::setModelData (editor, &hack, index);
|
||||
mUndoStack.push (new CSMWorld::ModifyCommand (*model, index, hack.getData()));
|
||||
}
|
||||
///< \todo provide some kind of feedback to the user, indicating that editing is currently not possible.
|
||||
}
|
||||
|
||||
void CSVWorld::CommandDelegate::setEditLock (bool locked)
|
||||
{
|
||||
mEditLock = locked;
|
||||
}
|
50
apps/opencs/view/world/util.hpp
Normal file
50
apps/opencs/view/world/util.hpp
Normal file
|
@ -0,0 +1,50 @@
|
|||
#ifndef CSV_WORLD_UTIL_H
|
||||
#define CSV_WORLD_UTIL_H
|
||||
|
||||
#include <QAbstractTableModel>
|
||||
#include <QStyledItemDelegate>
|
||||
|
||||
class QUndoStack;
|
||||
|
||||
namespace CSVWorld
|
||||
{
|
||||
///< \brief Getting the data out of an editor widget
|
||||
///
|
||||
/// Really, Qt? Really?
|
||||
class NastyTableModelHack : public QAbstractTableModel
|
||||
{
|
||||
QAbstractItemModel& mModel;
|
||||
QVariant mData;
|
||||
|
||||
public:
|
||||
|
||||
NastyTableModelHack (QAbstractItemModel& model);
|
||||
|
||||
int rowCount (const QModelIndex & parent = QModelIndex()) const;
|
||||
|
||||
int columnCount (const QModelIndex & parent = QModelIndex()) const;
|
||||
|
||||
QVariant data (const QModelIndex & index, int role = Qt::DisplayRole) const;
|
||||
|
||||
bool setData (const QModelIndex &index, const QVariant &value, int role = Qt::EditRole);
|
||||
|
||||
QVariant getData() const;
|
||||
};
|
||||
|
||||
///< \brief Use commands instead of manipulating the model directly
|
||||
class CommandDelegate : public QStyledItemDelegate
|
||||
{
|
||||
QUndoStack& mUndoStack;
|
||||
bool mEditLock;
|
||||
|
||||
public:
|
||||
|
||||
CommandDelegate (QUndoStack& undoStack, QObject *parent);
|
||||
|
||||
void setModelData (QWidget *editor, QAbstractItemModel *model, const QModelIndex& index) const;
|
||||
|
||||
void setEditLock (bool locked);
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
|
@ -16,7 +16,7 @@ source_group(game FILES ${GAME} ${GAME_HEADER})
|
|||
add_openmw_dir (mwrender
|
||||
renderingmanager debugging sky player animation npcanimation creatureanimation actors objects
|
||||
renderinginterface localmap occlusionquery terrain terrainmaterial water shadows
|
||||
compositors characterpreview externalrendering globalmap
|
||||
compositors characterpreview externalrendering globalmap videoplayer
|
||||
)
|
||||
|
||||
add_openmw_dir (mwinput
|
||||
|
@ -30,7 +30,7 @@ add_openmw_dir (mwgui
|
|||
formatting inventorywindow container hud countdialog tradewindow settingswindow
|
||||
confirmationdialog alchemywindow referenceinterface spellwindow mainmenu quickkeysmenu
|
||||
itemselection spellbuyingwindow loadingscreen levelupdialog waitdialog spellcreationdialog
|
||||
enchantingdialog trainingwindow travelwindow
|
||||
enchantingdialog trainingwindow travelwindow imagebutton
|
||||
)
|
||||
|
||||
add_openmw_dir (mwdialogue
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
|
||||
#include <components/bsa/bsa_archive.hpp>
|
||||
#include <components/files/configurationmanager.hpp>
|
||||
#include <components/translation/translation.hpp>
|
||||
#include <components/nifoverrides/nifoverrides.hpp>
|
||||
|
||||
#include <components/nifbullet/bullet_nif_loader.hpp>
|
||||
|
@ -163,9 +164,6 @@ void OMW::Engine::loadBSA()
|
|||
dataDirectory = iter->string();
|
||||
std::cout << "Data dir " << dataDirectory << std::endl;
|
||||
Bsa::addDir(dataDirectory, mFSStrict);
|
||||
|
||||
// Workaround until resource listing capabilities are added to DirArchive, we need those to list available splash screens
|
||||
addResourcesDirectory (dataDirectory);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -255,18 +253,9 @@ void OMW::Engine::setNewGame(bool newGame)
|
|||
mNewGame = newGame;
|
||||
}
|
||||
|
||||
// Initialise and enter main loop.
|
||||
|
||||
void OMW::Engine::go()
|
||||
std::string OMW::Engine::loadSettings (Settings::Manager & settings)
|
||||
{
|
||||
assert (!mCellName.empty());
|
||||
assert (!mMaster.empty());
|
||||
assert (!mOgre);
|
||||
|
||||
mOgre = new OEngine::Render::OgreRenderer;
|
||||
|
||||
// Create the settings manager and load default settings file
|
||||
Settings::Manager settings;
|
||||
const std::string localdefault = mCfgMgr.getLocalPath().string() + "/settings-default.cfg";
|
||||
const std::string globaldefault = mCfgMgr.getGlobalPath().string() + "/settings-default.cfg";
|
||||
|
||||
|
@ -287,10 +276,6 @@ void OMW::Engine::go()
|
|||
else if (boost::filesystem::exists(globaldefault))
|
||||
settings.loadUser(globaldefault);
|
||||
|
||||
// Get the path for the keybinder xml file
|
||||
std::string keybinderUser = (mCfgMgr.getUserPath() / "input.xml").string();
|
||||
bool keybinderUserExists = boost::filesystem::exists(keybinderUser);
|
||||
|
||||
mFpsLevel = settings.getInt("fps", "HUD");
|
||||
|
||||
// load nif overrides
|
||||
|
@ -300,6 +285,13 @@ void OMW::Engine::go()
|
|||
else if (boost::filesystem::exists(mCfgMgr.getGlobalPath().string() + "/transparency-overrides.cfg"))
|
||||
nifOverrides.loadTransparencyOverrides(mCfgMgr.getGlobalPath().string() + "/transparency-overrides.cfg");
|
||||
|
||||
return settingspath;
|
||||
}
|
||||
|
||||
void OMW::Engine::prepareEngine (Settings::Manager & settings)
|
||||
{
|
||||
Nif::NIFFile::CacheLock cachelock;
|
||||
|
||||
std::string renderSystem = settings.getString("render system", "Video");
|
||||
if (renderSystem == "")
|
||||
{
|
||||
|
@ -309,6 +301,9 @@ void OMW::Engine::go()
|
|||
renderSystem = "OpenGL Rendering Subsystem";
|
||||
#endif
|
||||
}
|
||||
|
||||
mOgre = new OEngine::Render::OgreRenderer;
|
||||
|
||||
mOgre->configure(
|
||||
mCfgMgr.getLogPath().string(),
|
||||
renderSystem,
|
||||
|
@ -345,14 +340,19 @@ void OMW::Engine::go()
|
|||
|
||||
// Create the world
|
||||
mEnvironment.setWorld( new MWWorld::World (*mOgre, mFileCollections, mMaster, mPlugins,
|
||||
mResDir, mCfgMgr.getCachePath(), mNewGame, mEncoding, mFallbackMap) );
|
||||
mResDir, mCfgMgr.getCachePath(), mNewGame, mEncoder, mFallbackMap,
|
||||
mActivationDistanceOverride));
|
||||
|
||||
//Load translation data
|
||||
mTranslationDataStorage.setEncoder(mEncoder);
|
||||
mTranslationDataStorage.loadTranslationData(mFileCollections, mMaster[0]);
|
||||
|
||||
// Create window manager - this manages all the MW-specific GUI windows
|
||||
MWScript::registerExtensions (mExtensions);
|
||||
|
||||
mEnvironment.setWindowManager (new MWGui::WindowManager(
|
||||
mExtensions, mFpsLevel, mNewGame, mOgre, mCfgMgr.getLogPath().string() + std::string("/"),
|
||||
mCfgMgr.getCachePath ().string(), mScriptConsoleMode));
|
||||
mCfgMgr.getCachePath ().string(), mScriptConsoleMode, mTranslationDataStorage));
|
||||
|
||||
// Create sound system
|
||||
mEnvironment.setSoundManager (new MWSound::SoundManager(mUseSound));
|
||||
|
@ -369,9 +369,14 @@ void OMW::Engine::go()
|
|||
|
||||
// Create dialog system
|
||||
mEnvironment.setJournal (new MWDialogue::Journal);
|
||||
mEnvironment.setDialogueManager (new MWDialogue::DialogueManager (mExtensions, mVerboseScripts));
|
||||
mEnvironment.setDialogueManager (new MWDialogue::DialogueManager (mExtensions, mVerboseScripts, mTranslationDataStorage));
|
||||
|
||||
// Sets up the input system
|
||||
|
||||
// Get the path for the keybinder xml file
|
||||
std::string keybinderUser = (mCfgMgr.getUserPath() / "input.xml").string();
|
||||
bool keybinderUserExists = boost::filesystem::exists(keybinderUser);
|
||||
|
||||
mEnvironment.setInputManager (new MWInput::InputManager (*mOgre,
|
||||
MWBase::Environment::get().getWorld()->getPlayer(),
|
||||
*MWBase::Environment::get().getWindowManager(), mDebug, *this, keybinderUser, keybinderUserExists));
|
||||
|
@ -395,13 +400,8 @@ void OMW::Engine::go()
|
|||
MWBase::Environment::get().getWorld()->changeToInteriorCell (mCellName, pos);
|
||||
}
|
||||
|
||||
std::cout << "\nPress Q/ESC or close window to exit.\n";
|
||||
|
||||
mOgre->getRoot()->addFrameListener (this);
|
||||
|
||||
// Play some good 'ol tunes
|
||||
MWBase::Environment::get().getSoundManager()->playPlaylist(std::string("Explore"));
|
||||
|
||||
// scripts
|
||||
if (mCompileAll)
|
||||
{
|
||||
|
@ -414,10 +414,35 @@ void OMW::Engine::go()
|
|||
<< "%)"
|
||||
<< std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
// Initialise and enter main loop.
|
||||
|
||||
void OMW::Engine::go()
|
||||
{
|
||||
assert (!mCellName.empty());
|
||||
assert (!mMaster.empty());
|
||||
assert (!mOgre);
|
||||
|
||||
Settings::Manager settings;
|
||||
std::string settingspath;
|
||||
|
||||
settingspath = loadSettings (settings);
|
||||
|
||||
// Create encoder
|
||||
ToUTF8::Utf8Encoder encoder (mEncoding);
|
||||
mEncoder = &encoder;
|
||||
|
||||
prepareEngine (settings);
|
||||
|
||||
// Play some good 'ol tunes
|
||||
MWBase::Environment::get().getSoundManager()->playPlaylist(std::string("Explore"));
|
||||
|
||||
if (!mStartupScript.empty())
|
||||
MWBase::Environment::get().getWindowManager()->executeInConsole (mStartupScript);
|
||||
|
||||
std::cout << "\nPress Q/ESC or close window to exit.\n";
|
||||
|
||||
// Start the main rendering loop
|
||||
mOgre->start();
|
||||
|
||||
|
@ -432,12 +457,7 @@ void OMW::Engine::activate()
|
|||
if (MWBase::Environment::get().getWindowManager()->isGuiMode())
|
||||
return;
|
||||
|
||||
std::string handle = MWBase::Environment::get().getWorld()->getFacedHandle();
|
||||
|
||||
if (handle.empty())
|
||||
return;
|
||||
|
||||
MWWorld::Ptr ptr = MWBase::Environment::get().getWorld()->searchPtrViaHandle (handle);
|
||||
MWWorld::Ptr ptr = MWBase::Environment::get().getWorld()->getFacedObject();
|
||||
|
||||
if (ptr.isEmpty())
|
||||
return;
|
||||
|
@ -500,7 +520,7 @@ void OMW::Engine::showFPS(int level)
|
|||
mFpsLevel = level;
|
||||
}
|
||||
|
||||
void OMW::Engine::setEncoding(const std::string& encoding)
|
||||
void OMW::Engine::setEncoding(const ToUTF8::FromType& encoding)
|
||||
{
|
||||
mEncoding = encoding;
|
||||
}
|
||||
|
@ -519,3 +539,9 @@ void OMW::Engine::setStartupScript (const std::string& path)
|
|||
{
|
||||
mStartupScript = path;
|
||||
}
|
||||
|
||||
|
||||
void OMW::Engine::setActivationDistanceOverride (int distance)
|
||||
{
|
||||
mActivationDistanceOverride = distance;
|
||||
}
|
||||
|
|
|
@ -5,6 +5,8 @@
|
|||
|
||||
#include <components/compiler/extensions.hpp>
|
||||
#include <components/files/collections.hpp>
|
||||
#include <components/translation/translation.hpp>
|
||||
#include <components/settings/settings.hpp>
|
||||
|
||||
#include "mwbase/environment.hpp"
|
||||
|
||||
|
@ -59,7 +61,8 @@ namespace OMW
|
|||
class Engine : private Ogre::FrameListener
|
||||
{
|
||||
MWBase::Environment mEnvironment;
|
||||
std::string mEncoding;
|
||||
ToUTF8::FromType mEncoding;
|
||||
ToUTF8::Utf8Encoder* mEncoder;
|
||||
Files::PathContainer mDataDirs;
|
||||
boost::filesystem::path mResDir;
|
||||
OEngine::Render::OgreRenderer *mOgre;
|
||||
|
@ -76,13 +79,14 @@ namespace OMW
|
|||
std::map<std::string,std::string> mFallbackMap;
|
||||
bool mScriptConsoleMode;
|
||||
std::string mStartupScript;
|
||||
int mActivationDistanceOverride;
|
||||
|
||||
Compiler::Extensions mExtensions;
|
||||
Compiler::Context *mScriptContext;
|
||||
|
||||
|
||||
Files::Collections mFileCollections;
|
||||
bool mFSStrict;
|
||||
Translation::Storage mTranslationDataStorage;
|
||||
|
||||
// not implemented
|
||||
Engine (const Engine&);
|
||||
|
@ -102,6 +106,12 @@ namespace OMW
|
|||
|
||||
virtual bool frameRenderingQueued (const Ogre::FrameEvent& evt);
|
||||
|
||||
/// Load settings from various files, returns the path to the user settings file
|
||||
std::string loadSettings (Settings::Manager & settings);
|
||||
|
||||
/// Prepare engine for game play
|
||||
void prepareEngine (Settings::Manager & settings);
|
||||
|
||||
public:
|
||||
Engine(Files::ConfigurationManager& configurationManager);
|
||||
virtual ~Engine();
|
||||
|
@ -158,7 +168,7 @@ namespace OMW
|
|||
void setCompileAll (bool all);
|
||||
|
||||
/// Font encoding
|
||||
void setEncoding(const std::string& encoding);
|
||||
void setEncoding(const ToUTF8::FromType& encoding);
|
||||
|
||||
void setAnimationVerbose(bool animverbose);
|
||||
|
||||
|
@ -170,6 +180,9 @@ namespace OMW
|
|||
/// Set path for a script that is run on startup in the console.
|
||||
void setStartupScript (const std::string& path);
|
||||
|
||||
/// Override the game setting specified activation distance.
|
||||
void setActivationDistanceOverride (int distance);
|
||||
|
||||
private:
|
||||
Files::ConfigurationManager& mCfgMgr;
|
||||
};
|
||||
|
|
|
@ -131,9 +131,7 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat
|
|||
->default_value(false), "enable console-only script functionality")
|
||||
|
||||
("script-run", bpo::value<std::string>()->default_value(""),
|
||||
"select a file that is executed in the console on startup\n\n"
|
||||
"Note: The file contains a list of script lines, but not a complete scripts. "
|
||||
"That means no begin/end and no variable declarations.")
|
||||
"select a file containing a list of console commands that is executed on startup")
|
||||
|
||||
("new-game", bpo::value<bool>()->implicit_value(true)
|
||||
->default_value(false), "activate char gen/new game mechanics")
|
||||
|
@ -151,6 +149,8 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat
|
|||
("fallback", bpo::value<FallbackMap>()->default_value(FallbackMap(), "")
|
||||
->multitoken()->composing(), "fallback values")
|
||||
|
||||
("activate-dist", bpo::value <int> ()->default_value (-1), "activation distance override");
|
||||
|
||||
;
|
||||
|
||||
bpo::parsed_options valid_opts = bpo::command_line_parser(argc, argv)
|
||||
|
@ -183,21 +183,8 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat
|
|||
|
||||
// Font encoding settings
|
||||
std::string encoding(variables["encoding"].as<std::string>());
|
||||
if (encoding == "win1250")
|
||||
{
|
||||
std::cout << "Using Central and Eastern European font encoding." << std::endl;
|
||||
engine.setEncoding(encoding);
|
||||
}
|
||||
else if (encoding == "win1251")
|
||||
{
|
||||
std::cout << "Using Cyrillic font encoding." << std::endl;
|
||||
engine.setEncoding(encoding);
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cout << "Using default (English) font encoding." << std::endl;
|
||||
engine.setEncoding("win1252");
|
||||
}
|
||||
std::cout << ToUTF8::encodingUsingMessage(encoding) << std::endl;
|
||||
engine.setEncoding(ToUTF8::calculateEncoding(encoding));
|
||||
|
||||
// directory settings
|
||||
engine.enableFSStrict(variables["fs-strict"].as<bool>());
|
||||
|
@ -252,6 +239,7 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat
|
|||
engine.setFallbackValues(variables["fallback"].as<FallbackMap>().mMap);
|
||||
engine.setScriptConsoleMode (variables["script-console"].as<bool>());
|
||||
engine.setStartupScript (variables["script-run"].as<std::string>());
|
||||
engine.setActivationDistanceOverride (variables["activate-dist"].as<int>());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -128,12 +128,6 @@ float MWBase::Environment::getFrameDuration() const
|
|||
|
||||
void MWBase::Environment::cleanup()
|
||||
{
|
||||
delete mInputManager;
|
||||
mInputManager = 0;
|
||||
|
||||
delete mSoundManager;
|
||||
mSoundManager = 0;
|
||||
|
||||
delete mMechanicsManager;
|
||||
mMechanicsManager = 0;
|
||||
|
||||
|
@ -146,11 +140,17 @@ void MWBase::Environment::cleanup()
|
|||
delete mScriptManager;
|
||||
mScriptManager = 0;
|
||||
|
||||
delete mWorld;
|
||||
mWorld = 0;
|
||||
|
||||
delete mSoundManager;
|
||||
mSoundManager = 0;
|
||||
|
||||
delete mWindowManager;
|
||||
mWindowManager = 0;
|
||||
|
||||
delete mWorld;
|
||||
mWorld = 0;
|
||||
delete mInputManager;
|
||||
mInputManager = 0;
|
||||
}
|
||||
|
||||
const MWBase::Environment& MWBase::Environment::get()
|
||||
|
|
|
@ -22,6 +22,8 @@ namespace MWWorld
|
|||
namespace MWSound
|
||||
{
|
||||
class Sound;
|
||||
class Sound_Decoder;
|
||||
typedef boost::shared_ptr<Sound_Decoder> DecoderPtr;
|
||||
}
|
||||
|
||||
namespace MWBase
|
||||
|
@ -32,7 +34,7 @@ namespace MWBase
|
|||
class SoundManager
|
||||
{
|
||||
public:
|
||||
|
||||
/* These must all fit together */
|
||||
enum PlayMode {
|
||||
Play_Normal = 0, /* tracked, non-looping, multi-instance, environment */
|
||||
Play_Loop = 1<<0, /* Sound will continually loop until explicitly stopped */
|
||||
|
@ -41,6 +43,13 @@ namespace MWBase
|
|||
* but do not keep it updated (the sound will not move with
|
||||
* the object and will not stop when the object is deleted. */
|
||||
};
|
||||
enum PlayType {
|
||||
Play_TypeSfx = 1<<3, /* Normal SFX sound */
|
||||
Play_TypeVoice = 1<<4, /* Voice sound */
|
||||
Play_TypeMusic = 1<<5, /* Music track */
|
||||
Play_TypeMovie = 1<<6, /* Movie audio track */
|
||||
Play_TypeMask = Play_TypeSfx|Play_TypeVoice|Play_TypeMusic|Play_TypeMovie
|
||||
};
|
||||
|
||||
private:
|
||||
|
||||
|
@ -75,7 +84,7 @@ namespace MWBase
|
|||
///< Start playing music from the selected folder
|
||||
/// \param name of the folder that contains the playlist
|
||||
|
||||
virtual void say(MWWorld::Ptr reference, const std::string& filename) = 0;
|
||||
virtual void say(const MWWorld::Ptr &reference, const std::string& filename) = 0;
|
||||
///< Make an actor say some text.
|
||||
/// \param filename name of a sound file in "Sound/" in the data directory.
|
||||
|
||||
|
@ -83,24 +92,27 @@ namespace MWBase
|
|||
///< Say some text, without an actor ref
|
||||
/// \param filename name of a sound file in "Sound/" in the data directory.
|
||||
|
||||
virtual bool sayDone(MWWorld::Ptr reference=MWWorld::Ptr()) const = 0;
|
||||
virtual bool sayDone(const MWWorld::Ptr &reference=MWWorld::Ptr()) const = 0;
|
||||
///< Is actor not speaking?
|
||||
|
||||
virtual void stopSay(MWWorld::Ptr reference=MWWorld::Ptr()) = 0;
|
||||
virtual void stopSay(const MWWorld::Ptr &reference=MWWorld::Ptr()) = 0;
|
||||
///< Stop an actor speaking
|
||||
|
||||
virtual SoundPtr playTrack(const MWSound::DecoderPtr& decoder, PlayType type) = 0;
|
||||
///< Play a 2D audio track, using a custom decoder
|
||||
|
||||
virtual SoundPtr playSound(const std::string& soundId, float volume, float pitch,
|
||||
int mode=Play_Normal) = 0;
|
||||
PlayMode mode=Play_Normal) = 0;
|
||||
///< Play a sound, independently of 3D-position
|
||||
|
||||
virtual SoundPtr playSound3D(MWWorld::Ptr reference, const std::string& soundId,
|
||||
float volume, float pitch, int mode=Play_Normal) = 0;
|
||||
virtual SoundPtr playSound3D(const MWWorld::Ptr &reference, const std::string& soundId,
|
||||
float volume, float pitch, PlayMode mode=Play_Normal) = 0;
|
||||
///< Play a sound from an object
|
||||
|
||||
virtual void stopSound3D(MWWorld::Ptr reference, const std::string& soundId) = 0;
|
||||
virtual void stopSound3D(const MWWorld::Ptr &reference, const std::string& soundId) = 0;
|
||||
///< Stop the given object from playing the given sound,
|
||||
|
||||
virtual void stopSound3D(MWWorld::Ptr reference) = 0;
|
||||
virtual void stopSound3D(const MWWorld::Ptr &reference) = 0;
|
||||
///< Stop the given object from playing all sounds.
|
||||
|
||||
virtual void stopSound(const MWWorld::CellStore *cell) = 0;
|
||||
|
@ -109,18 +121,19 @@ namespace MWBase
|
|||
virtual void stopSound(const std::string& soundId) = 0;
|
||||
///< Stop a non-3d looping sound
|
||||
|
||||
virtual bool getSoundPlaying(MWWorld::Ptr reference, const std::string& soundId) const = 0;
|
||||
virtual bool getSoundPlaying(const MWWorld::Ptr &reference, const std::string& soundId) const = 0;
|
||||
///< Is the given sound currently playing on the given object?
|
||||
|
||||
virtual void pauseSounds(int types=Play_TypeMask) = 0;
|
||||
///< Pauses all currently playing sounds, including music.
|
||||
|
||||
virtual void resumeSounds(int types=Play_TypeMask) = 0;
|
||||
///< Resumes all previously paused sounds.
|
||||
|
||||
virtual void update(float duration) = 0;
|
||||
|
||||
virtual void setListenerPosDir(const Ogre::Vector3 &pos, const Ogre::Vector3 &dir, const Ogre::Vector3 &up) = 0;
|
||||
};
|
||||
|
||||
inline int operator|(SoundManager::PlayMode a, SoundManager::PlayMode b)
|
||||
{ return static_cast<int> (a) | static_cast<int> (b); }
|
||||
inline int operator&(SoundManager::PlayMode a, SoundManager::PlayMode b)
|
||||
{ return static_cast<int> (a) & static_cast<int> (b); }
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -7,6 +7,8 @@
|
|||
|
||||
#include <components/settings/settings.hpp>
|
||||
|
||||
#include <components/translation/translation.hpp>
|
||||
|
||||
#include "../mwmechanics/stat.hpp"
|
||||
|
||||
#include "../mwgui/mode.hpp"
|
||||
|
@ -233,6 +235,8 @@ namespace MWBase
|
|||
virtual void startSpellMaking(MWWorld::Ptr actor) = 0;
|
||||
virtual void startEnchanting(MWWorld::Ptr actor) = 0;
|
||||
virtual void startTraining(MWWorld::Ptr actor) = 0;
|
||||
|
||||
virtual const Translation::Storage& getTranslationDataStorage() const = 0;
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -45,6 +45,7 @@ namespace MWWorld
|
|||
class Ptr;
|
||||
class TimeStamp;
|
||||
class ESMStore;
|
||||
class RefData;
|
||||
}
|
||||
|
||||
namespace MWBase
|
||||
|
@ -133,6 +134,13 @@ namespace MWBase
|
|||
|
||||
virtual char getGlobalVariableType (const std::string& name) const = 0;
|
||||
///< Return ' ', if there is no global variable with this name.
|
||||
|
||||
virtual std::vector<std::string> getGlobals () const = 0;
|
||||
|
||||
virtual std::string getCurrentCellName() const = 0;
|
||||
|
||||
virtual void removeRefScript (MWWorld::RefData *ref) = 0;
|
||||
//< Remove the script attached to ref from mLocalScripts
|
||||
|
||||
virtual MWWorld::Ptr getPtr (const std::string& name, bool activeOnly) = 0;
|
||||
///< Return a pointer to a liveCellRef with the given name.
|
||||
|
@ -195,8 +203,8 @@ namespace MWBase
|
|||
|
||||
virtual void markCellAsUnchanged() = 0;
|
||||
|
||||
virtual std::string getFacedHandle() = 0;
|
||||
///< Return handle of the object the player is looking at
|
||||
virtual MWWorld::Ptr getFacedObject() = 0;
|
||||
///< Return pointer to the object the player is looking at, if it is within activation range
|
||||
|
||||
virtual void deleteObject (const MWWorld::Ptr& ptr) = 0;
|
||||
|
||||
|
@ -276,7 +284,7 @@ namespace MWBase
|
|||
/// @param cursor Y (relative 0-1)
|
||||
/// @return true if the object was placed, or false if it was rejected because the position is too far away
|
||||
|
||||
virtual void dropObjectOnGround (const MWWorld::Ptr& object) = 0;
|
||||
virtual void dropObjectOnGround (const MWWorld::Ptr& actor, const MWWorld::Ptr& object) = 0;
|
||||
|
||||
virtual bool canPlaceObject (float cursorX, float cursorY) = 0;
|
||||
///< @return true if it is possible to place on object at specified cursor location
|
||||
|
@ -302,6 +310,11 @@ namespace MWBase
|
|||
/// 1 - only waiting \n
|
||||
/// 2 - player is underwater \n
|
||||
/// 3 - enemies are nearby (not implemented)
|
||||
|
||||
|
||||
/// \todo this does not belong here
|
||||
virtual void playVideo(const std::string& name, bool allowSkipping) = 0;
|
||||
virtual void stopVideo() = 0;
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -97,11 +97,11 @@ namespace MWClass
|
|||
|
||||
// make key id lowercase
|
||||
std::string keyId = ptr.getCellRef().mKey;
|
||||
std::transform(keyId.begin(), keyId.end(), keyId.begin(), ::tolower);
|
||||
Misc::StringUtils::toLower(keyId);
|
||||
for (MWWorld::ContainerStoreIterator it = invStore.begin(); it != invStore.end(); ++it)
|
||||
{
|
||||
std::string refId = it->getCellRef().mRefID;
|
||||
std::transform(refId.begin(), refId.end(), refId.begin(), ::tolower);
|
||||
Misc::StringUtils::toLower(refId);
|
||||
if (refId == keyId)
|
||||
{
|
||||
hasKey = true;
|
||||
|
|
|
@ -84,11 +84,11 @@ namespace MWClass
|
|||
|
||||
// make key id lowercase
|
||||
std::string keyId = ptr.getCellRef().mKey;
|
||||
std::transform(keyId.begin(), keyId.end(), keyId.begin(), ::tolower);
|
||||
Misc::StringUtils::toLower(keyId);
|
||||
for (MWWorld::ContainerStoreIterator it = invStore.begin(); it != invStore.end(); ++it)
|
||||
{
|
||||
std::string refId = it->getCellRef().mRefID;
|
||||
std::transform(refId.begin(), refId.end(), refId.begin(), ::tolower);
|
||||
Misc::StringUtils::toLower(refId);
|
||||
if (refId == keyId)
|
||||
{
|
||||
hasKey = true;
|
||||
|
@ -204,33 +204,10 @@ namespace MWClass
|
|||
|
||||
std::string text;
|
||||
|
||||
const MWWorld::ESMStore& store = MWBase::Environment::get().getWorld()->getStore();
|
||||
|
||||
if (ref->mRef.mTeleport)
|
||||
{
|
||||
std::string dest;
|
||||
if (ref->mRef.mDestCell != "")
|
||||
{
|
||||
// door leads to an interior, use interior name as tooltip
|
||||
dest = ref->mRef.mDestCell;
|
||||
}
|
||||
else
|
||||
{
|
||||
// door leads to exterior, use cell name (if any), otherwise translated region name
|
||||
int x,y;
|
||||
MWBase::Environment::get().getWorld()->positionToIndex (ref->mRef.mDoorDest.pos[0], ref->mRef.mDoorDest.pos[1], x, y);
|
||||
const ESM::Cell* cell = store.get<ESM::Cell>().find(x,y);
|
||||
if (cell->mName != "")
|
||||
dest = cell->mName;
|
||||
else
|
||||
{
|
||||
const ESM::Region* region =
|
||||
store.get<ESM::Region>().find(cell->mRegion);
|
||||
dest = region->mName;
|
||||
}
|
||||
}
|
||||
text += "\n#{sTo}";
|
||||
text += "\n"+dest;
|
||||
text += "\n" + getDestination(*ref);
|
||||
}
|
||||
|
||||
if (ref->mRef.mLockLevel > 0)
|
||||
|
@ -246,6 +223,37 @@ namespace MWClass
|
|||
return info;
|
||||
}
|
||||
|
||||
std::string Door::getDestination (const MWWorld::LiveCellRef<ESM::Door>& door)
|
||||
{
|
||||
const MWWorld::ESMStore& store = MWBase::Environment::get().getWorld()->getStore();
|
||||
|
||||
std::string dest;
|
||||
if (door.mRef.mDestCell != "")
|
||||
{
|
||||
// door leads to an interior, use interior name as tooltip
|
||||
dest = door.mRef.mDestCell;
|
||||
}
|
||||
else
|
||||
{
|
||||
// door leads to exterior, use cell name (if any), otherwise translated region name
|
||||
int x,y;
|
||||
MWBase::Environment::get().getWorld()->positionToIndex (door.mRef.mDoorDest.pos[0], door.mRef.mDoorDest.pos[1], x, y);
|
||||
const ESM::Cell* cell = store.get<ESM::Cell>().find(x,y);
|
||||
if (cell->mName != "")
|
||||
dest = cell->mName;
|
||||
else
|
||||
{
|
||||
const ESM::Region* region =
|
||||
store.get<ESM::Region>().find(cell->mRegion);
|
||||
|
||||
//name as is, not a token
|
||||
return region->mName;
|
||||
}
|
||||
}
|
||||
|
||||
return "#{sCell=" + dest + "}";
|
||||
}
|
||||
|
||||
MWWorld::Ptr
|
||||
Door::copyToCellImpl(const MWWorld::Ptr &ptr, MWWorld::CellStore &cell) const
|
||||
{
|
||||
|
|
|
@ -31,6 +31,9 @@ namespace MWClass
|
|||
virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::Ptr& ptr) const;
|
||||
///< @return the content of the tool tip to be displayed. raises exception if the object has no tooltip.
|
||||
|
||||
static std::string getDestination (const MWWorld::LiveCellRef<ESM::Door>& door);
|
||||
///< @return destination cell name or token
|
||||
|
||||
virtual void lock (const MWWorld::Ptr& ptr, int lockLevel) const;
|
||||
///< Lock object
|
||||
|
||||
|
|
|
@ -12,6 +12,9 @@
|
|||
#include "../mwworld/cellstore.hpp"
|
||||
#include "../mwworld/physicssystem.hpp"
|
||||
#include "../mwworld/actioneat.hpp"
|
||||
#include "../mwworld/player.hpp"
|
||||
|
||||
#include "../mwmechanics/npcstats.hpp"
|
||||
|
||||
#include "../mwgui/tooltips.hpp"
|
||||
|
||||
|
@ -154,6 +157,10 @@ namespace MWClass
|
|||
text += MWGui::ToolTips::getMiscString(ref->mBase->mScript, "Script");
|
||||
}
|
||||
|
||||
MWWorld::Ptr player = MWBase::Environment::get().getWorld ()->getPlayer ().getPlayer();
|
||||
MWMechanics::NpcStats& npcStats = MWWorld::Class::get(player).getNpcStats (player);
|
||||
int alchemySkill = npcStats.getSkill (ESM::Skill::Alchemy).getBase();
|
||||
|
||||
MWGui::Widgets::SpellEffectList list;
|
||||
for (int i=0; i<4; ++i)
|
||||
{
|
||||
|
@ -163,6 +170,12 @@ namespace MWClass
|
|||
params.mEffectID = ref->mBase->mData.mEffectID[i];
|
||||
params.mAttribute = ref->mBase->mData.mAttributes[i];
|
||||
params.mSkill = ref->mBase->mData.mSkills[i];
|
||||
|
||||
params.mKnown = ( (i == 0 && alchemySkill >= 15)
|
||||
|| (i == 1 && alchemySkill >= 30)
|
||||
|| (i == 2 && alchemySkill >= 45)
|
||||
|| (i == 3 && alchemySkill >= 60));
|
||||
|
||||
list.push_back(params);
|
||||
}
|
||||
info.effects = list;
|
||||
|
|
|
@ -65,7 +65,7 @@ namespace MWClass
|
|||
if (!ref->mBase->mFaction.empty())
|
||||
{
|
||||
std::string faction = ref->mBase->mFaction;
|
||||
boost::algorithm::to_lower(faction);
|
||||
Misc::StringUtils::toLower(faction);
|
||||
if(ref->mBase->mNpdt52.mGold != -10)
|
||||
{
|
||||
data->mNpcStats.getFactionRanks()[faction] = (int)ref->mBase->mNpdt52.mRank;
|
||||
|
@ -100,14 +100,15 @@ namespace MWClass
|
|||
}
|
||||
else
|
||||
{
|
||||
/// \todo do something with mNpdt12 maybe:p
|
||||
for (int i=0; i<8; ++i)
|
||||
data->mCreatureStats.getAttribute (i).set (10);
|
||||
|
||||
for (int i=0; i<3; ++i)
|
||||
data->mCreatureStats.setDynamic (i, 10);
|
||||
|
||||
data->mCreatureStats.setLevel (1);
|
||||
data->mCreatureStats.setLevel(ref->mBase->mNpdt12.mLevel);
|
||||
data->mNpcStats.setBaseDisposition(ref->mBase->mNpdt12.mDisposition);
|
||||
data->mNpcStats.setReputation(ref->mBase->mNpdt12.mReputation);
|
||||
}
|
||||
|
||||
data->mCreatureStats.setAiSetting (0, ref->mBase->mAiData.mHello);
|
||||
|
|
|
@ -16,9 +16,11 @@
|
|||
#include <components/compiler/scriptparser.hpp>
|
||||
|
||||
#include <components/interpreter/interpreter.hpp>
|
||||
#include <components/interpreter/defines.hpp>
|
||||
|
||||
#include "../mwbase/environment.hpp"
|
||||
#include "../mwbase/world.hpp"
|
||||
#include "../mwbase/journal.hpp"
|
||||
#include "../mwbase/scriptmanager.hpp"
|
||||
#include "../mwbase/windowmanager.hpp"
|
||||
#include "../mwbase/mechanicsmanager.hpp"
|
||||
|
@ -39,47 +41,14 @@
|
|||
|
||||
#include "filter.hpp"
|
||||
|
||||
namespace
|
||||
{
|
||||
std::string toLower (const std::string& name)
|
||||
{
|
||||
std::string lowerCase;
|
||||
|
||||
std::transform (name.begin(), name.end(), std::back_inserter (lowerCase),
|
||||
(int(*)(int)) std::tolower);
|
||||
|
||||
return lowerCase;
|
||||
}
|
||||
|
||||
bool stringCompareNoCase (std::string first, std::string second)
|
||||
{
|
||||
unsigned int i=0;
|
||||
while ( (i<first.length()) && (i<second.length()) )
|
||||
{
|
||||
if (tolower(first[i])<tolower(second[i])) return true;
|
||||
else if (tolower(first[i])>tolower(second[i])) return false;
|
||||
++i;
|
||||
}
|
||||
if (first.length()<second.length())
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
//helper function
|
||||
std::string::size_type find_str_ci(const std::string& str, const std::string& substr,size_t pos)
|
||||
{
|
||||
return toLower(str).find(toLower(substr),pos);
|
||||
}
|
||||
}
|
||||
|
||||
namespace MWDialogue
|
||||
{
|
||||
DialogueManager::DialogueManager (const Compiler::Extensions& extensions, bool scriptVerbose) :
|
||||
DialogueManager::DialogueManager (const Compiler::Extensions& extensions, bool scriptVerbose, Translation::Storage& translationDataStorage) :
|
||||
mCompilerContext (MWScript::CompilerContext::Type_Dialgoue),
|
||||
mErrorStream(std::cout.rdbuf()),mErrorHandler(mErrorStream)
|
||||
, mTemporaryDispositionChange(0.f)
|
||||
, mPermanentDispositionChange(0.f), mScriptVerbose (scriptVerbose)
|
||||
, mTranslationDataStorage(translationDataStorage)
|
||||
{
|
||||
mChoice = -1;
|
||||
mIsInChoice = false;
|
||||
|
@ -93,26 +62,55 @@ namespace MWDialogue
|
|||
MWWorld::Store<ESM::Dialogue>::iterator it = dialogs.begin();
|
||||
for (; it != dialogs.end(); ++it)
|
||||
{
|
||||
mDialogueMap[toLower(it->mId)] = *it;
|
||||
mDialogueMap[Misc::StringUtils::lowerCase(it->mId)] = *it;
|
||||
}
|
||||
}
|
||||
|
||||
void DialogueManager::addTopic (const std::string& topic)
|
||||
{
|
||||
mKnownTopics[toLower(topic)] = true;
|
||||
mKnownTopics[Misc::StringUtils::lowerCase(topic)] = true;
|
||||
}
|
||||
|
||||
void DialogueManager::parseText (const std::string& text)
|
||||
{
|
||||
std::list<std::string>::iterator it;
|
||||
for(it = mActorKnownTopics.begin();it != mActorKnownTopics.end();++it)
|
||||
std::vector<HyperTextToken> hypertext = ParseHyperText(text);
|
||||
|
||||
//calculation of standard form fir all hyperlinks
|
||||
for (size_t i = 0; i < hypertext.size(); ++i)
|
||||
{
|
||||
size_t pos = find_str_ci(text,*it,0);
|
||||
if(pos !=std::string::npos)
|
||||
if (hypertext[i].mLink)
|
||||
{
|
||||
mKnownTopics[*it] = true;
|
||||
size_t asterisk_count = MWDialogue::RemovePseudoAsterisks(hypertext[i].mText);
|
||||
for(; asterisk_count > 0; --asterisk_count)
|
||||
hypertext[i].mText.append("*");
|
||||
|
||||
hypertext[i].mText = mTranslationDataStorage.topicStandardForm(hypertext[i].mText);
|
||||
}
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < hypertext.size(); ++i)
|
||||
{
|
||||
std::list<std::string>::iterator it;
|
||||
for(it = mActorKnownTopics.begin(); it != mActorKnownTopics.end(); ++it)
|
||||
{
|
||||
if (hypertext[i].mLink)
|
||||
{
|
||||
if( hypertext[i].mText == *it )
|
||||
{
|
||||
mKnownTopics[hypertext[i].mText] = true;
|
||||
}
|
||||
}
|
||||
else if( !mTranslationDataStorage.hasTranslation() )
|
||||
{
|
||||
size_t pos = Misc::StringUtils::lowerCase(hypertext[i].mText).find(*it, 0);
|
||||
if(pos !=std::string::npos)
|
||||
{
|
||||
mKnownTopics[*it] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
updateTopics();
|
||||
}
|
||||
|
||||
|
@ -125,15 +123,9 @@ namespace MWDialogue
|
|||
|
||||
MWMechanics::CreatureStats& creatureStats = MWWorld::Class::get (actor).getCreatureStats (actor);
|
||||
mTalkedTo = creatureStats.hasTalkedToPlayer();
|
||||
creatureStats.talkedToPlayer();
|
||||
|
||||
mActorKnownTopics.clear();
|
||||
|
||||
//initialise the GUI
|
||||
MWBase::Environment::get().getWindowManager()->pushGuiMode(MWGui::GM_Dialogue);
|
||||
MWGui::DialogueWindow* win = MWBase::Environment::get().getWindowManager()->getDialogueWindow();
|
||||
win->startDialogue(actor, MWWorld::Class::get (actor).getName (actor));
|
||||
|
||||
//setup the list of topics known by the actor. Topics who are also on the knownTopics list will be added to the GUI
|
||||
updateTopics();
|
||||
|
||||
|
@ -147,15 +139,25 @@ namespace MWDialogue
|
|||
{
|
||||
if(it->mType == ESM::Dialogue::Greeting)
|
||||
{
|
||||
if (const ESM::DialInfo *info = filter.search (*it))
|
||||
// Search a response (we do not accept a fallback to "Info refusal" here)
|
||||
if (const ESM::DialInfo *info = filter.search (*it, false))
|
||||
{
|
||||
//initialise the GUI
|
||||
MWBase::Environment::get().getWindowManager()->pushGuiMode(MWGui::GM_Dialogue);
|
||||
MWGui::DialogueWindow* win = MWBase::Environment::get().getWindowManager()->getDialogueWindow();
|
||||
win->startDialogue(actor, MWWorld::Class::get (actor).getName (actor));
|
||||
|
||||
creatureStats.talkedToPlayer();
|
||||
|
||||
if (!info->mSound.empty())
|
||||
{
|
||||
// TODO play sound
|
||||
}
|
||||
|
||||
parseText (info->mResponse);
|
||||
win->addText (info->mResponse);
|
||||
|
||||
MWScript::InterpreterContext interpreterContext(&mActor.getRefData().getLocals(),mActor);
|
||||
win->addText (Interpreter::fixDefinesDialog(info->mResponse, interpreterContext));
|
||||
executeScript (info->mResultScript);
|
||||
mLastTopic = it->mId;
|
||||
mLastDialogue = *info;
|
||||
|
@ -238,6 +240,53 @@ namespace MWDialogue
|
|||
}
|
||||
}
|
||||
|
||||
void DialogueManager::executeTopic (const std::string& topic)
|
||||
{
|
||||
Filter filter (mActor, mChoice, mTalkedTo);
|
||||
|
||||
const MWWorld::Store<ESM::Dialogue> &dialogues =
|
||||
MWBase::Environment::get().getWorld()->getStore().get<ESM::Dialogue>();
|
||||
|
||||
const ESM::Dialogue& dialogue = *dialogues.find (topic);
|
||||
|
||||
MWGui::DialogueWindow* win = MWBase::Environment::get().getWindowManager()->getDialogueWindow();
|
||||
|
||||
if (const ESM::DialInfo *info = filter.search (dialogue, true))
|
||||
{
|
||||
parseText (info->mResponse);
|
||||
|
||||
if (dialogue.mType==ESM::Dialogue::Persuasion)
|
||||
{
|
||||
std::string modifiedTopic = "s" + topic;
|
||||
|
||||
modifiedTopic.erase (std::remove (modifiedTopic.begin(), modifiedTopic.end(), ' '), modifiedTopic.end());
|
||||
|
||||
const MWWorld::Store<ESM::GameSetting>& gmsts =
|
||||
MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>();
|
||||
|
||||
win->addTitle (gmsts.find (modifiedTopic)->getString());
|
||||
}
|
||||
else
|
||||
win->addTitle (topic);
|
||||
|
||||
MWScript::InterpreterContext interpreterContext(&mActor.getRefData().getLocals(),mActor);
|
||||
win->addText (Interpreter::fixDefinesDialog(info->mResponse, interpreterContext));
|
||||
MWBase::Environment::get().getJournal()->addTopic (topic, info->mId);
|
||||
|
||||
executeScript (info->mResultScript);
|
||||
|
||||
mLastTopic = topic;
|
||||
mLastDialogue = *info;
|
||||
}
|
||||
else
|
||||
{
|
||||
// no response found, print a fallback text
|
||||
win->addTitle (topic);
|
||||
win->addText ("…");
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void DialogueManager::updateTopics()
|
||||
{
|
||||
std::list<std::string> keywordList;
|
||||
|
@ -254,12 +303,13 @@ namespace MWDialogue
|
|||
{
|
||||
if (iter->mType == ESM::Dialogue::Topic)
|
||||
{
|
||||
if (filter.search (*iter))
|
||||
if (filter.responseAvailable (*iter))
|
||||
{
|
||||
mActorKnownTopics.push_back (toLower (iter->mId));
|
||||
std::string lower = Misc::StringUtils::lowerCase(iter->mId);
|
||||
mActorKnownTopics.push_back (lower);
|
||||
|
||||
//does the player know the topic?
|
||||
if (mKnownTopics.find (toLower (iter->mId)) != mKnownTopics.end())
|
||||
if (mKnownTopics.find (lower) != mKnownTopics.end())
|
||||
{
|
||||
keywordList.push_back (iter->mId);
|
||||
}
|
||||
|
@ -317,7 +367,7 @@ namespace MWDialogue
|
|||
win->setServices (windowServices);
|
||||
|
||||
// sort again, because the previous sort was case-sensitive
|
||||
keywordList.sort(stringCompareNoCase);
|
||||
keywordList.sort(Misc::StringUtils::ciEqual);
|
||||
win->setKeywords(keywordList);
|
||||
|
||||
mChoice = choice;
|
||||
|
@ -332,24 +382,7 @@ namespace MWDialogue
|
|||
ESM::Dialogue ndialogue = mDialogueMap[keyword];
|
||||
if (mDialogueMap[keyword].mType == ESM::Dialogue::Topic)
|
||||
{
|
||||
Filter filter (mActor, mChoice, mTalkedTo);
|
||||
|
||||
if (const ESM::DialInfo *info = filter.search (mDialogueMap[keyword]))
|
||||
{
|
||||
std::string text = info->mResponse;
|
||||
std::string script = info->mResultScript;
|
||||
|
||||
parseText (text);
|
||||
|
||||
MWGui::DialogueWindow* win = MWBase::Environment::get().getWindowManager()->getDialogueWindow();
|
||||
win->addTitle (keyword);
|
||||
win->addText (info->mResponse);
|
||||
|
||||
executeScript (script);
|
||||
|
||||
mLastTopic = keyword;
|
||||
mLastDialogue = *info;
|
||||
}
|
||||
executeTopic (keyword);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -359,6 +392,10 @@ namespace MWDialogue
|
|||
|
||||
void DialogueManager::goodbyeSelected()
|
||||
{
|
||||
// Do not close the dialogue window if the player has to answer a question
|
||||
if (mIsInChoice)
|
||||
return;
|
||||
|
||||
MWBase::Environment::get().getWindowManager()->removeGuiMode(MWGui::GM_Dialogue);
|
||||
|
||||
// Apply disposition change to NPC's base disposition
|
||||
|
@ -383,14 +420,17 @@ namespace MWDialogue
|
|||
{
|
||||
Filter filter (mActor, mChoice, mTalkedTo);
|
||||
|
||||
if (const ESM::DialInfo *info = filter.search (mDialogueMap[mLastTopic]))
|
||||
if (const ESM::DialInfo *info = filter.search (mDialogueMap[mLastTopic], true))
|
||||
{
|
||||
mChoiceMap.clear();
|
||||
mChoice = -1;
|
||||
mIsInChoice = false;
|
||||
std::string text = info->mResponse;
|
||||
parseText (text);
|
||||
MWBase::Environment::get().getWindowManager()->getDialogueWindow()->addText (text);
|
||||
|
||||
MWScript::InterpreterContext interpreterContext(&mActor.getRefData().getLocals(),mActor);
|
||||
MWBase::Environment::get().getWindowManager()->getDialogueWindow()->addText (Interpreter::fixDefinesDialog(text, interpreterContext));
|
||||
MWBase::Environment::get().getJournal()->addTopic (mLastTopic, info->mId);
|
||||
executeScript (info->mResultScript);
|
||||
mLastTopic = mLastTopic;
|
||||
mLastDialogue = *info;
|
||||
|
@ -412,7 +452,7 @@ namespace MWDialogue
|
|||
{
|
||||
MWGui::DialogueWindow* win = MWBase::Environment::get().getWindowManager()->getDialogueWindow();
|
||||
win->askQuestion(question);
|
||||
mChoiceMap[toLower(question)] = choice;
|
||||
mChoiceMap[Misc::StringUtils::lowerCase(question)] = choice;
|
||||
mIsInChoice = true;
|
||||
}
|
||||
|
||||
|
@ -445,30 +485,22 @@ namespace MWDialogue
|
|||
else if (curDisp + mTemporaryDispositionChange > 100)
|
||||
mTemporaryDispositionChange = 100 - curDisp;
|
||||
|
||||
// practice skill
|
||||
MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer();
|
||||
MWWorld::Class::get(player).skillUsageSucceeded(player, ESM::Skill::Speechcraft, success ? 0 : 1);
|
||||
|
||||
if (success)
|
||||
MWWorld::Class::get(player).skillUsageSucceeded(player, ESM::Skill::Speechcraft, 0);
|
||||
|
||||
// add status message to dialogue window
|
||||
std::string text;
|
||||
|
||||
if (type == MWBase::MechanicsManager::PT_Admire)
|
||||
text = "sAdmire";
|
||||
text = "Admire";
|
||||
else if (type == MWBase::MechanicsManager::PT_Taunt)
|
||||
text = "sTaunt";
|
||||
text = "Taunt";
|
||||
else if (type == MWBase::MechanicsManager::PT_Intimidate)
|
||||
text = "sIntimidate";
|
||||
else
|
||||
text = "sBribe";
|
||||
text = "Intimidate";
|
||||
else{
|
||||
text = "Bribe";
|
||||
}
|
||||
|
||||
text += (success ? "Success" : "Fail");
|
||||
|
||||
MWGui::DialogueWindow* win = MWBase::Environment::get().getWindowManager()->getDialogueWindow();
|
||||
win->addTitle(MyGUI::LanguageManager::getInstance().replaceTags("#{"+text+"}"));
|
||||
|
||||
/// \todo text from INFO record, how to get the ID?
|
||||
executeTopic (text + (success ? " Success" : " Fail"));
|
||||
}
|
||||
|
||||
int DialogueManager::getTemporaryDispositionChange() const
|
||||
|
@ -480,4 +512,57 @@ namespace MWDialogue
|
|||
{
|
||||
mTemporaryDispositionChange += delta;
|
||||
}
|
||||
|
||||
std::vector<HyperTextToken> ParseHyperText(const std::string& text)
|
||||
{
|
||||
std::vector<HyperTextToken> result;
|
||||
|
||||
MyGUI::UString utext(text);
|
||||
|
||||
size_t pos_begin, pos_end, iteration_pos = 0;
|
||||
for(;;)
|
||||
{
|
||||
pos_begin = utext.find('@', iteration_pos);
|
||||
if (pos_begin != std::string::npos)
|
||||
pos_end = utext.find('#', pos_begin);
|
||||
|
||||
if (pos_begin != std::string::npos && pos_end != std::string::npos)
|
||||
{
|
||||
result.push_back( HyperTextToken(utext.substr(iteration_pos, pos_begin - iteration_pos), false) );
|
||||
|
||||
std::string link = utext.substr(pos_begin + 1, pos_end - pos_begin - 1);
|
||||
result.push_back( HyperTextToken(link, true) );
|
||||
|
||||
iteration_pos = pos_end + 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
result.push_back( HyperTextToken(utext.substr(iteration_pos), false) );
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
size_t RemovePseudoAsterisks(std::string& phrase)
|
||||
{
|
||||
size_t pseudoAsterisksCount = 0;
|
||||
const char specialPseudoAsteriskCharacter = 127;
|
||||
|
||||
if( !phrase.empty() )
|
||||
{
|
||||
std::string::reverse_iterator rit = phrase.rbegin();
|
||||
|
||||
while( rit != phrase.rend() && *rit == specialPseudoAsteriskCharacter )
|
||||
{
|
||||
pseudoAsterisksCount++;
|
||||
++rit;
|
||||
}
|
||||
}
|
||||
|
||||
phrase = phrase.substr(0, phrase.length() - pseudoAsterisksCount);
|
||||
|
||||
return pseudoAsterisksCount;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
#include <list>
|
||||
|
||||
#include <components/compiler/streamerrorhandler.hpp>
|
||||
#include <components/translation/translation.hpp>
|
||||
|
||||
#include "../mwworld/ptr.hpp"
|
||||
|
||||
|
@ -20,10 +21,11 @@ namespace MWDialogue
|
|||
std::map<std::string, bool> mKnownTopics;// Those are the topics the player knows.
|
||||
std::list<std::string> mActorKnownTopics;
|
||||
|
||||
Translation::Storage& mTranslationDataStorage;
|
||||
MWScript::CompilerContext mCompilerContext;
|
||||
std::ostream mErrorStream;
|
||||
Compiler::StreamErrorHandler mErrorHandler;
|
||||
|
||||
|
||||
MWWorld::Ptr mActor;
|
||||
bool mTalkedTo;
|
||||
|
||||
|
@ -46,9 +48,11 @@ namespace MWDialogue
|
|||
|
||||
void printError (const std::string& error);
|
||||
|
||||
void executeTopic (const std::string& topic);
|
||||
|
||||
public:
|
||||
|
||||
DialogueManager (const Compiler::Extensions& extensions, bool scriptVerbose);
|
||||
DialogueManager (const Compiler::Extensions& extensions, bool scriptVerbose, Translation::Storage& translationDataStorage);
|
||||
|
||||
virtual void startDialogue (const MWWorld::Ptr& actor);
|
||||
|
||||
|
@ -70,6 +74,21 @@ namespace MWDialogue
|
|||
virtual int getTemporaryDispositionChange () const;
|
||||
virtual void applyTemporaryDispositionChange (int delta);
|
||||
};
|
||||
|
||||
|
||||
struct HyperTextToken
|
||||
{
|
||||
HyperTextToken(const std::string& text, bool link) : mText(text), mLink(link) {}
|
||||
|
||||
std::string mText;
|
||||
bool mLink;
|
||||
};
|
||||
|
||||
// In translations (at least Russian) the links are marked with @#, so
|
||||
// it should be a function to parse it
|
||||
std::vector<HyperTextToken> ParseHyperText(const std::string& text);
|
||||
|
||||
size_t RemovePseudoAsterisks(std::string& phrase);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -17,27 +17,21 @@
|
|||
|
||||
#include "selectwrapper.hpp"
|
||||
|
||||
namespace
|
||||
{
|
||||
std::string toLower (const std::string& name)
|
||||
{
|
||||
std::string lowerCase;
|
||||
|
||||
std::transform (name.begin(), name.end(), std::back_inserter (lowerCase),
|
||||
(int(*)(int)) std::tolower);
|
||||
|
||||
return lowerCase;
|
||||
}
|
||||
}
|
||||
|
||||
bool MWDialogue::Filter::testActor (const ESM::DialInfo& info) const
|
||||
{
|
||||
bool isCreature = (mActor.getTypeName() != typeid (ESM::NPC).name());
|
||||
|
||||
// actor id
|
||||
if (!info.mActor.empty())
|
||||
if (toLower (info.mActor)!=MWWorld::Class::get (mActor).getId (mActor))
|
||||
{
|
||||
if ( Misc::StringUtils::lowerCase (info.mActor)!=MWWorld::Class::get (mActor).getId (mActor))
|
||||
return false;
|
||||
|
||||
bool isCreature = (mActor.getTypeName() != typeid (ESM::NPC).name());
|
||||
}
|
||||
else if (isCreature)
|
||||
{
|
||||
// Creatures must not have topics aside of those specific to their id
|
||||
return false;
|
||||
}
|
||||
|
||||
// NPC race
|
||||
if (!info.mRace.empty())
|
||||
|
@ -47,7 +41,7 @@ bool MWDialogue::Filter::testActor (const ESM::DialInfo& info) const
|
|||
|
||||
MWWorld::LiveCellRef<ESM::NPC> *cellRef = mActor.get<ESM::NPC>();
|
||||
|
||||
if (toLower (info.mRace)!=toLower (cellRef->mBase->mRace))
|
||||
if (Misc::StringUtils::lowerCase (info.mRace)!= Misc::StringUtils::lowerCase (cellRef->mBase->mRace))
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -59,7 +53,7 @@ bool MWDialogue::Filter::testActor (const ESM::DialInfo& info) const
|
|||
|
||||
MWWorld::LiveCellRef<ESM::NPC> *cellRef = mActor.get<ESM::NPC>();
|
||||
|
||||
if (toLower (info.mClass)!=toLower (cellRef->mBase->mClass))
|
||||
if ( Misc::StringUtils::lowerCase (info.mClass)!= Misc::StringUtils::lowerCase (cellRef->mBase->mClass))
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -70,7 +64,7 @@ bool MWDialogue::Filter::testActor (const ESM::DialInfo& info) const
|
|||
return false;
|
||||
|
||||
MWMechanics::NpcStats& stats = MWWorld::Class::get (mActor).getNpcStats (mActor);
|
||||
std::map<std::string, int>::iterator iter = stats.getFactionRanks().find (toLower (info.mNpcFaction));
|
||||
std::map<std::string, int>::iterator iter = stats.getFactionRanks().find ( Misc::StringUtils::lowerCase (info.mNpcFaction));
|
||||
|
||||
if (iter==stats.getFactionRanks().end())
|
||||
return false;
|
||||
|
@ -99,7 +93,7 @@ bool MWDialogue::Filter::testPlayer (const ESM::DialInfo& info) const
|
|||
if (!info.mPcFaction.empty())
|
||||
{
|
||||
MWMechanics::NpcStats& stats = MWWorld::Class::get (player).getNpcStats (player);
|
||||
std::map<std::string,int>::iterator iter = stats.getFactionRanks().find (toLower (info.mPcFaction));
|
||||
std::map<std::string,int>::iterator iter = stats.getFactionRanks().find (Misc::StringUtils::lowerCase (info.mPcFaction));
|
||||
|
||||
if(iter==stats.getFactionRanks().end())
|
||||
return false;
|
||||
|
@ -111,7 +105,7 @@ bool MWDialogue::Filter::testPlayer (const ESM::DialInfo& info) const
|
|||
|
||||
// check cell
|
||||
if (!info.mCell.empty())
|
||||
if (toLower (player.getCell()->mCell->mName) != toLower (info.mCell))
|
||||
if (Misc::StringUtils::lowerCase (player.getCell()->mCell->mName) != Misc::StringUtils::lowerCase (info.mCell))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
|
@ -127,6 +121,18 @@ bool MWDialogue::Filter::testSelectStructs (const ESM::DialInfo& info) const
|
|||
return true;
|
||||
}
|
||||
|
||||
bool MWDialogue::Filter::testDisposition (const ESM::DialInfo& info) const
|
||||
{
|
||||
bool isCreature = (mActor.getTypeName() != typeid (ESM::NPC).name());
|
||||
|
||||
if (isCreature)
|
||||
return true;
|
||||
|
||||
int actorDisposition = MWBase::Environment::get().getMechanicsManager()->getDerivedDisposition(mActor);
|
||||
|
||||
return actorDisposition >= info.mData.mDisposition;
|
||||
}
|
||||
|
||||
bool MWDialogue::Filter::testSelectStruct (const SelectWrapper& select) const
|
||||
{
|
||||
if (select.isNpcOnly() && mActor.getTypeName()!=typeid (ESM::NPC).name())
|
||||
|
@ -168,7 +174,7 @@ bool MWDialogue::Filter::testSelectStructNumeric (const SelectWrapper& select) c
|
|||
int i = 0;
|
||||
|
||||
for (; i<static_cast<int> (script->mVarNames.size()); ++i)
|
||||
if (script->mVarNames[i]==name)
|
||||
if (Misc::StringUtils::lowerCase(script->mVarNames[i]) == name)
|
||||
break;
|
||||
|
||||
if (i>=static_cast<int> (script->mVarNames.size()))
|
||||
|
@ -242,7 +248,7 @@ int MWDialogue::Filter::getSelectStructInteger (const SelectWrapper& select) con
|
|||
std::string name = select.getName();
|
||||
|
||||
for (MWWorld::ContainerStoreIterator iter (store.begin()); iter!=store.end(); ++iter)
|
||||
if (toLower(iter->getCellRef().mRefID) == name)
|
||||
if (Misc::StringUtils::lowerCase(iter->getCellRef().mRefID) == name)
|
||||
sum += iter->getRefData().getCount();
|
||||
|
||||
return sum;
|
||||
|
@ -408,23 +414,23 @@ bool MWDialogue::Filter::getSelectStructBoolean (const SelectWrapper& select) co
|
|||
|
||||
case SelectWrapper::Function_Id:
|
||||
|
||||
return select.getName()==toLower (MWWorld::Class::get (mActor).getId (mActor));
|
||||
return select.getName()==Misc::StringUtils::lowerCase (MWWorld::Class::get (mActor).getId (mActor));
|
||||
|
||||
case SelectWrapper::Function_Faction:
|
||||
|
||||
return toLower (mActor.get<ESM::NPC>()->mBase->mFaction)==select.getName();
|
||||
return Misc::StringUtils::lowerCase (mActor.get<ESM::NPC>()->mBase->mFaction)==select.getName();
|
||||
|
||||
case SelectWrapper::Function_Class:
|
||||
|
||||
return toLower (mActor.get<ESM::NPC>()->mBase->mClass)==select.getName();
|
||||
return Misc::StringUtils::lowerCase (mActor.get<ESM::NPC>()->mBase->mClass)==select.getName();
|
||||
|
||||
case SelectWrapper::Function_Race:
|
||||
|
||||
return toLower (mActor.get<ESM::NPC>()->mBase->mRace)==select.getName();
|
||||
return Misc::StringUtils::lowerCase (mActor.get<ESM::NPC>()->mBase->mRace)==select.getName();
|
||||
|
||||
case SelectWrapper::Function_Cell:
|
||||
|
||||
return toLower (mActor.getCell()->mCell->mName)==select.getName();
|
||||
return Misc::StringUtils::lowerCase (mActor.getCell()->mCell->mName)==select.getName();
|
||||
|
||||
case SelectWrapper::Function_SameGender:
|
||||
|
||||
|
@ -433,8 +439,8 @@ bool MWDialogue::Filter::getSelectStructBoolean (const SelectWrapper& select) co
|
|||
|
||||
case SelectWrapper::Function_SameRace:
|
||||
|
||||
return toLower (mActor.get<ESM::NPC>()->mBase->mRace)!=
|
||||
toLower (player.get<ESM::NPC>()->mBase->mRace);
|
||||
return Misc::StringUtils::lowerCase (mActor.get<ESM::NPC>()->mBase->mRace)!=
|
||||
Misc::StringUtils::lowerCase (player.get<ESM::NPC>()->mBase->mRace);
|
||||
|
||||
case SelectWrapper::Function_SameFaction:
|
||||
|
||||
|
@ -553,18 +559,50 @@ MWDialogue::Filter::Filter (const MWWorld::Ptr& actor, int choice, bool talkedTo
|
|||
: mActor (actor), mChoice (choice), mTalkedToPlayer (talkedToPlayer)
|
||||
{}
|
||||
|
||||
bool MWDialogue::Filter::operator() (const ESM::DialInfo& info) const
|
||||
const ESM::DialInfo *MWDialogue::Filter::search (const ESM::Dialogue& dialogue, const bool fallbackToInfoRefusal) const
|
||||
{
|
||||
return testActor (info) && testPlayer (info) && testSelectStructs (info);
|
||||
}
|
||||
bool infoRefusal = false;
|
||||
|
||||
const ESM::DialInfo *MWDialogue::Filter::search (const ESM::Dialogue& dialogue) const
|
||||
{
|
||||
// Iterate over topic responses to find a matching one
|
||||
for (std::vector<ESM::DialInfo>::const_iterator iter = dialogue.mInfo.begin();
|
||||
iter!=dialogue.mInfo.end(); ++iter)
|
||||
if ((*this) (*iter))
|
||||
return &*iter;
|
||||
{
|
||||
if (testActor (*iter) && testPlayer (*iter) && testSelectStructs (*iter))
|
||||
{
|
||||
if (testDisposition (*iter))
|
||||
return &*iter;
|
||||
else
|
||||
infoRefusal = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (infoRefusal && fallbackToInfoRefusal)
|
||||
{
|
||||
// No response is valid because of low NPC disposition,
|
||||
// search a response in the topic "Info Refusal"
|
||||
|
||||
const MWWorld::Store<ESM::Dialogue> &dialogues =
|
||||
MWBase::Environment::get().getWorld()->getStore().get<ESM::Dialogue>();
|
||||
|
||||
const ESM::Dialogue& infoRefusalDialogue = *dialogues.find ("Info Refusal");
|
||||
|
||||
for (std::vector<ESM::DialInfo>::const_iterator iter = infoRefusalDialogue.mInfo.begin();
|
||||
iter!=infoRefusalDialogue.mInfo.end(); ++iter)
|
||||
if (testActor (*iter) && testPlayer (*iter) && testSelectStructs (*iter) && testDisposition(*iter))
|
||||
return &*iter;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool MWDialogue::Filter::responseAvailable (const ESM::Dialogue& dialogue) const
|
||||
{
|
||||
for (std::vector<ESM::DialInfo>::const_iterator iter = dialogue.mInfo.begin();
|
||||
iter!=dialogue.mInfo.end(); ++iter)
|
||||
{
|
||||
if (testActor (*iter) && testPlayer (*iter) && testSelectStructs (*iter))
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -18,40 +18,45 @@ namespace MWDialogue
|
|||
MWWorld::Ptr mActor;
|
||||
int mChoice;
|
||||
bool mTalkedToPlayer;
|
||||
|
||||
|
||||
bool testActor (const ESM::DialInfo& info) const;
|
||||
///< Is this the right actor for this \a info?
|
||||
|
||||
|
||||
bool testPlayer (const ESM::DialInfo& info) const;
|
||||
///< Do the player and the cell the player is currently in match \a info?
|
||||
|
||||
|
||||
bool testSelectStructs (const ESM::DialInfo& info) const;
|
||||
///< Are all select structs matching?
|
||||
|
||||
|
||||
bool testDisposition (const ESM::DialInfo& info) const;
|
||||
///< Is the actor disposition toward the player high enough?
|
||||
|
||||
bool testSelectStruct (const SelectWrapper& select) const;
|
||||
|
||||
|
||||
bool testSelectStructNumeric (const SelectWrapper& select) const;
|
||||
|
||||
|
||||
int getSelectStructInteger (const SelectWrapper& select) const;
|
||||
|
||||
|
||||
bool getSelectStructBoolean (const SelectWrapper& select) const;
|
||||
|
||||
|
||||
int getFactionRank (const MWWorld::Ptr& actor, const std::string& factionId) const;
|
||||
|
||||
|
||||
bool hasFactionRankSkillRequirements (const MWWorld::Ptr& actor, const std::string& factionId,
|
||||
int rank) const;
|
||||
|
||||
bool hasFactionRankReputationRequirements (const MWWorld::Ptr& actor, const std::string& factionId,
|
||||
int rank) const;
|
||||
|
||||
public:
|
||||
|
||||
Filter (const MWWorld::Ptr& actor, int choice, bool talkedToPlayer);
|
||||
|
||||
bool operator() (const ESM::DialInfo& info) const;
|
||||
///< \return does the dialogue match?
|
||||
|
||||
const ESM::DialInfo *search (const ESM::Dialogue& dialogue) const;
|
||||
public:
|
||||
|
||||
Filter (const MWWorld::Ptr& actor, int choice, bool talkedToPlayer);
|
||||
|
||||
const ESM::DialInfo *search (const ESM::Dialogue& dialogue, const bool fallbackToInfoRefusal) const;
|
||||
///< Get a matching response for the requested dialogue.
|
||||
/// Redirect to "Info Refusal" topic if a response fulfills all conditions but disposition.
|
||||
|
||||
bool responseAvailable (const ESM::Dialogue& dialogue) const;
|
||||
///< Does a matching response exist? (disposition is ignored for this check)
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -61,8 +61,8 @@ namespace MWDialogue
|
|||
StampedJournalEntry StampedJournalEntry::makeFromQuest (const std::string& topic, int index)
|
||||
{
|
||||
int day = MWBase::Environment::get().getWorld()->getGlobalVariable ("dayspassed").mLong;
|
||||
int month = MWBase::Environment::get().getWorld()->getGlobalVariable ("day").mLong;
|
||||
int dayOfMonth = MWBase::Environment::get().getWorld()->getGlobalVariable ("month").mLong;
|
||||
int month = MWBase::Environment::get().getWorld()->getGlobalVariable ("month").mLong;
|
||||
int dayOfMonth = MWBase::Environment::get().getWorld()->getGlobalVariable ("day").mLong;
|
||||
|
||||
return StampedJournalEntry (topic, idFromIndex (topic, index), day, month, dayOfMonth);
|
||||
}
|
||||
|
|
|
@ -31,6 +31,12 @@ namespace MWDialogue
|
|||
|
||||
void Journal::addEntry (const std::string& id, int index)
|
||||
{
|
||||
// bail out of we already have heard this...
|
||||
std::string infoId = JournalEntry::idFromIndex (id, index);
|
||||
for (TEntryIter i = mJournal.begin (); i != mJournal.end (); ++i)
|
||||
if (i->mTopic == id && i->mInfoId == infoId)
|
||||
return;
|
||||
|
||||
StampedJournalEntry entry = StampedJournalEntry::makeFromQuest (id, index);
|
||||
|
||||
mJournal.push_back (entry);
|
||||
|
|
|
@ -8,18 +8,10 @@
|
|||
#include <sstream>
|
||||
#include <iterator>
|
||||
|
||||
#include <components/misc/stringops.hpp>
|
||||
|
||||
namespace
|
||||
{
|
||||
std::string toLower (const std::string& name)
|
||||
{
|
||||
std::string lowerCase;
|
||||
|
||||
std::transform (name.begin(), name.end(), std::back_inserter (lowerCase),
|
||||
(int(*)(int)) std::tolower);
|
||||
|
||||
return lowerCase;
|
||||
}
|
||||
|
||||
template<typename T1, typename T2>
|
||||
bool selectCompareImp (char comp, T1 value1, T2 value2)
|
||||
{
|
||||
|
@ -307,5 +299,5 @@ bool MWDialogue::SelectWrapper::selectCompare (bool value) const
|
|||
|
||||
std::string MWDialogue::SelectWrapper::getName() const
|
||||
{
|
||||
return toLower (mSelect.mSelectRule.substr (5));
|
||||
return Misc::StringUtils::lowerCase (mSelect.mSelectRule.substr (5));
|
||||
}
|
||||
|
|
|
@ -27,17 +27,17 @@ namespace MWDialogue
|
|||
mEntries.push_back (entry.mInfoId);
|
||||
}
|
||||
|
||||
Topic::TEntryIter Topic::begin()
|
||||
Topic::TEntryIter Topic::begin() const
|
||||
{
|
||||
return mEntries.begin();
|
||||
}
|
||||
|
||||
Topic::TEntryIter Topic::end()
|
||||
Topic::TEntryIter Topic::end() const
|
||||
{
|
||||
return mEntries.end();
|
||||
}
|
||||
|
||||
JournalEntry Topic::getEntry (const std::string& infoId)
|
||||
JournalEntry Topic::getEntry (const std::string& infoId) const
|
||||
{
|
||||
return JournalEntry (mTopic, infoId);
|
||||
}
|
||||
|
|
|
@ -34,13 +34,15 @@ namespace MWDialogue
|
|||
///
|
||||
/// \note Redundant entries are ignored.
|
||||
|
||||
TEntryIter begin();
|
||||
std::string const & getName () const { return mTopic; }
|
||||
|
||||
TEntryIter begin() const;
|
||||
///< Iterator pointing to the begin of the journal for this topic.
|
||||
|
||||
TEntryIter end();
|
||||
TEntryIter end() const;
|
||||
///< Iterator pointing past the end of the journal for this topic.
|
||||
|
||||
JournalEntry getEntry (const std::string& infoId);
|
||||
JournalEntry getEntry (const std::string& infoId) const;
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -63,7 +63,7 @@ namespace MWGui
|
|||
void AlchemyWindow::onCancelButtonClicked(MyGUI::Widget* _sender)
|
||||
{
|
||||
mAlchemy.clear();
|
||||
|
||||
|
||||
mWindowManager.removeGuiMode(GM_Alchemy);
|
||||
mWindowManager.removeGuiMode(GM_Inventory);
|
||||
}
|
||||
|
@ -119,7 +119,6 @@ namespace MWGui
|
|||
if (mIngredients[i]->isUserString("ToolTipType"))
|
||||
{
|
||||
MWWorld::Ptr ingred = *mIngredients[i]->getUserData<MWWorld::Ptr>();
|
||||
ingred.getRefData().setCount(ingred.getRefData().getCount()-1);
|
||||
if (ingred.getRefData().getCount() == 0)
|
||||
removeIngredient(mIngredients[i]);
|
||||
}
|
||||
|
|
|
@ -88,7 +88,7 @@ void BookWindow::setTakeButtonShow(bool show)
|
|||
mTakeButton->setVisible(show);
|
||||
}
|
||||
|
||||
void BookWindow::onCloseButtonClicked (MyGUI::Widget* _sender)
|
||||
void BookWindow::onCloseButtonClicked (MyGUI::Widget* sender)
|
||||
{
|
||||
// no 3d sounds because the object could be in a container.
|
||||
MWBase::Environment::get().getSoundManager()->playSound ("book close", 1.0, 1.0);
|
||||
|
@ -96,7 +96,7 @@ void BookWindow::onCloseButtonClicked (MyGUI::Widget* _sender)
|
|||
mWindowManager.removeGuiMode(GM_Book);
|
||||
}
|
||||
|
||||
void BookWindow::onTakeButtonClicked (MyGUI::Widget* _sender)
|
||||
void BookWindow::onTakeButtonClicked (MyGUI::Widget* sender)
|
||||
{
|
||||
MWBase::Environment::get().getSoundManager()->playSound ("Item Book Up", 1.0, 1.0, MWBase::SoundManager::Play_NoTrack);
|
||||
|
||||
|
@ -106,7 +106,7 @@ void BookWindow::onTakeButtonClicked (MyGUI::Widget* _sender)
|
|||
mWindowManager.removeGuiMode(GM_Book);
|
||||
}
|
||||
|
||||
void BookWindow::onNextPageButtonClicked (MyGUI::Widget* _sender)
|
||||
void BookWindow::onNextPageButtonClicked (MyGUI::Widget* sender)
|
||||
{
|
||||
if ((mCurrentPage+1)*2 < mPages.size())
|
||||
{
|
||||
|
@ -118,7 +118,7 @@ void BookWindow::onNextPageButtonClicked (MyGUI::Widget* _sender)
|
|||
}
|
||||
}
|
||||
|
||||
void BookWindow::onPrevPageButtonClicked (MyGUI::Widget* _sender)
|
||||
void BookWindow::onPrevPageButtonClicked (MyGUI::Widget* sender)
|
||||
{
|
||||
if (mCurrentPage > 0)
|
||||
{
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue