1
0
Fork 0
mirror of https://github.com/OpenMW/openmw.git synced 2025-02-01 14:15:36 +00:00

Merge branch 'master' of git://github.com/zinnschlag/openmw

This commit is contained in:
scrawl 2013-06-27 17:31:00 +02:00
commit febc93a1c8
692 changed files with 62067 additions and 26173 deletions

3
.gitignore vendored
View file

@ -18,3 +18,6 @@ CMakeLists.txt.user
*.swp
*.swo
*.kate-swp
.cproject
.project
.settings/

39
.travis.yml Normal file
View file

@ -0,0 +1,39 @@
language: cpp
compiler:
- gcc
branches:
only:
- master
- next
before_install:
- pwd
- git submodule update --init --recursive
- echo "yes" | sudo add-apt-repository "deb http://archive.ubuntu.com/ubuntu `lsb_release -sc` main universe restricted multiverse"
- echo "yes" | sudo apt-add-repository ppa:openmw/deps
- sudo apt-get update -qq
- sudo apt-get install -qq libboost-all-dev libgtest-dev google-mock libzzip-dev
- sudo apt-get install -qq libqt4-dev libxaw7-dev libxrandr-dev libfreeimage-dev libpng-dev
- sudo apt-get install -qq libopenal-dev libmpg123-dev libsndfile1-dev
- sudo apt-get install -qq libavcodec-dev libavformat-dev libavdevice-dev libavutil-dev libswscale-dev libpostproc-dev
- sudo apt-get install -qq libbullet-dev libogre-static-dev libmygui-static-dev libsdl2-static-dev
- sudo mkdir /usr/src/gtest/build
- cd /usr/src/gtest/build
- sudo cmake .. -DBUILD_SHARED_LIBS=1
- sudo make -j4
- sudo ln -s /usr/src/gtest/build/libgtest.so /usr/lib/libgtest.so
- sudo ln -s /usr/src/gtest/build/libgtest_main.so /usr/lib/libgtest_main.so
before_script:
- cd -
- mkdir build
- cd build
- cmake .. -DOGRE_STATIC=1 -DMYGUI_STATIC=1 -DBOOST_STATIC=1 -DSDL2_STATIC=1 -DBUILD_WITH_CODE_COVERAGE=1 -DBUILD_UNITTESTS=1
script:
- make -j4
after_script:
- ./openmw_test_suite
notifications:
recipients:
- lgromanowski+travis.ci@gmail.com
email:
on_success: change
on_failure: always

View file

@ -4,6 +4,10 @@ if (APPLE)
set(APP_BUNDLE_NAME "${CMAKE_PROJECT_NAME}.app")
set(APP_BUNDLE_DIR "${OpenMW_BINARY_DIR}/${APP_BUNDLE_NAME}")
set(CMAKE_EXE_LINKER_FLAGS "-F /Library/Frameworks")
set(CMAKE_SHARED_LINKER_FLAGS "-F /Library/Frameworks")
set(CMAKE_MODULE_LINKER_FLAGS "-F /Library/Frameworks")
endif (APPLE)
# Macros
@ -15,7 +19,7 @@ include (OpenMWMacros)
# Version
set (OPENMW_VERSION_MAJOR 0)
set (OPENMW_VERSION_MINOR 22)
set (OPENMW_VERSION_MINOR 24)
set (OPENMW_VERSION_RELEASE 0)
set (OPENMW_VERSION "${OPENMW_VERSION_MAJOR}.${OPENMW_VERSION_MINOR}.${OPENMW_VERSION_RELEASE}")
@ -27,6 +31,7 @@ configure_file ("${OpenMW_SOURCE_DIR}/Docs/mainpage.hpp.cmake" "${OpenMW_SOURCE_
option(MYGUI_STATIC "Link static build of Mygui into the binaries" FALSE)
option(OGRE_STATIC "Link static build of Ogre and Ogre Plugins into the binaries" FALSE)
option(BOOST_STATIC "Link static build of Boost into the binaries" FALSE)
option(SDL2_STATIC "Link static build of SDL into the binaries" FALSE)
# Apps and tools
option(BUILD_BSATOOL "build BSA extractor" OFF)
@ -75,8 +80,15 @@ set(LIBDIR ${CMAKE_SOURCE_DIR}/libs)
set(OENGINE_OGRE
${LIBDIR}/openengine/ogre/renderer.cpp
${LIBDIR}/openengine/ogre/fader.cpp
${LIBDIR}/openengine/ogre/particles.cpp
${LIBDIR}/openengine/ogre/selectionbuffer.cpp
${LIBDIR}/openengine/ogre/imagerotate.cpp
)
if (APPLE)
set(OENGINE_OGRE ${OENGINE_OGRE} ${LIBDIR}/openengine/ogre/osx_utils.mm)
endif ()
set(OENGINE_GUI
${LIBDIR}/openengine/gui/manager.cpp
)
@ -180,15 +192,14 @@ if (UNIX AND NOT APPLE)
find_package (Threads)
endif()
# find boost without components so we can use Boost_VERSION
find_package(Boost REQUIRED)
include (CheckIncludeFileCXX)
check_include_file_cxx(unordered_map HAVE_UNORDERED_MAP)
if (HAVE_UNORDERED_MAP)
add_definitions(-DHAVE_UNORDERED_MAP)
endif ()
set(BOOST_COMPONENTS system filesystem program_options thread date_time)
if (Boost_VERSION LESS 104900)
set(SHINY_USE_WAVE_SYSTEM_INSTALL "TRUE")
set(BOOST_COMPONENTS ${BOOST_COMPONENTS} wave)
endif()
set(BOOST_COMPONENTS system filesystem program_options thread date_time wave)
IF(BOOST_STATIC)
set(Boost_USE_STATIC_LIBS ON)
@ -197,7 +208,7 @@ endif()
find_package(OGRE REQUIRED)
find_package(MyGUI REQUIRED)
find_package(Boost REQUIRED COMPONENTS ${BOOST_COMPONENTS})
find_package(OIS REQUIRED)
find_package(SDL2 REQUIRED)
find_package(OpenAL REQUIRED)
find_package(Bullet REQUIRED)
IF(OGRE_STATIC)
@ -211,7 +222,8 @@ ENDIF(OGRE_STATIC)
include_directories("."
${OGRE_INCLUDE_DIR} ${OGRE_INCLUDE_DIR}/Ogre ${OGRE_INCLUDE_DIR}/OGRE ${OGRE_PLUGIN_INCLUDE_DIRS}
${OGRE_Terrain_INCLUDE_DIR}
${OIS_INCLUDE_DIRS} ${Boost_INCLUDE_DIR}
${SDL2_INCLUDE_DIR}
${Boost_INCLUDE_DIR}
${PLATFORM_INCLUDE_DIR}
${MYGUI_INCLUDE_DIRS}
${MYGUI_PLATFORM_INCLUDE_DIRS}
@ -220,7 +232,7 @@ include_directories("."
${LIBDIR}
)
link_directories(${Boost_LIBRARY_DIRS} ${OGRE_LIB_DIR} ${MYGUI_LIB_DIR})
link_directories(${SDL2_LIBRARY_DIRS} ${Boost_LIBRARY_DIRS} ${OGRE_LIB_DIR} ${MYGUI_LIB_DIR})
if (APPLE)
# List used Ogre plugins
@ -293,9 +305,12 @@ configure_file(${OpenMW_SOURCE_DIR}/files/transparency-overrides.cfg
configure_file(${OpenMW_SOURCE_DIR}/files/openmw.cfg.local
"${OpenMW_BINARY_DIR}/openmw.cfg")
configure_file(${OpenMW_SOURCE_DIR}/files/openmw.cfg
"${OpenMW_BINARY_DIR}/openmw.cfg.install")
configure_file(${OpenMW_SOURCE_DIR}/files/opencs.cfg
"${OpenMW_BINARY_DIR}/opencs.cfg")
if (NOT WIN32 AND NOT APPLE)
configure_file(${OpenMW_SOURCE_DIR}/files/openmw.desktop
@ -340,6 +355,7 @@ if(DPKG_PROGRAM)
INSTALL(FILES "${OpenMW_BINARY_DIR}/settings-default.cfg" DESTINATION "../etc/openmw/" PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ COMPONENT "openmw")
INSTALL(FILES "${OpenMW_BINARY_DIR}/transparency-overrides.cfg" DESTINATION "../etc/openmw/" PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ COMPONENT "openmw")
INSTALL(FILES "${OpenMW_BINARY_DIR}/openmw.cfg.install" DESTINATION "../etc/openmw/" RENAME "openmw.cfg" PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ COMPONENT "openmw")
INSTALL(FILES "${OpenMW_BINARY_DIR}/opencs.cfg" DESTINATION "../etc/openmw/" PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ COMPONENT "openmw")
#Install resources
INSTALL(DIRECTORY "${OpenMW_BINARY_DIR}/resources" DESTINATION "share/games/openmw/" FILE_PERMISSIONS OWNER_READ GROUP_READ WORLD_READ COMPONENT "Resources")
@ -355,8 +371,8 @@ if(DPKG_PROGRAM)
Data files from the original game is required to run it.")
SET(CPACK_DEBIAN_PACKAGE_NAME "openmw")
SET(CPACK_DEBIAN_PACKAGE_VERSION "${VERSION_STRING}")
SET(CPACK_PACKAGE_EXECUTABLES "openmw;OpenMW bsatool;Bsatool esmtool;Esmtool omwlauncher;OMWLauncher mwiniimporter;MWiniImporter")
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_PACKAGE_EXECUTABLES "openmw;OpenMW bsatool;Bsatool esmtool;Esmtool omwlauncher;OMWLauncher mwiniimporter;MWiniImporter")
SET(CPACK_DEBIAN_PACKAGE_DEPENDS "libc6 (>= 2.11.2), libfreetype6 (>= 2.2.1), libgcc1 (>= 1:4.1.1), libmpg123-0 (>= 1.12.1), 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")
@ -443,6 +459,7 @@ endif(WIN32)
# Extern
add_subdirectory (extern/shiny)
add_subdirectory (extern/oics)
add_subdirectory (extern/sdl4ogre)
# Components
add_subdirectory (components)
@ -578,6 +595,7 @@ if (APPLE)
install(FILES "${OpenMW_BINARY_DIR}/openmw.cfg.install" RENAME "openmw.cfg" DESTINATION "${INSTALL_SUBDIR}" COMPONENT Runtime)
install(FILES "${OpenMW_BINARY_DIR}/settings-default.cfg" DESTINATION "${INSTALL_SUBDIR}" COMPONENT Runtime)
install(FILES "${OpenMW_BINARY_DIR}/transparency-overrides.cfg" DESTINATION "${INSTALL_SUBDIR}" COMPONENT Runtime)
install(FILES "${OpenMW_BINARY_DIR}/opencs.cfg" DESTINATION "${INSTALL_SUBDIR}" COMPONENT Runtime)
set(CPACK_GENERATOR "DragNDrop")
set(CPACK_PACKAGE_VERSION ${OPENMW_VERSION})
@ -654,12 +672,12 @@ endif (APPLE)
if (NOT WIN32 AND NOT DPKG_PROGRAM AND NOT APPLE)
## Non Debian based Linux building
# paths
set(BINDIR "${CMAKE_INSTALL_PREFIX}/usr/bin" CACHE PATH "Where to install binaries")
set(BINDIR "${CMAKE_INSTALL_PREFIX}/bin" CACHE PATH "Where to install binaries")
set(DATAROOTDIR "${CMAKE_INSTALL_PREFIX}/share" CACHE PATH "Sets the root of data directories to a non-default location")
set(DATADIR "${DATAROOTDIR}/openmw" CACHE PATH "Sets the openmw data directories to a non-default location")
set(DATADIR "${DATAROOTDIR}/games/openmw" CACHE PATH "Sets the openmw data directories to a non-default location")
set(DOCDIR "${DATAROOTDIR}/doc/openmw" CACHE PATH "Sets the doc directory to a non-default location.")
set(MANDIR "${DATAROOTDIR}/man" CACHE PATH "Where to install manpages")
set(SYSCONFDIR "${CMAKE_INSTALL_PREFIX}/etc/openmw" CACHE PATH "Set config dir")
set(SYSCONFDIR "/etc/openmw" CACHE PATH "Set config dir")
set(ICONDIR "${DATAROOTDIR}/pixmaps" CACHE PATH "Set icon dir")
# Install binaries
@ -683,12 +701,17 @@ if (NOT WIN32 AND NOT DPKG_PROGRAM AND NOT APPLE)
# Install icon and .desktop
INSTALL(FILES "${OpenMW_SOURCE_DIR}/files/launcher/images/openmw.png" DESTINATION "${ICONDIR}")
INSTALL(FILES "${OpenMW_BINARY_DIR}/openmw.desktop" DESTINATION "${DATAROOTDIR}/applications")
IF(BUILD_OPENCS)
INSTALL(FILES "${OpenMW_SOURCE_DIR}/files/opencs/opencs.png" DESTINATION "${ICONDIR}")
INSTALL(FILES "${OpenMW_BINARY_DIR}/opencs.desktop" DESTINATION "${DATAROOTDIR}/applications")
ENDIF(BUILD_OPENCS)
# Install global configuration files
INSTALL(FILES "${OpenMW_BINARY_DIR}/openmw.cfg.install" DESTINATION "${SYSCONFDIR}" RENAME "openmw.cfg" )
#INSTALL(FILES "${OpenMW_BINARY_DIR}/plugins.cfg" DESTINATION "${SYSCONFDIR}" )
INSTALL(FILES "${OpenMW_BINARY_DIR}/settings-default.cfg" DESTINATION "${SYSCONFDIR}" )
INSTALL(FILES "${OpenMW_BINARY_DIR}/transparency-overrides.cfg" DESTINATION "${SYSCONFDIR}" )
INSTALL(FILES "${OpenMW_BINARY_DIR}/opencs.cfg" DESTINATION "${SYSCONFDIR}" )
# Install resources
INSTALL(DIRECTORY "${OpenMW_BINARY_DIR}/resources" DESTINATION "${DATADIR}" )

View file

@ -17,11 +17,6 @@ target_link_libraries(esmtool
components
)
#if (APPLE)
# find_library(CARBON_FRAMEWORK Carbon)
# target_link_libraries(openmw ${CARBON_FRAMEWORK})
#endif (APPLE)
if (BUILD_WITH_CODE_COVERAGE)
add_definitions (--coverage)
target_link_libraries(esmtool gcov)

View file

@ -51,6 +51,7 @@ struct Arguments
unsigned int raw_given;
unsigned int quiet_given;
unsigned int loadcells_given;
bool plain_given;
std::string mode;
std::string encoding;
@ -77,6 +78,9 @@ bool parseOptions (int argc, char** argv, Arguments &info)
("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.")
("plain,p", "Print contents of dialogs, books and scripts. "
"(skipped by default)"
"Only affects dump mode.")
("quiet,q", "Supress all record information. Useful for speed tests.")
("loadcells,C", "Browse through contents of all cells.")
@ -104,11 +108,26 @@ bool parseOptions (int argc, char** argv, Arguments &info)
// there might be a better way to do this
bpo::options_description all;
all.add(desc).add(hidden);
bpo::parsed_options valid_opts = bpo::command_line_parser(argc, argv)
.options(all).positional(p).run();
bpo::variables_map variables;
bpo::store(valid_opts, variables);
try
{
bpo::parsed_options valid_opts = bpo::command_line_parser(argc, argv)
.options(all).positional(p).run();
bpo::store(valid_opts, variables);
}
catch(boost::program_options::unknown_option & x)
{
std::cerr << "ERROR: " << x.what() << std::endl;
return false;
}
catch(boost::program_options::invalid_command_line_syntax & x)
{
std::cerr << "ERROR: " << x.what() << std::endl;
return false;
}
bpo::notify(variables);
if (variables.count ("help"))
@ -161,6 +180,7 @@ bool parseOptions (int argc, char** argv, Arguments &info)
info.raw_given = variables.count ("raw");
info.quiet_given = variables.count ("quiet");
info.loadcells_given = variables.count ("loadcells");
info.plain_given = (variables.count("plain") > 0);
// Font encoding settings
info.encoding = variables["encoding"].as<std::string>();
@ -343,6 +363,7 @@ int load(Arguments& info)
}
record->setId(id);
record->setFlags((int) flags);
record->setPrintPlain(info.plain_given);
record->load(esm);
if (!quiet && interested) record->print();

View file

@ -439,7 +439,7 @@ void Record<ESM::Apparatus>::print()
template<>
void Record<ESM::BodyPart>::print()
{
std::cout << " Name: " << mData.mName << std::endl;
std::cout << " Race: " << mData.mRace << std::endl;
std::cout << " Model: " << mData.mModel << std::endl;
std::cout << " Type: " << meshTypeLabel(mData.mData.mType)
<< " (" << (int)mData.mData.mType << ")" << std::endl;
@ -464,12 +464,17 @@ void Record<ESM::Book>::print()
std::cout << " IsScroll: " << mData.mData.mIsScroll << std::endl;
std::cout << " SkillID: " << mData.mData.mSkillID << std::endl;
std::cout << " Enchantment Points: " << mData.mData.mEnchant << std::endl;
std::cout << " Text: [skipped]" << std::endl;
// Skip until multi-line fields is controllable by a command line option.
// Mildly problematic because there are no parameter to print() currently.
// std::cout << "-------------------------------------------" << std::endl;
// std::cout << mData.mText << std::endl;
// std::cout << "-------------------------------------------" << std::endl;
if (mPrintPlain)
{
std::cout << " Text:" << std::endl;
std::cout << "START--------------------------------------" << std::endl;
std::cout << mData.mText << std::endl;
std::cout << "END----------------------------------------" << std::endl;
}
else
{
std::cout << " Text: [skipped]" << std::endl;
}
}
template<>
@ -679,14 +684,14 @@ void Record<ESM::Faction>::print()
std::cout << " Hidden: " << mData.mData.mIsHidden << std::endl;
if (mData.mData.mUnknown != -1)
std::cout << " Unknown: " << mData.mData.mUnknown << std::endl;
std::cout << " Attribute1: " << attributeLabel(mData.mData.mAttribute1)
<< " (" << mData.mData.mAttribute1 << ")" << std::endl;
std::cout << " Attribute2: " << attributeLabel(mData.mData.mAttribute2)
<< " (" << mData.mData.mAttribute2 << ")" << std::endl;
std::cout << " Attribute1: " << attributeLabel(mData.mData.mAttribute[0])
<< " (" << mData.mData.mAttribute[0] << ")" << std::endl;
std::cout << " Attribute2: " << attributeLabel(mData.mData.mAttribute[1])
<< " (" << mData.mData.mAttribute[1] << ")" << std::endl;
for (int i = 0; i != 6; i++)
if (mData.mData.mSkillID[i] != -1)
std::cout << " Skill: " << skillLabel(mData.mData.mSkillID[i])
<< " (" << mData.mData.mSkillID[i] << ")" << std::endl;
if (mData.mData.mSkills[i] != -1)
std::cout << " Skill: " << skillLabel(mData.mData.mSkills[i])
<< " (" << mData.mData.mSkills[i] << ")" << std::endl;
for (int i = 0; i != 10; i++)
if (mData.mRanks[i] != "")
{
@ -753,15 +758,6 @@ void Record<ESM::DialInfo>::print()
if (mData.mSound != "")
std::cout << " Sound File: " << mData.mSound << std::endl;
if (mData.mResultScript != "")
{
std::cout << " Result Script: [skipped]" << std::endl;
// Skip until multi-line fields is controllable by a command line option.
// Mildly problematic because there are no parameter to print() currently.
// std::cout << "-------------------------------------------" << std::endl;
// std::cout << mData.mResultScript << std::endl;
// std::cout << "-------------------------------------------" << std::endl;
}
std::cout << " Quest Status: " << questStatusLabel(mData.mQuestStatus)
<< " (" << mData.mQuestStatus << ")" << std::endl;
@ -771,6 +767,21 @@ void Record<ESM::DialInfo>::print()
std::vector<ESM::DialInfo::SelectStruct>::iterator sit;
for (sit = mData.mSelects.begin(); sit != mData.mSelects.end(); sit++)
std::cout << " Select Rule: " << ruleString(*sit) << std::endl;
if (mData.mResultScript != "")
{
if (mPrintPlain)
{
std::cout << " Result Script:" << std::endl;
std::cout << "START--------------------------------------" << std::endl;
std::cout << mData.mResultScript << std::endl;
std::cout << "END----------------------------------------" << std::endl;
}
else
{
std::cout << " Result Script: [skipped]" << std::endl;
}
}
}
template<>
@ -1099,53 +1110,29 @@ void Record<ESM::Pathgrid>::print()
template<>
void Record<ESM::Race>::print()
{
static const char *sAttributeNames[8] =
{
"Strength", "Intelligence", "Willpower", "Agility",
"Speed", "Endurance", "Personality", "Luck"
};
std::cout << " Name: " << mData.mName << std::endl;
std::cout << " Description: " << mData.mDescription << std::endl;
std::cout << " Flags: " << raceFlags(mData.mData.mFlags) << std::endl;
std::cout << " Male:" << std::endl;
std::cout << " Strength: "
<< mData.mData.mStrength.mMale << std::endl;
std::cout << " Intelligence: "
<< mData.mData.mIntelligence.mMale << std::endl;
std::cout << " Willpower: "
<< mData.mData.mWillpower.mMale << std::endl;
std::cout << " Agility: "
<< mData.mData.mAgility.mMale << std::endl;
std::cout << " Speed: "
<< mData.mData.mSpeed.mMale << std::endl;
std::cout << " Endurance: "
<< mData.mData.mEndurance.mMale << std::endl;
std::cout << " Personality: "
<< mData.mData.mPersonality.mMale << std::endl;
std::cout << " Luck: "
<< mData.mData.mLuck.mMale << std::endl;
std::cout << " Height: "
<< mData.mData.mHeight.mMale << std::endl;
std::cout << " Weight: "
<< mData.mData.mWeight.mMale << std::endl;
for (int i=0; i<2; ++i)
{
bool male = i==0;
std::cout << " Female:" << std::endl;
std::cout << " Strength: "
<< mData.mData.mStrength.mFemale << std::endl;
std::cout << " Intelligence: "
<< mData.mData.mIntelligence.mFemale << std::endl;
std::cout << " Willpower: "
<< mData.mData.mWillpower.mFemale << std::endl;
std::cout << " Agility: "
<< mData.mData.mAgility.mFemale << std::endl;
std::cout << " Speed: "
<< mData.mData.mSpeed.mFemale << std::endl;
std::cout << " Endurance: "
<< mData.mData.mEndurance.mFemale << std::endl;
std::cout << " Personality: "
<< mData.mData.mPersonality.mFemale << std::endl;
std::cout << " Luck: "
<< mData.mData.mLuck.mFemale << std::endl;
std::cout << " Height: "
<< mData.mData.mHeight.mFemale << std::endl;
std::cout << " Weight: "
<< mData.mData.mWeight.mFemale << std::endl;
std::cout << (male ? " Male:" : " Female:") << std::endl;
for (int i=0; i<8; ++i)
std::cout << " " << sAttributeNames[i] << ": "
<< mData.mData.mAttributeValues[i].getValue (male) << std::endl;
std::cout << " Height: " << mData.mData.mHeight.getValue (male) << std::endl;
std::cout << " Weight: " << mData.mData.mWeight.getValue (male) << std::endl;
}
for (int i = 0; i != 7; i++)
// Not all races have 7 skills.
@ -1195,21 +1182,28 @@ void Record<ESM::Script>::print()
std::cout << " Script Data Size: " << mData.mData.mScriptDataSize << std::endl;
std::cout << " Table Size: " << mData.mData.mStringTableSize << std::endl;
std::cout << " Script: [skipped]" << std::endl;
// Skip until multi-line fields is controllable by a command line option.
// Mildly problematic because there are no parameter to print() currently.
// std::cout << "-------------------------------------------" << std::endl;
// std::cout << s->scriptText << std::endl;
// std::cout << "-------------------------------------------" << std::endl;
std::vector<std::string>::iterator vit;
for (vit = mData.mVarNames.begin(); vit != mData.mVarNames.end(); vit++)
std::cout << " Variable: " << *vit << std::endl;
std::cout << " ByteCode: ";
std::vector<char>::iterator cit;
std::vector<unsigned char>::iterator cit;
for (cit = mData.mScriptData.begin(); cit != mData.mScriptData.end(); cit++)
std::cout << boost::format("%02X") % (int)(*cit);
std::cout << std::endl;
if (mPrintPlain)
{
std::cout << " Script:" << std::endl;
std::cout << "START--------------------------------------" << std::endl;
std::cout << mData.mScriptText << std::endl;
std::cout << "END----------------------------------------" << std::endl;
}
else
{
std::cout << " Script: [skipped]" << std::endl;
}
}
template<>

View file

@ -21,9 +21,10 @@ namespace EsmTool
std::string mId;
int mFlags;
ESM::NAME mType;
bool mPrintPlain;
public:
RecordBase () {}
RecordBase () { mPrintPlain = false; }
virtual ~RecordBase() {}
const std::string &getId() const {
@ -46,6 +47,14 @@ namespace EsmTool
return mType;
}
bool getPrintPlain() const {
return mPrintPlain;
}
void setPrintPlain(bool plain) {
mPrintPlain = plain;
}
virtual void load(ESM::ESMReader &esm) = 0;
virtual void save(ESM::ESMWriter &esm) = 0;
virtual void print() = 0;

View file

@ -90,6 +90,7 @@ target_link_libraries(omwlauncher
${Boost_LIBRARIES}
${OGRE_LIBRARIES}
${OGRE_STATIC_PLUGINS}
${SDL2_LIBRARY}
${QT_LIBRARIES}
components
)
@ -102,3 +103,9 @@ if (BUILD_WITH_CODE_COVERAGE)
add_definitions (--coverage)
target_link_libraries(omwlauncher gcov)
endif()
# Workaround for binutil => 2.23 problem when linking, should be fixed eventually upstream
if (UNIX AND NOT APPLE)
target_link_libraries(omwlauncher dl Xt)
endif()

View file

@ -3,6 +3,7 @@
#include <QDesktopWidget>
#include <QMessageBox>
#include <QDir>
#include <SDL.h>
#include <cstdlib>
@ -35,13 +36,14 @@ GraphicsPage::GraphicsPage(Files::ConfigurationManager &cfg, GraphicsSettings &g
setupUi(this);
// Set the maximum res we can set in windowed mode
QRect res = QApplication::desktop()->screenGeometry();
QRect res = getMaximumResolution();
customWidthSpinBox->setMaximum(res.width());
customHeightSpinBox->setMaximum(res.height());
connect(rendererComboBox, SIGNAL(currentIndexChanged(const QString&)), this, SLOT(rendererChanged(const QString&)));
connect(fullScreenCheckBox, SIGNAL(stateChanged(int)), this, SLOT(slotFullScreenChanged(int)));
connect(standardRadioButton, SIGNAL(toggled(bool)), this, SLOT(slotStandardToggled(bool)));
connect(screenComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(screenChanged(int)));
}
@ -144,17 +146,41 @@ bool GraphicsPage::setupOgre()
}
antiAliasingComboBox->clear();
resolutionComboBox->clear();
antiAliasingComboBox->addItems(getAvailableOptions(QString("FSAA"), mSelectedRenderSystem));
resolutionComboBox->addItems(getAvailableResolutions(mSelectedRenderSystem));
// Load the rest of the values
loadSettings();
return true;
}
void GraphicsPage::loadSettings()
bool GraphicsPage::setupSDL()
{
int displays = SDL_GetNumVideoDisplays();
if (displays < 0)
{
QMessageBox msgBox;
msgBox.setWindowTitle(tr("Error receiving number of screens"));
msgBox.setIcon(QMessageBox::Critical);
msgBox.setStandardButtons(QMessageBox::Ok);
msgBox.setText(tr("<br><b>SDL_GetNumDisplayModes failed:</b><br><br>") + QString::fromStdString(SDL_GetError()) + "<br>");
msgBox.exec();
return false;
}
for (int i = 0; i < displays; i++)
{
screenComboBox->addItem(QString(tr("Screen ")) + QString::number(i + 1));
}
return true;
}
bool GraphicsPage::loadSettings()
{
if (!setupSDL())
return false;
if (!setupOgre())
return false;
if (mGraphicsSettings.value(QString("Video/vsync")) == QLatin1String("true"))
vSyncCheckBox->setCheckState(Qt::Checked);
@ -168,6 +194,9 @@ void GraphicsPage::loadSettings()
QString width = mGraphicsSettings.value(QString("Video/resolution x"));
QString height = mGraphicsSettings.value(QString("Video/resolution y"));
QString resolution = width + QString(" x ") + height;
QString screen = mGraphicsSettings.value(QString("Video/screen"));
screenComboBox->setCurrentIndex(screen.toInt());
int resIndex = resolutionComboBox->findText(resolution, Qt::MatchStartsWith);
@ -180,6 +209,8 @@ void GraphicsPage::loadSettings()
customHeightSpinBox->setValue(height.toInt());
}
return true;
}
void GraphicsPage::saveSettings()
@ -205,6 +236,8 @@ void GraphicsPage::saveSettings()
mGraphicsSettings.setValue(QString("Video/resolution x"), QString::number(customWidthSpinBox->value()));
mGraphicsSettings.setValue(QString("Video/resolution y"), QString::number(customHeightSpinBox->value()));
}
mGraphicsSettings.setValue(QString("Video/screen"), QString::number(screenComboBox->currentIndex()));
}
QStringList GraphicsPage::getAvailableOptions(const QString &key, Ogre::RenderSystem *renderer)
@ -240,64 +273,83 @@ QStringList GraphicsPage::getAvailableOptions(const QString &key, Ogre::RenderSy
return result;
}
QStringList GraphicsPage::getAvailableResolutions(Ogre::RenderSystem *renderer)
QStringList GraphicsPage::getAvailableResolutions(int screen)
{
QString key("Video Mode");
QStringList result;
SDL_DisplayMode mode;
int modeIndex, modes = SDL_GetNumDisplayModes(screen);
uint row = 0;
Ogre::ConfigOptionMap options = renderer->getConfigOptions();
for (Ogre::ConfigOptionMap::iterator i = options.begin (); i != options.end (); i++, row++)
if (modes < 0)
{
if (key.toStdString() != i->first)
continue;
Ogre::StringVector::iterator opt_it;
uint idx = 0;
for (opt_it = i->second.possibleValues.begin ();
opt_it != i->second.possibleValues.end (); opt_it++, idx++)
{
QRegExp resolutionRe(QString("(\\d+) x (\\d+).*"));
QString resolution = QString::fromStdString(*opt_it).simplified();
if (resolutionRe.exactMatch(resolution)) {
int width = resolutionRe.cap(1).toInt();
int height = resolutionRe.cap(2).toInt();
QString aspect = getAspect(width, height);
QString cleanRes = resolutionRe.cap(1) + QString(" x ") + resolutionRe.cap(2);
if (aspect == QLatin1String("16:9") || aspect == QLatin1String("16:10")) {
cleanRes.append(tr("\t(Wide ") + aspect + ")");
} else if (aspect == QLatin1String("4:3")) {
cleanRes.append(tr("\t(Standard 4:3)"));
}
// do not add duplicate resolutions
if (!result.contains(cleanRes))
result.append(cleanRes);
}
}
QMessageBox msgBox;
msgBox.setWindowTitle(tr("Error receiving resolutions"));
msgBox.setIcon(QMessageBox::Critical);
msgBox.setStandardButtons(QMessageBox::Ok);
msgBox.setText(tr("<br><b>SDL_GetNumDisplayModes failed:</b><br><br>") + QString::fromStdString(SDL_GetError()) + "<br>");
msgBox.exec();
return result;
}
// Sort the resolutions in descending order
qSort(result.begin(), result.end(), naturalSortGreaterThanCI);
for (modeIndex = 0; modeIndex < modes; modeIndex++)
{
if (SDL_GetDisplayMode(screen, modeIndex, &mode) < 0)
{
QMessageBox msgBox;
msgBox.setWindowTitle(tr("Error receiving resolutions"));
msgBox.setIcon(QMessageBox::Critical);
msgBox.setStandardButtons(QMessageBox::Ok);
msgBox.setText(tr("<br><b>SDL_GetDisplayMode failed:</b><br><br>") + QString::fromStdString(SDL_GetError()) + "<br>");
msgBox.exec();
return result;
}
QString aspect = getAspect(mode.w, mode.h);
QString resolution = QString::number(mode.w) + QString(" x ") + QString::number(mode.h);
if (aspect == QLatin1String("16:9") || aspect == QLatin1String("16:10")) {
resolution.append(tr("\t(Wide ") + aspect + ")");
} else if (aspect == QLatin1String("4:3")) {
resolution.append(tr("\t(Standard 4:3)"));
}
result.append(resolution);
}
result.removeDuplicates();
return result;
}
QRect GraphicsPage::getMaximumResolution()
{
QRect max;
int screens = QApplication::desktop()->screenCount();
for (int i = 0; i < screens; ++i)
{
QRect res = QApplication::desktop()->screenGeometry(i);
if (res.width() > max.width())
max.setWidth(res.width());
if (res.height() > max.height())
max.setHeight(res.height());
}
return max;
}
void GraphicsPage::rendererChanged(const QString &renderer)
{
mSelectedRenderSystem = mOgre->getRenderSystemByName(renderer.toStdString());
antiAliasingComboBox->clear();
resolutionComboBox->clear();
antiAliasingComboBox->addItems(getAvailableOptions(QString("FSAA"), mSelectedRenderSystem));
resolutionComboBox->addItems(getAvailableResolutions(mSelectedRenderSystem));
}
void GraphicsPage::screenChanged(int screen)
{
if (screen >= 0) {
resolutionComboBox->clear();
resolutionComboBox->addItems(getAvailableResolutions(screen));
}
}
void GraphicsPage::slotFullScreenChanged(int state)

View file

@ -30,10 +30,11 @@ public:
GraphicsPage(Files::ConfigurationManager &cfg, GraphicsSettings &graphicsSettings, QWidget *parent = 0);
void saveSettings();
bool setupOgre();
bool loadSettings();
public slots:
void rendererChanged(const QString &renderer);
void screenChanged(int screen);
private slots:
void slotFullScreenChanged(int state);
@ -55,10 +56,11 @@ private:
GraphicsSettings &mGraphicsSettings;
QStringList getAvailableOptions(const QString &key, Ogre::RenderSystem *renderer);
QStringList getAvailableResolutions(Ogre::RenderSystem *renderer);
void loadSettings();
QStringList getAvailableResolutions(int screen);
QRect getMaximumResolution();
bool setupOgre();
bool setupSDL();
};
#endif

View file

@ -1,11 +1,23 @@
#include <QApplication>
#include <QTextCodec>
#include <QDir>
#include <QDebug>
#include <SDL.h>
#include "maindialog.hpp"
// SDL workaround
#include "graphicspage.hpp"
int main(int argc, char *argv[])
{
SDL_SetHint(SDL_HINT_RENDER_DRIVER, "software");
if (SDL_Init(SDL_INIT_VIDEO) != 0)
{
qDebug() << "SDL_Init failed: " << QString::fromStdString(SDL_GetError());
return 0;
}
QApplication app(argc, argv);
// Now we make sure the current dir is set to application path
@ -41,6 +53,8 @@ int main(int argc, char *argv[])
return 0;
}
return app.exec();
int returnValue = app.exec();
SDL_Quit();
return returnValue;
}

View file

@ -292,8 +292,8 @@ bool MainDialog::setup()
// Now create the pages as they need the settings
createPages();
// Call this so we can exit on Ogre errors before mainwindow is shown
if (!mGraphicsPage->setupOgre())
// Call this so we can exit on Ogre/SDL errors before mainwindow is shown
if (!mGraphicsPage->loadSettings())
return false;
loadSettings();
@ -310,6 +310,8 @@ void MainDialog::changePage(QListWidgetItem *current, QListWidgetItem *previous)
bool MainDialog::setupLauncherSettings()
{
mLauncherSettings.setMultiValueEnabled(true);
QString userPath = QString::fromStdString(mCfgMgr.getUserPath().string());
QStringList paths;
@ -427,6 +429,8 @@ bool MainDialog::setupGameSettings()
bool MainDialog::setupGraphicsSettings()
{
mGraphicsSettings.setMultiValueEnabled(false);
QString userPath = QString::fromStdString(mCfgMgr.getUserPath().string());
QString globalPath = QString::fromStdString(mCfgMgr.getGlobalPath().string());
@ -608,8 +612,21 @@ void MainDialog::closeEvent(QCloseEvent *event)
void MainDialog::play()
{
if (!writeSettings())
if (!writeSettings()) {
qApp->quit();
return;
}
if(!mGameSettings.hasMaster()) {
QMessageBox msgBox;
msgBox.setWindowTitle(tr("No master file selected"));
msgBox.setIcon(QMessageBox::Warning);
msgBox.setStandardButtons(QMessageBox::Ok);
msgBox.setText(tr("<br><b>You do not have any master files selected.</b><br><br> \
OpenMW will not start without a master file selected.<br>"));
msgBox.exec();
return;
}
// Launch the game detached
startProgram(QString("openmw"), true);

View file

@ -2,9 +2,9 @@
#define MAINDIALOG_H
#include <QMainWindow>
#ifndef Q_MOC_RUN
#include <components/files/configurationmanager.hpp>
#endif
#include "settings/gamesettings.hpp"
#include "settings/graphicssettings.hpp"
#include "settings/launchersettings.hpp"

View file

@ -6,8 +6,6 @@
#include <QRegExp>
#include <QMap>
#include <QDebug>
#include <components/files/configurationmanager.hpp>
#include <boost/version.hpp>
@ -96,15 +94,15 @@ bool GameSettings::readFile(QTextStream &stream)
QRegExp keyRe("^([^=]+)\\s*=\\s*(.+)$");
while (!stream.atEnd()) {
QString line = stream.readLine().simplified();
QString line = stream.readLine();
if (line.isEmpty() || line.startsWith("#"))
continue;
if (keyRe.indexIn(line) != -1) {
QString key = keyRe.cap(1).simplified();
QString value = keyRe.cap(2).simplified();
QString key = keyRe.cap(1).trimmed();
QString value = keyRe.cap(2).trimmed();
// Don't remove existing data entries
if (key != QLatin1String("data"))

View file

@ -43,6 +43,7 @@ public:
inline QStringList getDataDirs() { return mDataDirs; }
inline void addDataDir(const QString &dir) { if(!dir.isEmpty()) mDataDirs.append(dir); }
inline QString getDataLocal() {return mDataLocal; }
inline bool hasMaster() { return mSettings.count(QString("master")) > 0; }
QStringList values(const QString &key, const QStringList &defaultValues = QStringList());
bool readFile(QTextStream &stream);

View file

@ -7,14 +7,12 @@
#include <QRegExp>
#include <QMap>
#include <QDebug>
template <class Map>
class SettingsBase
{
public:
SettingsBase() {}
SettingsBase() { mMultiValue = false; }
~SettingsBase() {}
inline QString value(const QString &key, const QString &defaultValue = QString())
@ -36,6 +34,11 @@ public:
mSettings.insertMulti(key, value);
}
inline void setMultiValueEnabled(bool enable)
{
mMultiValue = enable;
}
inline void remove(const QString &key)
{
mSettings.remove(key);
@ -48,11 +51,12 @@ public:
mCache.clear();
QString sectionPrefix;
QRegExp sectionRe("^\\[([^]]+)\\]");
QRegExp keyRe("^([^=]+)\\s*=\\s*(.+)$");
while (!stream.atEnd()) {
QString line = stream.readLine().simplified();
QString line = stream.readLine();
if (line.isEmpty() || line.startsWith("#"))
continue;
@ -65,8 +69,8 @@ public:
if (keyRe.indexIn(line) != -1) {
QString key = keyRe.cap(1).simplified();
QString value = keyRe.cap(2).simplified();
QString key = keyRe.cap(1).trimmed();
QString value = keyRe.cap(2).trimmed();
if (!sectionPrefix.isEmpty())
key.prepend(sectionPrefix);
@ -74,8 +78,13 @@ public:
mSettings.remove(key);
QStringList values = mCache.values(key);
if (!values.contains(value)) {
mCache.insertMulti(key, value);
if (mMultiValue) {
mCache.insertMulti(key, value);
} else {
mCache.insert(key, value);
}
}
}
}
@ -93,6 +102,8 @@ public:
private:
Map mSettings;
Map mCache;
bool mMultiValue;
};
#endif // SETTINGSBASE_HPP

View file

@ -645,7 +645,7 @@ std::string MwIniImporter::numberToString(int n) {
return str.str();
}
MwIniImporter::multistrmap MwIniImporter::loadIniFile(std::string filename) {
MwIniImporter::multistrmap MwIniImporter::loadIniFile(const std::string& filename) const {
std::cout << "load ini file: " << filename << std::endl;
std::string section("");
@ -701,7 +701,7 @@ MwIniImporter::multistrmap MwIniImporter::loadIniFile(std::string filename) {
return map;
}
MwIniImporter::multistrmap MwIniImporter::loadCfgFile(std::string filename) {
MwIniImporter::multistrmap MwIniImporter::loadCfgFile(const std::string& filename) {
std::cout << "load cfg file: " << filename << std::endl;
MwIniImporter::multistrmap map;
@ -738,12 +738,11 @@ MwIniImporter::multistrmap MwIniImporter::loadCfgFile(std::string filename) {
return map;
}
void MwIniImporter::merge(multistrmap &cfg, multistrmap &ini) {
multistrmap::iterator cfgIt;
multistrmap::iterator iniIt;
for(strmap::iterator it=mMergeMap.begin(); it!=mMergeMap.end(); ++it) {
void MwIniImporter::merge(multistrmap &cfg, const multistrmap &ini) const {
multistrmap::const_iterator iniIt;
for(strmap::const_iterator it=mMergeMap.begin(); it!=mMergeMap.end(); ++it) {
if((iniIt = ini.find(it->second)) != ini.end()) {
for(std::vector<std::string>::iterator vc = iniIt->second.begin(); vc != iniIt->second.end(); ++vc) {
for(std::vector<std::string>::const_iterator vc = iniIt->second.begin(); vc != iniIt->second.end(); ++vc) {
cfg.erase(it->first);
insertMultistrmap(cfg, it->first, *vc);
}
@ -751,14 +750,13 @@ void MwIniImporter::merge(multistrmap &cfg, multistrmap &ini) {
}
}
void MwIniImporter::mergeFallback(multistrmap &cfg, multistrmap &ini) {
void MwIniImporter::mergeFallback(multistrmap &cfg, const multistrmap &ini) const {
cfg.erase("fallback");
multistrmap::iterator cfgIt;
multistrmap::iterator iniIt;
for(std::vector<std::string>::iterator it=mMergeFallback.begin(); it!=mMergeFallback.end(); ++it) {
multistrmap::const_iterator iniIt;
for(std::vector<std::string>::const_iterator it=mMergeFallback.begin(); it!=mMergeFallback.end(); ++it) {
if((iniIt = ini.find(*it)) != ini.end()) {
for(std::vector<std::string>::iterator vc = iniIt->second.begin(); vc != iniIt->second.end(); ++vc) {
for(std::vector<std::string>::const_iterator vc = iniIt->second.begin(); vc != iniIt->second.end(); ++vc) {
std::string value(*it);
std::replace( value.begin(), value.end(), ' ', '_' );
std::replace( value.begin(), value.end(), ':', '_' );
@ -769,21 +767,21 @@ void MwIniImporter::mergeFallback(multistrmap &cfg, multistrmap &ini) {
}
}
void MwIniImporter::insertMultistrmap(multistrmap &cfg, std::string key, std::string value) {
multistrmap::iterator it = cfg.find(key);
void MwIniImporter::insertMultistrmap(multistrmap &cfg, const std::string& key, const std::string& value) {
const multistrmap::const_iterator it = cfg.find(key);
if(it == cfg.end()) {
cfg.insert(std::make_pair (key, std::vector<std::string>() ));
}
cfg[key].push_back(value);
}
void MwIniImporter::importArchives(multistrmap &cfg, multistrmap &ini) {
void MwIniImporter::importArchives(multistrmap &cfg, const multistrmap &ini) const {
std::vector<std::string> archives;
std::string baseArchive("Archives:Archive ");
std::string archive;
// Search archives listed in ini file
multistrmap::iterator it = ini.begin();
multistrmap::const_iterator it = ini.begin();
for(int i=0; it != ini.end(); i++) {
archive = baseArchive;
archive.append(this->numberToString(i));
@ -793,7 +791,7 @@ void MwIniImporter::importArchives(multistrmap &cfg, multistrmap &ini) {
break;
}
for(std::vector<std::string>::iterator entry = it->second.begin(); entry!=it->second.end(); ++entry) {
for(std::vector<std::string>::const_iterator entry = it->second.begin(); entry!=it->second.end(); ++entry) {
archives.push_back(*entry);
}
}
@ -805,18 +803,18 @@ void MwIniImporter::importArchives(multistrmap &cfg, multistrmap &ini) {
// does not appears in the ini file
cfg["fallback-archive"].push_back("Morrowind.bsa");
for(std::vector<std::string>::iterator it=archives.begin(); it!=archives.end(); ++it) {
for(std::vector<std::string>::const_iterator it=archives.begin(); it!=archives.end(); ++it) {
cfg["fallback-archive"].push_back(*it);
}
}
void MwIniImporter::importGameFiles(multistrmap &cfg, multistrmap &ini) {
void MwIniImporter::importGameFiles(multistrmap &cfg, const multistrmap &ini) const {
std::vector<std::string> esmFiles;
std::vector<std::string> espFiles;
std::string baseGameFile("Game Files:GameFile");
std::string gameFile("");
multistrmap::iterator it = ini.begin();
multistrmap::const_iterator it = ini.begin();
for(int i=0; it != ini.end(); i++) {
gameFile = baseGameFile;
gameFile.append(this->numberToString(i));
@ -826,7 +824,7 @@ void MwIniImporter::importGameFiles(multistrmap &cfg, multistrmap &ini) {
break;
}
for(std::vector<std::string>::iterator entry = it->second.begin(); entry!=it->second.end(); ++entry) {
for(std::vector<std::string>::const_iterator entry = it->second.begin(); entry!=it->second.end(); ++entry) {
std::string filetype(entry->substr(entry->length()-3));
Misc::StringUtils::toLower(filetype);
@ -844,22 +842,22 @@ void MwIniImporter::importGameFiles(multistrmap &cfg, multistrmap &ini) {
cfg.erase("master");
cfg.insert( std::make_pair<std::string, std::vector<std::string> > ("master", std::vector<std::string>() ) );
for(std::vector<std::string>::iterator it=esmFiles.begin(); it!=esmFiles.end(); ++it) {
for(std::vector<std::string>::const_iterator it=esmFiles.begin(); it!=esmFiles.end(); ++it) {
cfg["master"].push_back(*it);
}
cfg.erase("plugin");
cfg.insert( std::make_pair<std::string, std::vector<std::string> > ("plugin", std::vector<std::string>() ) );
for(std::vector<std::string>::iterator it=espFiles.begin(); it!=espFiles.end(); ++it) {
for(std::vector<std::string>::const_iterator it=espFiles.begin(); it!=espFiles.end(); ++it) {
cfg["plugin"].push_back(*it);
}
}
void MwIniImporter::writeToFile(boost::iostreams::stream<boost::iostreams::file_sink> &out, multistrmap &cfg) {
void MwIniImporter::writeToFile(boost::iostreams::stream<boost::iostreams::file_sink> &out, const multistrmap &cfg) {
for(multistrmap::iterator it=cfg.begin(); it != cfg.end(); ++it) {
for(std::vector<std::string>::iterator entry=it->second.begin(); entry != it->second.end(); ++entry) {
for(multistrmap::const_iterator it=cfg.begin(); it != cfg.end(); ++it) {
for(std::vector<std::string>::const_iterator entry=it->second.begin(); entry != it->second.end(); ++entry) {
out << (it->first) << "=" << (*entry) << std::endl;
}
}

View file

@ -18,18 +18,17 @@ class MwIniImporter {
MwIniImporter();
void setInputEncoding(const ToUTF8::FromType& encoding);
void setVerbose(bool verbose);
multistrmap loadIniFile(std::string filename);
multistrmap loadCfgFile(std::string filename);
void merge(multistrmap &cfg, multistrmap &ini);
void mergeFallback(multistrmap &cfg, multistrmap &ini);
void importGameFiles(multistrmap &cfg, multistrmap &ini);
void importArchives(multistrmap &cfg, multistrmap &ini);
void writeToFile(boost::iostreams::stream<boost::iostreams::file_sink> &out, multistrmap &cfg);
multistrmap loadIniFile(const std::string& filename) const;
static multistrmap loadCfgFile(const std::string& filename);
void merge(multistrmap &cfg, const multistrmap &ini) const;
void mergeFallback(multistrmap &cfg, const multistrmap &ini) const;
void importGameFiles(multistrmap &cfg, const multistrmap &ini) const;
void importArchives(multistrmap &cfg, const multistrmap &ini) const;
static void writeToFile(boost::iostreams::stream<boost::iostreams::file_sink> &out, const multistrmap &cfg);
private:
void insertMultistrmap(multistrmap &cfg, std::string key, std::string value);
std::string numberToString(int n);
std::string toUTF8(const std::string &str);
static void insertMultistrmap(multistrmap &cfg, const std::string& key, const std::string& value);
static std::string numberToString(int n);
bool mVerbose;
strmap mMergeMap;
std::vector<std::string> mMergeFallback;

View file

@ -28,12 +28,26 @@ int main(int argc, char *argv[]) {
p_desc.add("ini", 1).add("cfg", 1);
bpo::variables_map vm;
bpo::parsed_options parsed = bpo::command_line_parser(argc, argv)
.options(desc)
.positional(p_desc)
.run();
bpo::store(parsed, vm);
try
{
bpo::parsed_options parsed = bpo::command_line_parser(argc, argv)
.options(desc)
.positional(p_desc)
.run();
bpo::store(parsed, vm);
}
catch(boost::program_options::unknown_option & x)
{
std::cerr << "ERROR: " << x.what() << std::endl;
return false;
}
catch(boost::program_options::invalid_command_line_syntax & x)
{
std::cerr << "ERROR: " << x.what() << std::endl;
return false;
}
if(vm.count("help") || !vm.count("ini") || !vm.count("cfg")) {
std::cout << desc;
@ -55,10 +69,8 @@ int main(int argc, char *argv[]) {
std::cerr << "ini file does not exist" << std::endl;
return -3;
}
if(!boost::filesystem::exists(cfgFile)) {
if(!boost::filesystem::exists(cfgFile))
std::cerr << "cfg file does not exist" << std::endl;
return -4;
}
MwIniImporter importer;
importer.setVerbose(vm.count("verbose"));

View file

@ -2,6 +2,7 @@ set (OPENCS_SRC main.cpp)
opencs_units (. editor)
set (CMAKE_BUILD_TYPE DEBUG)
opencs_units (model/doc
document
@ -22,7 +23,8 @@ opencs_units (model/world
opencs_units_noqt (model/world
universalid data record idcollection commands columnbase
universalid data record idcollection commands columnbase scriptcontext cell refidcollection
refidadapter refiddata refidadapterimp
)
opencs_hdrs_noqt (model/world
@ -35,7 +37,8 @@ opencs_units (model/tools
)
opencs_units_noqt (model/tools
stage verifier mandatoryid skillcheck
stage verifier mandatoryid skillcheck classcheck factioncheck racecheck soundcheck regioncheck
birthsigncheck spellcheck
)
@ -54,11 +57,11 @@ opencs_hdrs_noqt (view/doc
opencs_units (view/world
table tablesubview
table tablesubview scriptsubview util
)
opencs_units_noqt (view/world
dialoguesubview util subviews enumdelegate vartypedelegate
dialoguesubview subviews enumdelegate vartypedelegate scripthighlighter recordstatusdelegate
)
@ -70,6 +73,36 @@ opencs_units_noqt (view/tools
subviews
)
opencs_units (view/settings
abstractblock
proxyblock
abstractwidget
usersettingsdialog
editorpage
windowpage
)
opencs_units_noqt (view/settings
abstractpage
blankpage
groupblock
customblock
groupbox
itemblock
settingwidget
toggleblock
support
)
opencs_units (model/settings
usersettings
settingcontainer
)
opencs_units_noqt (model/settings
support
settingsitem
)
set (OPENCS_US
)

View file

@ -61,6 +61,11 @@ void CS::Editor::setupDataFiles()
QString path = QString::fromStdString(iter->string());
mFileDialog.addFiles(path);
}
//load the settings into the userSettings instance.
const QString settingFileName = "opencs.cfg";
CSMSettings::UserSettings::instance().loadSettings(settingFileName);
}
void CS::Editor::createDocument()

View file

@ -2,14 +2,15 @@
#define CS_EDITOR_H
#include <QObject>
#ifndef Q_MOC_RUN
#include <components/files/configurationmanager.hpp>
#endif
#include "model/doc/documentmanager.hpp"
#include "view/doc/viewmanager.hpp"
#include "view/doc/startup.hpp"
#include "view/doc/filedialog.hpp"
#include "model/settings/usersettings.hpp"
namespace CS
{
@ -17,13 +18,13 @@ namespace CS
{
Q_OBJECT
CSMSettings::UserSettings mUserSettings;
CSMDoc::DocumentManager mDocumentManager;
CSVDoc::ViewManager mViewManager;
CSVDoc::StartupDialogue mStartup;
FileDialog mFileDialog;
Files::ConfigurationManager mCfgMgr;
void setupDataFiles();
// not implemented

File diff suppressed because it is too large Load diff

View file

@ -52,6 +52,8 @@ namespace CSMDoc
void createBase();
void addGmsts();
void addOptionalGmsts();
void addOptionalGlobals();

View file

@ -0,0 +1,82 @@
#include "settingcontainer.hpp"
#include <QStringList>
CSMSettings::SettingContainer::SettingContainer(QObject *parent) :
QObject(parent), mValue (0), mValues (0)
{
}
CSMSettings::SettingContainer::SettingContainer(const QString &value, QObject *parent) :
QObject(parent), mValue (new QString (value)), mValues (0)
{
}
void CSMSettings::SettingContainer::insert (const QString &value)
{
if (mValue)
{
mValues = new QStringList;
mValues->push_back (*mValue);
mValues->push_back (value);
delete mValue;
mValue = 0;
}
else
{
delete mValue;
mValue = new QString (value);
}
}
void CSMSettings::SettingContainer::update (const QString &value, int index)
{
if (isEmpty())
mValue = new QString(value);
else if (mValue)
*mValue = value;
else if (mValues)
mValues->replace(index, value);
}
QString CSMSettings::SettingContainer::getValue (int index) const
{
QString retVal("");
//if mValue is valid, it's a single-value property.
//ignore the index and return the value
if (mValue)
retVal = *mValue;
//otherwise, if it's a multivalued property
//return the appropriate value at the index
else if (mValues)
{
if (index == -1)
retVal = mValues->at(0);
else if (index < mValues->size())
retVal = mValues->at(index);
}
return retVal;
}
int CSMSettings::SettingContainer::count () const
{
int retVal = 0;
if (!isEmpty())
{
if (mValues)
retVal = mValues->size();
else
retVal = 1;
}
return retVal;
}

View file

@ -0,0 +1,47 @@
#ifndef SETTINGCONTAINER_HPP
#define SETTINGCONTAINER_HPP
#include <QObject>
class QStringList;
namespace CSMSettings
{
class SettingContainer : public QObject
{
Q_OBJECT
QString *mValue;
QStringList *mValues;
public:
explicit SettingContainer (QObject *parent = 0);
explicit SettingContainer (const QString &value, QObject *parent = 0);
/// add a value to the container
/// multiple values supported
void insert (const QString &value);
/// update an existing value
/// index specifies multiple values
void update (const QString &value, int index = 0);
/// return value at specified index
QString getValue (int index = -1) const;
/// retrieve list of all values
inline QStringList *getValues() const { return mValues; }
/// return size of list
int count() const;
/// test for empty container
/// useful for default-constructed containers returned by QMap when invalid key is passed
inline bool isEmpty() const { return (!mValue && !mValues); }
inline bool isMultiValue() const { return (mValues); }
};
}
#endif // SETTINGCONTAINER_HPP

View file

@ -0,0 +1,104 @@
#include "settingsitem.hpp"
#include <QStringList>
bool CSMSettings::SettingsItem::updateItem (const QStringList *values)
{
QStringList::ConstIterator it = values->begin();
//if the item is not multivalued,
//save the last value passed in the container
if (!mIsMultiValue)
{
it = values->end();
it--;
}
bool isValid = true;
QString value ("");
for (; it != values->end(); ++it)
{
value = *it;
isValid = validate(value);
//skip only the invalid values
if (!isValid)
continue;
insert(value);
}
return isValid;
}
bool CSMSettings::SettingsItem::updateItem (const QString &value)
{
//takes a value or a SettingsContainer and updates itself accordingly
//after validating the data against it's own definition
QString newValue = value;
if (!validate (newValue))
newValue = mDefaultValue;
bool success = (getValue() != newValue);
if (success)
{
if (mIsMultiValue)
insert (newValue);
else
update (newValue);
}
return success;
}
bool CSMSettings::SettingsItem::updateItem(int valueListIndex)
{
bool success = false;
if (mValueList)
{
if (mValueList->size() > valueListIndex)
success = updateItem (mValueList->at(valueListIndex));
}
return success;
}
bool CSMSettings::SettingsItem::validate (const QString &value)
{
//if there is no value list or value pair, there is no validation to do
bool isValid = !(!mValueList->isEmpty() || mValuePair);
if (!isValid && !mValueList->isEmpty())
{
for (QStringList::Iterator it = mValueList->begin(); it != mValueList->end(); ++it)
// foreach (QString listItem, *mValueList)
{
isValid = (value == *it);
if (isValid)
break;
}
}
else if (!isValid && mValuePair)
{
int numVal = value.toInt();
isValid = (numVal > mValuePair->left.toInt() && numVal < mValuePair->right.toInt());
}
return isValid;
}
void CSMSettings::SettingsItem::setDefaultValue (const QString &value)
{
mDefaultValue = value;
update (value);
}
QString CSMSettings::SettingsItem::getDefaultValue() const
{
return mDefaultValue;
}

View file

@ -0,0 +1,63 @@
#ifndef SETTINGSITEM_HPP
#define SETTINGSITEM_HPP
#include <QObject>
#include "support.hpp"
#include "settingcontainer.hpp"
namespace CSMSettings
{
/// Represents a setting including metadata
/// (valid values, ranges, defaults, and multivalue status
class SettingsItem : public SettingContainer
{
QStringPair *mValuePair;
QStringList *mValueList;
bool mIsMultiValue;
QString mDefaultValue;
public:
explicit SettingsItem(QString name, bool isMultiValue,
const QString& defaultValue, QObject *parent = 0)
: SettingContainer(defaultValue, parent),
mIsMultiValue (isMultiValue), mValueList (0),
mValuePair (0), mDefaultValue (defaultValue)
{
QObject::setObjectName(name);
}
/// updateItem overloads for updating setting value
/// provided a list of values (multi-valued),
/// a specific value
/// or an index value corresponding to the mValueList
bool updateItem (const QStringList *values);
bool updateItem (const QString &value);
bool updateItem (int valueListIndex);
/// retroeve list of valid values for setting
inline QStringList *getValueList() { return mValueList; }
/// write list of valid values for setting
inline void setValueList (QStringList *valueList) { mValueList = valueList; }
/// valuePair used for spin boxes (max / min)
inline QStringPair *getValuePair() { return mValuePair; }
/// set value range (spinbox / integer use)
inline void setValuePair (QStringPair valuePair) { mValuePair = new QStringPair(valuePair); }
inline bool isMultivalue () { return mIsMultiValue; }
void setDefaultValue (const QString &value);
QString getDefaultValue () const;
private:
/// Verifies that the supplied value is one of the following:
/// 1. Within the limits of the value pair (min / max)
/// 2. One of the values indicated in the value list
bool validate (const QString &value);
};
}
#endif // SETTINGSITEM_HPP

View file

@ -0,0 +1 @@
#include "support.hpp"

View file

@ -0,0 +1,39 @@
#ifndef MODEL_SUPPORT_HPP
#define MODEL_SUPPORT_HPP
#include <QObject>
#include <QStringList>
class QLayout;
class QWidget;
class QListWidgetItem;
namespace CSMSettings
{
class SettingContainer;
typedef QList<SettingContainer *> SettingList;
typedef QMap<QString, SettingContainer *> SettingMap;
typedef QMap<QString, SettingMap *> SectionMap;
struct QStringPair
{
QStringPair(): left (""), right ("")
{}
QStringPair (const QString &leftValue, const QString &rightValue)
: left (leftValue), right(rightValue)
{}
QStringPair (const QStringPair &pair)
: left (pair.left), right (pair.right)
{}
QString left;
QString right;
bool isEmpty() const
{ return (left.isEmpty() && right.isEmpty()); }
};
}
#endif // MODEL_SUPPORT_HPP

View file

@ -0,0 +1,266 @@
#include "usersettings.hpp"
#include <QTextStream>
#include <QDir>
#include <QString>
#include <QRegExp>
#include <QMap>
#include <QMessageBox>
#include <QTextCodec>
#include <QFile>
#include <QDebug>
#include <components/files/configurationmanager.hpp>
#include "settingcontainer.hpp"
#include <boost/version.hpp>
/**
* Workaround for problems with whitespaces in paths in older versions of Boost library
*/
#if (BOOST_VERSION <= 104600)
namespace boost
{
template<>
inline boost::filesystem::path lexical_cast<boost::filesystem::path, std::string>(const std::string& arg)
{
return boost::filesystem::path(arg);
}
} /* namespace boost */
#endif /* (BOOST_VERSION <= 104600) */
CSMSettings::UserSettings *CSMSettings::UserSettings::mUserSettingsInstance = 0;
CSMSettings::UserSettings::UserSettings()
{
assert(!mUserSettingsInstance);
mUserSettingsInstance = this;
mReadWriteMessage = QObject::tr("<br><b>Could not open or create file for writing</b><br><br> \
Please make sure you have the right permissions and try again.<br>");
mReadOnlyMessage = QObject::tr("<br><b>Could not open file for reading</b><br><br> \
Please make sure you have the right permissions and try again.<br>");
}
CSMSettings::UserSettings::~UserSettings()
{
mUserSettingsInstance = 0;
}
QTextStream *CSMSettings::UserSettings::openFileStream (const QString &filePath, bool isReadOnly) const
{
QIODevice::OpenMode openFlags = QIODevice::Text;
if (isReadOnly)
openFlags = QIODevice::ReadOnly | openFlags;
else
openFlags = QIODevice::ReadWrite | QIODevice::Truncate | openFlags;
QFile *file = new QFile(filePath);
QTextStream *stream = 0;
if (file->open(openFlags))
{
stream = new QTextStream(file);
stream->setCodec(QTextCodec::codecForName("UTF-8"));
}
return stream;
}
bool CSMSettings::UserSettings::writeSettings(QMap<QString, CSMSettings::SettingList *> &settings)
{
QTextStream *stream = openFileStream(mUserFilePath);
bool success = (stream);
if (success)
{
QList<QString> keyList = settings.keys();
foreach (QString key, keyList)
{
SettingList *sectionSettings = settings[key];
*stream << "[" << key << "]" << '\n';
foreach (SettingContainer *item, *sectionSettings)
*stream << item->objectName() << " = " << item->getValue() << '\n';
}
stream->device()->close();
delete stream;
stream = 0;
}
else
{
displayFileErrorMessage(mReadWriteMessage, false);
}
return (success);
}
const CSMSettings::SectionMap &CSMSettings::UserSettings::getSettings() const
{
return mSectionSettings;
}
bool CSMSettings::UserSettings::loadFromFile(const QString &filePath)
{
if (filePath.isEmpty())
return false;
mSectionSettings.clear();
QTextStream *stream = openFileStream (filePath, true);
bool success = (stream);
if (success)
{
//looks for a square bracket, "'\\["
//that has one or more "not nothing" in it, "([^]]+)"
//and is closed with a square bracket, "\\]"
QRegExp sectionRe("^\\[([^]]+)\\]");
//Find any character(s) that is/are not equal sign(s), "[^=]+"
//followed by an optional whitespace, an equal sign, and another optional whitespace, "\\s*=\\s*"
//and one or more periods, "(.+)"
QRegExp keyRe("^([^=]+)\\s*=\\s*(.+)$");
CSMSettings::SettingMap *settings = 0;
QString section = "none";
while (!stream->atEnd())
{
QString line = stream->readLine().simplified();
if (line.isEmpty() || line.startsWith("#"))
continue;
//if a section is found, push it onto a new QStringList
//and push the QStringList onto
if (sectionRe.exactMatch(line))
{
//add the previous section's settings to the member map
if (settings)
mSectionSettings.insert(section, settings);
//save new section and create a new list
section = sectionRe.cap(1);
settings = new SettingMap;
continue;
}
if (keyRe.indexIn(line) != -1)
{
SettingContainer *sc = new SettingContainer (keyRe.cap(2).simplified());
sc->setObjectName(keyRe.cap(1).simplified());
(*settings)[keyRe.cap(1).simplified()] = sc;
}
}
mSectionSettings.insert(section, settings);
stream->device()->close();
delete stream;
stream = 0;
}
return success;
}
void CSMSettings::UserSettings::loadSettings (const QString &fileName)
{
//global
QString globalFilePath = QString::fromStdString(mCfgMgr.getGlobalPath().string()) + fileName;
bool globalOk = loadFromFile(globalFilePath);
//local
QString localFilePath = QString::fromStdString(mCfgMgr.getLocalPath().string()) + fileName;
bool localOk = loadFromFile(localFilePath);
//user
mUserFilePath = QString::fromStdString(mCfgMgr.getUserPath().string()) + fileName;
loadFromFile(mUserFilePath);
if (!(localOk || globalOk))
{
QString message = QObject::tr("<br><b>Could not open user settings files for reading</b><br><br> \
Global and local settings files could not be read.\
You may have incorrect file permissions or the OpenCS installation may be corrupted.<br>");
message += QObject::tr("<br>Global filepath: ") + globalFilePath;
message += QObject::tr("<br>Local filepath: ") + localFilePath;
displayFileErrorMessage ( message, true);
}
}
void CSMSettings::UserSettings::updateSettings (const QString &sectionName, const QString &settingName)
{
if (mSectionSettings.find(sectionName) == mSectionSettings.end())
return;
SettingMap *settings = mSectionSettings.value(sectionName);
if (settingName.isEmpty())
{
foreach (const SettingContainer *setting, *settings)
emit signalUpdateEditorSetting (setting->objectName(), setting->getValue());
}
else
{
if (settings->find(settingName) != settings->end())
{
const SettingContainer *setting = settings->value(settingName);
emit signalUpdateEditorSetting (setting->objectName(), setting->getValue());
}
}
}
QString CSMSettings::UserSettings::getSetting (const QString &section, const QString &setting) const
{
QString retVal = "";
if (mSectionSettings.find(section) != mSectionSettings.end())
{
CSMSettings::SettingMap *settings = mSectionSettings.value(section);
if (settings->find(setting) != settings->end())
retVal = settings->value(setting)->getValue();
}
return retVal;
}
CSMSettings::UserSettings& CSMSettings::UserSettings::instance()
{
assert(mUserSettingsInstance);
return *mUserSettingsInstance;
}
void CSMSettings::UserSettings::displayFileErrorMessage(const QString &message, bool isReadOnly)
{
// File cannot be opened or created
QMessageBox msgBox;
msgBox.setWindowTitle(QObject::tr("OpenCS configuration file I/O error"));
msgBox.setIcon(QMessageBox::Critical);
msgBox.setStandardButtons(QMessageBox::Ok);
if (!isReadOnly)
msgBox.setText (mReadWriteMessage + message);
else
msgBox.setText (message);
msgBox.exec();
}

View file

@ -0,0 +1,83 @@
#ifndef USERSETTINGS_HPP
#define USERSETTINGS_HPP
#include <QTextStream>
#include <QStringList>
#include <QString>
#include <QMap>
#include <boost/filesystem/path.hpp>
#include "support.hpp"
#ifndef Q_MOC_RUN
#include <components/files/configurationmanager.hpp>
#endif
namespace Files { typedef std::vector<boost::filesystem::path> PathContainer;
struct ConfigurationManager;}
class QFile;
namespace CSMSettings {
struct UserSettings: public QObject
{
Q_OBJECT
SectionMap mSectionSettings;
static UserSettings *mUserSettingsInstance;
QString mUserFilePath;
Files::ConfigurationManager mCfgMgr;
QString mReadOnlyMessage;
QString mReadWriteMessage;
public:
/// Singleton implementation
static UserSettings& instance();
UserSettings();
~UserSettings();
UserSettings (UserSettings const &); //not implemented
void operator= (UserSettings const &); //not implemented
/// Writes settings to the last loaded settings file
bool writeSettings(QMap<QString, SettingList *> &sections);
/// Called from editor to trigger signal to update the specified setting.
/// If no setting name is specified, all settings found in the specified section are updated.
void updateSettings (const QString &sectionName, const QString &settingName = "");
/// Retrieves the settings file at all three levels (global, local and user).
/// \todo Multi-valued settings are not fully implemented. Setting values
/// \todo loaded in later files will always overwrite previously loaded values.
void loadSettings (const QString &fileName);
/// Returns the entire map of settings across all sections
const SectionMap &getSettings () const;
/// Retrieves the value as a QString of the specified setting in the specified section
QString getSetting(const QString &section, const QString &setting) const;
private:
/// Opens a QTextStream from the provided path as read-only or read-write.
QTextStream *openFileStream (const QString &filePath, bool isReadOnly = false) const;
/// Parses a setting file specified in filePath from the provided text stream.
bool loadFromFile (const QString &filePath = "");
void displayFileErrorMessage(const QString &message, bool isReadOnly);
signals:
void signalUpdateEditorSetting (const QString &settingName, const QString &settingValue);
};
}
#endif // USERSETTINGS_HPP

View file

@ -0,0 +1,39 @@
#include "birthsigncheck.hpp"
#include <sstream>
#include <map>
#include <components/esm/loadbsgn.hpp>
#include "../world/universalid.hpp"
CSMTools::BirthsignCheckStage::BirthsignCheckStage (const CSMWorld::IdCollection<ESM::BirthSign>& birthsigns)
: mBirthsigns (birthsigns)
{}
int CSMTools::BirthsignCheckStage::setup()
{
return mBirthsigns.getSize();
}
void CSMTools::BirthsignCheckStage::perform (int stage, std::vector<std::string>& messages)
{
const ESM::BirthSign& birthsign = mBirthsigns.getRecord (stage).get();
CSMWorld::UniversalId id (CSMWorld::UniversalId::Type_Birthsign, birthsign.mId);
// test for empty name, description and texture
if (birthsign.mName.empty())
messages.push_back (id.toString() + "|" + birthsign.mId + " has an empty name");
if (birthsign.mDescription.empty())
messages.push_back (id.toString() + "|" + birthsign.mId + " has an empty description");
if (birthsign.mTexture.empty())
messages.push_back (id.toString() + "|" + birthsign.mId + " is missing a texture");
/// \todo test if the texture exists
/// \todo check data members that can't be edited in the table view
}

View file

@ -0,0 +1,29 @@
#ifndef CSM_TOOLS_BIRTHSIGNCHECK_H
#define CSM_TOOLS_BIRTHSIGNCHECK_H
#include <components/esm/loadbsgn.hpp>
#include "../world/idcollection.hpp"
#include "stage.hpp"
namespace CSMTools
{
/// \brief VerifyStage: make sure that birthsign records are internally consistent
class BirthsignCheckStage : public Stage
{
const CSMWorld::IdCollection<ESM::BirthSign>& mBirthsigns;
public:
BirthsignCheckStage (const CSMWorld::IdCollection<ESM::BirthSign>& birthsigns);
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

View file

@ -0,0 +1,72 @@
#include "classcheck.hpp"
#include <sstream>
#include <map>
#include <components/esm/loadclas.hpp>
#include <components/esm/loadskil.hpp>
#include "../world/universalid.hpp"
CSMTools::ClassCheckStage::ClassCheckStage (const CSMWorld::IdCollection<ESM::Class>& classes)
: mClasses (classes)
{}
int CSMTools::ClassCheckStage::setup()
{
return mClasses.getSize();
}
void CSMTools::ClassCheckStage::perform (int stage, std::vector<std::string>& messages)
{
const ESM::Class& class_= mClasses.getRecord (stage).get();
CSMWorld::UniversalId id (CSMWorld::UniversalId::Type_Class, class_.mId);
// test for empty name and description
if (class_.mName.empty())
messages.push_back (id.toString() + "|" + class_.mId + " has an empty name");
if (class_.mDescription.empty())
messages.push_back (id.toString() + "|" + class_.mId + " has an empty description");
// test for invalid attributes
for (int i=0; i<2; ++i)
if (class_.mData.mAttribute[i]==-1)
{
std::ostringstream stream;
stream << id.toString() << "|Attribute #" << i << " of " << class_.mId << " is not set";
messages.push_back (stream.str());
}
if (class_.mData.mAttribute[0]==class_.mData.mAttribute[1] && class_.mData.mAttribute[0]!=-1)
{
std::ostringstream stream;
stream << id.toString() << "|Class lists same attribute twice";
messages.push_back (stream.str());
}
// test for non-unique skill
std::map<int, int> skills; // ID, number of occurrences
for (int i=0; i<5; ++i)
for (int i2=0; i2<2; ++i2)
++skills[class_.mData.mSkills[i][i2]];
for (std::map<int, int>::const_iterator iter (skills.begin()); iter!=skills.end(); ++iter)
if (iter->second>1)
{
std::ostringstream stream;
stream
<< id.toString() << "|"
<< ESM::Skill::indexToId (iter->first) << " is listed more than once";
messages.push_back (stream.str());
}
}

View file

@ -0,0 +1,29 @@
#ifndef CSM_TOOLS_CLASSCHECK_H
#define CSM_TOOLS_CLASSCHECK_H
#include <components/esm/loadclas.hpp>
#include "../world/idcollection.hpp"
#include "stage.hpp"
namespace CSMTools
{
/// \brief VerifyStage: make sure that class records are internally consistent
class ClassCheckStage : public Stage
{
const CSMWorld::IdCollection<ESM::Class>& mClasses;
public:
ClassCheckStage (const CSMWorld::IdCollection<ESM::Class>& classes);
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

View file

@ -0,0 +1,61 @@
#include "factioncheck.hpp"
#include <sstream>
#include <map>
#include <components/esm/loadfact.hpp>
#include <components/esm/loadskil.hpp>
#include "../world/universalid.hpp"
CSMTools::FactionCheckStage::FactionCheckStage (const CSMWorld::IdCollection<ESM::Faction>& factions)
: mFactions (factions)
{}
int CSMTools::FactionCheckStage::setup()
{
return mFactions.getSize();
}
void CSMTools::FactionCheckStage::perform (int stage, std::vector<std::string>& messages)
{
const ESM::Faction& faction = mFactions.getRecord (stage).get();
CSMWorld::UniversalId id (CSMWorld::UniversalId::Type_Faction, faction.mId);
// test for empty name
if (faction.mName.empty())
messages.push_back (id.toString() + "|" + faction.mId + " has an empty name");
// test for invalid attributes
if (faction.mData.mAttribute[0]==faction.mData.mAttribute[1] && faction.mData.mAttribute[0]!=-1)
{
std::ostringstream stream;
stream << id.toString() << "|Faction lists same attribute twice";
messages.push_back (stream.str());
}
// test for non-unique skill
std::map<int, int> skills; // ID, number of occurrences
for (int i=0; i<6; ++i)
if (faction.mData.mSkills[i]!=-1)
++skills[faction.mData.mSkills[i]];
for (std::map<int, int>::const_iterator iter (skills.begin()); iter!=skills.end(); ++iter)
if (iter->second>1)
{
std::ostringstream stream;
stream
<< id.toString() << "|"
<< ESM::Skill::indexToId (iter->first) << " is listed more than once";
messages.push_back (stream.str());
}
/// \todo check data members that can't be edited in the table view
}

View file

@ -0,0 +1,29 @@
#ifndef CSM_TOOLS_FACTIONCHECK_H
#define CSM_TOOLS_FACTIONCHECK_H
#include <components/esm/loadfact.hpp>
#include "../world/idcollection.hpp"
#include "stage.hpp"
namespace CSMTools
{
/// \brief VerifyStage: make sure that faction records are internally consistent
class FactionCheckStage : public Stage
{
const CSMWorld::IdCollection<ESM::Faction>& mFactions;
public:
FactionCheckStage (const CSMWorld::IdCollection<ESM::Faction>& factions);
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

View file

@ -0,0 +1,68 @@
#include "racecheck.hpp"
#include <sstream>
#include <components/esm/loadrace.hpp>
#include "../world/universalid.hpp"
void CSMTools::RaceCheckStage::performPerRecord (int stage, std::vector<std::string>& messages)
{
const ESM::Race& race = mRaces.getRecord (stage).get();
CSMWorld::UniversalId id (CSMWorld::UniversalId::Type_Race, race.mId);
// test for empty name and description
if (race.mName.empty())
messages.push_back (id.toString() + "|" + race.mId + " has an empty name");
if (race.mDescription.empty())
messages.push_back (id.toString() + "|" + race.mId + " has an empty description");
// test for positive height
if (race.mData.mHeight.mMale<=0)
messages.push_back (id.toString() + "|male " + race.mId + " has non-positive height");
if (race.mData.mHeight.mFemale<=0)
messages.push_back (id.toString() + "|female " + race.mId + " has non-positive height");
// test for non-negative weight
if (race.mData.mWeight.mMale<0)
messages.push_back (id.toString() + "|male " + race.mId + " has negative weight");
if (race.mData.mWeight.mFemale<0)
messages.push_back (id.toString() + "|female " + race.mId + " has negative weight");
// remember playable flag
if (race.mData.mFlags & 0x1)
mPlayable = true;
/// \todo check data members that can't be edited in the table view
}
void CSMTools::RaceCheckStage::performFinal (std::vector<std::string>& messages)
{
CSMWorld::UniversalId id (CSMWorld::UniversalId::Type_Races);
if (!mPlayable)
messages.push_back (id.toString() + "|No playable race");
}
CSMTools::RaceCheckStage::RaceCheckStage (const CSMWorld::IdCollection<ESM::Race>& races)
: mRaces (races), mPlayable (false)
{}
int CSMTools::RaceCheckStage::setup()
{
mPlayable = false;
return mRaces.getSize()+1;
}
void CSMTools::RaceCheckStage::perform (int stage, std::vector<std::string>& messages)
{
if (stage==mRaces.getSize())
performFinal (messages);
else
performPerRecord (stage, messages);
}

View file

@ -0,0 +1,34 @@
#ifndef CSM_TOOLS_RACECHECK_H
#define CSM_TOOLS_RACECHECK_H
#include <components/esm/loadrace.hpp>
#include "../world/idcollection.hpp"
#include "stage.hpp"
namespace CSMTools
{
/// \brief VerifyStage: make sure that race records are internally consistent
class RaceCheckStage : public Stage
{
const CSMWorld::IdCollection<ESM::Race>& mRaces;
bool mPlayable;
void performPerRecord (int stage, std::vector<std::string>& messages);
void performFinal (std::vector<std::string>& messages);
public:
RaceCheckStage (const CSMWorld::IdCollection<ESM::Race>& races);
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

View file

@ -0,0 +1,33 @@
#include "regioncheck.hpp"
#include <sstream>
#include <map>
#include <components/esm/loadregn.hpp>
#include "../world/universalid.hpp"
CSMTools::RegionCheckStage::RegionCheckStage (const CSMWorld::IdCollection<ESM::Region>& regions)
: mRegions (regions)
{}
int CSMTools::RegionCheckStage::setup()
{
return mRegions.getSize();
}
void CSMTools::RegionCheckStage::perform (int stage, std::vector<std::string>& messages)
{
const ESM::Region& region = mRegions.getRecord (stage).get();
CSMWorld::UniversalId id (CSMWorld::UniversalId::Type_Region, region.mId);
// test for empty name
if (region.mName.empty())
messages.push_back (id.toString() + "|" + region.mId + " has an empty name");
/// \todo test that the ID in mSleeplist exists
/// \todo check data members that can't be edited in the table view
}

View file

@ -0,0 +1,29 @@
#ifndef CSM_TOOLS_REGIONCHECK_H
#define CSM_TOOLS_REGIONCHECK_H
#include <components/esm/loadregn.hpp>
#include "../world/idcollection.hpp"
#include "stage.hpp"
namespace CSMTools
{
/// \brief VerifyStage: make sure that region records are internally consistent
class RegionCheckStage : public Stage
{
const CSMWorld::IdCollection<ESM::Region>& mRegions;
public:
RegionCheckStage (const CSMWorld::IdCollection<ESM::Region>& regions);
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

View file

@ -0,0 +1,29 @@
#include "soundcheck.hpp"
#include <sstream>
#include <components/esm/loadskil.hpp>
#include "../world/universalid.hpp"
CSMTools::SoundCheckStage::SoundCheckStage (const CSMWorld::IdCollection<ESM::Sound>& sounds)
: mSounds (sounds)
{}
int CSMTools::SoundCheckStage::setup()
{
return mSounds.getSize();
}
void CSMTools::SoundCheckStage::perform (int stage, std::vector<std::string>& messages)
{
const ESM::Sound& sound = mSounds.getRecord (stage).get();
CSMWorld::UniversalId id (CSMWorld::UniversalId::Type_Sound, sound.mId);
if (sound.mData.mMinRange>sound.mData.mMaxRange)
messages.push_back (id.toString() + "|Maximum range larger than minimum range");
/// \todo check, if the sound file exists
}

View file

@ -0,0 +1,29 @@
#ifndef CSM_TOOLS_SOUNDCHECK_H
#define CSM_TOOLS_SOUNDCHECK_H
#include <components/esm/loadsoun.hpp>
#include "../world/idcollection.hpp"
#include "stage.hpp"
namespace CSMTools
{
/// \brief VerifyStage: make sure that sound records are internally consistent
class SoundCheckStage : public Stage
{
const CSMWorld::IdCollection<ESM::Sound>& mSounds;
public:
SoundCheckStage (const CSMWorld::IdCollection<ESM::Sound>& sounds);
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

View file

@ -0,0 +1,35 @@
#include "spellcheck.hpp"
#include <sstream>
#include <map>
#include <components/esm/loadspel.hpp>
#include "../world/universalid.hpp"
CSMTools::SpellCheckStage::SpellCheckStage (const CSMWorld::IdCollection<ESM::Spell>& spells)
: mSpells (spells)
{}
int CSMTools::SpellCheckStage::setup()
{
return mSpells.getSize();
}
void CSMTools::SpellCheckStage::perform (int stage, std::vector<std::string>& messages)
{
const ESM::Spell& spell = mSpells.getRecord (stage).get();
CSMWorld::UniversalId id (CSMWorld::UniversalId::Type_Spell, spell.mId);
// test for empty name and description
if (spell.mName.empty())
messages.push_back (id.toString() + "|" + spell.mId + " has an empty name");
// test for invalid cost values
if (spell.mData.mCost<0)
messages.push_back (id.toString() + "|" + spell.mId + " has a negative spell costs");
/// \todo check data members that can't be edited in the table view
}

View file

@ -0,0 +1,29 @@
#ifndef CSM_TOOLS_SPELLCHECK_H
#define CSM_TOOLS_SPELLCHECK_H
#include <components/esm/loadspel.hpp>
#include "../world/idcollection.hpp"
#include "stage.hpp"
namespace CSMTools
{
/// \brief VerifyStage: make sure that spell records are internally consistent
class SpellCheckStage : public Stage
{
const CSMWorld::IdCollection<ESM::Spell>& mSpells;
public:
SpellCheckStage (const CSMWorld::IdCollection<ESM::Spell>& spells);
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

View file

@ -13,6 +13,13 @@
#include "reportmodel.hpp"
#include "mandatoryid.hpp"
#include "skillcheck.hpp"
#include "classcheck.hpp"
#include "factioncheck.hpp"
#include "racecheck.hpp"
#include "soundcheck.hpp"
#include "regioncheck.hpp"
#include "birthsigncheck.hpp"
#include "spellcheck.hpp"
CSMTools::Operation *CSMTools::Tools::get (int type)
{
@ -54,6 +61,20 @@ CSMTools::Verifier *CSMTools::Tools::getVerifier()
CSMWorld::UniversalId (CSMWorld::UniversalId::Type_Globals), mandatoryIds));
mVerifier->appendStage (new SkillCheckStage (mData.getSkills()));
mVerifier->appendStage (new ClassCheckStage (mData.getClasses()));
mVerifier->appendStage (new FactionCheckStage (mData.getFactions()));
mVerifier->appendStage (new RaceCheckStage (mData.getRaces()));
mVerifier->appendStage (new SoundCheckStage (mData.getSounds()));
mVerifier->appendStage (new RegionCheckStage (mData.getRegions()));
mVerifier->appendStage (new BirthsignCheckStage (mData.getBirthsigns()));
mVerifier->appendStage (new SpellCheckStage (mData.getSpells()));
}
return mVerifier;

View file

@ -0,0 +1,20 @@
#include "cell.hpp"
#include <sstream>
void CSMWorld::Cell::load (ESM::ESMReader &esm)
{
mName = mId;
ESM::Cell::load (esm, true); /// \todo set this to false, once the bug in ESM::Cell::load is fixed
if (!(mData.mFlags & Interior))
{
std::ostringstream stream;
stream << "#" << mData.mX << " " << mData.mY;
mId = stream.str();
}
}

View file

@ -0,0 +1,17 @@
#ifndef CSM_WOLRD_CELL_H
#define CSM_WOLRD_CELL_H
#include <components/esm/loadcell.hpp>
namespace CSMWorld
{
/// \brief Wrapper for Cell record
struct Cell : public ESM::Cell
{
std::string mId;
void load (ESM::ESMReader &esm);
};
}
#endif

View file

@ -34,7 +34,15 @@ namespace CSMWorld
Display_GlobalVarType,
Display_Specialisation,
Display_Attribute,
Display_Boolean
Display_Boolean,
Display_SpellType,
Display_Script,
Display_ApparatusType,
Display_ArmorType,
Display_ClothingType,
Display_CreatureType,
Display_WeaponType,
Display_RecordState
};
std::string mTitle;

View file

@ -5,6 +5,8 @@
#include <boost/lexical_cast.hpp>
#include <QColor>
#include "columnbase.hpp"
namespace CSMWorld
@ -51,7 +53,7 @@ namespace CSMWorld
template<typename ESXRecordT>
struct RecordStateColumn : public Column<ESXRecordT>
{
RecordStateColumn() : Column<ESXRecordT> ("*", ColumnBase::Display_Integer) {}
RecordStateColumn() : Column<ESXRecordT> ("*", ColumnBase::Display_RecordState) {}
virtual QVariant get (const Record<ESXRecordT>& record) const
{
@ -347,15 +349,15 @@ namespace CSMWorld
int mIndex;
bool mMajor;
SkillsColumn (int index, bool major)
: Column<ESXRecordT> ((major ? "Major Skill #" : "Minor Skill #")+
SkillsColumn (int index, bool typePrefix = false, bool major = false)
: Column<ESXRecordT> ((typePrefix ? (major ? "Major Skill #" : "Minor Skill #") : "Skill #")+
boost::lexical_cast<std::string> (index), ColumnBase::Display_String),
mIndex (index), mMajor (major)
{}
virtual QVariant get (const Record<ESXRecordT>& record) const
{
int skill = record.get().mData.mSkills[mIndex][mMajor ? 1 : 0];
int skill = record.get().mData.getSkill (mIndex, mMajor);
return QString::fromUtf8 (ESM::Skill::indexToId (skill).c_str());
}
@ -373,7 +375,7 @@ namespace CSMWorld
{
ESXRecordT record2 = record.get();
record2.mData.mSkills[mIndex][mMajor ? 1 : 0] = index;
record2.mData.getSkill (mIndex, mMajor) = index;
record.setModified (record2);
}
@ -409,6 +411,368 @@ namespace CSMWorld
return true;
}
};
template<typename ESXRecordT>
struct HiddenColumn : public Column<ESXRecordT>
{
HiddenColumn() : Column<ESXRecordT> ("Hidden", ColumnBase::Display_Boolean) {}
virtual QVariant get (const Record<ESXRecordT>& record) const
{
return record.get().mData.mIsHidden!=0;
}
virtual void set (Record<ESXRecordT>& record, const QVariant& data)
{
ESXRecordT record2 = record.get();
record2.mData.mIsHidden = data.toInt();
record.setModified (record2);
}
virtual bool isEditable() const
{
return true;
}
};
template<typename ESXRecordT>
struct FlagColumn : public Column<ESXRecordT>
{
int mMask;
FlagColumn (const std::string& name, int mask)
: Column<ESXRecordT> (name, ColumnBase::Display_Boolean), mMask (mask)
{}
virtual QVariant get (const Record<ESXRecordT>& record) const
{
return (record.get().mData.mFlags & mMask)!=0;
}
virtual void set (Record<ESXRecordT>& record, const QVariant& data)
{
ESXRecordT record2 = record.get();
int flags = record2.mData.mFlags & ~mMask;
if (data.toInt())
flags |= mMask;
record2.mData.mFlags = flags;
record.setModified (record2);
}
virtual bool isEditable() const
{
return true;
}
};
template<typename ESXRecordT>
struct WeightHeightColumn : public Column<ESXRecordT>
{
bool mMale;
bool mWeight;
WeightHeightColumn (bool male, bool weight)
: Column<ESXRecordT> (male ? (weight ? "Male Weight" : "Male Height") :
(weight ? "Female Weight" : "Female Height"), ColumnBase::Display_Float),
mMale (male), mWeight (weight)
{}
virtual QVariant get (const Record<ESXRecordT>& record) const
{
const ESM::Race::MaleFemaleF& value =
mWeight ? record.get().mData.mWeight : record.get().mData.mHeight;
return mMale ? value.mMale : value.mFemale;
}
virtual void set (Record<ESXRecordT>& record, const QVariant& data)
{
ESXRecordT record2 = record.get();
ESM::Race::MaleFemaleF& value =
mWeight ? record2.mData.mWeight : record2.mData.mHeight;
(mMale ? value.mMale : value.mFemale) = data.toFloat();
record.setModified (record2);
}
virtual bool isEditable() const
{
return true;
}
};
template<typename ESXRecordT>
struct SoundParamColumn : public Column<ESXRecordT>
{
enum Type
{
Type_Volume,
Type_MinRange,
Type_MaxRange
};
Type mType;
SoundParamColumn (Type type)
: Column<ESXRecordT> (
type==Type_Volume ? "Volume" : (type==Type_MinRange ? "Min Range" : "Max Range"),
ColumnBase::Display_Integer),
mType (type)
{}
virtual QVariant get (const Record<ESXRecordT>& record) const
{
int value = 0;
switch (mType)
{
case Type_Volume: value = record.get().mData.mVolume; break;
case Type_MinRange: value = record.get().mData.mMinRange; break;
case Type_MaxRange: value = record.get().mData.mMaxRange; break;
}
return value;
}
virtual void set (Record<ESXRecordT>& record, const QVariant& data)
{
int value = data.toInt();
if (value<0)
value = 0;
else if (value>255)
value = 255;
ESXRecordT record2 = record.get();
switch (mType)
{
case Type_Volume: record2.mData.mVolume = static_cast<unsigned char> (value); break;
case Type_MinRange: record2.mData.mMinRange = static_cast<unsigned char> (value); break;
case Type_MaxRange: record2.mData.mMaxRange = static_cast<unsigned char> (value); break;
}
record.setModified (record2);
}
virtual bool isEditable() const
{
return true;
}
};
template<typename ESXRecordT>
struct SoundFileColumn : public Column<ESXRecordT>
{
SoundFileColumn() : Column<ESXRecordT> ("Sound File", ColumnBase::Display_String) {}
virtual QVariant get (const Record<ESXRecordT>& record) const
{
return QString::fromUtf8 (record.get().mSound.c_str());
}
virtual void set (Record<ESXRecordT>& record, const QVariant& data)
{
ESXRecordT record2 = record.get();
record2.mSound = data.toString().toUtf8().constData();
record.setModified (record2);
}
virtual bool isEditable() const
{
return true;
}
};
/// \todo QColor is a GUI class and should not be in model. Need to think of an alternative
/// solution.
template<typename ESXRecordT>
struct MapColourColumn : public Column<ESXRecordT>
{
/// \todo Replace Display_Integer with something that displays the colour value more directly.
MapColourColumn() : Column<ESXRecordT> ("Map Colour", ColumnBase::Display_Integer) {}
virtual QVariant get (const Record<ESXRecordT>& record) const
{
int colour = record.get().mMapColor;
return QColor (colour & 0xff, (colour>>8) & 0xff, (colour>>16) & 0xff);
}
virtual void set (Record<ESXRecordT>& record, const QVariant& data)
{
ESXRecordT record2 = record.get();
QColor colour = data.value<QColor>();
record2.mMapColor = colour.rgb() & 0xffffff;
record.setModified (record2);
}
virtual bool isEditable() const
{
return true;
}
};
template<typename ESXRecordT>
struct SleepListColumn : public Column<ESXRecordT>
{
SleepListColumn() : Column<ESXRecordT> ("Sleep Encounter", ColumnBase::Display_String) {}
virtual QVariant get (const Record<ESXRecordT>& record) const
{
return QString::fromUtf8 (record.get().mSleepList.c_str());
}
virtual void set (Record<ESXRecordT>& record, const QVariant& data)
{
ESXRecordT record2 = record.get();
record2.mSleepList = data.toString().toUtf8().constData();
record.setModified (record2);
}
virtual bool isEditable() const
{
return true;
}
};
template<typename ESXRecordT>
struct TextureColumn : public Column<ESXRecordT>
{
TextureColumn() : Column<ESXRecordT> ("Texture", ColumnBase::Display_String) {}
virtual QVariant get (const Record<ESXRecordT>& record) const
{
return QString::fromUtf8 (record.get().mTexture.c_str());
}
virtual void set (Record<ESXRecordT>& record, const QVariant& data)
{
ESXRecordT record2 = record.get();
record2.mTexture = data.toString().toUtf8().constData();
record.setModified (record2);
}
virtual bool isEditable() const
{
return true;
}
};
template<typename ESXRecordT>
struct SpellTypeColumn : public Column<ESXRecordT>
{
SpellTypeColumn() : Column<ESXRecordT> ("Type", ColumnBase::Display_SpellType) {}
virtual QVariant get (const Record<ESXRecordT>& record) const
{
return record.get().mData.mType;
}
virtual void set (Record<ESXRecordT>& record, const QVariant& data)
{
ESXRecordT record2 = record.get();
record2.mData.mType = data.toInt();
record.setModified (record2);
}
virtual bool isEditable() const
{
return true;
}
};
template<typename ESXRecordT>
struct CostColumn : public Column<ESXRecordT>
{
CostColumn() : Column<ESXRecordT> ("Cost", ColumnBase::Display_Integer) {}
virtual QVariant get (const Record<ESXRecordT>& record) const
{
return record.get().mData.mCost;
}
virtual void set (Record<ESXRecordT>& record, const QVariant& data)
{
ESXRecordT record2 = record.get();
record2.mData.mCost = data.toInt();
record.setModified (record2);
}
virtual bool isEditable() const
{
return true;
}
};
template<typename ESXRecordT>
struct ScriptColumn : public Column<ESXRecordT>
{
ScriptColumn() : Column<ESXRecordT> ("Script", ColumnBase::Display_Script, 0) {}
virtual QVariant get (const Record<ESXRecordT>& record) const
{
return QString::fromUtf8 (record.get().mScriptText.c_str());
}
virtual void set (Record<ESXRecordT>& record, const QVariant& data)
{
ESXRecordT record2 = record.get();
record2.mScriptText = data.toString().toUtf8().constData();
record.setModified (record2);
}
virtual bool isEditable() const
{
return true;
}
};
template<typename ESXRecordT>
struct RegionColumn : public Column<ESXRecordT>
{
RegionColumn() : Column<ESXRecordT> ("Region", ColumnBase::Display_String) {}
virtual QVariant get (const Record<ESXRecordT>& record) const
{
return QString::fromUtf8 (record.get().mRegion.c_str());
}
virtual void set (Record<ESXRecordT>& record, const QVariant& data)
{
ESXRecordT record2 = record.get();
record2.mRegion = data.toString().toUtf8().constData();
record.setModified (record2);
}
virtual bool isEditable() const
{
return true;
}
};
}
#endif
#endif

View file

@ -71,7 +71,7 @@ void CSMWorld::RevertCommand::redo()
void CSMWorld::RevertCommand::undo()
{
mModel.setRecord (*mOld);
mModel.setRecord (mId, *mOld);
}
CSMWorld::DeleteCommand::DeleteCommand (IdTable& model, const std::string& id, QUndoCommand *parent)
@ -104,5 +104,5 @@ void CSMWorld::DeleteCommand::redo()
void CSMWorld::DeleteCommand::undo()
{
mModel.setRecord (*mOld);
mModel.setRecord (mId, *mOld);
}

View file

@ -33,11 +33,13 @@ CSMWorld::Data::Data()
mGmsts.addColumn (new StringIdColumn<ESM::GameSetting>);
mGmsts.addColumn (new RecordStateColumn<ESM::GameSetting>);
mGmsts.addColumn (new FixedRecordTypeColumn<ESM::GameSetting> (UniversalId::Type_Gmst));
mGmsts.addColumn (new FixedRecordTypeColumn<ESM::GameSetting> (UniversalId::Type_Gmst));
mGmsts.addColumn (new VarTypeColumn<ESM::GameSetting> (ColumnBase::Display_GmstVarType));
mGmsts.addColumn (new VarValueColumn<ESM::GameSetting>);
mSkills.addColumn (new StringIdColumn<ESM::Skill>);
mSkills.addColumn (new RecordStateColumn<ESM::Skill>);
mSkills.addColumn (new FixedRecordTypeColumn<ESM::Skill> (UniversalId::Type_Skill));
mSkills.addColumn (new AttributeColumn<ESM::Skill>);
mSkills.addColumn (new SpecialisationColumn<ESM::Skill>);
for (int i=0; i<4; ++i)
@ -46,21 +48,100 @@ CSMWorld::Data::Data()
mClasses.addColumn (new StringIdColumn<ESM::Class>);
mClasses.addColumn (new RecordStateColumn<ESM::Class>);
mClasses.addColumn (new FixedRecordTypeColumn<ESM::Class> (UniversalId::Type_Class));
mClasses.addColumn (new NameColumn<ESM::Class>);
mClasses.addColumn (new AttributesColumn<ESM::Class> (0));
mClasses.addColumn (new AttributesColumn<ESM::Class> (1));
mClasses.addColumn (new SpecialisationColumn<ESM::Class>);
for (int i=0; i<5; ++i)
mClasses.addColumn (new SkillsColumn<ESM::Class> (i, true));
mClasses.addColumn (new SkillsColumn<ESM::Class> (i, true, true));
for (int i=0; i<5; ++i)
mClasses.addColumn (new SkillsColumn<ESM::Class> (i, false));
mClasses.addColumn (new SkillsColumn<ESM::Class> (i, true, false));
mClasses.addColumn (new PlayableColumn<ESM::Class>);
mClasses.addColumn (new DescriptionColumn<ESM::Class>);
mFactions.addColumn (new StringIdColumn<ESM::Faction>);
mFactions.addColumn (new RecordStateColumn<ESM::Faction>);
mFactions.addColumn (new FixedRecordTypeColumn<ESM::Faction> (UniversalId::Type_Faction));
mFactions.addColumn (new NameColumn<ESM::Faction>);
mFactions.addColumn (new AttributesColumn<ESM::Faction> (0));
mFactions.addColumn (new AttributesColumn<ESM::Faction> (1));
mFactions.addColumn (new HiddenColumn<ESM::Faction>);
for (int i=0; i<6; ++i)
mFactions.addColumn (new SkillsColumn<ESM::Faction> (i));
mRaces.addColumn (new StringIdColumn<ESM::Race>);
mRaces.addColumn (new RecordStateColumn<ESM::Race>);
mRaces.addColumn (new FixedRecordTypeColumn<ESM::Race> (UniversalId::Type_Race));
mRaces.addColumn (new NameColumn<ESM::Race>);
mRaces.addColumn (new DescriptionColumn<ESM::Race>);
mRaces.addColumn (new FlagColumn<ESM::Race> ("Playable", 0x1));
mRaces.addColumn (new FlagColumn<ESM::Race> ("Beast Race", 0x2));
mRaces.addColumn (new WeightHeightColumn<ESM::Race> (true, true));
mRaces.addColumn (new WeightHeightColumn<ESM::Race> (true, false));
mRaces.addColumn (new WeightHeightColumn<ESM::Race> (false, true));
mRaces.addColumn (new WeightHeightColumn<ESM::Race> (false, false));
mSounds.addColumn (new StringIdColumn<ESM::Sound>);
mSounds.addColumn (new RecordStateColumn<ESM::Sound>);
mSounds.addColumn (new FixedRecordTypeColumn<ESM::Sound> (UniversalId::Type_Sound));
mSounds.addColumn (new SoundParamColumn<ESM::Sound> (SoundParamColumn<ESM::Sound>::Type_Volume));
mSounds.addColumn (new SoundParamColumn<ESM::Sound> (SoundParamColumn<ESM::Sound>::Type_MinRange));
mSounds.addColumn (new SoundParamColumn<ESM::Sound> (SoundParamColumn<ESM::Sound>::Type_MaxRange));
mSounds.addColumn (new SoundFileColumn<ESM::Sound>);
mScripts.addColumn (new StringIdColumn<ESM::Script>);
mScripts.addColumn (new RecordStateColumn<ESM::Script>);
mScripts.addColumn (new FixedRecordTypeColumn<ESM::Script> (UniversalId::Type_Script));
mScripts.addColumn (new ScriptColumn<ESM::Script>);
mRegions.addColumn (new StringIdColumn<ESM::Region>);
mRegions.addColumn (new RecordStateColumn<ESM::Region>);
mRegions.addColumn (new FixedRecordTypeColumn<ESM::Region> (UniversalId::Type_Region));
mRegions.addColumn (new NameColumn<ESM::Region>);
mRegions.addColumn (new MapColourColumn<ESM::Region>);
mRegions.addColumn (new SleepListColumn<ESM::Region>);
mBirthsigns.addColumn (new StringIdColumn<ESM::BirthSign>);
mBirthsigns.addColumn (new RecordStateColumn<ESM::BirthSign>);
mBirthsigns.addColumn (new FixedRecordTypeColumn<ESM::BirthSign> (UniversalId::Type_Birthsign));
mBirthsigns.addColumn (new NameColumn<ESM::BirthSign>);
mBirthsigns.addColumn (new TextureColumn<ESM::BirthSign>);
mBirthsigns.addColumn (new DescriptionColumn<ESM::BirthSign>);
mSpells.addColumn (new StringIdColumn<ESM::Spell>);
mSpells.addColumn (new RecordStateColumn<ESM::Spell>);
mSpells.addColumn (new FixedRecordTypeColumn<ESM::Spell> (UniversalId::Type_Spell));
mSpells.addColumn (new NameColumn<ESM::Spell>);
mSpells.addColumn (new SpellTypeColumn<ESM::Spell>);
mSpells.addColumn (new CostColumn<ESM::Spell>);
mSpells.addColumn (new FlagColumn<ESM::Spell> ("Autocalc", 0x1));
mSpells.addColumn (new FlagColumn<ESM::Spell> ("Starter Spell", 0x2));
mSpells.addColumn (new FlagColumn<ESM::Spell> ("Always Succeeds", 0x4));
mCells.addColumn (new StringIdColumn<Cell>);
mCells.addColumn (new RecordStateColumn<Cell>);
mCells.addColumn (new FixedRecordTypeColumn<Cell> (UniversalId::Type_Cell));
mCells.addColumn (new NameColumn<Cell>);
mCells.addColumn (new FlagColumn<Cell> ("Sleep forbidden", ESM::Cell::NoSleep));
mCells.addColumn (new FlagColumn<Cell> ("Interior Water", ESM::Cell::HasWater));
mCells.addColumn (new FlagColumn<Cell> ("Interior Sky", ESM::Cell::QuasiEx));
mCells.addColumn (new RegionColumn<Cell>);
addModel (new IdTable (&mGlobals), UniversalId::Type_Globals, UniversalId::Type_Global);
addModel (new IdTable (&mGmsts), UniversalId::Type_Gmsts, UniversalId::Type_Gmst);
addModel (new IdTable (&mSkills), UniversalId::Type_Skills, UniversalId::Type_Skill);
addModel (new IdTable (&mClasses), UniversalId::Type_Classes, UniversalId::Type_Class);
addModel (new IdTable (&mFactions), UniversalId::Type_Factions, UniversalId::Type_Faction);
addModel (new IdTable (&mRaces), UniversalId::Type_Races, UniversalId::Type_Race);
addModel (new IdTable (&mSounds), UniversalId::Type_Sounds, UniversalId::Type_Sound);
addModel (new IdTable (&mScripts), UniversalId::Type_Scripts, UniversalId::Type_Script);
addModel (new IdTable (&mRegions), UniversalId::Type_Regions, UniversalId::Type_Region);
addModel (new IdTable (&mBirthsigns), UniversalId::Type_Birthsigns, UniversalId::Type_Birthsign);
addModel (new IdTable (&mSpells), UniversalId::Type_Spells, UniversalId::Type_Spell);
addModel (new IdTable (&mCells), UniversalId::Type_Cells, UniversalId::Type_Cell);
addModel (new IdTable (&mReferenceables), UniversalId::Type_Referenceables,
UniversalId::Type_Referenceable);
}
CSMWorld::Data::~Data()
@ -99,6 +180,106 @@ CSMWorld::IdCollection<ESM::Skill>& CSMWorld::Data::getSkills()
return mSkills;
}
const CSMWorld::IdCollection<ESM::Class>& CSMWorld::Data::getClasses() const
{
return mClasses;
}
CSMWorld::IdCollection<ESM::Class>& CSMWorld::Data::getClasses()
{
return mClasses;
}
const CSMWorld::IdCollection<ESM::Faction>& CSMWorld::Data::getFactions() const
{
return mFactions;
}
CSMWorld::IdCollection<ESM::Faction>& CSMWorld::Data::getFactions()
{
return mFactions;
}
const CSMWorld::IdCollection<ESM::Race>& CSMWorld::Data::getRaces() const
{
return mRaces;
}
CSMWorld::IdCollection<ESM::Race>& CSMWorld::Data::getRaces()
{
return mRaces;
}
const CSMWorld::IdCollection<ESM::Sound>& CSMWorld::Data::getSounds() const
{
return mSounds;
}
CSMWorld::IdCollection<ESM::Sound>& CSMWorld::Data::getSounds()
{
return mSounds;
}
const CSMWorld::IdCollection<ESM::Script>& CSMWorld::Data::getScripts() const
{
return mScripts;
}
CSMWorld::IdCollection<ESM::Script>& CSMWorld::Data::getScripts()
{
return mScripts;
}
const CSMWorld::IdCollection<ESM::Region>& CSMWorld::Data::getRegions() const
{
return mRegions;
}
CSMWorld::IdCollection<ESM::Region>& CSMWorld::Data::getRegions()
{
return mRegions;
}
const CSMWorld::IdCollection<ESM::BirthSign>& CSMWorld::Data::getBirthsigns() const
{
return mBirthsigns;
}
CSMWorld::IdCollection<ESM::BirthSign>& CSMWorld::Data::getBirthsigns()
{
return mBirthsigns;
}
const CSMWorld::IdCollection<ESM::Spell>& CSMWorld::Data::getSpells() const
{
return mSpells;
}
CSMWorld::IdCollection<ESM::Spell>& CSMWorld::Data::getSpells()
{
return mSpells;
}
const CSMWorld::IdCollection<CSMWorld::Cell>& CSMWorld::Data::getCells() const
{
return mCells;
}
CSMWorld::IdCollection<CSMWorld::Cell>& CSMWorld::Data::getCells()
{
return mCells;
}
const CSMWorld::RefIdCollection& CSMWorld::Data::getReferenceables() const
{
return mReferenceables;
}
CSMWorld::RefIdCollection& CSMWorld::Data::getReferenceables()
{
return mReferenceables;
}
QAbstractItemModel *CSMWorld::Data::getTableModel (const UniversalId& id)
{
std::map<UniversalId::Type, QAbstractItemModel *>::iterator iter = mModelIndex.find (id.getType());
@ -137,6 +318,38 @@ void CSMWorld::Data::loadFile (const boost::filesystem::path& path, bool base)
case ESM::REC_GMST: mGmsts.load (reader, base); break;
case ESM::REC_SKIL: mSkills.load (reader, base); break;
case ESM::REC_CLAS: mClasses.load (reader, base); break;
case ESM::REC_FACT: mFactions.load (reader, base); break;
case ESM::REC_RACE: mRaces.load (reader, base); break;
case ESM::REC_SOUN: mSounds.load (reader, base); break;
case ESM::REC_SCPT: mScripts.load (reader, base); break;
case ESM::REC_REGN: mRegions.load (reader, base); break;
case ESM::REC_BSGN: mBirthsigns.load (reader, base); break;
case ESM::REC_SPEL: mSpells.load (reader, base); break;
case ESM::REC_CELL: mCells.load (reader, base); break;
case ESM::REC_ACTI: mReferenceables.load (reader, base, UniversalId::Type_Activator); break;
case ESM::REC_ALCH: mReferenceables.load (reader, base, UniversalId::Type_Potion); break;
case ESM::REC_APPA: mReferenceables.load (reader, base, UniversalId::Type_Apparatus); break;
case ESM::REC_ARMO: mReferenceables.load (reader, base, UniversalId::Type_Armor); break;
case ESM::REC_BOOK: mReferenceables.load (reader, base, UniversalId::Type_Book); break;
case ESM::REC_CLOT: mReferenceables.load (reader, base, UniversalId::Type_Clothing); break;
case ESM::REC_CONT: mReferenceables.load (reader, base, UniversalId::Type_Container); break;
case ESM::REC_CREA: mReferenceables.load (reader, base, UniversalId::Type_Creature); break;
case ESM::REC_DOOR: mReferenceables.load (reader, base, UniversalId::Type_Door); break;
case ESM::REC_INGR: mReferenceables.load (reader, base, UniversalId::Type_Ingredient); break;
case ESM::REC_LEVC:
mReferenceables.load (reader, base, UniversalId::Type_CreatureLevelledList); break;
case ESM::REC_LEVI:
mReferenceables.load (reader, base, UniversalId::Type_ItemLevelledList); break;
case ESM::REC_LIGH: mReferenceables.load (reader, base, UniversalId::Type_Light); break;
case ESM::REC_LOCK: mReferenceables.load (reader, base, UniversalId::Type_Lockpick); break;
case ESM::REC_MISC:
mReferenceables.load (reader, base, UniversalId::Type_Miscellaneous); break;
case ESM::REC_NPC_: mReferenceables.load (reader, base, UniversalId::Type_Npc); break;
case ESM::REC_PROB: mReferenceables.load (reader, base, UniversalId::Type_Probe); break;
case ESM::REC_REPA: mReferenceables.load (reader, base, UniversalId::Type_Repair); break;
case ESM::REC_STAT: mReferenceables.load (reader, base, UniversalId::Type_Static); break;
case ESM::REC_WEAP: mReferenceables.load (reader, base, UniversalId::Type_Weapon); break;
default:

View file

@ -10,9 +10,18 @@
#include <components/esm/loadgmst.hpp>
#include <components/esm/loadskil.hpp>
#include <components/esm/loadclas.hpp>
#include <components/esm/loadfact.hpp>
#include <components/esm/loadrace.hpp>
#include <components/esm/loadsoun.hpp>
#include <components/esm/loadscpt.hpp>
#include <components/esm/loadregn.hpp>
#include <components/esm/loadbsgn.hpp>
#include <components/esm/loadspel.hpp>
#include "idcollection.hpp"
#include "universalid.hpp"
#include "cell.hpp"
#include "refidcollection.hpp"
class QAbstractItemModel;
@ -24,6 +33,15 @@ namespace CSMWorld
IdCollection<ESM::GameSetting> mGmsts;
IdCollection<ESM::Skill> mSkills;
IdCollection<ESM::Class> mClasses;
IdCollection<ESM::Faction> mFactions;
IdCollection<ESM::Race> mRaces;
IdCollection<ESM::Sound> mSounds;
IdCollection<ESM::Script> mScripts;
IdCollection<ESM::Region> mRegions;
IdCollection<ESM::BirthSign> mBirthsigns;
IdCollection<ESM::Spell> mSpells;
IdCollection<Cell> mCells;
RefIdCollection mReferenceables;
std::vector<QAbstractItemModel *> mModels;
std::map<UniversalId::Type, QAbstractItemModel *> mModelIndex;
@ -52,6 +70,46 @@ namespace CSMWorld
IdCollection<ESM::Skill>& getSkills();
const IdCollection<ESM::Class>& getClasses() const;
IdCollection<ESM::Class>& getClasses();
const IdCollection<ESM::Faction>& getFactions() const;
IdCollection<ESM::Faction>& getFactions();
const IdCollection<ESM::Race>& getRaces() const;
IdCollection<ESM::Race>& getRaces();
const IdCollection<ESM::Sound>& getSounds() const;
IdCollection<ESM::Sound>& getSounds();
const IdCollection<ESM::Script>& getScripts() const;
IdCollection<ESM::Script>& getScripts();
const IdCollection<ESM::Region>& getRegions() const;
IdCollection<ESM::Region>& getRegions();
const IdCollection<ESM::BirthSign>& getBirthsigns() const;
IdCollection<ESM::BirthSign>& getBirthsigns();
const IdCollection<ESM::Spell>& getSpells() const;
IdCollection<ESM::Spell>& getSpells();
const IdCollection<Cell>& getCells() const;
IdCollection<Cell>& getCells();
const RefIdCollection& getReferenceables() const;
RefIdCollection& getReferenceables();
QAbstractItemModel *getTableModel (const UniversalId& id);
///< If no table model is available for \a id, an exception is thrown.
///

View file

@ -16,6 +16,7 @@
#include <components/misc/stringops.hpp>
#include "columnbase.hpp"
#include "universalid.hpp"
namespace CSMWorld
{
@ -45,15 +46,19 @@ namespace CSMWorld
virtual void setData (int index, int column, const QVariant& data) = 0;
virtual void merge() = 0;
// Not in use. Temporarily removed so that the implementation of RefIdCollection can continue without
// these functions for now.
// virtual void merge() = 0;
///< Merge modified into base.
virtual void purge() = 0;
// 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 void appendBlankRecord (const std::string& id,
UniversalId::Type type = UniversalId::Type_None) = 0;
///< \param type Will be ignored, unless the collection supports multiple record types
virtual int searchId (const std::string& id) const = 0;
////< Search record with \a id.
@ -63,24 +68,47 @@ namespace CSMWorld
///< If the record type does not match, an exception is thrown.
///
/// \attention \a record must not change the ID.
///< \param type Will be ignored, unless the collection supports multiple record types
virtual void appendRecord (const RecordBase& record) = 0;
virtual void appendRecord (const RecordBase& record,
UniversalId::Type type = UniversalId::Type_None) = 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 Throws an exception, if the type of \a record does not match.
virtual const RecordBase& getRecord (const std::string& id) const = 0;
virtual const RecordBase& getRecord (int index) const = 0;
virtual void load (ESM::ESMReader& reader, bool base) = 0;
virtual void load (ESM::ESMReader& reader, bool base,
UniversalId::Type type = UniversalId::Type_None) = 0;
///< \param type Will be ignored, unless the collection supports multiple record types
virtual int getAppendIndex (UniversalId::Type type = UniversalId::Type_None) const = 0;
///< \param type Will be ignored, unless the collection supports multiple record types
};
///< \brief Collection of ID-based records
///< \brief Access to ID field in records
template<typename ESXRecordT>
struct IdAccessor
{
std::string& getId (ESXRecordT& record);
const std::string getId (const ESXRecordT& record) const;
};
template<typename ESXRecordT>
std::string& IdAccessor<ESXRecordT>::getId (ESXRecordT& record)
{
return record.mId;
}
template<typename ESXRecordT>
const std::string IdAccessor<ESXRecordT>::getId (const ESXRecordT& record) const
{
return record.mId;
}
///< \brief Collection of ID-based records
template<typename ESXRecordT, typename IdAccessorT = IdAccessor<ESXRecordT> >
class IdCollection : public IdCollectionBase
{
std::vector<Record<ESXRecordT> > mRecords;
@ -122,7 +150,9 @@ namespace CSMWorld
virtual void removeRows (int index, int count) ;
virtual void appendBlankRecord (const std::string& id);
virtual void appendBlankRecord (const std::string& id,
UniversalId::Type type = UniversalId::Type_None);
///< \param type Will be ignored, unless the collection supports multiple record types
virtual int searchId (const std::string& id) const;
////< Search record with \a id.
@ -133,38 +163,40 @@ namespace CSMWorld
///
/// \attention \a record must not change the ID.
virtual void appendRecord (const RecordBase& record);
virtual void appendRecord (const RecordBase& record,
UniversalId::Type type = UniversalId::Type_None);
///< 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.
///< \param type Will be ignored, unless the collection supports multiple record types
virtual const Record<ESXRecordT>& getRecord (const std::string& id) const;
virtual const Record<ESXRecordT>& getRecord (int index) const;
virtual void load (ESM::ESMReader& reader, bool base);
virtual void load (ESM::ESMReader& reader, bool base,
UniversalId::Type type = UniversalId::Type_None);
///< \param type Will be ignored, unless the collection supports multiple record types
virtual int getAppendIndex (UniversalId::Type type = UniversalId::Type_None) const;
///< \param type Will be ignored, unless the collection supports multiple record types
void addColumn (Column<ESXRecordT> *column);
};
template<typename ESXRecordT>
IdCollection<ESXRecordT>::IdCollection()
template<typename ESXRecordT, typename IdAccessorT>
IdCollection<ESXRecordT, IdAccessorT>::IdCollection()
{}
template<typename ESXRecordT>
IdCollection<ESXRecordT>::~IdCollection()
template<typename ESXRecordT, typename IdAccessorT>
IdCollection<ESXRecordT, IdAccessorT>::~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)
template<typename ESXRecordT, typename IdAccessorT>
void IdCollection<ESXRecordT, IdAccessorT>::add (const ESXRecordT& record)
{
std::string id = Misc::StringUtils::lowerCase(record.mId);
std::string id = Misc::StringUtils::lowerCase (IdAccessorT().getId (record));
std::map<std::string, int>::iterator iter = mIndex.find (id);
@ -183,20 +215,20 @@ namespace CSMWorld
}
}
template<typename ESXRecordT>
int IdCollection<ESXRecordT>::getSize() const
template<typename ESXRecordT, typename IdAccessorT>
int IdCollection<ESXRecordT, IdAccessorT>::getSize() const
{
return mRecords.size();
}
template<typename ESXRecordT>
std::string IdCollection<ESXRecordT>::getId (int index) const
template<typename ESXRecordT, typename IdAccessorT>
std::string IdCollection<ESXRecordT, IdAccessorT>::getId (int index) const
{
return mRecords.at (index).get().mId;
return IdAccessorT().getId (mRecords.at (index).get());
}
template<typename ESXRecordT>
int IdCollection<ESXRecordT>::getIndex (const std::string& id) const
template<typename ESXRecordT, typename IdAccessorT>
int IdCollection<ESXRecordT, IdAccessorT>::getIndex (const std::string& id) const
{
int index = searchId (id);
@ -206,38 +238,38 @@ namespace CSMWorld
return index;
}
template<typename ESXRecordT>
int IdCollection<ESXRecordT>::getColumns() const
template<typename ESXRecordT, typename IdAccessorT>
int IdCollection<ESXRecordT, IdAccessorT>::getColumns() const
{
return mColumns.size();
}
template<typename ESXRecordT>
QVariant IdCollection<ESXRecordT>::getData (int index, int column) const
template<typename ESXRecordT, typename IdAccessorT>
QVariant IdCollection<ESXRecordT, IdAccessorT>::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)
template<typename ESXRecordT, typename IdAccessorT>
void IdCollection<ESXRecordT, IdAccessorT>::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
template<typename ESXRecordT, typename IdAccessorT>
const ColumnBase& IdCollection<ESXRecordT, IdAccessorT>::getColumn (int column) const
{
return *mColumns.at (column);
}
template<typename ESXRecordT>
void IdCollection<ESXRecordT>::addColumn (Column<ESXRecordT> *column)
template<typename ESXRecordT, typename IdAccessorT>
void IdCollection<ESXRecordT, IdAccessorT>::addColumn (Column<ESXRecordT> *column)
{
mColumns.push_back (column);
}
template<typename ESXRecordT>
void IdCollection<ESXRecordT>::merge()
template<typename ESXRecordT, typename IdAccessorT>
void IdCollection<ESXRecordT, IdAccessorT>::merge()
{
for (typename std::vector<Record<ESXRecordT> >::iterator iter (mRecords.begin()); iter!=mRecords.end(); ++iter)
iter->merge();
@ -245,16 +277,22 @@ namespace CSMWorld
purge();
}
template<typename ESXRecordT>
void IdCollection<ESXRecordT>::purge()
template<typename ESXRecordT, typename IdAccessorT>
void IdCollection<ESXRecordT, IdAccessorT>::purge()
{
mRecords.erase (std::remove_if (mRecords.begin(), mRecords.end(),
std::mem_fun_ref (&Record<ESXRecordT>::isErased) // I want lambda :(
), mRecords.end());
int i = 0;
while (i<static_cast<int> (mRecords.size()))
{
if (mRecords[i].isErased())
removeRows (i, 1);
else
++i;
}
}
template<typename ESXRecordT>
void IdCollection<ESXRecordT>::removeRows (int index, int count)
template<typename ESXRecordT, typename IdAccessorT>
void IdCollection<ESXRecordT, IdAccessorT>::removeRows (int index, int count)
{
mRecords.erase (mRecords.begin()+index, mRecords.begin()+index+count);
@ -278,17 +316,18 @@ namespace CSMWorld
}
}
template<typename ESXRecordT>
void IdCollection<ESXRecordT>::appendBlankRecord (const std::string& id)
template<typename ESXRecordT, typename IdAccessorT>
void IdCollection<ESXRecordT, IdAccessorT>::appendBlankRecord (const std::string& id,
UniversalId::Type type)
{
ESXRecordT record;
record.mId = id;
IdAccessorT().getId (record) = id;
record.blank();
add (record);
}
template<typename ESXRecordT>
int IdCollection<ESXRecordT>::searchId (const std::string& id) const
template<typename ESXRecordT, typename IdAccessorT>
int IdCollection<ESXRecordT, IdAccessorT>::searchId (const std::string& id) const
{
std::string id2 = Misc::StringUtils::lowerCase(id);
@ -300,35 +339,32 @@ namespace CSMWorld
return iter->second;
}
template<typename ESXRecordT>
void IdCollection<ESXRecordT>::replace (int index, const RecordBase& record)
template<typename ESXRecordT, typename IdAccessorT>
void IdCollection<ESXRecordT, IdAccessorT>::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)
template<typename ESXRecordT, typename IdAccessorT>
void IdCollection<ESXRecordT, IdAccessorT>::appendRecord (const RecordBase& record,
UniversalId::Type type)
{
mRecords.push_back (dynamic_cast<const Record<ESXRecordT>&> (record));
mIndex.insert (std::make_pair (Misc::StringUtils::lowerCase (getId (record)), mRecords.size()-1));
mIndex.insert (std::make_pair (Misc::StringUtils::lowerCase (IdAccessorT().getId (
dynamic_cast<const Record<ESXRecordT>&> (record).get())),
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>
void IdCollection<ESXRecordT>::load (ESM::ESMReader& reader, bool base)
template<typename ESXRecordT, typename IdAccessorT>
void IdCollection<ESXRecordT, IdAccessorT>::load (ESM::ESMReader& reader, bool base,
UniversalId::Type type)
{
std::string id = reader.getHNOString ("NAME");
int index = searchId (id);
if (reader.isNextSub ("DELE"))
{
int index = searchId (id);
reader.skipRecord();
if (index==-1)
@ -351,9 +387,11 @@ namespace CSMWorld
else
{
ESXRecordT record;
record.mId = id;
IdAccessorT().getId (record) = id;
record.load (reader);
int index = searchId (IdAccessorT().getId (record));
if (index==-1)
{
// new record
@ -376,15 +414,21 @@ namespace CSMWorld
}
}
template<typename ESXRecordT>
const Record<ESXRecordT>& IdCollection<ESXRecordT>::getRecord (const std::string& id) const
template<typename ESXRecordT, typename IdAccessorT>
int IdCollection<ESXRecordT, IdAccessorT>::getAppendIndex (UniversalId::Type type) const
{
return static_cast<int> (mRecords.size());
}
template<typename ESXRecordT, typename IdAccessorT>
const Record<ESXRecordT>& IdCollection<ESXRecordT, IdAccessorT>::getRecord (const std::string& id) const
{
int index = getIndex (id);
return mRecords.at (index);
}
template<typename ESXRecordT>
const Record<ESXRecordT>& IdCollection<ESXRecordT>::getRecord (int index) const
template<typename ESXRecordT, typename IdAccessorT>
const Record<ESXRecordT>& IdCollection<ESXRecordT, IdAccessorT>::getRecord (int index) const
{
return mRecords.at (index);
}

View file

@ -117,7 +117,7 @@ QModelIndex CSMWorld::IdTable::parent (const QModelIndex& index) const
void CSMWorld::IdTable::addRecord (const std::string& id)
{
int index = mIdCollection->getSize();
int index = mIdCollection->getAppendIndex();
beginInsertRows (QModelIndex(), index, index);
@ -131,13 +131,13 @@ QModelIndex CSMWorld::IdTable::getModelIndex (const std::string& id, int column)
return index (mIdCollection->getIndex (id), column);
}
void CSMWorld::IdTable::setRecord (const RecordBase& record)
void CSMWorld::IdTable::setRecord (const std::string& id, const RecordBase& record)
{
int index = mIdCollection->searchId (mIdCollection->getId (record));
int index = mIdCollection->searchId (id);
if (index==-1)
{
int index = mIdCollection->getSize();
int index = mIdCollection->getAppendIndex();
beginInsertRows (QModelIndex(), index, index);

View file

@ -48,7 +48,7 @@ namespace CSMWorld
QModelIndex getModelIndex (const std::string& id, int column) const;
void setRecord (const RecordBase& record);
void setRecord (const std::string& id, const RecordBase& record);
///< Add record or overwrite existing recrod.
const RecordBase& getRecord (const std::string& id) const;

View file

@ -22,6 +22,9 @@ namespace CSMWorld
virtual RecordBase *clone() const = 0;
virtual void assign (const RecordBase& record) = 0;
///< Will throw an exception if the types don't match.
bool isDeleted() const;
bool isErased() const;
@ -37,9 +40,14 @@ namespace CSMWorld
virtual RecordBase *clone() const;
virtual void assign (const RecordBase& record);
const ESXRecordT& get() const;
///< Throws an exception, if the record is deleted.
ESXRecordT& get();
///< 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.
@ -56,6 +64,12 @@ namespace CSMWorld
return new Record<ESXRecordT> (*this);
}
template <typename ESXRecordT>
void Record<ESXRecordT>::assign (const RecordBase& record)
{
*this = dynamic_cast<const Record<ESXRecordT>& > (record);
}
template <typename ESXRecordT>
const ESXRecordT& Record<ESXRecordT>::get() const
{
@ -65,6 +79,15 @@ namespace CSMWorld
return mState==State_BaseOnly || mState==State_Deleted ? mBase : mModified;
}
template <typename ESXRecordT>
ESXRecordT& Record<ESXRecordT>::get()
{
if (mState==State_Erased)
throw std::logic_error ("attempt to access a deleted record");
return mState==State_BaseOnly || mState==State_Deleted ? mBase : mModified;
}
template <typename ESXRecordT>
const ESXRecordT& Record<ESXRecordT>::getBase() const
{
@ -81,7 +104,9 @@ namespace CSMWorld
throw std::logic_error ("attempt to modify a deleted record");
mModified = modified;
mState = State_Modified;
if (mState!=State_ModifiedOnly)
mState = State_Modified;
}
template <typename ESXRecordT>

View file

@ -0,0 +1,6 @@
#include "refidadapter.hpp"
CSMWorld::RefIdAdapter::RefIdAdapter() {}
CSMWorld::RefIdAdapter::~RefIdAdapter() {}

View file

@ -0,0 +1,37 @@
#ifndef CSM_WOLRD_REFIDADAPTER_H
#define CSM_WOLRD_REFIDADAPTER_H
#include <string>
class QVariant;
namespace CSMWorld
{
class RefIdColumn;
class RefIdData;
class RecordBase;
class RefIdAdapter
{
// not implemented
RefIdAdapter (const RefIdAdapter&);
RefIdAdapter& operator= (const RefIdAdapter&);
public:
RefIdAdapter();
virtual ~RefIdAdapter();
virtual QVariant getData (const RefIdColumn *column, const RefIdData& data, int idnex)
const = 0;
virtual void setData (const RefIdColumn *column, RefIdData& data, int index,
const QVariant& value) const = 0;
///< If the data type does not match an exception is thrown.
virtual std::string getId (const RecordBase& record) const = 0;
};
}
#endif

View file

@ -0,0 +1,575 @@
#include "refidadapterimp.hpp"
CSMWorld::PotionRefIdAdapter::PotionRefIdAdapter (const InventoryColumns& columns,
const RefIdColumn *autoCalc)
: InventoryRefIdAdapter<ESM::Potion> (UniversalId::Type_Potion, columns),
mAutoCalc (autoCalc)
{}
QVariant CSMWorld::PotionRefIdAdapter::getData (const RefIdColumn *column, const RefIdData& data,
int index) const
{
const Record<ESM::Potion>& record = static_cast<const Record<ESM::Potion>&> (
data.getRecord (RefIdData::LocalIndex (index, UniversalId::Type_Potion)));
if (column==mAutoCalc)
return record.get().mData.mAutoCalc!=0;
return InventoryRefIdAdapter<ESM::Potion>::getData (column, data, index);
}
void CSMWorld::PotionRefIdAdapter::setData (const RefIdColumn *column, RefIdData& data, int index,
const QVariant& value) const
{
Record<ESM::Potion>& record = static_cast<Record<ESM::Potion>&> (
data.getRecord (RefIdData::LocalIndex (index, UniversalId::Type_Potion)));
if (column==mAutoCalc)
record.get().mData.mAutoCalc = value.toInt();
else
InventoryRefIdAdapter<ESM::Potion>::setData (column, data, index, value);
}
CSMWorld::ApparatusRefIdAdapter::ApparatusRefIdAdapter (const InventoryColumns& columns,
const RefIdColumn *type, const RefIdColumn *quality)
: InventoryRefIdAdapter<ESM::Apparatus> (UniversalId::Type_Apparatus, columns),
mType (type), mQuality (quality)
{}
QVariant CSMWorld::ApparatusRefIdAdapter::getData (const RefIdColumn *column,
const RefIdData& data, int index) const
{
const Record<ESM::Apparatus>& record = static_cast<const Record<ESM::Apparatus>&> (
data.getRecord (RefIdData::LocalIndex (index, UniversalId::Type_Apparatus)));
if (column==mType)
return record.get().mData.mType;
if (column==mQuality)
return record.get().mData.mQuality;
return InventoryRefIdAdapter<ESM::Apparatus>::getData (column, data, index);
}
void CSMWorld::ApparatusRefIdAdapter::setData (const RefIdColumn *column, RefIdData& data, int index,
const QVariant& value) const
{
Record<ESM::Apparatus>& record = static_cast<Record<ESM::Apparatus>&> (
data.getRecord (RefIdData::LocalIndex (index, UniversalId::Type_Apparatus)));
if (column==mType)
record.get().mData.mType = value.toInt();
else if (column==mQuality)
record.get().mData.mQuality = value.toFloat();
else
InventoryRefIdAdapter<ESM::Apparatus>::setData (column, data, index, value);
}
CSMWorld::ArmorRefIdAdapter::ArmorRefIdAdapter (const EnchantableColumns& columns,
const RefIdColumn *type, const RefIdColumn *health, const RefIdColumn *armor)
: EnchantableRefIdAdapter<ESM::Armor> (UniversalId::Type_Armor, columns),
mType (type), mHealth (health), mArmor (armor)
{}
QVariant CSMWorld::ArmorRefIdAdapter::getData (const RefIdColumn *column,
const RefIdData& data, int index) const
{
const Record<ESM::Armor>& record = static_cast<const Record<ESM::Armor>&> (
data.getRecord (RefIdData::LocalIndex (index, UniversalId::Type_Armor)));
if (column==mType)
return record.get().mData.mType;
if (column==mHealth)
return record.get().mData.mHealth;
if (column==mArmor)
return record.get().mData.mArmor;
return EnchantableRefIdAdapter<ESM::Armor>::getData (column, data, index);
}
void CSMWorld::ArmorRefIdAdapter::setData (const RefIdColumn *column, RefIdData& data, int index,
const QVariant& value) const
{
Record<ESM::Armor>& record = static_cast<Record<ESM::Armor>&> (
data.getRecord (RefIdData::LocalIndex (index, UniversalId::Type_Armor)));
if (column==mType)
record.get().mData.mType = value.toInt();
else if (column==mHealth)
record.get().mData.mHealth = value.toInt();
else if (column==mArmor)
record.get().mData.mArmor = value.toInt();
else
EnchantableRefIdAdapter<ESM::Armor>::setData (column, data, index, value);
}
CSMWorld::BookRefIdAdapter::BookRefIdAdapter (const EnchantableColumns& columns,
const RefIdColumn *scroll, const RefIdColumn *skill)
: EnchantableRefIdAdapter<ESM::Book> (UniversalId::Type_Book, columns),
mScroll (scroll), mSkill (skill)
{}
QVariant CSMWorld::BookRefIdAdapter::getData (const RefIdColumn *column,
const RefIdData& data, int index) const
{
const Record<ESM::Book>& record = static_cast<const Record<ESM::Book>&> (
data.getRecord (RefIdData::LocalIndex (index, UniversalId::Type_Book)));
if (column==mScroll)
return record.get().mData.mIsScroll!=0;
if (column==mSkill)
return record.get().mData.mSkillID;
return EnchantableRefIdAdapter<ESM::Book>::getData (column, data, index);
}
void CSMWorld::BookRefIdAdapter::setData (const RefIdColumn *column, RefIdData& data, int index,
const QVariant& value) const
{
Record<ESM::Book>& record = static_cast<Record<ESM::Book>&> (
data.getRecord (RefIdData::LocalIndex (index, UniversalId::Type_Book)));
if (column==mScroll)
record.get().mData.mIsScroll = value.toInt();
else if (column==mSkill)
record.get().mData.mSkillID = value.toInt();
else
EnchantableRefIdAdapter<ESM::Book>::setData (column, data, index, value);
}
CSMWorld::ClothingRefIdAdapter::ClothingRefIdAdapter (const EnchantableColumns& columns,
const RefIdColumn *type)
: EnchantableRefIdAdapter<ESM::Clothing> (UniversalId::Type_Clothing, columns), mType (type)
{}
QVariant CSMWorld::ClothingRefIdAdapter::getData (const RefIdColumn *column,
const RefIdData& data, int index) const
{
const Record<ESM::Clothing>& record = static_cast<const Record<ESM::Clothing>&> (
data.getRecord (RefIdData::LocalIndex (index, UniversalId::Type_Clothing)));
if (column==mType)
return record.get().mData.mType;
return EnchantableRefIdAdapter<ESM::Clothing>::getData (column, data, index);
}
void CSMWorld::ClothingRefIdAdapter::setData (const RefIdColumn *column, RefIdData& data, int index,
const QVariant& value) const
{
Record<ESM::Clothing>& record = static_cast<Record<ESM::Clothing>&> (
data.getRecord (RefIdData::LocalIndex (index, UniversalId::Type_Clothing)));
if (column==mType)
record.get().mData.mType = value.toInt();
else
EnchantableRefIdAdapter<ESM::Clothing>::setData (column, data, index, value);
}
CSMWorld::ContainerRefIdAdapter::ContainerRefIdAdapter (const NameColumns& columns,
const RefIdColumn *weight, const RefIdColumn *organic, const RefIdColumn *respawn)
: NameRefIdAdapter<ESM::Container> (UniversalId::Type_Container, columns), mWeight (weight),
mOrganic (organic), mRespawn (respawn)
{}
QVariant CSMWorld::ContainerRefIdAdapter::getData (const RefIdColumn *column, const RefIdData& data,
int index) const
{
const Record<ESM::Container>& record = static_cast<const Record<ESM::Container>&> (
data.getRecord (RefIdData::LocalIndex (index, UniversalId::Type_Container)));
if (column==mWeight)
return record.get().mWeight;
if (column==mOrganic)
return (record.get().mFlags & ESM::Container::Organic)!=0;
if (column==mRespawn)
return (record.get().mFlags & ESM::Container::Respawn)!=0;
return NameRefIdAdapter<ESM::Container>::getData (column, data, index);
}
void CSMWorld::ContainerRefIdAdapter::setData (const RefIdColumn *column, RefIdData& data, int index,
const QVariant& value) const
{
Record<ESM::Container>& record = static_cast<Record<ESM::Container>&> (
data.getRecord (RefIdData::LocalIndex (index, UniversalId::Type_Container)));
if (column==mWeight)
record.get().mWeight = value.toFloat();
else if (column==mOrganic)
{
if (value.toInt())
record.get().mFlags |= ESM::Container::Organic;
else
record.get().mFlags &= ~ESM::Container::Organic;
}
else if (column==mRespawn)
{
if (value.toInt())
record.get().mFlags |= ESM::Container::Respawn;
else
record.get().mFlags &= ~ESM::Container::Respawn;
}
else
NameRefIdAdapter<ESM::Container>::setData (column, data, index, value);
}
CSMWorld::CreatureColumns::CreatureColumns (const ActorColumns& actorColumns)
: ActorColumns (actorColumns)
{}
CSMWorld::CreatureRefIdAdapter::CreatureRefIdAdapter (const CreatureColumns& columns)
: ActorRefIdAdapter<ESM::Creature> (UniversalId::Type_Creature, columns), mColumns (columns)
{}
QVariant CSMWorld::CreatureRefIdAdapter::getData (const RefIdColumn *column, const RefIdData& data,
int index) const
{
const Record<ESM::Creature>& record = static_cast<const Record<ESM::Creature>&> (
data.getRecord (RefIdData::LocalIndex (index, UniversalId::Type_Creature)));
if (column==mColumns.mType)
return record.get().mData.mType;
if (column==mColumns.mSoul)
return record.get().mData.mSoul;
if (column==mColumns.mScale)
return record.get().mScale;
if (column==mColumns.mOriginal)
return QString::fromUtf8 (record.get().mOriginal.c_str());
std::map<const RefIdColumn *, unsigned int>::const_iterator iter =
mColumns.mFlags.find (column);
if (iter!=mColumns.mFlags.end())
return (record.get().mFlags & iter->second)!=0;
return ActorRefIdAdapter<ESM::Creature>::getData (column, data, index);
}
void CSMWorld::CreatureRefIdAdapter::setData (const RefIdColumn *column, RefIdData& data, int index,
const QVariant& value) const
{
Record<ESM::Creature>& record = static_cast<Record<ESM::Creature>&> (
data.getRecord (RefIdData::LocalIndex (index, UniversalId::Type_Creature)));
if (column==mColumns.mType)
record.get().mData.mType = value.toInt();
else if (column==mColumns.mSoul)
record.get().mData.mSoul = value.toInt();
else if (column==mColumns.mScale)
record.get().mScale = value.toFloat();
else if (column==mColumns.mOriginal)
record.get().mOriginal = value.toString().toUtf8().constData();
else
{
std::map<const RefIdColumn *, unsigned int>::const_iterator iter =
mColumns.mFlags.find (column);
if (iter!=mColumns.mFlags.end())
{
if (value.toInt()!=0)
record.get().mFlags |= iter->second;
else
record.get().mFlags &= ~iter->second;
}
else
ActorRefIdAdapter<ESM::Creature>::setData (column, data, index, value);
}
}
CSMWorld::DoorRefIdAdapter::DoorRefIdAdapter (const NameColumns& columns,
const RefIdColumn *openSound, const RefIdColumn *closeSound)
: NameRefIdAdapter<ESM::Door> (UniversalId::Type_Door, columns), mOpenSound (openSound),
mCloseSound (closeSound)
{}
QVariant CSMWorld::DoorRefIdAdapter::getData (const RefIdColumn *column, const RefIdData& data,
int index) const
{
const Record<ESM::Door>& record = static_cast<const Record<ESM::Door>&> (
data.getRecord (RefIdData::LocalIndex (index, UniversalId::Type_Door)));
if (column==mOpenSound)
return QString::fromUtf8 (record.get().mOpenSound.c_str());
if (column==mCloseSound)
return QString::fromUtf8 (record.get().mCloseSound.c_str());
return NameRefIdAdapter<ESM::Door>::getData (column, data, index);
}
void CSMWorld::DoorRefIdAdapter::setData (const RefIdColumn *column, RefIdData& data, int index,
const QVariant& value) const
{
Record<ESM::Door>& record = static_cast<Record<ESM::Door>&> (
data.getRecord (RefIdData::LocalIndex (index, UniversalId::Type_Door)));
if (column==mOpenSound)
record.get().mOpenSound = value.toString().toUtf8().constData();
else if (column==mCloseSound)
record.get().mCloseSound = value.toString().toUtf8().constData();
else
NameRefIdAdapter<ESM::Door>::setData (column, data, index, value);
}
CSMWorld::LightColumns::LightColumns (const InventoryColumns& columns)
: InventoryColumns (columns) {}
CSMWorld::LightRefIdAdapter::LightRefIdAdapter (const LightColumns& columns)
: InventoryRefIdAdapter<ESM::Light> (UniversalId::Type_Light, columns), mColumns (columns)
{}
QVariant CSMWorld::LightRefIdAdapter::getData (const RefIdColumn *column, const RefIdData& data,
int index) const
{
const Record<ESM::Light>& record = static_cast<const Record<ESM::Light>&> (
data.getRecord (RefIdData::LocalIndex (index, UniversalId::Type_Light)));
if (column==mColumns.mTime)
return record.get().mData.mTime;
if (column==mColumns.mRadius)
return record.get().mData.mRadius;
if (column==mColumns.mColor)
return record.get().mData.mColor;
if (column==mColumns.mSound)
return QString::fromUtf8 (record.get().mSound.c_str());
std::map<const RefIdColumn *, unsigned int>::const_iterator iter =
mColumns.mFlags.find (column);
if (iter!=mColumns.mFlags.end())
return (record.get().mData.mFlags & iter->second)!=0;
return InventoryRefIdAdapter<ESM::Light>::getData (column, data, index);
}
void CSMWorld::LightRefIdAdapter::setData (const RefIdColumn *column, RefIdData& data, int index,
const QVariant& value) const
{
Record<ESM::Light>& record = static_cast<Record<ESM::Light>&> (
data.getRecord (RefIdData::LocalIndex (index, UniversalId::Type_Light)));
if (column==mColumns.mTime)
record.get().mData.mTime = value.toInt();
else if (column==mColumns.mRadius)
record.get().mData.mRadius = value.toInt();
else if (column==mColumns.mColor)
record.get().mData.mColor = value.toInt();
else if (column==mColumns.mSound)
record.get().mSound = value.toString().toUtf8().constData();
else
{
std::map<const RefIdColumn *, unsigned int>::const_iterator iter =
mColumns.mFlags.find (column);
if (iter!=mColumns.mFlags.end())
{
if (value.toInt()!=0)
record.get().mData.mFlags |= iter->second;
else
record.get().mData.mFlags &= ~iter->second;
}
else
InventoryRefIdAdapter<ESM::Light>::setData (column, data, index, value);
}
}
CSMWorld::MiscRefIdAdapter::MiscRefIdAdapter (const InventoryColumns& columns, const RefIdColumn *key)
: InventoryRefIdAdapter<ESM::Miscellaneous> (UniversalId::Type_Miscellaneous, columns), mKey (key)
{}
QVariant CSMWorld::MiscRefIdAdapter::getData (const RefIdColumn *column, const RefIdData& data,
int index) const
{
const Record<ESM::Miscellaneous>& record = static_cast<const Record<ESM::Miscellaneous>&> (
data.getRecord (RefIdData::LocalIndex (index, UniversalId::Type_Miscellaneous)));
if (column==mKey)
return record.get().mData.mIsKey!=0;
return InventoryRefIdAdapter<ESM::Miscellaneous>::getData (column, data, index);
}
void CSMWorld::MiscRefIdAdapter::setData (const RefIdColumn *column, RefIdData& data, int index,
const QVariant& value) const
{
Record<ESM::Miscellaneous>& record = static_cast<Record<ESM::Miscellaneous>&> (
data.getRecord (RefIdData::LocalIndex (index, UniversalId::Type_Miscellaneous)));
if (column==mKey)
record.get().mData.mIsKey = value.toInt();
else
InventoryRefIdAdapter<ESM::Miscellaneous>::setData (column, data, index, value);
}
CSMWorld::NpcColumns::NpcColumns (const ActorColumns& actorColumns) : ActorColumns (actorColumns) {}
CSMWorld::NpcRefIdAdapter::NpcRefIdAdapter (const NpcColumns& columns)
: ActorRefIdAdapter<ESM::NPC> (UniversalId::Type_Npc, columns), mColumns (columns)
{}
QVariant CSMWorld::NpcRefIdAdapter::getData (const RefIdColumn *column, const RefIdData& data, int index)
const
{
const Record<ESM::NPC>& record = static_cast<const Record<ESM::NPC>&> (
data.getRecord (RefIdData::LocalIndex (index, UniversalId::Type_Npc)));
if (column==mColumns.mRace)
return QString::fromUtf8 (record.get().mRace.c_str());
if (column==mColumns.mClass)
return QString::fromUtf8 (record.get().mClass.c_str());
if (column==mColumns.mFaction)
return QString::fromUtf8 (record.get().mFaction.c_str());
if (column==mColumns.mHair)
return QString::fromUtf8 (record.get().mHair.c_str());
if (column==mColumns.mHead)
return QString::fromUtf8 (record.get().mHead.c_str());
std::map<const RefIdColumn *, unsigned int>::const_iterator iter =
mColumns.mFlags.find (column);
if (iter!=mColumns.mFlags.end())
return (record.get().mFlags & iter->second)!=0;
return ActorRefIdAdapter<ESM::NPC>::getData (column, data, index);
}
void CSMWorld::NpcRefIdAdapter::setData (const RefIdColumn *column, RefIdData& data, int index,
const QVariant& value) const
{
Record<ESM::NPC>& record = static_cast<Record<ESM::NPC>&> (
data.getRecord (RefIdData::LocalIndex (index, UniversalId::Type_Npc)));
if (column==mColumns.mRace)
record.get().mRace = value.toString().toUtf8().constData();
else if (column==mColumns.mClass)
record.get().mClass = value.toString().toUtf8().constData();
else if (column==mColumns.mFaction)
record.get().mFaction = value.toString().toUtf8().constData();
else if (column==mColumns.mHair)
record.get().mHair = value.toString().toUtf8().constData();
else if (column==mColumns.mHead)
record.get().mHead = value.toString().toUtf8().constData();
else
{
std::map<const RefIdColumn *, unsigned int>::const_iterator iter =
mColumns.mFlags.find (column);
if (iter!=mColumns.mFlags.end())
{
if (value.toInt()!=0)
record.get().mFlags |= iter->second;
else
record.get().mFlags &= ~iter->second;
}
else
ActorRefIdAdapter<ESM::NPC>::setData (column, data, index, value);
}
}
CSMWorld::WeaponColumns::WeaponColumns (const EnchantableColumns& columns)
: EnchantableColumns (columns) {}
CSMWorld::WeaponRefIdAdapter::WeaponRefIdAdapter (const WeaponColumns& columns)
: EnchantableRefIdAdapter<ESM::Weapon> (UniversalId::Type_Weapon, columns), mColumns (columns)
{}
QVariant CSMWorld::WeaponRefIdAdapter::getData (const RefIdColumn *column, const RefIdData& data,
int index) const
{
const Record<ESM::Weapon>& record = static_cast<const Record<ESM::Weapon>&> (
data.getRecord (RefIdData::LocalIndex (index, UniversalId::Type_Weapon)));
if (column==mColumns.mType)
return record.get().mData.mType;
if (column==mColumns.mHealth)
return record.get().mData.mHealth;
if (column==mColumns.mSpeed)
return record.get().mData.mSpeed;
if (column==mColumns.mReach)
return record.get().mData.mReach;
for (int i=0; i<2; ++i)
{
if (column==mColumns.mChop[i])
return record.get().mData.mChop[i];
if (column==mColumns.mSlash[i])
return record.get().mData.mSlash[i];
if (column==mColumns.mThrust[i])
return record.get().mData.mThrust[i];
}
std::map<const RefIdColumn *, unsigned int>::const_iterator iter =
mColumns.mFlags.find (column);
if (iter!=mColumns.mFlags.end())
return (record.get().mData.mFlags & iter->second)!=0;
return EnchantableRefIdAdapter<ESM::Weapon>::getData (column, data, index);
}
void CSMWorld::WeaponRefIdAdapter::setData (const RefIdColumn *column, RefIdData& data, int index,
const QVariant& value) const
{
Record<ESM::Weapon>& record = static_cast<Record<ESM::Weapon>&> (
data.getRecord (RefIdData::LocalIndex (index, UniversalId::Type_Weapon)));
if (column==mColumns.mType)
record.get().mData.mType = value.toInt();
else if (column==mColumns.mHealth)
record.get().mData.mHealth = value.toInt();
else if (column==mColumns.mSpeed)
record.get().mData.mSpeed = value.toFloat();
else if (column==mColumns.mReach)
record.get().mData.mReach = value.toFloat();
else if (column==mColumns.mChop[0])
record.get().mData.mChop[0] = value.toInt();
else if (column==mColumns.mChop[1])
record.get().mData.mChop[1] = value.toInt();
else if (column==mColumns.mSlash[0])
record.get().mData.mSlash[0] = value.toInt();
else if (column==mColumns.mSlash[1])
record.get().mData.mSlash[1] = value.toInt();
else if (column==mColumns.mThrust[0])
record.get().mData.mThrust[0] = value.toInt();
else if (column==mColumns.mThrust[1])
record.get().mData.mThrust[1] = value.toInt();
else
{
std::map<const RefIdColumn *, unsigned int>::const_iterator iter =
mColumns.mFlags.find (column);
if (iter!=mColumns.mFlags.end())
{
if (value.toInt()!=0)
record.get().mData.mFlags |= iter->second;
else
record.get().mData.mFlags &= ~iter->second;
}
else
EnchantableRefIdAdapter<ESM::Weapon>::setData (column, data, index, value);
}
}

View file

@ -0,0 +1,766 @@
#ifndef CSM_WOLRD_REFIDADAPTERIMP_H
#define CSM_WOLRD_REFIDADAPTERIMP_H
#include <map>
#include <QVariant>
#include <components/esm/loadalch.hpp>
#include <components/esm/loadappa.hpp>
#include "record.hpp"
#include "refiddata.hpp"
#include "universalid.hpp"
#include "refidadapter.hpp"
namespace CSMWorld
{
struct BaseColumns
{
const RefIdColumn *mId;
const RefIdColumn *mModified;
const RefIdColumn *mType;
};
/// \brief Base adapter for all refereceable record types
template<typename RecordT>
class BaseRefIdAdapter : public RefIdAdapter
{
UniversalId::Type mType;
BaseColumns mBase;
public:
BaseRefIdAdapter (UniversalId::Type type, const BaseColumns& base);
virtual std::string getId (const RecordBase& record) const;
virtual QVariant getData (const RefIdColumn *column, const RefIdData& data, int index)
const;
virtual void setData (const RefIdColumn *column, RefIdData& data, int index,
const QVariant& value) const;
///< If the data type does not match an exception is thrown.
UniversalId::Type getType() const;
};
template<typename RecordT>
BaseRefIdAdapter<RecordT>::BaseRefIdAdapter (UniversalId::Type type, const BaseColumns& base)
: mType (type), mBase (base)
{}
template<typename RecordT>
std::string BaseRefIdAdapter<RecordT>::getId (const RecordBase& record) const
{
return dynamic_cast<const Record<RecordT>&> (record).get().mId;
}
template<typename RecordT>
QVariant BaseRefIdAdapter<RecordT>::getData (const RefIdColumn *column, const RefIdData& data,
int index) const
{
const Record<RecordT>& record = static_cast<const Record<RecordT>&> (
data.getRecord (RefIdData::LocalIndex (index, mType)));
if (column==mBase.mId)
return QString::fromUtf8 (record.get().mId.c_str());
if (column==mBase.mModified)
{
if (record.mState==Record<RecordT>::State_Erased)
return static_cast<int> (Record<RecordT>::State_Deleted);
return static_cast<int> (record.mState);
}
if (column==mBase.mType)
return static_cast<int> (mType);
return QVariant();
}
template<typename RecordT>
void BaseRefIdAdapter<RecordT>::setData (const RefIdColumn *column, RefIdData& data, int index,
const QVariant& value) const
{
Record<RecordT>& record = static_cast<Record<RecordT>&> (
data.getRecord (RefIdData::LocalIndex (index, mType)));
if (column==mBase.mModified)
record.mState = static_cast<RecordBase::State> (value.toInt());
}
template<typename RecordT>
UniversalId::Type BaseRefIdAdapter<RecordT>::getType() const
{
return mType;
}
struct ModelColumns : public BaseColumns
{
const RefIdColumn *mModel;
ModelColumns (const BaseColumns& base) : BaseColumns (base) {}
};
/// \brief Adapter for IDs with models (all but levelled lists)
template<typename RecordT>
class ModelRefIdAdapter : public BaseRefIdAdapter<RecordT>
{
ModelColumns mModel;
public:
ModelRefIdAdapter (UniversalId::Type type, const ModelColumns& columns);
virtual QVariant getData (const RefIdColumn *column, const RefIdData& data, int index)
const;
virtual void setData (const RefIdColumn *column, RefIdData& data, int index,
const QVariant& value) const;
///< If the data type does not match an exception is thrown.
};
template<typename RecordT>
ModelRefIdAdapter<RecordT>::ModelRefIdAdapter (UniversalId::Type type, const ModelColumns& columns)
: BaseRefIdAdapter<RecordT> (type, columns), mModel (columns)
{}
template<typename RecordT>
QVariant ModelRefIdAdapter<RecordT>::getData (const RefIdColumn *column, const RefIdData& data,
int index) const
{
const Record<RecordT>& record = static_cast<const Record<RecordT>&> (
data.getRecord (RefIdData::LocalIndex (index, BaseRefIdAdapter<RecordT>::getType())));
if (column==mModel.mModel)
return QString::fromUtf8 (record.get().mModel.c_str());
return BaseRefIdAdapter<RecordT>::getData (column, data, index);
}
template<typename RecordT>
void ModelRefIdAdapter<RecordT>::setData (const RefIdColumn *column, RefIdData& data, int index,
const QVariant& value) const
{
Record<RecordT>& record = static_cast<Record<RecordT>&> (
data.getRecord (RefIdData::LocalIndex (index, BaseRefIdAdapter<RecordT>::getType())));
if (column==mModel.mModel)
record.get().mModel = value.toString().toUtf8().constData();
else
BaseRefIdAdapter<RecordT>::setData (column, data, index, value);
}
struct NameColumns : public ModelColumns
{
const RefIdColumn *mName;
const RefIdColumn *mScript;
NameColumns (const ModelColumns& base) : ModelColumns (base) {}
};
/// \brief Adapter for IDs with names (all but levelled lists and statics)
template<typename RecordT>
class NameRefIdAdapter : public ModelRefIdAdapter<RecordT>
{
NameColumns mName;
public:
NameRefIdAdapter (UniversalId::Type type, const NameColumns& columns);
virtual QVariant getData (const RefIdColumn *column, const RefIdData& data, int index)
const;
virtual void setData (const RefIdColumn *column, RefIdData& data, int index,
const QVariant& value) const;
///< If the data type does not match an exception is thrown.
};
template<typename RecordT>
NameRefIdAdapter<RecordT>::NameRefIdAdapter (UniversalId::Type type, const NameColumns& columns)
: ModelRefIdAdapter<RecordT> (type, columns), mName (columns)
{}
template<typename RecordT>
QVariant NameRefIdAdapter<RecordT>::getData (const RefIdColumn *column, const RefIdData& data,
int index) const
{
const Record<RecordT>& record = static_cast<const Record<RecordT>&> (
data.getRecord (RefIdData::LocalIndex (index, BaseRefIdAdapter<RecordT>::getType())));
if (column==mName.mName)
return QString::fromUtf8 (record.get().mName.c_str());
if (column==mName.mScript)
return QString::fromUtf8 (record.get().mScript.c_str());
return ModelRefIdAdapter<RecordT>::getData (column, data, index);
}
template<typename RecordT>
void NameRefIdAdapter<RecordT>::setData (const RefIdColumn *column, RefIdData& data, int index,
const QVariant& value) const
{
Record<RecordT>& record = static_cast<Record<RecordT>&> (
data.getRecord (RefIdData::LocalIndex (index, BaseRefIdAdapter<RecordT>::getType())));
if (column==mName.mName)
record.get().mName = value.toString().toUtf8().constData();
else if (column==mName.mScript)
record.get().mScript = value.toString().toUtf8().constData();
else
ModelRefIdAdapter<RecordT>::setData (column, data, index, value);
}
struct InventoryColumns : public NameColumns
{
const RefIdColumn *mIcon;
const RefIdColumn *mWeight;
const RefIdColumn *mValue;
InventoryColumns (const NameColumns& base) : NameColumns (base) {}
};
/// \brief Adapter for IDs that can go into an inventory
template<typename RecordT>
class InventoryRefIdAdapter : public NameRefIdAdapter<RecordT>
{
InventoryColumns mInventory;
public:
InventoryRefIdAdapter (UniversalId::Type type, const InventoryColumns& columns);
virtual QVariant getData (const RefIdColumn *column, const RefIdData& data, int index)
const;
virtual void setData (const RefIdColumn *column, RefIdData& data, int index,
const QVariant& value) const;
///< If the data type does not match an exception is thrown.
};
template<typename RecordT>
InventoryRefIdAdapter<RecordT>::InventoryRefIdAdapter (UniversalId::Type type,
const InventoryColumns& columns)
: NameRefIdAdapter<RecordT> (type, columns), mInventory (columns)
{}
template<typename RecordT>
QVariant InventoryRefIdAdapter<RecordT>::getData (const RefIdColumn *column, const RefIdData& data,
int index) const
{
const Record<RecordT>& record = static_cast<const Record<RecordT>&> (
data.getRecord (RefIdData::LocalIndex (index, BaseRefIdAdapter<RecordT>::getType())));
if (column==mInventory.mIcon)
return QString::fromUtf8 (record.get().mIcon.c_str());
if (column==mInventory.mWeight)
return record.get().mData.mWeight;
if (column==mInventory.mValue)
return record.get().mData.mValue;
return NameRefIdAdapter<RecordT>::getData (column, data, index);
}
template<typename RecordT>
void InventoryRefIdAdapter<RecordT>::setData (const RefIdColumn *column, RefIdData& data, int index,
const QVariant& value) const
{
Record<RecordT>& record = static_cast<Record<RecordT>&> (
data.getRecord (RefIdData::LocalIndex (index, BaseRefIdAdapter<RecordT>::getType())));
if (column==mInventory.mIcon)
record.get().mIcon = value.toString().toUtf8().constData();
else if (column==mInventory.mWeight)
record.get().mData.mWeight = value.toFloat();
else if (column==mInventory.mValue)
record.get().mData.mValue = value.toInt();
else
NameRefIdAdapter<RecordT>::setData (column, data, index, value);
}
class PotionRefIdAdapter : public InventoryRefIdAdapter<ESM::Potion>
{
const RefIdColumn *mAutoCalc;
public:
PotionRefIdAdapter (const InventoryColumns& columns, const RefIdColumn *autoCalc);
virtual QVariant getData (const RefIdColumn *column, const RefIdData& data, int index)
const;
virtual void setData (const RefIdColumn *column, RefIdData& data, int index,
const QVariant& value) const;
///< If the data type does not match an exception is thrown.
};
struct EnchantableColumns : public InventoryColumns
{
const RefIdColumn *mEnchantment;
const RefIdColumn *mEnchantmentPoints;
EnchantableColumns (const InventoryColumns& base) : InventoryColumns (base) {}
};
/// \brief Adapter for enchantable IDs
template<typename RecordT>
class EnchantableRefIdAdapter : public InventoryRefIdAdapter<RecordT>
{
EnchantableColumns mEnchantable;
public:
EnchantableRefIdAdapter (UniversalId::Type type, const EnchantableColumns& columns);
virtual QVariant getData (const RefIdColumn *column, const RefIdData& data, int index)
const;
virtual void setData (const RefIdColumn *column, RefIdData& data, int index,
const QVariant& value) const;
///< If the data type does not match an exception is thrown.
};
template<typename RecordT>
EnchantableRefIdAdapter<RecordT>::EnchantableRefIdAdapter (UniversalId::Type type,
const EnchantableColumns& columns)
: InventoryRefIdAdapter<RecordT> (type, columns), mEnchantable (columns)
{}
template<typename RecordT>
QVariant EnchantableRefIdAdapter<RecordT>::getData (const RefIdColumn *column, const RefIdData& data,
int index) const
{
const Record<RecordT>& record = static_cast<const Record<RecordT>&> (
data.getRecord (RefIdData::LocalIndex (index, BaseRefIdAdapter<RecordT>::getType())));
if (column==mEnchantable.mEnchantment)
return QString::fromUtf8 (record.get().mEnchant.c_str());
if (column==mEnchantable.mEnchantmentPoints)
return static_cast<int> (record.get().mData.mEnchant);
return InventoryRefIdAdapter<RecordT>::getData (column, data, index);
}
template<typename RecordT>
void EnchantableRefIdAdapter<RecordT>::setData (const RefIdColumn *column, RefIdData& data,
int index, const QVariant& value) const
{
Record<RecordT>& record = static_cast<Record<RecordT>&> (
data.getRecord (RefIdData::LocalIndex (index, BaseRefIdAdapter<RecordT>::getType())));
if (column==mEnchantable.mEnchantment)
record.get().mEnchant = value.toString().toUtf8().constData();
else if (column==mEnchantable.mEnchantmentPoints)
record.get().mData.mEnchant = value.toInt();
else
InventoryRefIdAdapter<RecordT>::setData (column, data, index, value);
}
struct ToolColumns : public InventoryColumns
{
const RefIdColumn *mQuality;
const RefIdColumn *mUses;
ToolColumns (const InventoryColumns& base) : InventoryColumns (base) {}
};
/// \brief Adapter for tools with limited uses IDs (lockpick, repair, probes)
template<typename RecordT>
class ToolRefIdAdapter : public InventoryRefIdAdapter<RecordT>
{
ToolColumns mTools;
public:
ToolRefIdAdapter (UniversalId::Type type, const ToolColumns& columns);
virtual QVariant getData (const RefIdColumn *column, const RefIdData& data, int index)
const;
virtual void setData (const RefIdColumn *column, RefIdData& data, int index,
const QVariant& value) const;
///< If the data type does not match an exception is thrown.
};
template<typename RecordT>
ToolRefIdAdapter<RecordT>::ToolRefIdAdapter (UniversalId::Type type, const ToolColumns& columns)
: InventoryRefIdAdapter<RecordT> (type, columns), mTools (columns)
{}
template<typename RecordT>
QVariant ToolRefIdAdapter<RecordT>::getData (const RefIdColumn *column, const RefIdData& data,
int index) const
{
const Record<RecordT>& record = static_cast<const Record<RecordT>&> (
data.getRecord (RefIdData::LocalIndex (index, BaseRefIdAdapter<RecordT>::getType())));
if (column==mTools.mQuality)
return record.get().mData.mQuality;
if (column==mTools.mUses)
return record.get().mData.mUses;
return InventoryRefIdAdapter<RecordT>::getData (column, data, index);
}
template<typename RecordT>
void ToolRefIdAdapter<RecordT>::setData (const RefIdColumn *column, RefIdData& data,
int index, const QVariant& value) const
{
Record<RecordT>& record = static_cast<Record<RecordT>&> (
data.getRecord (RefIdData::LocalIndex (index, BaseRefIdAdapter<RecordT>::getType())));
if (column==mTools.mQuality)
record.get().mData.mQuality = value.toFloat();
else if (column==mTools.mUses)
record.get().mData.mUses = value.toInt();
else
InventoryRefIdAdapter<RecordT>::setData (column, data, index, value);
}
struct ActorColumns : public NameColumns
{
const RefIdColumn *mHasAi;
const RefIdColumn *mHello;
const RefIdColumn *mFlee;
const RefIdColumn *mFight;
const RefIdColumn *mAlarm;
std::map<const RefIdColumn *, unsigned int> mServices;
ActorColumns (const NameColumns& base) : NameColumns (base) {}
};
/// \brief Adapter for actor IDs (handles common AI functionality)
template<typename RecordT>
class ActorRefIdAdapter : public NameRefIdAdapter<RecordT>
{
ActorColumns mActors;
public:
ActorRefIdAdapter (UniversalId::Type type, const ActorColumns& columns);
virtual QVariant getData (const RefIdColumn *column, const RefIdData& data, int index)
const;
virtual void setData (const RefIdColumn *column, RefIdData& data, int index,
const QVariant& value) const;
///< If the data type does not match an exception is thrown.
};
template<typename RecordT>
ActorRefIdAdapter<RecordT>::ActorRefIdAdapter (UniversalId::Type type,
const ActorColumns& columns)
: NameRefIdAdapter<RecordT> (type, columns), mActors (columns)
{}
template<typename RecordT>
QVariant ActorRefIdAdapter<RecordT>::getData (const RefIdColumn *column, const RefIdData& data,
int index) const
{
const Record<RecordT>& record = static_cast<const Record<RecordT>&> (
data.getRecord (RefIdData::LocalIndex (index, BaseRefIdAdapter<RecordT>::getType())));
if (column==mActors.mHasAi)
return record.get().mHasAI!=0;
if (column==mActors.mHello)
return record.get().mAiData.mHello;
if (column==mActors.mFlee)
return record.get().mAiData.mFlee;
if (column==mActors.mFight)
return record.get().mAiData.mFight;
if (column==mActors.mAlarm)
return record.get().mAiData.mAlarm;
std::map<const RefIdColumn *, unsigned int>::const_iterator iter =
mActors.mServices.find (column);
if (iter!=mActors.mServices.end())
return (record.get().mAiData.mServices & iter->second)!=0;
return NameRefIdAdapter<RecordT>::getData (column, data, index);
}
template<typename RecordT>
void ActorRefIdAdapter<RecordT>::setData (const RefIdColumn *column, RefIdData& data, int index,
const QVariant& value) const
{
Record<RecordT>& record = static_cast<Record<RecordT>&> (
data.getRecord (RefIdData::LocalIndex (index, BaseRefIdAdapter<RecordT>::getType())));
if (column==mActors.mHasAi)
record.get().mHasAI = value.toInt();
else if (column==mActors.mHello)
record.get().mAiData.mHello = value.toInt();
else if (column==mActors.mFlee)
record.get().mAiData.mFlee = value.toInt();
else if (column==mActors.mFight)
record.get().mAiData.mFight = value.toInt();
else if (column==mActors.mAlarm)
record.get().mAiData.mAlarm = value.toInt();
else
{
typename std::map<const RefIdColumn *, unsigned int>::const_iterator iter =
mActors.mServices.find (column);
if (iter!=mActors.mServices.end())
{
if (value.toInt()!=0)
record.get().mAiData.mServices |= iter->second;
else
record.get().mAiData.mServices &= ~iter->second;
}
else
NameRefIdAdapter<RecordT>::setData (column, data, index, value);
}
}
class ApparatusRefIdAdapter : public InventoryRefIdAdapter<ESM::Apparatus>
{
const RefIdColumn *mType;
const RefIdColumn *mQuality;
public:
ApparatusRefIdAdapter (const InventoryColumns& columns, const RefIdColumn *type,
const RefIdColumn *quality);
virtual QVariant getData (const RefIdColumn *column, const RefIdData& data, int index)
const;
virtual void setData (const RefIdColumn *column, RefIdData& data, int index,
const QVariant& value) const;
///< If the data type does not match an exception is thrown.
};
class ArmorRefIdAdapter : public EnchantableRefIdAdapter<ESM::Armor>
{
const RefIdColumn *mType;
const RefIdColumn *mHealth;
const RefIdColumn *mArmor;
public:
ArmorRefIdAdapter (const EnchantableColumns& columns, const RefIdColumn *type,
const RefIdColumn *health, const RefIdColumn *armor);
virtual QVariant getData (const RefIdColumn *column, const RefIdData& data, int index)
const;
virtual void setData (const RefIdColumn *column, RefIdData& data, int index,
const QVariant& value) const;
///< If the data type does not match an exception is thrown.
};
class BookRefIdAdapter : public EnchantableRefIdAdapter<ESM::Book>
{
const RefIdColumn *mScroll;
const RefIdColumn *mSkill;
public:
BookRefIdAdapter (const EnchantableColumns& columns, const RefIdColumn *scroll,
const RefIdColumn *skill);
virtual QVariant getData (const RefIdColumn *column, const RefIdData& data, int index)
const;
virtual void setData (const RefIdColumn *column, RefIdData& data, int index,
const QVariant& value) const;
///< If the data type does not match an exception is thrown.
};
class ClothingRefIdAdapter : public EnchantableRefIdAdapter<ESM::Clothing>
{
const RefIdColumn *mType;
public:
ClothingRefIdAdapter (const EnchantableColumns& columns, const RefIdColumn *type);
virtual QVariant getData (const RefIdColumn *column, const RefIdData& data, int index)
const;
virtual void setData (const RefIdColumn *column, RefIdData& data, int index,
const QVariant& value) const;
///< If the data type does not match an exception is thrown.
};
class ContainerRefIdAdapter : public NameRefIdAdapter<ESM::Container>
{
const RefIdColumn *mWeight;
const RefIdColumn *mOrganic;
const RefIdColumn *mRespawn;
public:
ContainerRefIdAdapter (const NameColumns& columns, const RefIdColumn *weight,
const RefIdColumn *organic, const RefIdColumn *respawn);
virtual QVariant getData (const RefIdColumn *column, const RefIdData& data, int index)
const;
virtual void setData (const RefIdColumn *column, RefIdData& data, int index,
const QVariant& value) const;
///< If the data type does not match an exception is thrown.
};
struct CreatureColumns : public ActorColumns
{
std::map<const RefIdColumn *, unsigned int> mFlags;
const RefIdColumn *mType;
const RefIdColumn *mSoul;
const RefIdColumn *mScale;
const RefIdColumn *mOriginal;
CreatureColumns (const ActorColumns& actorColumns);
};
class CreatureRefIdAdapter : public ActorRefIdAdapter<ESM::Creature>
{
CreatureColumns mColumns;
public:
CreatureRefIdAdapter (const CreatureColumns& columns);
virtual QVariant getData (const RefIdColumn *column, const RefIdData& data, int index)
const;
virtual void setData (const RefIdColumn *column, RefIdData& data, int index,
const QVariant& value) const;
///< If the data type does not match an exception is thrown.
};
class DoorRefIdAdapter : public NameRefIdAdapter<ESM::Door>
{
const RefIdColumn *mOpenSound;
const RefIdColumn *mCloseSound;
public:
DoorRefIdAdapter (const NameColumns& columns, const RefIdColumn *openSound,
const RefIdColumn *closeSound);
virtual QVariant getData (const RefIdColumn *column, const RefIdData& data, int index)
const;
virtual void setData (const RefIdColumn *column, RefIdData& data, int index,
const QVariant& value) const;
///< If the data type does not match an exception is thrown.
};
struct LightColumns : public InventoryColumns
{
const RefIdColumn *mTime;
const RefIdColumn *mRadius;
const RefIdColumn *mColor;
const RefIdColumn *mSound;
std::map<const RefIdColumn *, unsigned int> mFlags;
LightColumns (const InventoryColumns& columns);
};
class LightRefIdAdapter : public InventoryRefIdAdapter<ESM::Light>
{
LightColumns mColumns;
public:
LightRefIdAdapter (const LightColumns& columns);
virtual QVariant getData (const RefIdColumn *column, const RefIdData& data, int index)
const;
virtual void setData (const RefIdColumn *column, RefIdData& data, int index,
const QVariant& value) const;
///< If the data type does not match an exception is thrown.
};
class MiscRefIdAdapter : public InventoryRefIdAdapter<ESM::Miscellaneous>
{
const RefIdColumn *mKey;
public:
MiscRefIdAdapter (const InventoryColumns& columns, const RefIdColumn *key);
virtual QVariant getData (const RefIdColumn *column, const RefIdData& data, int index)
const;
virtual void setData (const RefIdColumn *column, RefIdData& data, int index,
const QVariant& value) const;
///< If the data type does not match an exception is thrown.
};
struct NpcColumns : public ActorColumns
{
std::map<const RefIdColumn *, unsigned int> mFlags;
const RefIdColumn *mRace;
const RefIdColumn *mClass;
const RefIdColumn *mFaction;
const RefIdColumn *mHair;
const RefIdColumn *mHead;
NpcColumns (const ActorColumns& actorColumns);
};
class NpcRefIdAdapter : public ActorRefIdAdapter<ESM::NPC>
{
NpcColumns mColumns;
public:
NpcRefIdAdapter (const NpcColumns& columns);
virtual QVariant getData (const RefIdColumn *column, const RefIdData& data, int index)
const;
virtual void setData (const RefIdColumn *column, RefIdData& data, int index,
const QVariant& value) const;
///< If the data type does not match an exception is thrown.
};
struct WeaponColumns : public EnchantableColumns
{
const RefIdColumn *mType;
const RefIdColumn *mHealth;
const RefIdColumn *mSpeed;
const RefIdColumn *mReach;
const RefIdColumn *mChop[2];
const RefIdColumn *mSlash[2];
const RefIdColumn *mThrust[2];
std::map<const RefIdColumn *, unsigned int> mFlags;
WeaponColumns (const EnchantableColumns& columns);
};
class WeaponRefIdAdapter : public EnchantableRefIdAdapter<ESM::Weapon>
{
WeaponColumns mColumns;
public:
WeaponRefIdAdapter (const WeaponColumns& columns);
virtual QVariant getData (const RefIdColumn *column, const RefIdData& data, int index)
const;
virtual void setData (const RefIdColumn *column, RefIdData& data, int index,
const QVariant& value) const;
///< If the data type does not match an exception is thrown.
};
}
#endif

View file

@ -0,0 +1,540 @@
#include "refidcollection.hpp"
#include <stdexcept>
#include "refidadapter.hpp"
#include "refidadapterimp.hpp"
CSMWorld::RefIdColumn::RefIdColumn (const std::string& title, Display displayType, int flag,
bool editable, bool userEditable)
: ColumnBase (title, displayType, flag), mEditable (editable), mUserEditable (userEditable)
{}
bool CSMWorld::RefIdColumn::isEditable() const
{
return mEditable;
}
bool CSMWorld::RefIdColumn::isUserEditable() const
{
return mUserEditable;
}
const CSMWorld::RefIdAdapter& CSMWorld::RefIdCollection::findAdaptor (UniversalId::Type type) const
{
std::map<UniversalId::Type, RefIdAdapter *>::const_iterator iter = mAdapters.find (type);
if (iter==mAdapters.end())
throw std::logic_error ("unsupported type in RefIdCollection");
return *iter->second;
}
CSMWorld::RefIdCollection::RefIdCollection()
{
BaseColumns baseColumns;
mColumns.push_back (RefIdColumn ("ID", ColumnBase::Display_String,
ColumnBase::Flag_Table | ColumnBase::Flag_Dialogue, false, false));
baseColumns.mId = &mColumns.back();
mColumns.push_back (RefIdColumn ("*", ColumnBase::Display_RecordState,
ColumnBase::Flag_Table | ColumnBase::Flag_Dialogue, false, false));
baseColumns.mModified = &mColumns.back();
mColumns.push_back (RefIdColumn ("Type", ColumnBase::Display_Integer,
ColumnBase::Flag_Table | ColumnBase::Flag_Dialogue, false, false));
baseColumns.mType = &mColumns.back();
ModelColumns modelColumns (baseColumns);
mColumns.push_back (RefIdColumn ("Model", ColumnBase::Display_String));
modelColumns.mModel = &mColumns.back();
NameColumns nameColumns (modelColumns);
mColumns.push_back (RefIdColumn ("Name", ColumnBase::Display_String));
nameColumns.mName = &mColumns.back();
mColumns.push_back (RefIdColumn ("Script", ColumnBase::Display_String));
nameColumns.mScript = &mColumns.back();
InventoryColumns inventoryColumns (nameColumns);
mColumns.push_back (RefIdColumn ("Icon", ColumnBase::Display_String));
inventoryColumns.mIcon = &mColumns.back();
mColumns.push_back (RefIdColumn ("Weight", ColumnBase::Display_Float));
inventoryColumns.mWeight = &mColumns.back();
mColumns.push_back (RefIdColumn ("Value", ColumnBase::Display_Integer));
inventoryColumns.mValue = &mColumns.back();
EnchantableColumns enchantableColumns (inventoryColumns);
mColumns.push_back (RefIdColumn ("Enchantment", ColumnBase::Display_String));
enchantableColumns.mEnchantment = &mColumns.back();
mColumns.push_back (RefIdColumn ("Enchantment Points", ColumnBase::Display_Integer));
enchantableColumns.mEnchantmentPoints = &mColumns.back();
ToolColumns toolsColumns (inventoryColumns);
mColumns.push_back (RefIdColumn ("Quality", ColumnBase::Display_Float));
toolsColumns.mQuality = &mColumns.back();
mColumns.push_back (RefIdColumn ("Uses", ColumnBase::Display_Integer));
toolsColumns.mUses = &mColumns.back();
ActorColumns actorsColumns (nameColumns);
mColumns.push_back (RefIdColumn ("AI", ColumnBase::Display_Boolean));
actorsColumns.mHasAi = &mColumns.back();
mColumns.push_back (RefIdColumn ("AI Hello", ColumnBase::Display_Integer));
actorsColumns.mHello = &mColumns.back();
mColumns.push_back (RefIdColumn ("AI Flee", ColumnBase::Display_Integer));
actorsColumns.mFlee = &mColumns.back();
mColumns.push_back (RefIdColumn ("AI Fight", ColumnBase::Display_Integer));
actorsColumns.mFight = &mColumns.back();
mColumns.push_back (RefIdColumn ("AI Alarm", ColumnBase::Display_Integer));
actorsColumns.mAlarm = &mColumns.back();
static const struct
{
const char *mName;
unsigned int mFlag;
} sServiceTable[] =
{
{ "Buys Weapons", ESM::NPC::Weapon},
{ "Buys Armor", ESM::NPC::Armor},
{ "Buys Clothing", ESM::NPC::Clothing},
{ "Buys Books", ESM::NPC::Books},
{ "Buys Ingredients", ESM::NPC::Ingredients},
{ "Buys Lockpicks", ESM::NPC::Picks},
{ "Buys Probes", ESM::NPC::Probes},
{ "Buys Lights", ESM::NPC::Lights},
{ "Buys Apparati", ESM::NPC::Apparatus},
{ "Buys Repair Items", ESM::NPC::RepairItem},
{ "Buys Misc Items", ESM::NPC::Misc},
{ "Buys Potions", ESM::NPC::Potions},
{ "Buys Magic Items", ESM::NPC::MagicItems},
{ "Sells Spells", ESM::NPC::Spells},
{ "Trainer", ESM::NPC::Training},
{ "Spellmaking", ESM::NPC::Spellmaking},
{ "Enchanting Service", ESM::NPC::Enchanting},
{ "Repair Serivce", ESM::NPC::Repair},
{ 0, 0 }
};
for (int i=0; sServiceTable[i].mName; ++i)
{
mColumns.push_back (RefIdColumn (sServiceTable[i].mName, ColumnBase::Display_Boolean));
actorsColumns.mServices.insert (std::make_pair (&mColumns.back(), sServiceTable[i].mFlag));
}
mColumns.push_back (RefIdColumn ("Auto Calc", ColumnBase::Display_Boolean));
const RefIdColumn *autoCalc = &mColumns.back();
mColumns.push_back (RefIdColumn ("Apparatus Type", ColumnBase::Display_ApparatusType));
const RefIdColumn *apparatusType = &mColumns.back();
mColumns.push_back (RefIdColumn ("Armor Type", ColumnBase::Display_ArmorType));
const RefIdColumn *armorType = &mColumns.back();
mColumns.push_back (RefIdColumn ("Health", ColumnBase::Display_Integer));
const RefIdColumn *health = &mColumns.back();
mColumns.push_back (RefIdColumn ("Armor Value", ColumnBase::Display_Integer));
const RefIdColumn *armor = &mColumns.back();
mColumns.push_back (RefIdColumn ("Scroll", ColumnBase::Display_Boolean));
const RefIdColumn *scroll = &mColumns.back();
mColumns.push_back (RefIdColumn ("Attribute", ColumnBase::Display_Attribute));
const RefIdColumn *attribute = &mColumns.back();
mColumns.push_back (RefIdColumn ("Clothing Type", ColumnBase::Display_ClothingType));
const RefIdColumn *clothingType = &mColumns.back();
mColumns.push_back (RefIdColumn ("Weight Capacity", ColumnBase::Display_Float));
const RefIdColumn *weightCapacity = &mColumns.back();
mColumns.push_back (RefIdColumn ("Organic Container", ColumnBase::Display_Boolean));
const RefIdColumn *organic = &mColumns.back();
mColumns.push_back (RefIdColumn ("Respawn", ColumnBase::Display_Boolean));
const RefIdColumn *respawn = &mColumns.back();
CreatureColumns creatureColumns (actorsColumns);
mColumns.push_back (RefIdColumn ("Creature Type", ColumnBase::Display_CreatureType));
creatureColumns.mType = &mColumns.back();
mColumns.push_back (RefIdColumn ("Soul Points", ColumnBase::Display_Integer));
creatureColumns.mSoul = &mColumns.back();
mColumns.push_back (RefIdColumn ("Scale", ColumnBase::Display_Float));
creatureColumns.mScale = &mColumns.back();
mColumns.push_back (RefIdColumn ("Original Creature", ColumnBase::Display_String));
creatureColumns.mOriginal = &mColumns.back();
static const struct
{
const char *mName;
unsigned int mFlag;
} sCreatureFlagTable[] =
{
{ "Biped", ESM::Creature::Biped },
{ "Has Weapon", ESM::Creature::Weapon },
{ "No Movement", ESM::Creature::None },
{ "Swims", ESM::Creature::Swims },
{ "Flies", ESM::Creature::Flies },
{ "Walks", ESM::Creature::Walks },
{ "Essential", ESM::Creature::Essential },
{ "Skeleton Blood", ESM::Creature::Skeleton },
{ "Metal Blood", ESM::Creature::Metal },
{ 0, 0 }
};
// for re-use in NPC records
const RefIdColumn *essential = 0;
const RefIdColumn *skeletonBlood = 0;
const RefIdColumn *metalBlood = 0;
for (int i=0; sCreatureFlagTable[i].mName; ++i)
{
mColumns.push_back (RefIdColumn (sCreatureFlagTable[i].mName, ColumnBase::Display_Boolean));
creatureColumns.mFlags.insert (std::make_pair (&mColumns.back(), sCreatureFlagTable[i].mFlag));
switch (sCreatureFlagTable[i].mFlag)
{
case ESM::Creature::Essential: essential = &mColumns.back(); break;
case ESM::Creature::Skeleton: skeletonBlood = &mColumns.back(); break;
case ESM::Creature::Metal: metalBlood = &mColumns.back(); break;
}
}
creatureColumns.mFlags.insert (std::make_pair (respawn, ESM::Creature::Respawn));
mColumns.push_back (RefIdColumn ("Open Sound", ColumnBase::Display_String));
const RefIdColumn *openSound = &mColumns.back();
mColumns.push_back (RefIdColumn ("Close Sound", ColumnBase::Display_String));
const RefIdColumn *closeSound = &mColumns.back();
LightColumns lightColumns (inventoryColumns);
mColumns.push_back (RefIdColumn ("Duration", ColumnBase::Display_Integer));
lightColumns.mTime = &mColumns.back();
mColumns.push_back (RefIdColumn ("Radius", ColumnBase::Display_Integer));
lightColumns.mRadius = &mColumns.back();
mColumns.push_back (RefIdColumn ("Colour", ColumnBase::Display_Integer));
lightColumns.mColor = &mColumns.back();
mColumns.push_back (RefIdColumn ("Sound", ColumnBase::Display_String));
lightColumns.mSound = &mColumns.back();
static const struct
{
const char *mName;
unsigned int mFlag;
} sLightFlagTable[] =
{
{ "Dynamic", ESM::Light::Dynamic },
{ "Portable", ESM::Light::Carry },
{ "Negative Light", ESM::Light::Negative },
{ "Flickering", ESM::Light::Flicker },
{ "Slow Flickering", ESM::Light::Flicker },
{ "Pulsing", ESM::Light::Pulse },
{ "Slow Pulsing", ESM::Light::PulseSlow },
{ "Fire", ESM::Light::Fire },
{ "Off by default", ESM::Light::OffDefault },
{ 0, 0 }
};
for (int i=0; sLightFlagTable[i].mName; ++i)
{
mColumns.push_back (RefIdColumn (sLightFlagTable[i].mName, ColumnBase::Display_Boolean));
lightColumns.mFlags.insert (std::make_pair (&mColumns.back(), sLightFlagTable[i].mFlag));
}
mColumns.push_back (RefIdColumn ("Key", ColumnBase::Display_Boolean));
const RefIdColumn *key = &mColumns.back();
NpcColumns npcColumns (actorsColumns);
mColumns.push_back (RefIdColumn ("Race", ColumnBase::Display_String));
npcColumns.mRace = &mColumns.back();
mColumns.push_back (RefIdColumn ("Class", ColumnBase::Display_String));
npcColumns.mClass = &mColumns.back();
mColumns.push_back (RefIdColumn ("Faction", ColumnBase::Display_String));
npcColumns.mFaction = &mColumns.back();
mColumns.push_back (RefIdColumn ("Hair", ColumnBase::Display_String));
npcColumns.mHair = &mColumns.back();
mColumns.push_back (RefIdColumn ("Head", ColumnBase::Display_String));
npcColumns.mHead = &mColumns.back();
mColumns.push_back (RefIdColumn ("Female", ColumnBase::Display_Boolean));
npcColumns.mFlags.insert (std::make_pair (&mColumns.back(), ESM::NPC::Female));
npcColumns.mFlags.insert (std::make_pair (essential, ESM::NPC::Essential));
npcColumns.mFlags.insert (std::make_pair (respawn, ESM::NPC::Respawn));
npcColumns.mFlags.insert (std::make_pair (autoCalc, ESM::NPC::Autocalc));
npcColumns.mFlags.insert (std::make_pair (skeletonBlood, ESM::NPC::Skeleton));
npcColumns.mFlags.insert (std::make_pair (metalBlood, ESM::NPC::Metal));
WeaponColumns weaponColumns (enchantableColumns);
mColumns.push_back (RefIdColumn ("Weapon Type", ColumnBase::Display_WeaponType));
weaponColumns.mType = &mColumns.back();
weaponColumns.mHealth = health;
mColumns.push_back (RefIdColumn ("Weapon Speed", ColumnBase::Display_Float));
weaponColumns.mSpeed = &mColumns.back();
mColumns.push_back (RefIdColumn ("Weapon Reach", ColumnBase::Display_Float));
weaponColumns.mReach = &mColumns.back();
for (int i=0; i<2; ++i)
{
std::string suffix = i==0 ? "Min " : "Max ";
mColumns.push_back (RefIdColumn ("Chop" + suffix, ColumnBase::Display_Integer));
weaponColumns.mChop[i] = &mColumns.back();
mColumns.push_back (RefIdColumn ("Slash" + suffix, ColumnBase::Display_Integer));
weaponColumns.mSlash[i] = &mColumns.back();
mColumns.push_back (RefIdColumn ("Thrust" + suffix, ColumnBase::Display_Integer));
weaponColumns.mThrust[i] = &mColumns.back();
}
static const struct
{
const char *mName;
unsigned int mFlag;
} sWeaponFlagTable[] =
{
{ "Magical", ESM::Weapon::Magical },
{ "Silver", ESM::Weapon::Silver },
{ 0, 0 }
};
for (int i=0; sWeaponFlagTable[i].mName; ++i)
{
mColumns.push_back (RefIdColumn (sWeaponFlagTable[i].mName, ColumnBase::Display_Boolean));
weaponColumns.mFlags.insert (std::make_pair (&mColumns.back(), sWeaponFlagTable[i].mFlag));
}
mAdapters.insert (std::make_pair (UniversalId::Type_Activator,
new NameRefIdAdapter<ESM::Activator> (UniversalId::Type_Activator, nameColumns)));
mAdapters.insert (std::make_pair (UniversalId::Type_Potion,
new PotionRefIdAdapter (inventoryColumns, autoCalc)));
mAdapters.insert (std::make_pair (UniversalId::Type_Apparatus,
new ApparatusRefIdAdapter (inventoryColumns, apparatusType, toolsColumns.mQuality)));
mAdapters.insert (std::make_pair (UniversalId::Type_Armor,
new ArmorRefIdAdapter (enchantableColumns, armorType, health, armor)));
mAdapters.insert (std::make_pair (UniversalId::Type_Book,
new BookRefIdAdapter (enchantableColumns, scroll, attribute)));
mAdapters.insert (std::make_pair (UniversalId::Type_Clothing,
new ClothingRefIdAdapter (enchantableColumns, clothingType)));
mAdapters.insert (std::make_pair (UniversalId::Type_Container,
new ContainerRefIdAdapter (nameColumns, weightCapacity, organic, respawn)));
mAdapters.insert (std::make_pair (UniversalId::Type_Creature,
new CreatureRefIdAdapter (creatureColumns)));
mAdapters.insert (std::make_pair (UniversalId::Type_Door,
new DoorRefIdAdapter (nameColumns, openSound, closeSound)));
mAdapters.insert (std::make_pair (UniversalId::Type_Ingredient,
new InventoryRefIdAdapter<ESM::Ingredient> (UniversalId::Type_Ingredient, inventoryColumns)));
mAdapters.insert (std::make_pair (UniversalId::Type_CreatureLevelledList,
new BaseRefIdAdapter<ESM::CreatureLevList> (
UniversalId::Type_CreatureLevelledList, baseColumns)));
mAdapters.insert (std::make_pair (UniversalId::Type_ItemLevelledList,
new BaseRefIdAdapter<ESM::ItemLevList> (UniversalId::Type_ItemLevelledList, baseColumns)));
mAdapters.insert (std::make_pair (UniversalId::Type_Light,
new LightRefIdAdapter (lightColumns)));
mAdapters.insert (std::make_pair (UniversalId::Type_Lockpick,
new ToolRefIdAdapter<ESM::Lockpick> (UniversalId::Type_Lockpick, toolsColumns)));
mAdapters.insert (std::make_pair (UniversalId::Type_Miscellaneous,
new MiscRefIdAdapter (inventoryColumns, key)));
mAdapters.insert (std::make_pair (UniversalId::Type_Npc,
new NpcRefIdAdapter (npcColumns)));
mAdapters.insert (std::make_pair (UniversalId::Type_Probe,
new ToolRefIdAdapter<ESM::Probe> (UniversalId::Type_Probe, toolsColumns)));
mAdapters.insert (std::make_pair (UniversalId::Type_Repair,
new ToolRefIdAdapter<ESM::Repair> (UniversalId::Type_Repair, toolsColumns)));
mAdapters.insert (std::make_pair (UniversalId::Type_Static,
new ModelRefIdAdapter<ESM::Static> (UniversalId::Type_Static, modelColumns)));
mAdapters.insert (std::make_pair (UniversalId::Type_Weapon,
new WeaponRefIdAdapter (weaponColumns)));
}
CSMWorld::RefIdCollection::~RefIdCollection()
{
for (std::map<UniversalId::Type, RefIdAdapter *>::iterator iter (mAdapters.begin());
iter!=mAdapters.end(); ++iter)
delete iter->second;
}
int CSMWorld::RefIdCollection::getSize() const
{
return mData.getSize();
}
std::string CSMWorld::RefIdCollection::getId (int index) const
{
return getData (index, 0).toString().toUtf8().constData();
}
int CSMWorld::RefIdCollection::getIndex (const std::string& id) const
{
int index = searchId (id);
if (index==-1)
throw std::runtime_error ("invalid ID: " + id);
return index;
}
int CSMWorld::RefIdCollection::getColumns() const
{
return mColumns.size();
}
const CSMWorld::ColumnBase& CSMWorld::RefIdCollection::getColumn (int column) const
{
return mColumns.at (column);
}
QVariant CSMWorld::RefIdCollection::getData (int index, int column) const
{
RefIdData::LocalIndex localIndex = mData.globalToLocalIndex (index);
const RefIdAdapter& adaptor = findAdaptor (localIndex.second);
return adaptor.getData (&mColumns.at (column), mData, localIndex.first);
}
void CSMWorld::RefIdCollection::setData (int index, int column, const QVariant& data)
{
RefIdData::LocalIndex localIndex = mData.globalToLocalIndex (index);
const RefIdAdapter& adaptor = findAdaptor (localIndex.second);
adaptor.setData (&mColumns.at (column), mData, localIndex.first, data);
}
void CSMWorld::RefIdCollection::removeRows (int index, int count)
{
mData.erase (index, count);
}
void CSMWorld::RefIdCollection::appendBlankRecord (const std::string& id, UniversalId::Type type)
{
mData.appendRecord (type, id);
}
int CSMWorld::RefIdCollection::searchId (const std::string& id) const
{
RefIdData::LocalIndex localIndex = mData.searchId (id);
if (localIndex.first==-1)
return -1;
return mData.localToGlobalIndex (localIndex);
}
void CSMWorld::RefIdCollection::replace (int index, const RecordBase& record)
{
mData.getRecord (mData.globalToLocalIndex (index)).assign (record);
}
void CSMWorld::RefIdCollection::appendRecord (const RecordBase& record,
UniversalId::Type type)
{
std::string id = findAdaptor (type).getId (record);
int index = mData.getAppendIndex (type);
mData.appendRecord (type, id);
mData.getRecord (mData.globalToLocalIndex (index)).assign (record);
}
const CSMWorld::RecordBase& CSMWorld::RefIdCollection::getRecord (const std::string& id) const
{
return mData.getRecord (mData.searchId (id));
}
const CSMWorld::RecordBase& CSMWorld::RefIdCollection::getRecord (int index) const
{
return mData.getRecord (mData.globalToLocalIndex (index));
}
void CSMWorld::RefIdCollection::load (ESM::ESMReader& reader, bool base, UniversalId::Type type)
{
std::string id = reader.getHNOString ("NAME");
int index = searchId (id);
if (reader.isNextSub ("DELE"))
{
reader.skipRecord();
if (index==-1)
{
// deleting a record that does not exist
// ignore it for now
/// \todo report the problem to the user
}
else if (base)
{
mData.erase (index, 1);
}
else
{
mData.getRecord (mData.globalToLocalIndex (index)).mState = RecordBase::State_Deleted;
}
}
else
{
if (index==-1)
{
// new record
int index = mData.getAppendIndex (type);
mData.appendRecord (type, id);
RefIdData::LocalIndex localIndex = mData.globalToLocalIndex (index);
mData.load (localIndex, reader, base);
mData.getRecord (localIndex).mState =
base ? RecordBase::State_BaseOnly : RecordBase::State_ModifiedOnly;
}
else
{
// old record
RefIdData::LocalIndex localIndex = mData.globalToLocalIndex (index);
if (!base)
if (mData.getRecord (localIndex).mState==RecordBase::State_Erased)
throw std::logic_error ("attempt to access a deleted record");
mData.load (localIndex, reader, base);
if (!base)
mData.getRecord (localIndex).mState = RecordBase::State_Modified;
}
}
}
int CSMWorld::RefIdCollection::getAppendIndex (UniversalId::Type type) const
{
return mData.getAppendIndex (type);
}

View file

@ -0,0 +1,95 @@
#ifndef CSM_WOLRD_REFIDCOLLECTION_H
#define CSM_WOLRD_REFIDCOLLECTION_H
#include <vector>
#include <map>
#include <deque>
#include "columnbase.hpp"
#include "idcollection.hpp"
#include "refiddata.hpp"
namespace CSMWorld
{
class RefIdAdapter;
class RefIdColumn : public ColumnBase
{
bool mEditable;
bool mUserEditable;
public:
RefIdColumn (const std::string& title, Display displayType,
int flag = Flag_Table | Flag_Dialogue, bool editable = true,
bool userEditable = true);
virtual bool isEditable() const;
virtual bool isUserEditable() const;
};
class RefIdCollection : public IdCollectionBase
{
private:
RefIdData mData;
std::deque<RefIdColumn> mColumns;
std::map<UniversalId::Type, RefIdAdapter *> mAdapters;
private:
const RefIdAdapter& findAdaptor (UniversalId::Type) const;
///< Throws an exception if no adaptor for \a Type can be found.
public:
RefIdCollection();
virtual ~RefIdCollection();
virtual int getSize() const;
virtual std::string getId (int index) const;
virtual int getIndex (const std::string& id) const;
virtual int getColumns() const;
virtual const ColumnBase& getColumn (int column) const;
virtual QVariant getData (int index, int column) const;
virtual void setData (int index, int column, const QVariant& data);
virtual void removeRows (int index, int count);
virtual void appendBlankRecord (const std::string& id, UniversalId::Type type);
///< \param type Will be ignored, unless the collection supports multiple record types
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, UniversalId::Type type);
///< If the record type does not match, an exception is thrown.
///
///< \param type Will be ignored, unless the collection supports multiple record types
virtual const RecordBase& getRecord (const std::string& id) const;
virtual const RecordBase& getRecord (int index) const;
virtual void load (ESM::ESMReader& reader, bool base, UniversalId::Type type);
virtual int getAppendIndex (UniversalId::Type type) const;
///< \param type Will be ignored, unless the collection supports multiple record types
};
}
#endif

View file

@ -0,0 +1,198 @@
#include "refiddata.hpp"
#include <cassert>
#include <components/misc/stringops.hpp>
CSMWorld::RefIdDataContainerBase::~RefIdDataContainerBase() {}
CSMWorld::RefIdData::RefIdData()
{
mRecordContainers.insert (std::make_pair (UniversalId::Type_Activator, &mActivators));
mRecordContainers.insert (std::make_pair (UniversalId::Type_Potion, &mPotions));
mRecordContainers.insert (std::make_pair (UniversalId::Type_Apparatus, &mApparati));
mRecordContainers.insert (std::make_pair (UniversalId::Type_Armor, &mArmors));
mRecordContainers.insert (std::make_pair (UniversalId::Type_Book, &mBooks));
mRecordContainers.insert (std::make_pair (UniversalId::Type_Clothing, &mClothing));
mRecordContainers.insert (std::make_pair (UniversalId::Type_Container, &mContainers));
mRecordContainers.insert (std::make_pair (UniversalId::Type_Creature, &mCreatures));
mRecordContainers.insert (std::make_pair (UniversalId::Type_Door, &mDoors));
mRecordContainers.insert (std::make_pair (UniversalId::Type_Ingredient, &mIngredients));
mRecordContainers.insert (std::make_pair (UniversalId::Type_CreatureLevelledList,
&mCreatureLevelledLists));
mRecordContainers.insert (std::make_pair (UniversalId::Type_ItemLevelledList, &mItemLevelledLists));
mRecordContainers.insert (std::make_pair (UniversalId::Type_Light, &mLights));
mRecordContainers.insert (std::make_pair (UniversalId::Type_Lockpick, &mLockpicks));
mRecordContainers.insert (std::make_pair (UniversalId::Type_Miscellaneous, &mMiscellaneous));
mRecordContainers.insert (std::make_pair (UniversalId::Type_Npc, &mNpcs));
mRecordContainers.insert (std::make_pair (UniversalId::Type_Probe, &mProbes));
mRecordContainers.insert (std::make_pair (UniversalId::Type_Repair, &mRepairs));
mRecordContainers.insert (std::make_pair (UniversalId::Type_Static, &mStatics));
mRecordContainers.insert (std::make_pair (UniversalId::Type_Weapon, &mWeapons));
}
CSMWorld::RefIdData::LocalIndex CSMWorld::RefIdData::globalToLocalIndex (int index) const
{
for (std::map<UniversalId::Type, RefIdDataContainerBase *>::const_iterator iter (
mRecordContainers.begin()); iter!=mRecordContainers.end(); ++iter)
{
if (index<iter->second->getSize())
return LocalIndex (index, iter->first);
index -= iter->second->getSize();
}
throw std::runtime_error ("RefIdData index out of range");
}
int CSMWorld::RefIdData::localToGlobalIndex (const LocalIndex& index)
const
{
std::map<UniversalId::Type, RefIdDataContainerBase *>::const_iterator end =
mRecordContainers.find (index.second);
if (end==mRecordContainers.end())
throw std::logic_error ("invalid local index type");
int globalIndex = index.first;
for (std::map<UniversalId::Type, RefIdDataContainerBase *>::const_iterator iter (
mRecordContainers.begin()); iter!=end; ++iter)
globalIndex += iter->second->getSize();
return globalIndex;
}
CSMWorld::RefIdData::LocalIndex CSMWorld::RefIdData::searchId (
const std::string& id) const
{
std::string id2 = Misc::StringUtils::lowerCase (id);
std::map<std::string, std::pair<int, UniversalId::Type> >::const_iterator iter = mIndex.find (id2);
if (iter==mIndex.end())
return std::make_pair (-1, CSMWorld::UniversalId::Type_None);
return iter->second;
}
void CSMWorld::RefIdData::erase (int index, int count)
{
LocalIndex localIndex = globalToLocalIndex (index);
std::map<UniversalId::Type, RefIdDataContainerBase *>::const_iterator iter =
mRecordContainers.find (localIndex.second);
while (count>0 && iter!=mRecordContainers.end())
{
int size = iter->second->getSize();
if (localIndex.first+count>size)
{
erase (localIndex, size-localIndex.first);
count -= size-localIndex.first;
++iter;
if (iter==mRecordContainers.end())
throw std::runtime_error ("invalid count value for erase operation");
localIndex.first = 0;
localIndex.second = iter->first;
}
else
{
erase (localIndex, count);
count = 0;
}
}
}
const CSMWorld::RecordBase& CSMWorld::RefIdData::getRecord (const LocalIndex& index) const
{
std::map<UniversalId::Type, RefIdDataContainerBase *>::const_iterator iter =
mRecordContainers.find (index.second);
if (iter==mRecordContainers.end())
throw std::logic_error ("invalid local index type");
return iter->second->getRecord (index.first);
}
CSMWorld::RecordBase& CSMWorld::RefIdData::getRecord (const LocalIndex& index)
{
std::map<UniversalId::Type, RefIdDataContainerBase *>::iterator iter =
mRecordContainers.find (index.second);
if (iter==mRecordContainers.end())
throw std::logic_error ("invalid local index type");
return iter->second->getRecord (index.first);
}
void CSMWorld::RefIdData::appendRecord (UniversalId::Type type, const std::string& id)
{
std::map<UniversalId::Type, RefIdDataContainerBase *>::iterator iter =
mRecordContainers.find (type);
if (iter==mRecordContainers.end())
throw std::logic_error ("invalid local index type");
iter->second->appendRecord (id);
mIndex.insert (std::make_pair (Misc::StringUtils::lowerCase (id),
LocalIndex (iter->second->getSize()-1, type)));
}
int CSMWorld::RefIdData::getAppendIndex (UniversalId::Type type) const
{
int index = 0;
for (std::map<UniversalId::Type, RefIdDataContainerBase *>::const_iterator iter (
mRecordContainers.begin()); iter!=mRecordContainers.end(); ++iter)
{
index += iter->second->getSize();
if (type==iter->first)
break;
}
return index;
}
void CSMWorld::RefIdData::load (const LocalIndex& index, ESM::ESMReader& reader, bool base)
{
std::map<UniversalId::Type, RefIdDataContainerBase *>::iterator iter =
mRecordContainers.find (index.second);
if (iter==mRecordContainers.end())
throw std::logic_error ("invalid local index type");
iter->second->load (index.first, reader, base);
}
void CSMWorld::RefIdData::erase (const LocalIndex& index, int count)
{
std::map<UniversalId::Type, RefIdDataContainerBase *>::iterator iter =
mRecordContainers.find (index.second);
if (iter==mRecordContainers.end())
throw std::logic_error ("invalid local index type");
for (int i=index.first; i<index.first+count; ++i)
{
std::map<std::string, LocalIndex>::iterator result =
mIndex.find (Misc::StringUtils::lowerCase (iter->second->getId (i)));
if (result!=mIndex.end())
mIndex.erase (result);
}
iter->second->erase (index.first, count);
}
int CSMWorld::RefIdData::getSize() const
{
return mIndex.size();
}

View file

@ -0,0 +1,188 @@
#ifndef CSM_WOLRD_REFIDDATA_H
#define CSM_WOLRD_REFIDDATA_H
#include <vector>
#include <map>
#include <components/esm/loadacti.hpp>
#include <components/esm/loadalch.hpp>
#include <components/esm/loadappa.hpp>
#include <components/esm/loadarmo.hpp>
#include <components/esm/loadbook.hpp>
#include <components/esm/loadclot.hpp>
#include <components/esm/loadcont.hpp>
#include <components/esm/loadcrea.hpp>
#include <components/esm/loaddoor.hpp>
#include <components/esm/loadingr.hpp>
#include <components/esm/loadlevlist.hpp>
#include <components/esm/loadligh.hpp>
#include <components/esm/loadlock.hpp>
#include <components/esm/loadprob.hpp>
#include <components/esm/loadrepa.hpp>
#include <components/esm/loadstat.hpp>
#include <components/esm/loadweap.hpp>
#include <components/esm/loadnpc.hpp>
#include <components/esm/loadmisc.hpp>
#include "record.hpp"
#include "universalid.hpp"
namespace ESM
{
class ESMReader;
}
namespace CSMWorld
{
struct RefIdDataContainerBase
{
virtual ~RefIdDataContainerBase();
virtual int getSize() const = 0;
virtual const RecordBase& getRecord (int index) const = 0;
virtual RecordBase& getRecord (int index)= 0;
virtual void appendRecord (const std::string& id) = 0;
virtual void load (int index, ESM::ESMReader& reader, bool base) = 0;
virtual void erase (int index, int count) = 0;
virtual std::string getId (int index) const = 0;
};
template<typename RecordT>
struct RefIdDataContainer : public RefIdDataContainerBase
{
std::vector<Record<RecordT> > mContainer;
virtual int getSize() const;
virtual const RecordBase& getRecord (int index) const;
virtual RecordBase& getRecord (int index);
virtual void appendRecord (const std::string& id);
virtual void load (int index, ESM::ESMReader& reader, bool base);
virtual void erase (int index, int count);
virtual std::string getId (int index) const;
};
template<typename RecordT>
int RefIdDataContainer<RecordT>::getSize() const
{
return static_cast<int> (mContainer.size());
}
template<typename RecordT>
const RecordBase& RefIdDataContainer<RecordT>::getRecord (int index) const
{
return mContainer.at (index);
}
template<typename RecordT>
RecordBase& RefIdDataContainer<RecordT>::getRecord (int index)
{
return mContainer.at (index);
}
template<typename RecordT>
void RefIdDataContainer<RecordT>::appendRecord (const std::string& id)
{
Record<RecordT> record;
record.mModified.mId = id;
record.mModified.blank();
record.mState = RecordBase::State_ModifiedOnly;
mContainer.push_back (record);
}
template<typename RecordT>
void RefIdDataContainer<RecordT>::load (int index, ESM::ESMReader& reader, bool base)
{
(base ? mContainer.at (index).mBase : mContainer.at (index).mModified).load (reader);
}
template<typename RecordT>
void RefIdDataContainer<RecordT>::erase (int index, int count)
{
if (index<0 || index+count>=getSize())
throw std::runtime_error ("invalid RefIdDataContainer index");
mContainer.erase (mContainer.begin()+index, mContainer.begin()+index+count);
}
template<typename RecordT>
std::string RefIdDataContainer<RecordT>::getId (int index) const
{
return mContainer.at (index).get().mId;
}
class RefIdData
{
public:
typedef std::pair<int, UniversalId::Type> LocalIndex;
private:
RefIdDataContainer<ESM::Activator> mActivators;
RefIdDataContainer<ESM::Potion> mPotions;
RefIdDataContainer<ESM::Apparatus> mApparati;
RefIdDataContainer<ESM::Armor> mArmors;
RefIdDataContainer<ESM::Book> mBooks;
RefIdDataContainer<ESM::Clothing> mClothing;
RefIdDataContainer<ESM::Container> mContainers;
RefIdDataContainer<ESM::Creature> mCreatures;
RefIdDataContainer<ESM::Door> mDoors;
RefIdDataContainer<ESM::Ingredient> mIngredients;
RefIdDataContainer<ESM::CreatureLevList> mCreatureLevelledLists;
RefIdDataContainer<ESM::ItemLevList> mItemLevelledLists;
RefIdDataContainer<ESM::Light> mLights;
RefIdDataContainer<ESM::Lockpick> mLockpicks;
RefIdDataContainer<ESM::Miscellaneous> mMiscellaneous;
RefIdDataContainer<ESM::NPC> mNpcs;
RefIdDataContainer<ESM::Probe> mProbes;
RefIdDataContainer<ESM::Repair> mRepairs;
RefIdDataContainer<ESM::Static> mStatics;
RefIdDataContainer<ESM::Weapon> mWeapons;
std::map<std::string, LocalIndex> mIndex;
std::map<UniversalId::Type, RefIdDataContainerBase *> mRecordContainers;
void erase (const LocalIndex& index, int count);
///< Must not spill over into another type.
public:
RefIdData();
LocalIndex globalToLocalIndex (int index) const;
int localToGlobalIndex (const LocalIndex& index) const;
LocalIndex searchId (const std::string& id) const;
void erase (int index, int count);
const RecordBase& getRecord (const LocalIndex& index) const;
RecordBase& getRecord (const LocalIndex& index);
void appendRecord (UniversalId::Type type, const std::string& id);
int getAppendIndex (UniversalId::Type type) const;
void load (const LocalIndex& index, ESM::ESMReader& reader, bool base);
int getSize() const;
};
}
#endif

View file

@ -0,0 +1,22 @@
#include "scriptcontext.hpp"
bool CSMWorld::ScriptContext::canDeclareLocals() const
{
return false;
}
char CSMWorld::ScriptContext::getGlobalType (const std::string& name) const
{
return ' ';
}
char CSMWorld::ScriptContext::getMemberType (const std::string& name, const std::string& id) const
{
return ' ';
}
bool CSMWorld::ScriptContext::isId (const std::string& name) const
{
return false;
}

View file

@ -0,0 +1,26 @@
#ifndef CSM_WORLD_SCRIPTCONTEXT_H
#define CSM_WORLD_SCRIPTCONTEXT_H
#include <components/compiler/context.hpp>
namespace CSMWorld
{
class ScriptContext : public Compiler::Context
{
public:
virtual bool canDeclareLocals() const;
///< Is the compiler allowed to declare local variables?
virtual char getGlobalType (const std::string& name) const;
///< 'l: long, 's': short, 'f': float, ' ': does not exist.
virtual char getMemberType (const std::string& name, const std::string& id) const;
///< 'l: long, 's': short, 'f': float, ' ': does not exist.
virtual bool isId (const std::string& name) const;
///< Does \a name match an ID, that can be referenced?
};
}
#endif

View file

@ -21,6 +21,16 @@ namespace
{ CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Gmsts, "Game Settings" },
{ CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Skills, "Skills" },
{ CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Classes, "Classes" },
{ CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Factions, "Factions" },
{ CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Races, "Races" },
{ CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Sounds, "Sounds" },
{ CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Scripts, "Scripts" },
{ CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Regions, "Regions" },
{ CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Birthsigns, "Birthsigns" },
{ CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Spells, "Spells" },
{ CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Cells, "Cells" },
{ CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Referenceables,
"Referenceables" },
{ CSMWorld::UniversalId::Class_None, CSMWorld::UniversalId::Type_None, 0 } // end marker
};
@ -31,6 +41,38 @@ namespace
{ CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Gmst, "Game Setting" },
{ CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Skill, "Skill" },
{ CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Class, "Class" },
{ CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Faction, "Faction" },
{ CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Race, "Race" },
{ CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Sound, "Sound" },
{ CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Script, "Script" },
{ CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Region, "Region" },
{ CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Birthsign, "Birthsign" },
{ CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Spell, "Spell" },
{ CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Cell, "Cell" },
{ CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Referenceable, "Referenceables" },
{ CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Activator, "Activator" },
{ CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Potion, "Potion" },
{ CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Apparatus, "Apparatus" },
{ CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Armor, "Armor" },
{ CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Book, "Book" },
{ CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Clothing, "Clothing" },
{ CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Container, "Container" },
{ CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Creature, "Creature" },
{ CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Door, "Door" },
{ CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Ingredient, "Ingredient" },
{ CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_CreatureLevelledList,
"Creature Levelled List" },
{ CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_ItemLevelledList,
"Item Levelled List" },
{ CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Light, "Light" },
{ CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Lockpick, "Lockpick" },
{ CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Miscellaneous,
"Miscellaneous" },
{ CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Npc, "NPC" },
{ CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Probe, "Probe" },
{ CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Repair, "Repair" },
{ CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Static, "Static" },
{ CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Weapon, "Weapon" },
{ CSMWorld::UniversalId::Class_None, CSMWorld::UniversalId::Type_None, 0 } // end marker
};
@ -51,44 +93,41 @@ CSMWorld::UniversalId::UniversalId (const std::string& universalId)
{
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;
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 (index+2);
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 (index+2));
if (stream >> mIndex)
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;
}
}
break;
}
}
else
{
for (int i=0; sNoArg[i].mName; ++i)
if (universalId==sNoArg[i].mName)
{
mArgumentType = ArgumentType_None;
mType = sNoArg[i].mType;
mClass = sNoArg[i].mClass;
return;
}
}
throw std::runtime_error ("invalid UniversalId: " + universalId);

View file

@ -41,7 +41,46 @@ namespace CSMWorld
Type_Skills,
Type_Skill,
Type_Classes,
Type_Class
Type_Class,
Type_Factions,
Type_Faction,
Type_Races,
Type_Race,
Type_Sounds,
Type_Sound,
Type_Scripts,
Type_Script,
Type_Regions,
Type_Region,
Type_Birthsigns,
Type_Birthsign,
Type_Spells,
Type_Spell,
Type_Cells,
Type_Cell,
Type_Referenceables,
Type_Referenceable,
Type_Activator,
Type_Potion,
Type_Apparatus,
Type_Armor,
Type_Book,
Type_Clothing,
Type_Container,
Type_Creature,
Type_Door,
Type_Ingredient,
Type_CreatureLevelledList,
Type_ItemLevelledList,
Type_Light,
Type_Lockpick,
Type_Miscellaneous,
Type_Npc,
Type_Probe,
Type_Repair,
Type_Static,
Type_Weapon
};
private:

View file

@ -0,0 +1,6 @@
#include "ocspropertywidget.hpp"
OcsPropertyWidget::OcsPropertyWidget(QObject *parent) :
QObject(parent)
{
}

View file

@ -0,0 +1,18 @@
#ifndef OCSPROPERTYWIDGET_HPP
#define OCSPROPERTYWIDGET_HPP
#include <QObject>
class OcsPropertyWidget : public QObject
{
Q_OBJECT
public:
explicit OcsPropertyWidget(QObject *parent = 0);
signals:
public slots:
};
#endif // OCSPROPERTYWIDGET_HPP

View file

@ -1,8 +1,11 @@
#include "startup.hpp"
#include <QApplication>
#include <QDesktopWidget>
#include <QPushButton>
#include <QHBoxLayout>
#include <QRect>
CSVDoc::StartupDialogue::StartupDialogue()
{
@ -17,4 +20,8 @@ CSVDoc::StartupDialogue::StartupDialogue()
layout->addWidget (loadDocument);
setLayout (layout);
}
QRect scr = QApplication::desktop()->screenGeometry();
QRect rect = geometry();
move (scr.center().x() - rect.center().x(), scr.center().y() - rect.center().y());
}

View file

@ -1,5 +1,6 @@
#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
@ -15,3 +16,7 @@ CSMWorld::UniversalId CSVDoc::SubView::getUniversalId() const
{
return mUniversalId;
}
void CSVDoc::SubView::updateEditorSetting (const QString &settingName, const QString &settingValue)
{
}

View file

@ -35,6 +35,7 @@ namespace CSVDoc
CSMWorld::UniversalId getUniversalId() const;
virtual void setEditLock (bool locked) = 0;
virtual void updateEditorSetting (const QString &, const QString &);
signals:
@ -42,4 +43,4 @@ namespace CSVDoc
};
}
#endif
#endif

View file

@ -10,11 +10,9 @@
#include <QtGui/QApplication>
#include "../../model/doc/document.hpp"
#include "../world/subviews.hpp"
#include "../tools/subviews.hpp"
#include "../settings/usersettingsdialog.hpp"
#include "viewmanager.hpp"
#include "operations.hpp"
#include "subview.hpp"
@ -41,6 +39,10 @@ void CSVDoc::View::setupFileMenu()
connect (mSave, SIGNAL (triggered()), this, SLOT (save()));
file->addAction (mSave);
mVerify = new QAction (tr ("&Verify"), this);
connect (mVerify, SIGNAL (triggered()), this, SLOT (verify()));
file->addAction (mVerify);
QAction *close = new QAction (tr ("&Close"), this);
connect (close, SIGNAL (triggered()), this, SLOT (close()));
file->addAction(close);
@ -63,6 +65,10 @@ void CSVDoc::View::setupEditMenu()
mRedo= mDocument->getUndoStack().createRedoAction (this, tr("&Redo"));
mRedo->setShortcuts (QKeySequence::Redo);
edit->addAction (mRedo);
QAction *userSettings = new QAction (tr ("&Preferences"), this);
connect (userSettings, SIGNAL (triggered()), this, SLOT (showUserSettings()));
edit->addAction (userSettings);
}
void CSVDoc::View::setupViewMenu()
@ -94,9 +100,42 @@ void CSVDoc::View::setupWorldMenu()
connect (classes, SIGNAL (triggered()), this, SLOT (addClassesSubView()));
world->addAction (classes);
mVerify = new QAction (tr ("&Verify"), this);
connect (mVerify, SIGNAL (triggered()), this, SLOT (verify()));
world->addAction (mVerify);
QAction *factions = new QAction (tr ("Factions"), this);
connect (factions, SIGNAL (triggered()), this, SLOT (addFactionsSubView()));
world->addAction (factions);
QAction *races = new QAction (tr ("Races"), this);
connect (races, SIGNAL (triggered()), this, SLOT (addRacesSubView()));
world->addAction (races);
QAction *sounds = new QAction (tr ("Sounds"), this);
connect (sounds, SIGNAL (triggered()), this, SLOT (addSoundsSubView()));
world->addAction (sounds);
QAction *scripts = new QAction (tr ("Scripts"), this);
connect (scripts, SIGNAL (triggered()), this, SLOT (addScriptsSubView()));
world->addAction (scripts);
QAction *regions = new QAction (tr ("Regions"), this);
connect (regions, SIGNAL (triggered()), this, SLOT (addRegionsSubView()));
world->addAction (regions);
QAction *birthsigns = new QAction (tr ("Birthsigns"), this);
connect (birthsigns, SIGNAL (triggered()), this, SLOT (addBirthsignsSubView()));
world->addAction (birthsigns);
QAction *spells = new QAction (tr ("Spells"), this);
connect (spells, SIGNAL (triggered()), this, SLOT (addSpellsSubView()));
world->addAction (spells);
QAction *cells = new QAction (tr ("Cells"), this);
connect (cells, SIGNAL (triggered()), this, SLOT (addCellsSubView()));
world->addAction (cells);
QAction *referenceables = new QAction (tr ("Referenceables"), this);
connect (referenceables, SIGNAL (triggered()), this, SLOT (addReferenceablesSubView()));
world->addAction (referenceables);
}
void CSVDoc::View::setupUi()
@ -140,7 +179,13 @@ CSVDoc::View::View (ViewManager& viewManager, CSMDoc::Document *document, int to
: mViewManager (viewManager), mDocument (document), mViewIndex (totalViews-1),
mViewTotal (totalViews)
{
resize (300, 300); /// \todo get default size from settings and set reasonable minimal size
QString width = CSMSettings::UserSettings::instance().getSetting(QString("Window Size"), QString("Width"));
QString height = CSMSettings::UserSettings::instance().getSetting(QString("Window Size"), QString("Height"));
if(width==QString() || height==QString())
resize(800, 600);
else
resize (width.toInt(), height.toInt());
mSubViewWindow.setDockOptions (QMainWindow::AllowNestedDocks);
@ -219,11 +264,14 @@ void CSVDoc::View::addSubView (const CSMWorld::UniversalId& id)
/// \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);
view->setObjectName ("subview");
mSubViewWindow.addDockWidget (Qt::TopDockWidgetArea, view);
connect (view, SIGNAL (focusId (const CSMWorld::UniversalId&)), this,
SLOT (addSubView (const CSMWorld::UniversalId&)));
CSMSettings::UserSettings::instance().updateSettings("Editor", "Record Status Display");
view->show();
}
@ -262,6 +310,51 @@ void CSVDoc::View::addClassesSubView()
addSubView (CSMWorld::UniversalId::Type_Classes);
}
void CSVDoc::View::addFactionsSubView()
{
addSubView (CSMWorld::UniversalId::Type_Factions);
}
void CSVDoc::View::addRacesSubView()
{
addSubView (CSMWorld::UniversalId::Type_Races);
}
void CSVDoc::View::addSoundsSubView()
{
addSubView (CSMWorld::UniversalId::Type_Sounds);
}
void CSVDoc::View::addScriptsSubView()
{
addSubView (CSMWorld::UniversalId::Type_Scripts);
}
void CSVDoc::View::addRegionsSubView()
{
addSubView (CSMWorld::UniversalId::Type_Regions);
}
void CSVDoc::View::addBirthsignsSubView()
{
addSubView (CSMWorld::UniversalId::Type_Birthsigns);
}
void CSVDoc::View::addSpellsSubView()
{
addSubView (CSMWorld::UniversalId::Type_Spells);
}
void CSVDoc::View::addCellsSubView()
{
addSubView (CSMWorld::UniversalId::Type_Cells);
}
void CSVDoc::View::addReferenceablesSubView()
{
addSubView (CSMWorld::UniversalId::Type_Referenceables);
}
void CSVDoc::View::abortOperation (int type)
{
mDocument->abortOperation (type);
@ -277,3 +370,39 @@ void CSVDoc::View::exit()
{
emit exitApplicationRequest (this);
}
void CSVDoc::View::showUserSettings()
{
CSVSettings::UserSettingsDialog *settingsDialog = new CSVSettings::UserSettingsDialog(this);
settingsDialog->show();
}
void CSVDoc::View::resizeViewWidth (int width)
{
if (width >= 0)
resize (width, geometry().height());
}
void CSVDoc::View::resizeViewHeight (int height)
{
if (height >= 0)
resize (geometry().width(), height);
}
void CSVDoc::View::updateEditorSetting (const QString &settingName, const QString &settingValue)
{
if (settingName == "Record Status Display")
{
foreach (QObject *view, mSubViewWindow.children())
{
if (view->objectName() == "subview")
dynamic_cast<CSVDoc::SubView *>(view)->updateEditorSetting (settingName, settingValue);
}
}
else if (settingName == "Width")
resizeViewWidth (settingValue.toInt());
else if (settingName == "Height")
resizeViewHeight (settingValue.toInt());
}

View file

@ -68,6 +68,14 @@ namespace CSVDoc
void exitApplication();
void loadUserSettings();
/// User preference function
void resizeViewWidth (int width);
/// User preference function
void resizeViewHeight (int height);
public:
View (ViewManager& viewManager, CSMDoc::Document *document, int totalViews);
@ -88,6 +96,9 @@ namespace CSVDoc
Operations *getOperations() const;
/// Function called by view manager when user preferences are updated
void updateEditorSetting (const QString &, const QString &);
signals:
void newDocumentRequest();
@ -119,6 +130,26 @@ namespace CSVDoc
void addSkillsSubView();
void addClassesSubView();
void addFactionsSubView();
void addRacesSubView();
void addSoundsSubView();
void addScriptsSubView();
void addRegionsSubView();
void addBirthsignsSubView();
void addSpellsSubView();
void addCellsSubView();
void addReferenceablesSubView();
void showUserSettings();
};
}

View file

@ -3,19 +3,23 @@
#include <map>
#include <QApplication>
#include <QDesktopWidget>
#include "../../model/doc/documentmanager.hpp"
#include "../../model/doc/document.hpp"
#include "../world/util.hpp"
#include "../world/enumdelegate.hpp"
#include "../world/vartypedelegate.hpp"
#include "../world/recordstatusdelegate.hpp"
#include "../settings/usersettingsdialog.hpp"
#include "view.hpp"
#include <QMessageBox>
#include <QPushButton>
#include <QtGui/QApplication>
#include <QDebug>
void CSVDoc::ViewManager::updateIndices()
{
@ -49,6 +53,40 @@ CSVDoc::ViewManager::ViewManager (CSMDoc::DocumentManager& documentManager)
"Luck", 0
};
static const char *sSpellTypes[] =
{
"Spell", "Ability", "Blight", "Disease", "Curse", "Power", 0
};
static const char *sApparatusTypes[] =
{
"Mortar & Pestle", "Albemic", "Calcinator", "Retort", 0
};
static const char *sArmorTypes[] =
{
"Helmet", "Cuirass", "Left Pauldron", "Right Pauldron", "Greaves", "Boots", "Left Gauntlet",
"Right Gauntlet", "Shield", "Left Bracer", "Right Bracer", 0
};
static const char *sClothingTypes[] =
{
"Pants", "Shoes", "Shirt", "Belt", "Robe", "Right Glove", "Left Glove", "Skirt", "Ring",
"Amulet", 0
};
static const char *sCreatureTypes[] =
{
"Creature", "Deadra", "Undead", "Humanoid", 0
};
static const char *sWeaponTypes[] =
{
"Short Blade 1H", "Long Blade 1H", "Long Blade 2H", "Blunt 1H", "Blunt 2H Close",
"Blunt 2H Wide", "Spear 2H", "Axe 1H", "Axe 2H", "Bow", "Crossbow", "Thrown", "Arrow",
"Bolt", 0
};
mDelegateFactories = new CSVWorld::CommandDelegateFactoryCollection;
mDelegateFactories->add (CSMWorld::ColumnBase::Display_GmstVarType,
@ -61,7 +99,31 @@ CSVDoc::ViewManager::ViewManager (CSMDoc::DocumentManager& documentManager)
new CSVWorld::EnumDelegateFactory (sSpecialisations));
mDelegateFactories->add (CSMWorld::ColumnBase::Display_Attribute,
new CSVWorld::EnumDelegateFactory (sAttributes));
new CSVWorld::EnumDelegateFactory (sAttributes, true));
mDelegateFactories->add (CSMWorld::ColumnBase::Display_SpellType,
new CSVWorld::EnumDelegateFactory (sSpellTypes));
mDelegateFactories->add (CSMWorld::ColumnBase::Display_ApparatusType,
new CSVWorld::EnumDelegateFactory (sApparatusTypes));
mDelegateFactories->add (CSMWorld::ColumnBase::Display_ArmorType,
new CSVWorld::EnumDelegateFactory (sArmorTypes));
mDelegateFactories->add (CSMWorld::ColumnBase::Display_ClothingType,
new CSVWorld::EnumDelegateFactory (sClothingTypes));
mDelegateFactories->add (CSMWorld::ColumnBase::Display_CreatureType,
new CSVWorld::EnumDelegateFactory (sCreatureTypes));
mDelegateFactories->add (CSMWorld::ColumnBase::Display_WeaponType,
new CSVWorld::EnumDelegateFactory (sWeaponTypes));
mDelegateFactories->add (CSMWorld::ColumnBase::Display_RecordState,
new CSVWorld::RecordStatusDelegateFactory() );
connect (&CSMSettings::UserSettings::instance(), SIGNAL (signalUpdateEditorSetting (const QString &, const QString &)),
this, SLOT (slotUpdateEditorSetting (const QString &, const QString &)));
}
CSVDoc::ViewManager::~ViewManager()
@ -288,3 +350,13 @@ void CSVDoc::ViewManager::exitApplication (CSVDoc::View *view)
if (notifySaveOnClose (view))
QApplication::instance()->exit();
}
void CSVDoc::ViewManager::slotUpdateEditorSetting (const QString &settingName, const QString &settingValue)
{
if (settingName == "Record Status Display" ||
settingName == "Width" || settingName == "Height")
{
foreach (CSVDoc::View *view, mViews)
view->updateEditorSetting (settingName, settingValue);
}
}

View file

@ -72,6 +72,9 @@ namespace CSVDoc
void progress (int current, int max, int type, int threads, CSMDoc::Document *document);
void onExitWarningHandler(int state, CSMDoc::Document* document);
/// connected to update signal in UserSettings
void slotUpdateEditorSetting (const QString &, const QString &);
};
}

View file

@ -0,0 +1,112 @@
#include "abstractblock.hpp"
CSVSettings::AbstractBlock::AbstractBlock(QWidget* parent)
: QObject (parent), mBox ( new GroupBox (parent) ), mWidgetParent (parent)
{}
CSVSettings::AbstractBlock::AbstractBlock(bool isVisible, QWidget* parent)
: QObject (parent), mBox ( new GroupBox (isVisible, parent)), mWidgetParent (parent)
{}
QLayout *CSVSettings::AbstractBlock::createLayout (Orientation direction,
bool isZeroMargin, QWidget* parent)
{
QLayout *layout = 0;
if (direction == Orient_Vertical)
layout = new QVBoxLayout (parent);
else
layout = new QHBoxLayout (parent);
if (isZeroMargin)
layout->setContentsMargins(0, 0, 0, 0);
return layout;
}
QGroupBox *CSVSettings::AbstractBlock::getGroupBox()
{
return mBox;
}
CSVSettings::AbstractWidget *CSVSettings::AbstractBlock::buildWidget (const QString& widgetName, WidgetDef &def,
QLayout *layout, bool isConnected) const
{
AbstractWidget *widg = 0;
switch (def.type)
{
case Widget_RadioButton:
widg = new SettingWidget<QRadioButton> (def, layout, mBox);
break;
case Widget_SpinBox:
widg = new SettingWidget<QSpinBox> (def, layout, mBox);
break;
case Widget_CheckBox:
widg = new SettingWidget<QCheckBox> (def, layout, mBox);
break;
case Widget_LineEdit:
widg = new SettingWidget<QLineEdit> (def, layout, mBox);
break;
case Widget_ListBox:
widg = new SettingWidget<QListWidget> (def, layout, mBox);
break;
case Widget_ComboBox:
widg = new SettingWidget<QComboBox> (def, layout, mBox);
break;
default:
break;
};
if (!mBox->layout())
mBox->setLayout(widg->getLayout());
widg->widget()->setObjectName(widgetName);
if (isConnected)
connect (widg, SIGNAL (signalUpdateItem (const QString &)), this, SLOT (slotUpdate (const QString &)));
connect (this, SIGNAL (signalUpdateWidget (const QString &)), widg, SLOT (slotUpdateWidget (const QString &) ));
return widg;
}
void CSVSettings::AbstractBlock::setVisible (bool isVisible)
{
mBox->setBorderVisibility (isVisible);
}
bool CSVSettings::AbstractBlock::isVisible () const
{
return mBox->borderVisibile();
}
QWidget *CSVSettings::AbstractBlock::getParent() const
{
return mWidgetParent;
}
void CSVSettings::AbstractBlock::slotUpdate (const QString &value)
{
slotUpdateSetting (objectName(), value);
}
void CSVSettings::AbstractBlock::slotSetEnabled(bool value)
{
mBox->setEnabled(value);
}
void CSVSettings::AbstractBlock::slotUpdateSetting (const QString &settingName, const QString &settingValue)
{
bool doEmit = true;
updateBySignal (settingName, settingValue, doEmit);
if (doEmit)
emit signalUpdateSetting (settingName, settingValue);
}

View file

@ -0,0 +1,82 @@
#ifndef ABSTRACTBLOCK_HPP
#define ABSTRACTBLOCK_HPP
#include <QObject>
#include <QList>
#include "settingwidget.hpp"
#include "../../model/settings/settingsitem.hpp"
#include "groupbox.hpp"
namespace CSVSettings
{
/// Abstract base class for all blocks
class AbstractBlock : public QObject
{
Q_OBJECT
protected:
typedef QMap<QString, CSMSettings::SettingsItem*> SettingsItemMap;
GroupBox *mBox;
QWidget *mWidgetParent;
public:
explicit AbstractBlock (QWidget *parent = 0);
explicit AbstractBlock (bool isVisible, QWidget *parent = 0);
QGroupBox *getGroupBox();
void setVisible (bool isVisible);
bool isVisible() const;
virtual CSMSettings::SettingList *getSettings() = 0;
/// update settings found in the passed map and are encapsulated by the block
virtual bool updateSettings (const CSMSettings::SettingMap &settings) = 0;
/// update callback function called from update slot
/// used for updating application-level settings in the editor
virtual bool updateBySignal (const QString &name, const QString &value, bool &doEmit)
{ return false; }
protected:
/// Creates the layout which for the blocks QGroupBox
QLayout *createLayout (Orientation direction, bool isZeroMargin, QWidget* parent = 0);
/// Creates widgets that exist as direct children of the block
AbstractWidget *buildWidget (const QString &widgetName, WidgetDef &wDef,
QLayout *layout = 0, bool isConnected = true) const;
QWidget *getParent() const;
public slots:
/// enables / disables block-level widgets based on signals from other widgets
/// used in ToggleBlock
void slotSetEnabled (bool value);
/// receives updates to applicaion-level settings in the Editor
void slotUpdateSetting (const QString &settingName, const QString &settingValue);
private slots:
/// receives updates to a setting in the block pushed from the application level
void slotUpdate (const QString &value);
signals:
/// signal to UserSettings instance
void signalUpdateSetting (const QString &propertyName, const QString &propertyValue);
/// signal to widget for updating widget value
void signalUpdateWidget (const QString & value);
/// ProxyBlock use only.
/// Name and value correspond to settings for which the block is a proxy.
void signalUpdateProxySetting (const QString &propertyName, const QString &propertyValue);
};
}
#endif // ABSTRACTBLOCK_HPP

View file

@ -0,0 +1,44 @@
#include "abstractpage.hpp"
#include <QGroupBox>
#include <QLabel>
#include <QVBoxLayout>
#include <QRadioButton>
#include <QCheckBox>
#include <QSpinBox>
#include <QComboBox>
#include <QLineEdit>
#include <QMargins>
CSVSettings::AbstractPage::AbstractPage(QWidget *parent):
QWidget(parent)
{
QGridLayout *pageLayout = new QGridLayout(this);
setLayout (pageLayout);
}
CSVSettings::AbstractPage::AbstractPage(const QString &pageName, QWidget *parent):
QWidget(parent)
{
QWidget::setObjectName (pageName);
QGridLayout *pageLayout = new QGridLayout(this);
setLayout (pageLayout);
}
CSVSettings::AbstractPage::~AbstractPage()
{
}
CSMSettings::SettingList *CSVSettings::AbstractPage::getSettings()
{
CSMSettings::SettingList *settings = new CSMSettings::SettingList();
foreach (AbstractBlock *block, mAbstractBlocks)
{
CSMSettings::SettingList *groupSettings = block->getSettings();
settings->append (*groupSettings);
}
return settings;
}

View file

@ -0,0 +1,70 @@
#ifndef ABSTRACTPAGE_HPP
#define ABSTRACTPAGE_HPP
#include <QWidget>
#include <QList>
#include <QLayout>
#include "abstractblock.hpp"
class SettingMap;
class SettingList;
namespace CSVSettings {
typedef QList<AbstractBlock *> AbstractBlockList;
/// Abstract base class for all setting pages in the dialog
/// \todo Scripted implementation of settings should eliminate the need
/// \todo derive page classes.
/// \todo AbstractPage should be replaced with a general page construction class.
class AbstractPage: public QWidget
{
protected:
AbstractBlockList mAbstractBlocks;
public:
AbstractPage(QWidget *parent = 0);
AbstractPage (const QString &pageName, QWidget* parent = 0);
~AbstractPage();
virtual void setupUi() = 0;
/// triggers widgiet initialization at the page level. All widgets updated to
/// current setting values
virtual void initializeWidgets (const CSMSettings::SettingMap &settings) = 0;
/// retrieve the list of settings local to the page.
CSMSettings::SettingList *getSettings();
void setObjectName();
protected:
/// Create a block for the page.
/// Block is constructed using passed definition struct
/// Page level-layout is created and assigned
template <typename S, typename T>
AbstractBlock *buildBlock (T *def)
{
S *block = new S (this);
int ret = block->build (def);
if (ret < 0)
return 0;
QGroupBox *box = block->getGroupBox();
QWidget::layout()->addWidget (box);
return block;
}
};
}
#endif // ABSTRACTPAGE_HPP

View file

@ -0,0 +1,78 @@
#include "abstractwidget.hpp"
#include <QLayout>
#include <QLabel>
void CSVSettings::AbstractWidget::build(QWidget *widget, WidgetDef &def, bool noLabel)
{
if (!mLayout)
createLayout(def.orientation, true);
buildLabelAndWidget (widget, def, noLabel);
}
void CSVSettings::AbstractWidget::buildLabelAndWidget (QWidget *widget, WidgetDef &def, bool noLabel)
{
if (def.widgetWidth > -1)
widget->setFixedWidth (def.widgetWidth);
if (!(def.caption.isEmpty() || noLabel) )
{
QLabel *label = new QLabel (def.caption, dynamic_cast<QWidget*>(parent()));
label->setBuddy (widget);
mLayout->addWidget (label);
if (def.labelWidth > -1)
label->setFixedWidth(def.labelWidth);
}
mLayout->addWidget (widget);
mLayout->setAlignment (widget, getAlignment (def.widgetAlignment));
}
void CSVSettings::AbstractWidget::createLayout
(Orientation direction, bool isZeroMargin)
{
if (direction == Orient_Vertical)
mLayout = new QVBoxLayout ();
else
mLayout = new QHBoxLayout ();
if (isZeroMargin)
mLayout->setContentsMargins(0, 0, 0, 0);
}
QFlags<Qt::AlignmentFlag> CSVSettings::AbstractWidget::getAlignment (CSVSettings::Alignment flag)
{
return QFlags<Qt::AlignmentFlag>(static_cast<int>(flag));
}
QLayout *CSVSettings::AbstractWidget::getLayout()
{
return mLayout;
}
void CSVSettings::AbstractWidget::slotUpdateWidget (const QString &value)
{
updateWidget (value);
}
void CSVSettings::AbstractWidget::slotUpdateItem(const QString &value)
{
emit signalUpdateItem (value);
}
void CSVSettings::AbstractWidget::slotUpdateItem(bool value)
{
if (value)
emit signalUpdateItem (widget()->objectName());
}
void CSVSettings::AbstractWidget::slotUpdateItem(int value)
{
emit signalUpdateItem (QString::number(value));
}
void CSVSettings::AbstractWidget::slotUpdateItem (QListWidgetItem* current, QListWidgetItem* previous)
{}

View file

@ -0,0 +1,69 @@
#ifndef ABSTRACTWIDGET_HPP
#define ABSTRACTWIDGET_HPP
#include <QWidget>
#include "support.hpp"
class QLayout;
namespace CSVSettings
{
/// Abstract base class for widgets which are used in user preferences dialog
class AbstractWidget : public QObject
{
Q_OBJECT
QLayout *mLayout;
public:
/// Passed layout is assigned the constructed widget.
/// if no layout is passed, one is created.
explicit AbstractWidget (QLayout *layout = 0, QWidget* parent = 0)
: QObject (parent), mLayout (layout)
{}
/// retrieve layout for insertion into itemblock
QLayout *getLayout();
/// create the derived widget instance
void build (QWidget* widget, WidgetDef &def, bool noLabel = false);
/// reference to the derived widget instance
virtual QWidget *widget() = 0;
protected:
/// Callback called by receiving slot for widget udpates
virtual void updateWidget (const QString &value) = 0;
/// Converts user-defined enum to Qt equivalents
QFlags<Qt::AlignmentFlag> getAlignment (Alignment flag);
private:
/// Creates layout and assigns label and widget as appropriate
void createLayout (Orientation direction, bool isZeroMargin);
/// Creates label and widget according to passed definition
void buildLabelAndWidget (QWidget *widget, WidgetDef &def, bool noLabel);
signals:
/// outbound update signal
void signalUpdateItem (const QString &value);
public slots:
/// receives inbound updates
void slotUpdateWidget (const QString &value);
/// Overloads for outbound updates from derived widget signal
void slotUpdateItem (const QString &value);
void slotUpdateItem (bool value);
void slotUpdateItem (int value);
void slotUpdateItem (QListWidgetItem* current, QListWidgetItem* previous);
};
}
#endif // ABSTRACTWIDGET_HPP

View file

@ -0,0 +1,50 @@
#include "blankpage.hpp"
#include <QList>
#include <QListView>
#include <QGroupBox>
#include <QRadioButton>
#include <QDockWidget>
#include <QVBoxLayout>
#include <QGridLayout>
#include <QStyle>
#ifdef Q_OS_MAC
#include <QPlastiqueStyle>
#endif
#include "../../model/settings/usersettings.hpp"
#include "groupblock.hpp"
#include "toggleblock.hpp"
CSVSettings::BlankPage::BlankPage(QWidget *parent):
AbstractPage("Blank", parent)
{
}
CSVSettings::BlankPage::BlankPage(const QString &title, QWidget *parent):
AbstractPage(title, parent)
{
// Hacks to get the stylesheet look properly
#ifdef Q_OS_MAC
QPlastiqueStyle *style = new QPlastiqueStyle;
//profilesComboBox->setStyle(style);
#endif
setupUi();
}
void CSVSettings::BlankPage::setupUi()
{
QGroupBox *pageBox = new QGroupBox(this);
layout()->addWidget(pageBox);
}
void CSVSettings::BlankPage::initializeWidgets (const CSMSettings::SettingMap &settings)
{
//iterate each item in each blocks in this section
//validate the corresponding setting against the defined valuelist if any.
foreach (AbstractBlock *block, mAbstractBlocks)
block->updateSettings (settings);
}

View file

@ -0,0 +1,28 @@
#ifndef BLANKPAGE_HPP
#define BLANKPAGE_HPP
#include "abstractpage.hpp"
class QGroupBox;
namespace CSVSettings {
class UserSettings;
class AbstractBlock;
/// Derived page with no widgets
/// Reference use only.
class BlankPage : public AbstractPage
{
public:
BlankPage (QWidget *parent = 0);
BlankPage (const QString &title, QWidget *parent);
void setupUi();
void initializeWidgets (const CSMSettings::SettingMap &settings);
};
}
#endif // BLANKPAGE_HPP

View file

@ -0,0 +1,121 @@
#include "customblock.hpp"
#include "groupblock.hpp"
#include "itemblock.hpp"
#include "proxyblock.hpp"
CSVSettings::CustomBlock::CustomBlock (QWidget *parent) : AbstractBlock (parent)
{
}
int CSVSettings::CustomBlock::build(GroupBlockDefList &defList, GroupBlockDefList::iterator *it)
{
int retVal = 0;
GroupBlockDefList::iterator defaultIt;
GroupBlockDefList::iterator listIt = defList.begin();
GroupBlockDefList::iterator proxyIt = defaultIt;
if (it)
listIt = *it;
ProxyBlock *proxyBlock = new ProxyBlock(getParent());
for (; listIt != defList.end(); ++listIt)
{
if (!(*listIt)->isProxy)
retVal = buildGroupBlock (*listIt);
else
{
mGroupList << proxyBlock;
proxyIt = listIt;
}
}
if (proxyIt != defaultIt)
retVal = buildProxyBlock (*proxyIt, proxyBlock);
return retVal;
}
CSVSettings::GroupBox *CSVSettings::CustomBlock::buildGroupBox (Orientation orientation)
{
GroupBox *box = new GroupBox (false, mBox);
createLayout (orientation, true, box);
return box;
}
int CSVSettings::CustomBlock::buildGroupBlock(GroupBlockDef *def)
{
GroupBlock *block = new GroupBlock (getParent());
mGroupList << block;
connect (block, SIGNAL (signalUpdateSetting(const QString &, const QString &)),
this, SLOT (slotUpdateSetting (const QString &, const QString &)));
return block->build(def);
}
int CSVSettings::CustomBlock::buildProxyBlock(GroupBlockDef *def, ProxyBlock *block)
{
if (def->settingItems.size() != 1)
return -1;
int retVal = block->build(def);
if (retVal != 0)
return retVal;
// The first settingItem is the proxy setting, containing the list of settings bound to it.
foreach (QStringList *list, *(def->settingItems.at(0)->proxyList))
{
QString proxiedBlockName = list->at(0);
//iterate each group in the custom block, matching it to each proxied setting
//and connecting it appropriately
foreach (GroupBlock *groupBlock, mGroupList)
{
ItemBlock *proxiedBlock = groupBlock->getItemBlock (proxiedBlockName);
if (proxiedBlock)
{
block->addSetting(proxiedBlock, list);
//connect the proxy block's update signal to the custom block's slot
connect (block, SIGNAL (signalUpdateSetting (const QString &, const QString &)),
this, SLOT (slotUpdateSetting (const QString &, const QString &)));
}
}
}
return 0;
}
CSMSettings::SettingList *CSVSettings::CustomBlock::getSettings()
{
CSMSettings::SettingList *settings = new CSMSettings::SettingList();
foreach (GroupBlock *block, mGroupList)
{
CSMSettings::SettingList *groupSettings = block->getSettings();
if (groupSettings)
settings->append(*groupSettings);
}
return settings;
}
bool CSVSettings::CustomBlock::updateSettings (const CSMSettings::SettingMap &settings)
{
bool success = true;
foreach (GroupBlock *block, mGroupList)
{
bool success2 = block->updateSettings (settings);
success = success && success2;
}
return success;
}

View file

@ -0,0 +1,47 @@
#ifndef CUSTOMBLOCK_HPP
#define CUSTOMBLOCK_HPP
#include "abstractblock.hpp"
namespace CSVSettings
{
class ProxyBlock;
/// Base class for customized user preference setting blocks
/// Special block classes should be derived from CustomBlock
class CustomBlock : public AbstractBlock
{
protected:
GroupBlockList mGroupList;
public:
explicit CustomBlock (QWidget *parent = 0);
/// Update settings local to the block
bool updateSettings (const CSMSettings::SettingMap &settings);
/// Retrieve settings local to the block
CSMSettings::SettingList *getSettings();
/// construct the block using the passed definition
int build (GroupBlockDefList &defList, GroupBlockDefList::Iterator *it = 0);
protected:
/// construct the block groupbox
GroupBox *buildGroupBox (Orientation orientation);
private:
/// Construction function for creating a standard GroupBlock child
int buildGroupBlock(GroupBlockDef *def);
/// Construction function for creating a standard ProxyBlock child
int buildProxyBlock(GroupBlockDef *def, ProxyBlock *block);
};
}
#endif // CUSTOMBLOCK_HPP

View file

@ -0,0 +1,53 @@
#include "editorpage.hpp"
#include "groupblock.hpp"
#include "../../model/settings/usersettings.hpp"
CSVSettings::EditorPage::EditorPage(QWidget* parent) :
AbstractPage("Display Format", parent)
{
setupUi();
}
CSVSettings::GroupBlockDef *CSVSettings::EditorPage::setupRecordStatusDisplay()
{
GroupBlockDef *statusBlock = new GroupBlockDef(QString("Record Status Display"));
SettingsItemDef *statusItem = new SettingsItemDef (statusBlock->title, "Icon and Text");
*(statusItem->valueList) << QString("Icon and Text") << QString("Icon Only") << QString("Text Only");
WidgetDef statusWidget (Widget_RadioButton);
statusWidget.valueList = statusItem->valueList;
statusItem->widget = statusWidget;
statusBlock->settingItems << statusItem;
return statusBlock;
}
void CSVSettings::EditorPage::setupUi()
{
mAbstractBlocks << buildBlock<GroupBlock>(setupRecordStatusDisplay());
foreach (AbstractBlock *block, mAbstractBlocks)
{
connect (block, SIGNAL (signalUpdateSetting (const QString &, const QString &)),
this, SIGNAL (signalUpdateEditorSetting (const QString &, const QString &)) );
}
connect ( this,
SIGNAL ( signalUpdateEditorSetting (const QString &, const QString &)),
&(CSMSettings::UserSettings::instance()),
SIGNAL ( signalUpdateEditorSetting (const QString &, const QString &)));
}
void CSVSettings::EditorPage::initializeWidgets (const CSMSettings::SettingMap &settings)
{
//iterate each item in each blocks in this section
//validate the corresponding setting against the defined valuelist if any.
for (AbstractBlockList::Iterator it_block = mAbstractBlocks.begin();
it_block != mAbstractBlocks.end(); ++it_block)
(*it_block)->updateSettings (settings);
}

View file

@ -0,0 +1,33 @@
#ifndef EDITORPAGE_HPP
#define EDITORPAGE_HPP
#include "support.hpp"
#include "abstractpage.hpp"
namespace CSVSettings
{
class EditorPage : public AbstractPage
{
Q_OBJECT
public:
explicit EditorPage(QWidget *parent = 0);
void initializeWidgets (const CSMSettings::SettingMap &settings);
void setupUi();
private:
/// User preference view of the record status delegate's icon / text setting
GroupBlockDef *setupRecordStatusDisplay();
signals:
/// Signals up for changes to editor application-level settings
void signalUpdateEditorSetting (const QString &settingName, const QString &settingValue);
public slots:
};
}
#endif // EDITORPAGE_HPP

View file

@ -0,0 +1,108 @@
#include "groupblock.hpp"
#include "itemblock.hpp"
CSVSettings::GroupBlock::GroupBlock (QWidget* parent)
: AbstractBlock (parent)
{}
CSVSettings::GroupBlock::GroupBlock (bool isVisible, QWidget *parent)
: AbstractBlock (isVisible, parent)
{}
int CSVSettings::GroupBlock::build (GroupBlockDef *def)
{
if (def->settingItems.size() == 0)
return -1;
int retVal = 0;
setVisible (def->isVisible);
mBox->setLayout(createLayout (def->widgetOrientation, true));
setObjectName (def->title);
mBox->setTitle (def->title);
foreach (SettingsItemDef *itemDef, def->settingItems)
{
ItemBlock *block = new ItemBlock (mBox);
if (block->build (*itemDef) < 0)
{
retVal = -2;
break;
}
mItemBlockList << block;
mBox->layout()->addWidget (block->getGroupBox());
connect (block, SIGNAL (signalUpdateSetting (const QString &, const QString &)),
this, SLOT (slotUpdateSetting (const QString &, const QString &) ));
}
return retVal;
}
CSMSettings::SettingList *CSVSettings::GroupBlock::getSettings()
{
CSMSettings::SettingList *settings = 0;
foreach (ItemBlock *block, mItemBlockList)
{
if (!settings)
settings = new CSMSettings::SettingList();
settings->append(*(block->getSettings ()));
}
return settings;
}
CSVSettings::ItemBlock *CSVSettings::GroupBlock::getItemBlock (const QString &name, ItemBlockList *blockList)
{
ItemBlock *retBlock = 0;
if (!blockList)
blockList = &mItemBlockList;
foreach (ItemBlock *block, *blockList)
{
if (block->objectName() == name)
{
retBlock = block;
break;
}
}
return retBlock;
}
CSVSettings::ItemBlock *CSVSettings::GroupBlock::getItemBlock (int index)
{
ItemBlock *retBlock = 0;
if (mItemBlockList.size() > index)
retBlock = mItemBlockList.at(index);
return retBlock;
}
bool CSVSettings::GroupBlock::updateSettings (const CSMSettings::SettingMap &settings)
{
bool success = true;
//update all non-proxy settings
foreach (ItemBlock *block, mItemBlockList)
{
CSMSettings::SettingContainer *setting = settings[block->objectName()];
if (setting)
{
bool success2 = block->update (setting->getValue());
success = success && success2;
}
}
return success;
}

View file

@ -0,0 +1,43 @@
#ifndef GROUPBLOCK_HPP
#define GROUPBLOCK_HPP
#include <QList>
#include "abstractblock.hpp"
namespace CSVSettings
{
class ItemBlock;
/// Base class for group blocks.
/// Derived block classes should use CustomBlock
class GroupBlock : public AbstractBlock
{
ItemBlockList mItemBlockList;
public:
GroupBlock (QWidget* parent = 0);
GroupBlock (bool isVisible, QWidget *parent = 0);
/// build the gorup block based on passed definition
int build (GroupBlockDef *def);
/// update settings local to the group block
bool updateSettings (const CSMSettings::SettingMap &settings);
/// retrieve setting list local to the group block
CSMSettings::SettingList *getSettings();
/// retrieve item block by name from the passed list or local list
ItemBlock *getItemBlock (const QString &name, ItemBlockList *blockList = 0);
/// retrieve the item block by index from the local list
ItemBlock *getItemBlock (int index);
protected:
/// create block layout based on passed definition
int buildLayout (GroupBlockDef &def);
};
}
#endif // GROUPBLOCK_HPP

View file

@ -0,0 +1,56 @@
#include "groupbox.hpp"
const QString CSVSettings::GroupBox::INVISIBLE_BOX_STYLE =
QString::fromUtf8("QGroupBox { border: 0px; padding 0px; margin: 0px;}");
CSVSettings::GroupBox::GroupBox(QWidget *parent) :
QGroupBox (parent)
{
initBox();
}
CSVSettings::GroupBox::GroupBox (bool isVisible, QWidget *parent) :
QGroupBox (parent)
{
initBox(isVisible);
}
void CSVSettings::GroupBox::initBox(bool isVisible)
{
setFlat (true);
VISIBLE_BOX_STYLE = styleSheet();
if (!isVisible)
setStyleSheet (INVISIBLE_BOX_STYLE);
}
bool CSVSettings::GroupBox::borderVisibile() const
{
return (styleSheet() != INVISIBLE_BOX_STYLE);
}
void CSVSettings::GroupBox::setTitle (const QString &title)
{
if (borderVisibile() )
{
QGroupBox::setTitle (title);
setMinimumWidth();
}
}
void CSVSettings::GroupBox::setBorderVisibility (bool value)
{
if (value)
setStyleSheet(VISIBLE_BOX_STYLE);
else
setStyleSheet(INVISIBLE_BOX_STYLE);
}
void CSVSettings::GroupBox::setMinimumWidth()
{
//set minimum width to accommodate title, if needed
//1.5 multiplier to account for bold title.
QFontMetrics fm (font());
int minWidth = fm.width(title());
QGroupBox::setMinimumWidth (minWidth * 1.5);
}

View file

@ -0,0 +1,28 @@
#ifndef GROUPBOX_HPP
#define GROUPBOX_HPP
#include <QGroupBox>
namespace CSVSettings
{
/// Custom implementation of QGroupBox to be used with block classes
class GroupBox : public QGroupBox
{
static const QString INVISIBLE_BOX_STYLE;
QString VISIBLE_BOX_STYLE; //not a const...
public:
explicit GroupBox (QWidget *parent = 0);
explicit GroupBox (bool isVisible, QWidget *parent = 0);
void setTitle (const QString &title);
void setBorderVisibility (bool value);
bool borderVisibile() const;
private:
void setMinimumWidth();
void initBox(bool isVisible = true);
};
}
#endif // GROUPBOX_HPP

View file

@ -0,0 +1,115 @@
#include "itemblock.hpp"
#include <QFontMetrics>
CSVSettings::ItemBlock::ItemBlock (QWidget* parent)
: mSetting (0), AbstractBlock (false, parent)
{
}
int CSVSettings::ItemBlock::build(SettingsItemDef &iDef)
{
buildItemBlock (iDef);
buildItemBlockWidgets (iDef);
return 0;
}
void CSVSettings::ItemBlock::buildItemBlockWidgets (SettingsItemDef &iDef)
{
WidgetDef wDef = iDef.widget;
QLayout *blockLayout = 0;
QString defaultValue = iDef.defaultValue;
switch (wDef.type)
{
case Widget_CheckBox:
case Widget_RadioButton:
foreach (QString item, *(iDef.valueList))
{
wDef.caption = item;
wDef.isDefault = (item == defaultValue);
blockLayout = buildWidget (item, wDef, blockLayout)->getLayout();
}
break;
case Widget_ComboBox:
case Widget_ListBox:
//assign the item's value list to the widget's value list.
//pass through to default to finish widget construction.
if (!wDef.valueList)
wDef.valueList = iDef.valueList;
default:
//only one instance of this non-list widget type.
//Set it's value to the default value for the item and build the widget.
if (wDef.value.isEmpty())
wDef.value = iDef.defaultValue;
buildWidget (iDef.name, wDef);
}
}
void CSVSettings::ItemBlock::buildItemBlock (SettingsItemDef &iDef)
{
QString defaultValue = iDef.defaultValue;
setObjectName(iDef.name);
mSetting = new CSMSettings::SettingsItem (objectName(),
iDef.hasMultipleValues, iDef.defaultValue,
parent());
if (iDef.valueList)
mSetting->setValueList(iDef.valueList);
if (!iDef.minMax.isEmpty())
mSetting->setValuePair(iDef.minMax);
}
bool CSVSettings::ItemBlock::update (const QString &value)
{
bool success = updateItem (value);
if (success)
signalUpdateWidget (value);
return success;
}
bool CSVSettings::ItemBlock::updateItem (const QString &value)
{
return mSetting->updateItem(value);
}
bool CSVSettings::ItemBlock::updateBySignal(const QString &name, const QString &value, bool &doEmit)
{
bool success = (mSetting->getValue() != value);
if (success)
success = updateItem(value);
return success;
}
CSMSettings::SettingList *CSVSettings::ItemBlock::getSettings ()
{
CSMSettings::SettingList *list = new CSMSettings::SettingList();
list->push_back(mSetting);
return list;
}
QString CSVSettings::ItemBlock::getValue() const
{
return mSetting->getValue();
}

View file

@ -0,0 +1,48 @@
#ifndef ITEMBLOCK_HPP
#define ITEMBLOCK_HPP
#include "abstractblock.hpp"
namespace CSVSettings
{
class ItemBlock : public AbstractBlock
{
CSMSettings::SettingsItem *mSetting;
WidgetList mWidgetList;
public:
ItemBlock (QWidget* parent = 0);
/// pure virtual function not implemneted
bool updateSettings (const CSMSettings::SettingMap &settings) { return false; }
CSMSettings::SettingList *getSettings ();
QString getValue () const;
/// item blocks encapsulate only one setting
int getSettingCount();
/// update setting value and corresponding widget
bool update (const QString &value);
/// virtual construction function
int build(SettingsItemDef &iDef);
private:
/// custom construction function
void buildItemBlock (SettingsItemDef& iDef);
void buildItemBlockWidgets (SettingsItemDef& iDef);
/// update the setting value
bool updateItem (const QString &);
/// callback function triggered when update to application level is signalled
bool updateBySignal (const QString &name, const QString &value, bool &doEmit);
};
}
#endif // ITEMBLOCK_HPP

View file

@ -0,0 +1,152 @@
#include "proxyblock.hpp"
#include "itemblock.hpp"
CSVSettings::ProxyBlock::ProxyBlock (QWidget *parent)
: GroupBlock (parent)
{
}
int CSVSettings::ProxyBlock::build (GroupBlockDef *proxyDef)
{
//get the list of pre-defined values for the proxy
mValueList = proxyDef->settingItems.at(0)->valueList;
bool success = GroupBlock::build(proxyDef);
//connect the item block of the proxy setting to the proxy-update slot
connect (getItemBlock(0), SIGNAL (signalUpdateSetting(const QString &, const QString &)),
this, SLOT (slotUpdateProxySetting (const QString &, const QString &)));
return success;
}
void CSVSettings::ProxyBlock::addSetting (ItemBlock *settingBlock, QStringList *proxyList)
{
//connect the item block of the proxied seting to the generic update slot
connect (settingBlock, SIGNAL (signalUpdateSetting(const QString &, const QString &)),
this, SLOT (slotUpdateProxySetting(const QString &, const QString &)));
mProxiedItemBlockList << settingBlock;
mProxyList << proxyList;
}
bool CSVSettings::ProxyBlock::updateSettings (const CSMSettings::SettingMap &settings)
{
return updateByProxiedSettings(&settings);
}
bool CSVSettings::ProxyBlock::updateBySignal(const QString &name, const QString &value, bool &doEmit)
{
doEmit = false;
return updateProxiedSettings();
}
void CSVSettings::ProxyBlock::slotUpdateProxySetting (const QString &name, const QString &value)
{
updateByProxiedSettings();
}
bool CSVSettings::ProxyBlock::updateProxiedSettings()
{
foreach (ItemBlock *block, mProxiedItemBlockList)
{
QString value = getItemBlock(0)->getValue();
bool success = false;
int i = 0;
//find the value index of the selected value in the proxy setting
for (; i < mValueList->size(); ++i)
{
success = (value == mValueList->at(i));
if (success)
break;
}
if (!success)
return false;
// update the containing the proxied item's name
foreach (QStringList *list, mProxyList)
{
if ( list->at(0) == block->objectName())
block->update (list->at(++i));
}
}
return true;
}
bool CSVSettings::ProxyBlock::updateByProxiedSettings(const CSMSettings::SettingMap *settings)
{
bool success = false;
int commonIndex = -1;
//update all proxy settings based on values from non-proxies
foreach (QStringList *list, mProxyList)
{
//Iterate each proxy item's proxied setting list, getting the current values
//Compare those value indices.
//If indices match, they correlate to one of the proxy's values in it's value list
//first value is always the name of the setting the proxy setting manages
QStringList::Iterator itProxyValue = list->begin();
QString proxiedSettingName = (*itProxyValue);
QString proxiedSettingValue = "";
itProxyValue++;
if (!settings)
{
//get the actual setting value
ItemBlock *block = getProxiedItemBlock (proxiedSettingName);
if (block)
proxiedSettingValue = block->getValue();
}
else
proxiedSettingValue = (*settings)[proxiedSettingName]->getValue();
int j = 0;
//iterate each value in the proxy string list
for (; itProxyValue != (list)->end(); ++itProxyValue)
{
success = ((*itProxyValue) == proxiedSettingValue);
if (success)
break;
j++;
}
//break if no match was found
if ( !success )
break;
if (commonIndex != -1)
success = (commonIndex == j);
else
commonIndex = j;
//break if indices were found, but mismatch
if (!success)
break;
}
//if successful, the proxied setting values match a pre-defined value in the
//proxy's value list. Set the proxy to that value index
if (success)
{
ItemBlock *block = getItemBlock(0);
if (block)
block->update (mValueList->at(commonIndex));
}
return success;
}
CSVSettings::ItemBlock *CSVSettings::ProxyBlock::getProxiedItemBlock (const QString &name)
{
return getItemBlock (name, &mProxiedItemBlockList);
}

View file

@ -0,0 +1,52 @@
#ifndef PROXYBLOCK_HPP
#define PROXYBLOCK_HPP
#include "groupblock.hpp"
namespace CSVSettings
{
class ProxyBlock : public GroupBlock
{
Q_OBJECT
/// TODO: Combine mProxyItemBlockList and mProxyList.
ItemBlockList mProxiedItemBlockList;
ProxyList mProxyList;
QStringList *mValueList;
public:
explicit ProxyBlock (QWidget *parent = 0);
explicit ProxyBlock (ItemBlock *proxyItemBlock, QWidget *parent = 0);
/// Add a block that contains a proxied setting to the proxy block.
void addSetting (ItemBlock* settingBlock, QStringList *proxyList);
int build (GroupBlockDef *def);
CSMSettings::SettingList *getSettings() { return 0; }
/// Update settings local to the proxy block pushed from application level
bool updateSettings (const CSMSettings::SettingMap &settings);
/// callback function triggered when update to the application level is signaled.
bool updateBySignal (const QString &name, const QString &value, bool &doEmit);
private:
/// return the item block of a proxied setting
ItemBlock *getProxiedItemBlock (const QString &name);
/// update the proxy setting with data from the proxied settings
bool updateByProxiedSettings(const CSMSettings::SettingMap *settings = 0);
/// update proxied settings with data from the proxy setting
bool updateProxiedSettings();
private slots:
void slotUpdateProxySetting (const QString &name, const QString &value);
};
}
#endif // PROXYBLOCK_HPP

View file

@ -0,0 +1 @@
#include "settingwidget.hpp"

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