1
0
Fork 0
mirror of https://github.com/OpenMW/openmw.git synced 2025-01-31 09:45:40 +00:00

Merge branch 'master' into cc9cii

Conflicts:
	apps/opencs/view/doc/view.hpp
This commit is contained in:
cc9cii 2015-06-19 07:49:18 +10:00
commit 3b27e643b8
122 changed files with 1581 additions and 500 deletions

View file

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

View file

@ -98,25 +98,29 @@ endif()
cmake_minimum_required(VERSION 2.6) cmake_minimum_required(VERSION 2.6)
# Sound setup # Sound setup
set(FFmpeg_FIND_COMPONENTS AVCODEC AVFORMAT AVUTIL SWSCALE SWRESAMPLE AVRESAMPLE)
unset(FFMPEG_LIBRARIES CACHE) unset(FFMPEG_LIBRARIES CACHE)
find_package(FFmpeg)
find_package(FFmpeg REQUIRED)
set (FFMPEG_LIBRARIES ${FFMPEG_LIBRARIES} ${SWSCALE_LIBRARY})
if ( NOT AVCODEC_FOUND OR NOT AVFORMAT_FOUND OR NOT AVUTIL_FOUND OR NOT SWSCALE_FOUND ) if ( NOT AVCODEC_FOUND OR NOT AVFORMAT_FOUND OR NOT AVUTIL_FOUND OR NOT SWSCALE_FOUND )
message(FATAL_ERROR "FFmpeg component required, but not found!") message(FATAL_ERROR "FFmpeg component required, but not found!")
endif() endif()
set(SOUND_INPUT_INCLUDES ${FFMPEG_INCLUDE_DIRS}) set(SOUND_INPUT_INCLUDES ${FFMPEG_INCLUDE_DIRS})
set(SOUND_INPUT_LIBRARY ${FFMPEG_LIBRARIES} ${SWSCALE_LIBRARIES})
if( SWRESAMPLE_FOUND ) if( SWRESAMPLE_FOUND )
add_definitions(-DHAVE_LIBSWRESAMPLE) add_definitions(-DHAVE_LIBSWRESAMPLE)
set(SOUND_INPUT_LIBRARY ${FFMPEG_LIBRARIES} ${SWRESAMPLE_LIBRARIES}) set (FFMPEG_LIBRARIES ${FFMPEG_LIBRARIES} ${SWRESAMPLE_LIBRARIES})
else() else()
if( AVRESAMPLE_FOUND ) if( AVRESAMPLE_FOUND )
set(SOUND_INPUT_LIBRARY ${FFMPEG_LIBRARIES} ${AVRESAMPLE_LIBRARIES}) set (FFMPEG_LIBRARIES ${FFMPEG_LIBRARIES} ${AVRESAMPLE_LIBRARIES})
else() else()
message(FATAL_ERROR "Install either libswresample (FFmpeg) or libavresample (Libav).") message(FATAL_ERROR "Install either libswresample (FFmpeg) or libavresample (Libav).")
endif() endif()
endif() endif()
set(SOUND_INPUT_LIBRARY ${FFMPEG_LIBRARIES})
# TinyXML # TinyXML
option(USE_SYSTEM_TINYXML "Use system TinyXML library instead of internal." OFF) option(USE_SYSTEM_TINYXML "Use system TinyXML library instead of internal." OFF)
if(USE_SYSTEM_TINYXML) if(USE_SYSTEM_TINYXML)
@ -151,6 +155,19 @@ endif()
# Dependencies # Dependencies
set(DESIRED_QT_VERSION 4 CACHE STRING "The QT version OpenMW should use (4 or 5)")
message(STATUS "Using Qt${DESIRED_QT_VERSION}")
if (DESIRED_QT_VERSION MATCHES 4)
find_package(Qt4 REQUIRED COMPONENTS QtCore QtGui QtNetwork)
else()
find_package(Qt5Widgets REQUIRED)
find_package(Qt5Core REQUIRED)
find_package(Qt5Network REQUIRED)
# Instruct CMake to run moc automatically when needed.
#set(CMAKE_AUTOMOC ON)
endif()
# Fix for not visible pthreads functions for linker with glibc 2.15 # Fix for not visible pthreads functions for linker with glibc 2.15
if (UNIX AND NOT APPLE) if (UNIX AND NOT APPLE)
find_package (Threads) find_package (Threads)
@ -171,7 +188,7 @@ if (HAVE_UNORDERED_MAP)
endif () endif ()
set(BOOST_COMPONENTS system filesystem program_options) set(BOOST_COMPONENTS system filesystem program_options thread wave)
if(WIN32) if(WIN32)
set(BOOST_COMPONENTS ${BOOST_COMPONENTS} locale) set(BOOST_COMPONENTS ${BOOST_COMPONENTS} locale)
endif(WIN32) endif(WIN32)

View file

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

View file

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

View file

@ -830,12 +830,12 @@ std::string npcFlags(int flags)
std::string properties = ""; std::string properties = "";
if (flags == 0) properties += "[None] "; if (flags == 0) properties += "[None] ";
// Mythicmods and the ESM component differ. Mythicmods says // Mythicmods and the ESM component differ. Mythicmods says
// 0x8=None and 0x10=AutoCalc, while our code defines 0x8 as // 0x8=None and 0x10=AutoCalc, while our code previously defined
// AutoCalc. The former seems to be correct. All Bethesda // 0x8 as AutoCalc. The former seems to be correct. All Bethesda
// records have bit 0x8 set. A suspiciously large portion of // records have bit 0x8 set. Previously, suspiciously large portion
// females have autocalc turned off. // of females had autocalc turned off.
if (flags & ESM::NPC::Autocalc) properties += "Unknown "; if (flags & 0x00000008) properties += "Unknown ";
if (flags & 0x00000010) properties += "Autocalc "; if (flags & ESM::NPC::Autocalc) properties += "Autocalc ";
if (flags & ESM::NPC::Female) properties += "Female "; if (flags & ESM::NPC::Female) properties += "Female ";
if (flags & ESM::NPC::Respawn) properties += "Respawn "; if (flags & ESM::NPC::Respawn) properties += "Respawn ";
if (flags & ESM::NPC::Essential) properties += "Essential "; if (flags & ESM::NPC::Essential) properties += "Essential ";
@ -847,8 +847,8 @@ std::string npcFlags(int flags)
// however the only unknown bit occurs on ALL records, and // however the only unknown bit occurs on ALL records, and
// relatively few NPCs have this bit set. // relatively few NPCs have this bit set.
int unused = (0xFFFFFFFF ^ int unused = (0xFFFFFFFF ^
(ESM::NPC::Autocalc| (0x00000008|
0x00000010| ESM::NPC::Autocalc|
ESM::NPC::Female| ESM::NPC::Female|
ESM::NPC::Respawn| ESM::NPC::Respawn|
ESM::NPC::Essential| ESM::NPC::Essential|

View file

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

View file

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

View file

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

View file

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

View file

@ -18,7 +18,7 @@ opencs_hdrs_noqt (model/doc
opencs_units (model/world opencs_units (model/world
idtable idtableproxymodel regionmap data commanddispatcher idtablebase resourcetable nestedtableproxymodel idtree idtable idtableproxymodel regionmap data commanddispatcher idtablebase resourcetable nestedtableproxymodel idtree infotableproxymodel
) )
@ -41,7 +41,7 @@ opencs_units (model/tools
opencs_units_noqt (model/tools opencs_units_noqt (model/tools
mandatoryid skillcheck classcheck factioncheck racecheck soundcheck regioncheck mandatoryid skillcheck classcheck factioncheck racecheck soundcheck regioncheck
birthsigncheck spellcheck referencecheck referenceablecheck scriptcheck bodypartcheck birthsigncheck spellcheck referencecheck referenceablecheck scriptcheck bodypartcheck
startscriptcheck search searchoperation searchstage pathgridcheck startscriptcheck search searchoperation searchstage pathgridcheck soundgencheck
) )
@ -70,11 +70,12 @@ opencs_units (view/world
opencs_units_noqt (view/world opencs_units_noqt (view/world
subviews enumdelegate vartypedelegate recordstatusdelegate idtypedelegate datadisplaydelegate subviews enumdelegate vartypedelegate recordstatusdelegate idtypedelegate datadisplaydelegate
scripthighlighter idvalidator dialoguecreator physicssystem idcompletiondelegate scripthighlighter idvalidator dialoguecreator physicssystem idcompletiondelegate
colordelegate
) )
opencs_units (view/widget opencs_units (view/widget
scenetoolbar scenetool scenetoolmode pushbutton scenetooltoggle scenetoolrun modebutton scenetoolbar scenetool scenetoolmode pushbutton scenetooltoggle scenetoolrun modebutton
scenetooltoggle2 completerpopup scenetooltoggle2 completerpopup coloreditor colorpickerpopup
) )
opencs_units (view/render opencs_units (view/render
@ -153,19 +154,16 @@ if(WIN32)
set(QT_USE_QTMAIN TRUE) set(QT_USE_QTMAIN TRUE)
endif(WIN32) endif(WIN32)
set(BOOST_COMPONENTS system filesystem program_options thread wave) if (DESIRED_QT_VERSION MATCHES 4)
if(WIN32)
set(BOOST_COMPONENTS ${BOOST_COMPONENTS} locale)
endif(WIN32)
find_package(Boost REQUIRED COMPONENTS ${BOOST_COMPONENTS})
find_package(Qt4 COMPONENTS QtCore QtGui QtNetwork REQUIRED)
include(${QT_USE_FILE}) include(${QT_USE_FILE})
qt4_wrap_ui(OPENCS_UI_HDR ${OPENCS_UI}) qt4_wrap_ui(OPENCS_UI_HDR ${OPENCS_UI})
qt4_wrap_cpp(OPENCS_MOC_SRC ${OPENCS_HDR_QT}) qt4_wrap_cpp(OPENCS_MOC_SRC ${OPENCS_HDR_QT})
qt4_add_resources(OPENCS_RES_SRC ${OPENCS_RES}) qt4_add_resources(OPENCS_RES_SRC ${OPENCS_RES})
else()
qt5_wrap_ui(OPENCS_UI_HDR ${OPENCS_UI})
qt5_wrap_cpp(OPENCS_MOC_SRC ${OPENCS_HDR_QT})
qt5_add_resources(OPENCS_RES_SRC ${OPENCS_RES})
endif()
# for compiled .ui files # for compiled .ui files
include_directories(${CMAKE_CURRENT_BINARY_DIR}) include_directories(${CMAKE_CURRENT_BINARY_DIR})
@ -206,12 +204,36 @@ target_link_libraries(openmw-cs
${OGRE_Overlay_LIBRARIES} ${OGRE_Overlay_LIBRARIES}
${OGRE_STATIC_PLUGINS} ${OGRE_STATIC_PLUGINS}
${SHINY_LIBRARIES} ${SHINY_LIBRARIES}
${Boost_LIBRARIES} ${Boost_SYSTEM_LIBRARY}
${Boost_FILESYSTEM_LIBRARY}
${Boost_PROGRAM_OPTIONS_LIBRARY}
${Boost_WAVE_LIBRARY}
${BULLET_LIBRARIES} ${BULLET_LIBRARIES}
${QT_LIBRARIES}
components components
) )
if (DESIRED_QT_VERSION MATCHES 4)
target_link_libraries(openmw-cs
${QT_QTGUI_LIBRARY}
${QT_QTCORE_LIBRARY}
${QT_QTNETWORK_LIBRARY})
if (WIN32)
target_link_libraries(openmw-cs ${QT_QTMAIN_LIBRARY})
endif()
else()
qt5_use_modules(openmw-cs Widgets Core Network)
if (WIN32)
target_link_libraries(Qt5::WinMain)
endif()
endif()
if (WIN32)
target_link_libraries(openmw-cs ${Boost_LOCALE_LIBRARY})
endif()
if(APPLE) if(APPLE)
INSTALL(TARGETS openmw-cs BUNDLE DESTINATION OpenMW COMPONENT BUNDLE) INSTALL(TARGETS openmw-cs BUNDLE DESTINATION OpenMW COMPONENT BUNDLE)
endif() endif()

View file

@ -98,7 +98,7 @@ void CS::Editor::setupDataFiles (const Files::PathContainer& dataDirs)
} }
} }
std::pair<Files::PathContainer, std::vector<std::string> > CS::Editor::readConfig() std::pair<Files::PathContainer, std::vector<std::string> > CS::Editor::readConfig(bool quiet)
{ {
boost::program_options::variables_map variables; boost::program_options::variables_map variables;
boost::program_options::options_description desc("Syntax: openmw-cs <options>\nAllowed options"); boost::program_options::options_description desc("Syntax: openmw-cs <options>\nAllowed options");
@ -118,7 +118,7 @@ std::pair<Files::PathContainer, std::vector<std::string> > CS::Editor::readConfi
boost::program_options::notify(variables); boost::program_options::notify(variables);
mCfgMgr.readConfiguration(variables, desc); mCfgMgr.readConfiguration(variables, desc, quiet);
mDocumentManager.setEncoding ( mDocumentManager.setEncoding (
ToUTF8::calculateEncoding (variables["encoding"].as<std::string>())); ToUTF8::calculateEncoding (variables["encoding"].as<std::string>()));
@ -198,6 +198,11 @@ void CS::Editor::cancelCreateGame()
void CS::Editor::createAddon() void CS::Editor::createAddon()
{ {
mStartup.hide(); mStartup.hide();
mFileDialog.clearFiles();
std::pair<Files::PathContainer, std::vector<std::string> > config = readConfig(/*quiet*/true);
setupDataFiles (config.first);
mFileDialog.showDialog (CSVDoc::ContentAction_New); mFileDialog.showDialog (CSVDoc::ContentAction_New);
} }
@ -218,6 +223,11 @@ void CS::Editor::cancelFileDialog()
void CS::Editor::loadDocument() void CS::Editor::loadDocument()
{ {
mStartup.hide(); mStartup.hide();
mFileDialog.clearFiles();
std::pair<Files::PathContainer, std::vector<std::string> > config = readConfig(/*quiet*/true);
setupDataFiles (config.first);
mFileDialog.showDialog (CSVDoc::ContentAction_Edit); mFileDialog.showDialog (CSVDoc::ContentAction_Edit);
} }
@ -312,12 +322,12 @@ bool CS::Editor::makeIPCServer()
mServer->close(); mServer->close();
fullPath.remove(QRegExp("dummy$")); fullPath.remove(QRegExp("dummy$"));
fullPath += mIpcServerName; fullPath += mIpcServerName;
if(boost::filesystem::exists(fullPath.toStdString().c_str())) if(boost::filesystem::exists(fullPath.toUtf8().constData()))
{ {
// TODO: compare pid of the current process with that in the file // TODO: compare pid of the current process with that in the file
std::cout << "Detected unclean shutdown." << std::endl; std::cout << "Detected unclean shutdown." << std::endl;
// delete the stale file // delete the stale file
if(remove(fullPath.toStdString().c_str())) if(remove(fullPath.toUtf8().constData()))
std::cerr << "ERROR removing stale connection file" << std::endl; std::cerr << "ERROR removing stale connection file" << std::endl;
} }
} }

View file

@ -64,7 +64,7 @@ namespace CS
void setupDataFiles (const Files::PathContainer& dataDirs); void setupDataFiles (const Files::PathContainer& dataDirs);
std::pair<Files::PathContainer, std::vector<std::string> > readConfig(); std::pair<Files::PathContainer, std::vector<std::string> > readConfig(bool quiet=false);
///< \return data paths ///< \return data paths
// not implemented // not implemented

View file

@ -2272,7 +2272,7 @@ CSMDoc::Document::Document (const Files::ConfigurationManager& configuration,
if (boost::filesystem::exists (customFiltersPath)) if (boost::filesystem::exists (customFiltersPath))
{ {
destination << std::ifstream(customFiltersPath.c_str(), std::ios::binary).rdbuf(); destination << std::ifstream(customFiltersPath.string().c_str(), std::ios::binary).rdbuf();
} }
else else
{ {

View file

@ -244,6 +244,47 @@ void CSMSettings::UserSettings::buildSettingModelDefaults()
jumpToAdded->setDeclaredValues (jumpValues); jumpToAdded->setDeclaredValues (jumpValues);
} }
declareSection ("report-input", "Report Input");
{
QString none ("None");
QString edit ("Edit");
QString remove ("Remove");
QString editAndRemove ("Edit And Remove");
QStringList values;
values << none << edit << remove << editAndRemove;
QString toolTip = "<ul>"
"<li>None</li>"
"<li>Edit: Open a table or dialogue suitable for addressing the listed report</li>"
"<li>Remove: Remove the report from the report table</li>"
"<li>Edit and Remove: Open a table or dialogue suitable for addressing the listed report, then remove the report from the report table</li>"
"</ul>";
Setting *doubleClick = createSetting (Type_ComboBox, "double", "Double Click");
doubleClick->setDeclaredValues (values);
doubleClick->setDefaultValue (edit);
doubleClick->setToolTip ("Action on double click in report table:<p>" + toolTip);
Setting *shiftDoubleClick = createSetting (Type_ComboBox, "double-s",
"Shift Double Click");
shiftDoubleClick->setDeclaredValues (values);
shiftDoubleClick->setDefaultValue (remove);
shiftDoubleClick->setToolTip ("Action on shift double click in report table:<p>" + toolTip);
Setting *ctrlDoubleClick = createSetting (Type_ComboBox, "double-c",
"Control Double Click");
ctrlDoubleClick->setDeclaredValues (values);
ctrlDoubleClick->setDefaultValue (editAndRemove);
ctrlDoubleClick->setToolTip ("Action on control double click in report table:<p>" + toolTip);
Setting *shiftCtrlDoubleClick = createSetting (Type_ComboBox, "double-sc",
"Shift Control Double Click");
shiftCtrlDoubleClick->setDeclaredValues (values);
shiftCtrlDoubleClick->setDefaultValue (none);
shiftCtrlDoubleClick->setToolTip ("Action on shift control double click in report table:<p>" + toolTip);
}
declareSection ("search", "Search & Replace"); declareSection ("search", "Search & Replace");
{ {
Setting *before = createSetting (Type_SpinBox, "char-before", Setting *before = createSetting (Type_SpinBox, "char-before",

View file

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

View file

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

View file

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

View file

@ -27,6 +27,7 @@
#include "startscriptcheck.hpp" #include "startscriptcheck.hpp"
#include "searchoperation.hpp" #include "searchoperation.hpp"
#include "pathgridcheck.hpp" #include "pathgridcheck.hpp"
#include "soundgencheck.hpp"
CSMDoc::OperationHolder *CSMTools::Tools::get (int type) CSMDoc::OperationHolder *CSMTools::Tools::get (int type)
{ {
@ -99,6 +100,10 @@ CSMDoc::OperationHolder *CSMTools::Tools::getVerifier()
mVerifierOperation->appendStage (new PathgridCheckStage (mData.getPathgrids())); mVerifierOperation->appendStage (new PathgridCheckStage (mData.getPathgrids()));
mVerifierOperation->appendStage (new SoundGenCheckStage (mData.getSoundGens(),
mData.getSounds(),
mData.getReferenceables()));
mVerifier.setOperation (mVerifierOperation); mVerifier.setOperation (mVerifierOperation);
} }

View file

@ -694,7 +694,7 @@ namespace CSMWorld
QColor colour = data.value<QColor>(); QColor colour = data.value<QColor>();
record2.mMapColor = colour.rgb() & 0xffffff; record2.mMapColor = (colour.blue() << 16) | (colour.green() << 8) | colour.red();
record.setModified (record2); record.setModified (record2);
} }

View file

@ -52,9 +52,10 @@ QModelIndex CSMWorld::IdTableProxyModel::getModelIndex (const std::string& id, i
void CSMWorld::IdTableProxyModel::setFilter (const boost::shared_ptr<CSMFilter::Node>& filter) void CSMWorld::IdTableProxyModel::setFilter (const boost::shared_ptr<CSMFilter::Node>& filter)
{ {
beginResetModel();
mFilter = filter; mFilter = filter;
updateColumnMap(); updateColumnMap();
reset(); endResetModel();
} }
bool CSMWorld::IdTableProxyModel::lessThan(const QModelIndex &left, const QModelIndex &right) const bool CSMWorld::IdTableProxyModel::lessThan(const QModelIndex &left, const QModelIndex &right) const

View file

@ -0,0 +1,58 @@
#include "infotableproxymodel.hpp"
#include "idtablebase.hpp"
#include "columns.hpp"
CSMWorld::InfoTableProxyModel::InfoTableProxyModel(CSMWorld::UniversalId::Type type, QObject *parent)
: IdTableProxyModel(parent),
mType(type),
mSourceModel(NULL)
{
Q_ASSERT(type == UniversalId::Type_TopicInfos || type == UniversalId::Type_JournalInfos);
}
void CSMWorld::InfoTableProxyModel::setSourceModel(QAbstractItemModel *sourceModel)
{
IdTableProxyModel::setSourceModel(sourceModel);
mSourceModel = dynamic_cast<IdTableBase *>(sourceModel);
connect(mSourceModel,
SIGNAL(dataChanged(const QModelIndex &, const QModelIndex &)),
this,
SLOT(modelDataChanged(const QModelIndex &, const QModelIndex &)));
mFirstRowCache.clear();
}
bool CSMWorld::InfoTableProxyModel::lessThan(const QModelIndex &left, const QModelIndex &right) const
{
QModelIndex first = mSourceModel->index(getFirstInfoRow(left.row()), left.column());
QModelIndex second = mSourceModel->index(getFirstInfoRow(right.row()), right.column());
return IdTableProxyModel::lessThan(first, second);
}
int CSMWorld::InfoTableProxyModel::getFirstInfoRow(int currentRow) const
{
Columns::ColumnId columnId = Columns::ColumnId_Topic;
if (mType == UniversalId::Type_JournalInfos)
{
columnId = Columns::ColumnId_Journal;
}
int column = mSourceModel->findColumnIndex(columnId);
QString info = mSourceModel->data(mSourceModel->index(currentRow, column)).toString();
if (mFirstRowCache.contains(info))
{
return mFirstRowCache[info];
}
while (--currentRow >= 0 &&
mSourceModel->data(mSourceModel->index(currentRow, column)) == info);
mFirstRowCache[info] = currentRow + 1;
return currentRow + 1;
}
void CSMWorld::InfoTableProxyModel::modelDataChanged(const QModelIndex &/*topLeft*/, const QModelIndex &/*bottomRight*/)
{
mFirstRowCache.clear();
}

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -7,7 +7,7 @@
#include <QMenuBar> #include <QMenuBar>
#include <QMdiArea> #include <QMdiArea>
#include <QDockWidget> #include <QDockWidget>
#include <QtGui/QApplication> #include <QApplication>
#include <QDesktopWidget> #include <QDesktopWidget>
#include <QScrollArea> #include <QScrollArea>
#include <QHBoxLayout> #include <QHBoxLayout>
@ -546,6 +546,10 @@ void CSVDoc::View::addSubView (const CSMWorld::UniversalId& id, const std::strin
} }
} }
if (mScroll)
QObject::connect(mScroll->horizontalScrollBar(),
SIGNAL(rangeChanged(int,int)), this, SLOT(moveScrollBarToEnd(int,int)));
// User setting for limiting the number of sub views per top level view. // User setting for limiting the number of sub views per top level view.
// Automatically open a new top level view if this number is exceeded // Automatically open a new top level view if this number is exceeded
// //
@ -617,12 +621,6 @@ void CSVDoc::View::addSubView (const CSMWorld::UniversalId& id, const std::strin
mSubViewWindow.setMinimumWidth(mSubViewWindow.width()+minWidth); mSubViewWindow.setMinimumWidth(mSubViewWindow.width()+minWidth);
move(0, y()); move(0, y());
} }
// Make the new subview visible, setFocus() or raise() don't seem to work
// On Ubuntu the scrollbar does not go right to the end, even if using
// mScroll->horizontalScrollBar()->setValue(mScroll->horizontalScrollBar()->maximum());
if (mSubViewWindow.width() > rect.width())
mScroll->horizontalScrollBar()->setValue(mSubViewWindow.width());
} }
mSubViewWindow.addDockWidget (Qt::TopDockWidgetArea, view); mSubViewWindow.addDockWidget (Qt::TopDockWidgetArea, view);
@ -645,6 +643,17 @@ void CSVDoc::View::addSubView (const CSMWorld::UniversalId& id, const std::strin
view->useHint (hint); view->useHint (hint);
} }
void CSVDoc::View::moveScrollBarToEnd(int min, int max)
{
if (mScroll)
{
mScroll->horizontalScrollBar()->setValue(max);
QObject::disconnect(mScroll->horizontalScrollBar(),
SIGNAL(rangeChanged(int,int)), this, SLOT(moveScrollBarToEnd(int,int)));
}
}
void CSVDoc::View::newView() void CSVDoc::View::newView()
{ {
mViewManager.addView (mDocument); mViewManager.addView (mDocument);

View file

@ -243,6 +243,8 @@ namespace CSVDoc
void closeRequest (SubView *subView); void closeRequest (SubView *subView);
void saveWindowState(); void saveWindowState();
void moveScrollBarToEnd(int min, int max);
}; };
} }

View file

@ -6,6 +6,8 @@
#include <QApplication> #include <QApplication>
#include <QDesktopWidget> #include <QDesktopWidget>
#include <QMessageBox>
#include <QPushButton>
#include "../../model/doc/documentmanager.hpp" #include "../../model/doc/documentmanager.hpp"
#include "../../model/doc/document.hpp" #include "../../model/doc/document.hpp"
@ -19,15 +21,12 @@
#include "../world/recordstatusdelegate.hpp" #include "../world/recordstatusdelegate.hpp"
#include "../world/idtypedelegate.hpp" #include "../world/idtypedelegate.hpp"
#include "../world/idcompletiondelegate.hpp" #include "../world/idcompletiondelegate.hpp"
#include "../world/colordelegate.hpp"
#include "../../model/settings/usersettings.hpp" #include "../../model/settings/usersettings.hpp"
#include "view.hpp" #include "view.hpp"
#include <QMessageBox>
#include <QPushButton>
#include <QtGui/QApplication>
void CSVDoc::ViewManager::updateIndices() void CSVDoc::ViewManager::updateIndices()
{ {
std::map<CSMDoc::Document *, std::pair<int, int> > documents; std::map<CSMDoc::Document *, std::pair<int, int> > documents;
@ -63,6 +62,9 @@ CSVDoc::ViewManager::ViewManager (CSMDoc::DocumentManager& documentManager)
mDelegateFactories->add (CSMWorld::ColumnBase::Display_RefRecordType, mDelegateFactories->add (CSMWorld::ColumnBase::Display_RefRecordType,
new CSVWorld::IdTypeDelegateFactory()); new CSVWorld::IdTypeDelegateFactory());
mDelegateFactories->add (CSMWorld::ColumnBase::Display_Colour,
new CSVWorld::ColorDelegateFactory());
std::vector<CSMWorld::ColumnBase::Display> idCompletionColumns = CSMWorld::IdCompletionManager::getDisplayTypes(); std::vector<CSMWorld::ColumnBase::Display> idCompletionColumns = CSMWorld::IdCompletionManager::getDisplayTypes();
for (std::vector<CSMWorld::ColumnBase::Display>::const_iterator current = idCompletionColumns.begin(); for (std::vector<CSMWorld::ColumnBase::Display>::const_iterator current = idCompletionColumns.begin();
current != idCompletionColumns.end(); current != idCompletionColumns.end();

View file

@ -6,7 +6,7 @@
#include <OgreColourValue.h> #include <OgreColourValue.h>
#include <OgreCamera.h> #include <OgreCamera.h>
#include <QtGui/qevent.h> #include <QEvent>
#include "../../model/doc/document.hpp" #include "../../model/doc/document.hpp"

View file

@ -7,7 +7,12 @@
#include <OgreSceneManager.h> #include <OgreSceneManager.h>
#include <OgreEntity.h> #include <OgreEntity.h>
#include <QtGui/qevent.h> #include <QEvent>
#include <QDragEnterEvent>
#include <QDragMoveEvent>
#include <QDropEvent>
#include <QMouseEvent>
#include <QKeyEvent>
#include "../../model/world/universalid.hpp" #include "../../model/world/universalid.hpp"
#include "../../model/world/idtable.hpp" #include "../../model/world/idtable.hpp"

View file

@ -8,19 +8,12 @@
#include <QStackedWidget> #include <QStackedWidget>
#include <QtGui> #include <QtGui>
#include <QSplitter> #include <QSplitter>
#include <QDesktopWidget>
#include "../../model/settings/usersettings.hpp" #include "../../model/settings/usersettings.hpp"
#include "page.hpp" #include "page.hpp"
#include <QApplication>
#include <QTreeView>
#include <QListView>
#include <QTableView>
#include <QStandardItemModel>
#include <QStandardItem>
CSVSettings::Dialog::Dialog(QMainWindow *parent) CSVSettings::Dialog::Dialog(QMainWindow *parent)
: SettingWindow (parent), mStackedWidget (0), mDebugMode (false) : SettingWindow (parent), mStackedWidget (0), mDebugMode (false)

View file

@ -3,7 +3,6 @@
#include "settingwindow.hpp" #include "settingwindow.hpp"
#include "resizeablestackedwidget.hpp" #include "resizeablestackedwidget.hpp"
#include <QStandardItem>
class QStackedWidget; class QStackedWidget;
class QListWidget; class QListWidget;
@ -26,10 +25,6 @@ namespace CSVSettings {
explicit Dialog (QMainWindow *parent = 0); explicit Dialog (QMainWindow *parent = 0);
///Enables setting debug mode. When the dialog opens, a page is created
///which displays the SettingModel's contents in a Tree view.
void enableDebugMode (bool state, QStandardItemModel *model = 0);
protected: protected:
/// Settings are written on close /// Settings are written on close

View file

@ -9,6 +9,8 @@
#include <QStyledItemDelegate> #include <QStyledItemDelegate>
#include <QTextDocument> #include <QTextDocument>
#include <QPainter> #include <QPainter>
#include <QContextMenuEvent>
#include <QMouseEvent>
#include "../../model/tools/reportmodel.hpp" #include "../../model/tools/reportmodel.hpp"
@ -94,21 +96,35 @@ void CSVTools::ReportTable::mouseDoubleClickEvent (QMouseEvent *event)
selectionModel()->select (index, selectionModel()->select (index,
QItemSelectionModel::Clear | QItemSelectionModel::Select | QItemSelectionModel::Rows); QItemSelectionModel::Clear | QItemSelectionModel::Select | QItemSelectionModel::Rows);
switch (modifiers) std::map<Qt::KeyboardModifiers, DoubleClickAction>::iterator iter =
mDoubleClickActions.find (modifiers);
if (iter==mDoubleClickActions.end())
{ {
case 0: event->accept();
return;
}
switch (iter->second)
{
case Action_None:
event->accept();
break;
case Action_Edit:
event->accept(); event->accept();
showSelection(); showSelection();
break; break;
case Qt::ShiftModifier: case Action_Remove:
event->accept(); event->accept();
removeSelection(); removeSelection();
break; break;
case Qt::ControlModifier: case Action_EditAndRemove:
event->accept(); event->accept();
showSelection(); showSelection();
@ -121,7 +137,11 @@ CSVTools::ReportTable::ReportTable (CSMDoc::Document& document,
const CSMWorld::UniversalId& id, bool richTextDescription, QWidget *parent) const CSMWorld::UniversalId& id, bool richTextDescription, QWidget *parent)
: CSVWorld::DragRecordTable (document, parent), mModel (document.getReport (id)) : CSVWorld::DragRecordTable (document, parent), mModel (document.getReport (id))
{ {
#if QT_VERSION >= QT_VERSION_CHECK(5,0,0)
horizontalHeader()->setSectionResizeMode (QHeaderView::Interactive);
#else
horizontalHeader()->setResizeMode (QHeaderView::Interactive); horizontalHeader()->setResizeMode (QHeaderView::Interactive);
#endif
horizontalHeader()->setStretchLastSection (true); horizontalHeader()->setStretchLastSection (true);
verticalHeader()->hide(); verticalHeader()->hide();
setSortingEnabled (true); setSortingEnabled (true);
@ -150,6 +170,10 @@ CSVTools::ReportTable::ReportTable (CSMDoc::Document& document,
mReplaceAction = new QAction (tr ("Replace"), this); mReplaceAction = new QAction (tr ("Replace"), this);
connect (mReplaceAction, SIGNAL (triggered()), this, SIGNAL (replaceRequest())); connect (mReplaceAction, SIGNAL (triggered()), this, SIGNAL (replaceRequest()));
addAction (mReplaceAction); addAction (mReplaceAction);
mDoubleClickActions.insert (std::make_pair (Qt::NoModifier, Action_Edit));
mDoubleClickActions.insert (std::make_pair (Qt::ShiftModifier, Action_Remove));
mDoubleClickActions.insert (std::make_pair (Qt::ControlModifier, Action_EditAndRemove));
} }
std::vector<CSMWorld::UniversalId> CSVTools::ReportTable::getDraggedRecords() const std::vector<CSMWorld::UniversalId> CSVTools::ReportTable::getDraggedRecords() const
@ -170,6 +194,35 @@ std::vector<CSMWorld::UniversalId> CSVTools::ReportTable::getDraggedRecords() co
void CSVTools::ReportTable::updateUserSetting (const QString& name, const QStringList& list) void CSVTools::ReportTable::updateUserSetting (const QString& name, const QStringList& list)
{ {
mIdTypeDelegate->updateUserSetting (name, list); mIdTypeDelegate->updateUserSetting (name, list);
QString base ("report-input/double");
if (name.startsWith (base))
{
QString modifierString = name.mid (base.size());
Qt::KeyboardModifiers modifiers = 0;
if (modifierString=="-s")
modifiers = Qt::ShiftModifier;
else if (modifierString=="-c")
modifiers = Qt::ControlModifier;
else if (modifierString=="-sc")
modifiers = Qt::ShiftModifier | Qt::ControlModifier;
DoubleClickAction action = Action_None;
QString value = list.at (0);
if (value=="Edit")
action = Action_Edit;
else if (value=="Remove")
action = Action_Remove;
else if (value=="Edit And Remove")
action = Action_EditAndRemove;
mDoubleClickActions[modifiers] = action;
return;
}
} }
std::vector<int> CSVTools::ReportTable::getReplaceIndices (bool selection) const std::vector<int> CSVTools::ReportTable::getReplaceIndices (bool selection) const

View file

@ -1,6 +1,8 @@
#ifndef CSV_TOOLS_REPORTTABLE_H #ifndef CSV_TOOLS_REPORTTABLE_H
#define CSV_TOOLS_REPORTTABLE_H #define CSV_TOOLS_REPORTTABLE_H
#include <map>
#include "../world/dragrecordtable.hpp" #include "../world/dragrecordtable.hpp"
class QAction; class QAction;
@ -21,11 +23,20 @@ namespace CSVTools
{ {
Q_OBJECT Q_OBJECT
enum DoubleClickAction
{
Action_None,
Action_Edit,
Action_Remove,
Action_EditAndRemove
};
CSMTools::ReportModel *mModel; CSMTools::ReportModel *mModel;
CSVWorld::CommandDelegate *mIdTypeDelegate; CSVWorld::CommandDelegate *mIdTypeDelegate;
QAction *mShowAction; QAction *mShowAction;
QAction *mRemoveAction; QAction *mRemoveAction;
QAction *mReplaceAction; QAction *mReplaceAction;
std::map<Qt::KeyboardModifiers, DoubleClickAction> mDoubleClickActions;
private: private:

View file

@ -0,0 +1,113 @@
#include "coloreditor.hpp"
#include <QApplication>
#include <QColor>
#include <QColorDialog>
#include <QDesktopWidget>
#include <QPainter>
#include <QRect>
#include <QShowEvent>
#include "colorpickerpopup.hpp"
CSVWidget::ColorEditor::ColorEditor(const QColor &color, QWidget *parent, bool popupOnStart)
: QPushButton(parent),
mColor(color),
mColorPicker(new ColorPickerPopup(this)),
mPopupOnStart(popupOnStart)
{
setCheckable(true);
connect(this, SIGNAL(clicked()), this, SLOT(showPicker()));
connect(mColorPicker, SIGNAL(hid()), this, SLOT(pickerHid()));
connect(mColorPicker, SIGNAL(colorChanged(const QColor &)), this, SLOT(pickerColorChanged(const QColor &)));
}
void CSVWidget::ColorEditor::paintEvent(QPaintEvent *event)
{
QPushButton::paintEvent(event);
QRect buttonRect = rect();
QRect coloredRect(buttonRect.x() + qRound(buttonRect.width() / 4.0),
buttonRect.y() + qRound(buttonRect.height() / 4.0),
buttonRect.width() / 2,
buttonRect.height() / 2);
QPainter painter(this);
painter.fillRect(coloredRect, mColor);
painter.setPen(Qt::black);
painter.drawRect(coloredRect);
}
void CSVWidget::ColorEditor::showEvent(QShowEvent *event)
{
QPushButton::showEvent(event);
if (isVisible() && mPopupOnStart)
{
setChecked(true);
showPicker();
mPopupOnStart = false;
}
}
QColor CSVWidget::ColorEditor::color() const
{
return mColor;
}
void CSVWidget::ColorEditor::setColor(const QColor &color)
{
mColor = color;
update();
}
void CSVWidget::ColorEditor::showPicker()
{
if (isChecked())
{
mColorPicker->showPicker(calculatePopupPosition(), mColor);
}
else
{
mColorPicker->hide();
}
}
void CSVWidget::ColorEditor::pickerHid()
{
setChecked(false);
emit pickingFinished();
}
void CSVWidget::ColorEditor::pickerColorChanged(const QColor &color)
{
mColor = color;
update();
}
QPoint CSVWidget::ColorEditor::calculatePopupPosition()
{
QRect editorGeometry = geometry();
QRect popupGeometry = mColorPicker->geometry();
QRect screenGeometry = QApplication::desktop()->screenGeometry();
// Center the popup horizontally relative to the editor
int localPopupX = (editorGeometry.width() - popupGeometry.width()) / 2;
// Popup position need to be specified in global coords
QPoint popupPosition = mapToGlobal(QPoint(localPopupX, editorGeometry.height()));
// Make sure that the popup isn't out of the screen
if (popupPosition.x() < screenGeometry.left())
{
popupPosition.setX(screenGeometry.left() + 1);
}
else if (popupPosition.x() + popupGeometry.width() > screenGeometry.right())
{
popupPosition.setX(screenGeometry.right() - popupGeometry.width() - 1);
}
if (popupPosition.y() + popupGeometry.height() > screenGeometry.bottom())
{
// Place the popup above the editor
popupPosition.setY(popupPosition.y() - popupGeometry.height() - editorGeometry.height() - 1);
}
return popupPosition;
}

View file

@ -0,0 +1,44 @@
#ifndef CSV_WIDGET_COLOREDITOR_HPP
#define CSV_WIDGET_COLOREDITOR_HPP
#include <QPushButton>
class QColor;
class QPoint;
class QSize;
namespace CSVWidget
{
class ColorPickerPopup;
class ColorEditor : public QPushButton
{
Q_OBJECT
QColor mColor;
ColorPickerPopup *mColorPicker;
bool mPopupOnStart;
QPoint calculatePopupPosition();
public:
ColorEditor(const QColor &color, QWidget *parent = 0, bool popupOnStart = false);
QColor color() const;
void setColor(const QColor &color);
protected:
virtual void paintEvent(QPaintEvent *event);
virtual void showEvent(QShowEvent *event);
private slots:
void showPicker();
void pickerHid();
void pickerColorChanged(const QColor &color);
signals:
void pickingFinished();
};
}
#endif

View file

@ -0,0 +1,86 @@
#include "colorpickerpopup.hpp"
#include <QColorDialog>
#include <QPushButton>
#include <QEvent>
#include <QKeyEvent>
#include <QMouseEvent>
#include <QLayout>
#include <QStyleOption>
CSVWidget::ColorPickerPopup::ColorPickerPopup(QWidget *parent)
: QFrame(parent)
{
setWindowFlags(Qt::Popup);
setFrameStyle(QFrame::Box | QFrame::Plain);
hide();
mColorPicker = new QColorDialog(this);
mColorPicker->setWindowFlags(Qt::Widget);
mColorPicker->setOptions(QColorDialog::NoButtons | QColorDialog::DontUseNativeDialog);
mColorPicker->installEventFilter(this);
mColorPicker->open();
connect(mColorPicker,
SIGNAL(currentColorChanged(const QColor &)),
this,
SIGNAL(colorChanged(const QColor &)));
QVBoxLayout *layout = new QVBoxLayout(this);
layout->addWidget(mColorPicker);
layout->setAlignment(Qt::AlignTop | Qt::AlignLeft);
layout->setContentsMargins(0, 0, 0, 0);
setLayout(layout);
setFixedSize(mColorPicker->size());
}
void CSVWidget::ColorPickerPopup::showPicker(const QPoint &position, const QColor &initialColor)
{
QRect geometry = this->geometry();
geometry.moveTo(position);
setGeometry(geometry);
mColorPicker->setCurrentColor(initialColor);
show();
}
void CSVWidget::ColorPickerPopup::mousePressEvent(QMouseEvent *event)
{
QPushButton *button = qobject_cast<QPushButton *>(parentWidget());
if (button != NULL)
{
QStyleOptionButton option;
option.init(button);
QRect buttonRect = option.rect;
buttonRect.moveTo(button->mapToGlobal(buttonRect.topLeft()));
// If the mouse is pressed above the pop-up parent,
// the pop-up will be hidden and the pressed signal won't be repeated for the parent
if (buttonRect.contains(event->globalPos()) || buttonRect.contains(event->pos()))
{
setAttribute(Qt::WA_NoMouseReplay);
}
}
QFrame::mousePressEvent(event);
}
void CSVWidget::ColorPickerPopup::hideEvent(QHideEvent *event)
{
QFrame::hideEvent(event);
emit hid();
}
bool CSVWidget::ColorPickerPopup::eventFilter(QObject *object, QEvent *event)
{
if (object == mColorPicker && event->type() == QEvent::KeyPress)
{
QKeyEvent *keyEvent = static_cast<QKeyEvent *>(event);
// Prevent QColorDialog from closing when Escape is pressed.
// Instead, hide the popup.
if (keyEvent->key() == Qt::Key_Escape)
{
hide();
return true;
}
}
return QFrame::eventFilter(object, event);
}

View file

@ -0,0 +1,32 @@
#ifndef CSVWIDGET_COLORPICKERPOPUP_HPP
#define CSVWIDGET_COLORPICKERPOPUP_HPP
#include <QFrame>
class QColorDialog;
namespace CSVWidget
{
class ColorPickerPopup : public QFrame
{
Q_OBJECT
QColorDialog *mColorPicker;
public:
explicit ColorPickerPopup(QWidget *parent);
void showPicker(const QPoint &position, const QColor &initialColor);
protected:
virtual void mousePressEvent(QMouseEvent *event);
virtual void hideEvent(QHideEvent *event);
virtual bool eventFilter(QObject *object, QEvent *event);
signals:
void hid();
void colorChanged(const QColor &color);
};
}
#endif

View file

@ -65,8 +65,13 @@ CSVWidget::SceneToolRun::SceneToolRun (SceneToolbar *parent, const QString& tool
mTable->setShowGrid (false); mTable->setShowGrid (false);
mTable->verticalHeader()->hide(); mTable->verticalHeader()->hide();
mTable->horizontalHeader()->hide(); mTable->horizontalHeader()->hide();
#if QT_VERSION >= QT_VERSION_CHECK(5,0,0)
mTable->horizontalHeader()->setSectionResizeMode (0, QHeaderView::Stretch);
mTable->horizontalHeader()->setSectionResizeMode (1, QHeaderView::ResizeToContents);
#else
mTable->horizontalHeader()->setResizeMode (0, QHeaderView::Stretch); mTable->horizontalHeader()->setResizeMode (0, QHeaderView::Stretch);
mTable->horizontalHeader()->setResizeMode (1, QHeaderView::ResizeToContents); mTable->horizontalHeader()->setResizeMode (1, QHeaderView::ResizeToContents);
#endif
mTable->setSelectionMode (QAbstractItemView::NoSelection); mTable->setSelectionMode (QAbstractItemView::NoSelection);
layout->addWidget (mTable); layout->addWidget (mTable);

View file

@ -0,0 +1,36 @@
#include "colordelegate.hpp"
#include <QPainter>
#include <QPushButton>
#include "../widget/coloreditor.hpp"
CSVWorld::ColorDelegate::ColorDelegate(CSMWorld::CommandDispatcher *dispatcher,
CSMDoc::Document& document,
QObject *parent)
: CommandDelegate(dispatcher, document, parent)
{}
void CSVWorld::ColorDelegate::paint(QPainter *painter,
const QStyleOptionViewItem &option,
const QModelIndex &index) const
{
QRect coloredRect(option.rect.x() + qRound(option.rect.width() / 4.0),
option.rect.y() + qRound(option.rect.height() / 4.0),
option.rect.width() / 2,
option.rect.height() / 2);
painter->save();
painter->fillRect(coloredRect, index.data().value<QColor>());
painter->setPen(Qt::black);
painter->drawRect(coloredRect);
painter->restore();
}
CSVWorld::CommandDelegate *CSVWorld::ColorDelegateFactory::makeDelegate(CSMWorld::CommandDispatcher *dispatcher,
CSMDoc::Document &document,
QObject *parent) const
{
return new ColorDelegate(dispatcher, document, parent);
}

View file

@ -0,0 +1,37 @@
#ifndef CSV_WORLD_COLORDELEGATE_HPP
#define CSV_WORLD_COLORDELEGATE_HPP
#include "util.hpp"
class QRect;
namespace CSVWidget
{
class ColorEditButton;
}
namespace CSVWorld
{
class ColorDelegate : public CommandDelegate
{
public:
ColorDelegate(CSMWorld::CommandDispatcher *dispatcher,
CSMDoc::Document& document,
QObject *parent);
virtual void paint(QPainter *painter,
const QStyleOptionViewItem &option,
const QModelIndex &index) const;
};
class ColorDelegateFactory : public CommandDelegateFactory
{
public:
virtual CommandDelegate *makeDelegate(CSMWorld::CommandDispatcher *dispatcher,
CSMDoc::Document &document,
QObject *parent) const;
///< The ownership of the returned CommandDelegate is transferred to the caller.
};
}
#endif

View file

@ -12,11 +12,10 @@ CSVWorld::DataDisplayDelegate::DataDisplayDelegate(const ValueList &values,
const QString &settingName, const QString &settingName,
QObject *parent) QObject *parent)
: EnumDelegate (values, dispatcher, document, parent), mDisplayMode (Mode_TextOnly), : EnumDelegate (values, dispatcher, document, parent), mDisplayMode (Mode_TextOnly),
mIcons (icons), mIconSize (QSize(16, 16)), mIconLeftOffset(3), mIcons (icons), mIconSize (QSize(16, 16)),
mHorizontalMargin(QApplication::style()->pixelMetric(QStyle::PM_FocusFrameHMargin) + 1),
mTextLeftOffset(8), mSettingKey (pageName + '/' + settingName) mTextLeftOffset(8), mSettingKey (pageName + '/' + settingName)
{ {
mTextAlignment.setAlignment (Qt::AlignLeft | Qt::AlignVCenter );
buildPixmaps(); buildPixmaps();
QString value = QString value =
@ -45,16 +44,35 @@ void CSVWorld::DataDisplayDelegate::setIconSize(const QSize& size)
buildPixmaps(); buildPixmaps();
} }
void CSVWorld::DataDisplayDelegate::setIconLeftOffset(int offset)
{
mIconLeftOffset = offset;
}
void CSVWorld::DataDisplayDelegate::setTextLeftOffset(int offset) void CSVWorld::DataDisplayDelegate::setTextLeftOffset(int offset)
{ {
mTextLeftOffset = offset; mTextLeftOffset = offset;
} }
QSize CSVWorld::DataDisplayDelegate::sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const
{
QSize size = EnumDelegate::sizeHint(option, index);
int valueIndex = getValueIndex(index);
if (valueIndex != -1)
{
if (mDisplayMode == Mode_IconOnly)
{
size.setWidth(mIconSize.width() + 2 * mHorizontalMargin);
}
else if (mDisplayMode == Mode_IconAndText)
{
size.setWidth(size.width() + mIconSize.width() + mTextLeftOffset);
}
if (mDisplayMode != Mode_TextOnly)
{
size.setHeight(qMax(size.height(), mIconSize.height()));
}
}
return size;
}
void CSVWorld::DataDisplayDelegate::paint (QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const void CSVWorld::DataDisplayDelegate::paint (QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
{ {
painter->save(); painter->save();
@ -64,16 +82,11 @@ void CSVWorld::DataDisplayDelegate::paint (QPainter *painter, const QStyleOption
EnumDelegate::paint(painter, option, index); EnumDelegate::paint(painter, option, index);
else else
{ {
unsigned int i = 0; int valueIndex = getValueIndex(index);
if (valueIndex != -1)
for (; i < mValues.size(); ++i)
{ {
if (mValues.at(i).first == index.data().toInt()) paintIcon(painter, option, valueIndex);
break;
} }
if (i < mValues.size() )
paintIcon (painter, option, i);
} }
painter->restore(); painter->restore();
@ -81,24 +94,28 @@ void CSVWorld::DataDisplayDelegate::paint (QPainter *painter, const QStyleOption
void CSVWorld::DataDisplayDelegate::paintIcon (QPainter *painter, const QStyleOptionViewItem &option, int index) const void CSVWorld::DataDisplayDelegate::paintIcon (QPainter *painter, const QStyleOptionViewItem &option, int index) const
{ {
//function-level statics
QRect iconRect = option.rect; QRect iconRect = option.rect;
QRect textRect = iconRect; QRect textRect = iconRect;
const QString &text = mValues.at(index).second; iconRect.setLeft(iconRect.left() + mHorizontalMargin);
iconRect.setRight(option.rect.right() - mHorizontalMargin);
iconRect.setSize (mIconSize);
iconRect.translate(mIconLeftOffset, (option.rect.height() - iconRect.height())/2);
if (mDisplayMode == Mode_IconAndText) if (mDisplayMode == Mode_IconAndText)
{ {
textRect.translate (iconRect.width() + mTextLeftOffset, 0 ); iconRect.setWidth(mIconSize.width());
painter->drawText (textRect, text, mTextAlignment); textRect.setLeft(iconRect.right() + mTextLeftOffset);
} textRect.setRight(option.rect.right() - mHorizontalMargin);
else
iconRect.translate( (option.rect.width() - iconRect.width()) / 2, 0);
painter->drawPixmap (iconRect, mPixmaps.at(index).second); QString text = option.fontMetrics.elidedText(mValues.at(index).second,
option.textElideMode,
textRect.width());
QApplication::style()->drawItemText(painter,
textRect,
Qt::AlignLeft | Qt::AlignVCenter,
option.palette,
true,
text);
}
QApplication::style()->drawItemPixmap(painter, iconRect, Qt::AlignCenter, mPixmaps.at(index).second);
} }
void CSVWorld::DataDisplayDelegate::updateUserSetting (const QString &name, void CSVWorld::DataDisplayDelegate::updateUserSetting (const QString &name,

View file

@ -30,9 +30,8 @@ namespace CSVWorld
private: private:
std::vector <std::pair <int, QPixmap> > mPixmaps; std::vector <std::pair <int, QPixmap> > mPixmaps;
QTextOption mTextAlignment;
QSize mIconSize; QSize mIconSize;
int mIconLeftOffset; int mHorizontalMargin;
int mTextLeftOffset; int mTextLeftOffset;
QString mSettingKey; QString mSettingKey;
@ -46,12 +45,11 @@ namespace CSVWorld
virtual void paint (QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const; virtual void paint (QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const;
virtual QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const;
/// pass a QSize defining height / width of icon. Default is QSize (16,16). /// pass a QSize defining height / width of icon. Default is QSize (16,16).
void setIconSize (const QSize& icon); void setIconSize (const QSize& icon);
/// offset the horizontal position of the icon from the left edge of the cell. Default is 3 pixels.
void setIconLeftOffset (int offset);
/// offset the horizontal position of the text from the right edge of the icon. Default is 8 pixels. /// offset the horizontal position of the text from the right edge of the icon. Default is 8 pixels.
void setTextLeftOffset (int offset); void setTextLeftOffset (int offset);

View file

@ -33,6 +33,8 @@
#include "../../model/world/commands.hpp" #include "../../model/world/commands.hpp"
#include "../../model/doc/document.hpp" #include "../../model/doc/document.hpp"
#include "../widget/coloreditor.hpp"
#include "recordstatusdelegate.hpp" #include "recordstatusdelegate.hpp"
#include "util.hpp" #include "util.hpp"
#include "tablebottombox.hpp" #include "tablebottombox.hpp"
@ -331,6 +333,10 @@ QWidget* CSVWorld::DialogueDelegateDispatcher::makeEditor(CSMWorld::ColumnBase::
{ {
connect(editor, SIGNAL(editingFinished()), proxy, SLOT(editorDataCommited())); connect(editor, SIGNAL(editingFinished()), proxy, SLOT(editorDataCommited()));
} }
else if (qobject_cast<CSVWidget::ColorEditor *>(editor))
{
connect(editor, SIGNAL(pickingFinished()), proxy, SLOT(editorDataCommited()));
}
else // throw an exception because this is a coding error else // throw an exception because this is a coding error
throw std::logic_error ("Dialogue editor type missing"); throw std::logic_error ("Dialogue editor type missing");
@ -469,8 +475,7 @@ void CSVWorld::EditWidget::remake(int row)
mTable->data (mTable->index (row, idColumn)).toString().toUtf8().constData()); mTable->data (mTable->index (row, idColumn)).toString().toUtf8().constData());
NestedTable* table = new NestedTable(mDocument, id, mNestedModels.back(), this); NestedTable* table = new NestedTable(mDocument, id, mNestedModels.back(), this);
// FIXME: does not work well when enum delegates are used table->resizeColumnsToContents();
//table->resizeColumnsToContents();
if(mTable->index(row, i).data().type() == QVariant::UserType) if(mTable->index(row, i).data().type() == QVariant::UserType)
{ {

View file

@ -1,4 +1,5 @@
#include <QDrag> #include <QDrag>
#include <QDragEnterEvent>
#include "../../model/world/tablemimedata.hpp" #include "../../model/world/tablemimedata.hpp"
#include "dragrecordtable.hpp" #include "dragrecordtable.hpp"

View file

@ -2,7 +2,7 @@
#define CSV_WORLD_DRAGRECORDTABLE_H #define CSV_WORLD_DRAGRECORDTABLE_H
#include <QTableView> #include <QTableView>
#include <QtGui/qevent.h> #include <QEvent>
class QWidget; class QWidget;
class QAction; class QAction;

View file

@ -10,6 +10,24 @@
#include "../../model/world/commands.hpp" #include "../../model/world/commands.hpp"
int CSVWorld::EnumDelegate::getValueIndex(const QModelIndex &index, int role) const
{
if (index.isValid() && index.data(role).isValid())
{
int value = index.data(role).toInt();
int size = static_cast<int>(mValues.size());
for (int i = 0; i < size; ++i)
{
if (value == mValues.at(i).first)
{
return i;
}
}
}
return -1;
}
void CSVWorld::EnumDelegate::setModelDataImp (QWidget *editor, QAbstractItemModel *model, void CSVWorld::EnumDelegate::setModelDataImp (QWidget *editor, QAbstractItemModel *model,
const QModelIndex& index) const const QModelIndex& index) const
{ {
@ -69,26 +87,20 @@ void CSVWorld::EnumDelegate::setEditorData (QWidget *editor, const QModelIndex&
{ {
if (QComboBox *comboBox = dynamic_cast<QComboBox *>(editor)) if (QComboBox *comboBox = dynamic_cast<QComboBox *>(editor))
{ {
QVariant data = index.data (Qt::EditRole); int role = Qt::EditRole;
if (tryDisplay && !index.data(role).isValid())
if (tryDisplay && !data.isValid())
{ {
data = index.data (Qt::DisplayRole); role = Qt::DisplayRole;
if (!data.isValid()) if (!index.data(role).isValid())
{ {
return; return;
} }
} }
int value = data.toInt(); int valueIndex = getValueIndex(index, role);
if (valueIndex != -1)
std::size_t size = mValues.size();
for (std::size_t i=0; i<size; ++i)
if (mValues[i].first==value)
{ {
comboBox->setCurrentIndex (i); comboBox->setCurrentIndex(valueIndex);
break;
} }
} }
} }
@ -96,25 +108,36 @@ void CSVWorld::EnumDelegate::setEditorData (QWidget *editor, const QModelIndex&
void CSVWorld::EnumDelegate::paint (QPainter *painter, const QStyleOptionViewItem& option, void CSVWorld::EnumDelegate::paint (QPainter *painter, const QStyleOptionViewItem& option,
const QModelIndex& index) const const QModelIndex& index) const
{ {
if (index.data().isValid()) int valueIndex = getValueIndex(index);
if (valueIndex != -1)
{ {
QStyleOptionViewItemV4 option2 (option); QStyleOptionViewItemV4 itemOption(option);
itemOption.text = mValues.at(valueIndex).second;
QApplication::style()->drawControl(QStyle::CE_ItemViewItem, &itemOption, painter);
}
}
int value = index.data().toInt(); QSize CSVWorld::EnumDelegate::sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const
for (std::vector<std::pair<int, QString> >::const_iterator iter (mValues.begin());
iter!=mValues.end(); ++iter)
if (iter->first==value)
{ {
option2.text = iter->second; int valueIndex = getValueIndex(index);
if (valueIndex != -1)
{
// Calculate the size hint as for a combobox.
// So, the whole text is visible (isn't elided) when the editor is created
QStyleOptionComboBox itemOption;
itemOption.fontMetrics = option.fontMetrics;
itemOption.palette = option.palette;
itemOption.rect = option.rect;
itemOption.state = option.state;
QApplication::style()->drawControl (QStyle::CE_ItemViewItem, &option2, painter); const QString &valueText = mValues.at(valueIndex).second;
QSize valueSize = QSize(itemOption.fontMetrics.width(valueText), itemOption.fontMetrics.height());
break; itemOption.currentText = valueText;
return QApplication::style()->sizeFromContents(QStyle::CT_ComboBox, &itemOption, valueSize);
} }
return option.rect.size();
} }
}
CSVWorld::EnumDelegateFactory::EnumDelegateFactory() {} CSVWorld::EnumDelegateFactory::EnumDelegateFactory() {}

View file

@ -19,6 +19,8 @@ namespace CSVWorld
std::vector<std::pair<int, QString> > mValues; std::vector<std::pair<int, QString> > mValues;
int getValueIndex(const QModelIndex &index, int role = Qt::DisplayRole) const;
private: private:
virtual void setModelDataImp (QWidget *editor, QAbstractItemModel *model, virtual void setModelDataImp (QWidget *editor, QAbstractItemModel *model,
@ -46,6 +48,8 @@ namespace CSVWorld
virtual void paint (QPainter *painter, const QStyleOptionViewItem& option, virtual void paint (QPainter *painter, const QStyleOptionViewItem& option,
const QModelIndex& index) const; const QModelIndex& index) const;
virtual QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const;
}; };
class EnumDelegateFactory : public CommandDelegateFactory class EnumDelegateFactory : public CommandDelegateFactory

View file

@ -23,7 +23,11 @@ CSVWorld::NestedTable::NestedTable(CSMDoc::Document& document,
setSelectionBehavior (QAbstractItemView::SelectRows); setSelectionBehavior (QAbstractItemView::SelectRows);
setSelectionMode (QAbstractItemView::ExtendedSelection); setSelectionMode (QAbstractItemView::ExtendedSelection);
#if QT_VERSION >= QT_VERSION_CHECK(5,0,0)
horizontalHeader()->setSectionResizeMode (QHeaderView::Interactive);
#else
horizontalHeader()->setResizeMode (QHeaderView::Interactive); horizontalHeader()->setResizeMode (QHeaderView::Interactive);
#endif
verticalHeader()->hide(); verticalHeader()->hide();
int columns = model->columnCount(QModelIndex()); int columns = model->columnCount(QModelIndex());

View file

@ -2,7 +2,7 @@
#define CSV_WORLD_NESTEDTABLE_H #define CSV_WORLD_NESTEDTABLE_H
#include <QTableView> #include <QTableView>
#include <QtGui/qevent.h> #include <QEvent>
class QUndoStack; class QUndoStack;
class QAction; class QAction;

View file

@ -68,10 +68,10 @@ void CSVWorld::addSubViewFactories (CSVDoc::SubViewFactoryManager& manager)
new CSVDoc::SubViewFactoryWithCreator<TableSubView, JournalCreatorFactory>); new CSVDoc::SubViewFactoryWithCreator<TableSubView, JournalCreatorFactory>);
manager.add (CSMWorld::UniversalId::Type_TopicInfos, manager.add (CSMWorld::UniversalId::Type_TopicInfos,
new CSVDoc::SubViewFactoryWithCreator<TableSubView, CreatorFactory<InfoCreator> > (false)); new CSVDoc::SubViewFactoryWithCreator<TableSubView, CreatorFactory<InfoCreator> >);
manager.add (CSMWorld::UniversalId::Type_JournalInfos, manager.add (CSMWorld::UniversalId::Type_JournalInfos,
new CSVDoc::SubViewFactoryWithCreator<TableSubView, CreatorFactory<InfoCreator> > (false)); new CSVDoc::SubViewFactoryWithCreator<TableSubView, CreatorFactory<InfoCreator> >);
// Subviews for resources tables // Subviews for resources tables
manager.add (CSMWorld::UniversalId::Type_Meshes, manager.add (CSMWorld::UniversalId::Type_Meshes,

View file

@ -13,6 +13,7 @@
#include "../../model/world/data.hpp" #include "../../model/world/data.hpp"
#include "../../model/world/commands.hpp" #include "../../model/world/commands.hpp"
#include "../../model/world/infotableproxymodel.hpp"
#include "../../model/world/idtableproxymodel.hpp" #include "../../model/world/idtableproxymodel.hpp"
#include "../../model/world/idtablebase.hpp" #include "../../model/world/idtablebase.hpp"
#include "../../model/world/idtable.hpp" #include "../../model/world/idtable.hpp"
@ -279,13 +280,26 @@ CSVWorld::Table::Table (const CSMWorld::UniversalId& id,
mModel = &dynamic_cast<CSMWorld::IdTableBase&> (*mDocument.getData().getTableModel (id)); mModel = &dynamic_cast<CSMWorld::IdTableBase&> (*mDocument.getData().getTableModel (id));
bool isInfoTable = id.getType() == CSMWorld::UniversalId::Type_TopicInfos ||
id.getType() == CSMWorld::UniversalId::Type_JournalInfos;
if (isInfoTable)
{
mProxyModel = new CSMWorld::InfoTableProxyModel(id.getType(), this);
}
else
{
mProxyModel = new CSMWorld::IdTableProxyModel (this); mProxyModel = new CSMWorld::IdTableProxyModel (this);
}
mProxyModel->setSourceModel (mModel); mProxyModel->setSourceModel (mModel);
mDispatcher = new CSMWorld::CommandDispatcher (document, id, this); mDispatcher = new CSMWorld::CommandDispatcher (document, id, this);
setModel (mProxyModel); setModel (mProxyModel);
#if QT_VERSION >= QT_VERSION_CHECK(5,0,0)
horizontalHeader()->setSectionResizeMode (QHeaderView::Interactive);
#else
horizontalHeader()->setResizeMode (QHeaderView::Interactive); horizontalHeader()->setResizeMode (QHeaderView::Interactive);
#endif
verticalHeader()->hide(); verticalHeader()->hide();
setSortingEnabled (sorting); setSortingEnabled (sorting);
setSelectionBehavior (QAbstractItemView::SelectRows); setSelectionBehavior (QAbstractItemView::SelectRows);

View file

@ -4,7 +4,7 @@
#include <vector> #include <vector>
#include <string> #include <string>
#include <QtGui/qevent.h> #include <QEvent>
#include "../../model/filter/node.hpp" #include "../../model/filter/node.hpp"
#include "../../model/world/columnbase.hpp" #include "../../model/world/columnbase.hpp"

View file

@ -8,6 +8,7 @@
#include <QHeaderView> #include <QHeaderView>
#include <QApplication> #include <QApplication>
#include <QDesktopWidget> #include <QDesktopWidget>
#include <QDropEvent>
#include "../../model/doc/document.hpp" #include "../../model/doc/document.hpp"
#include "../../model/world/tablemimedata.hpp" #include "../../model/world/tablemimedata.hpp"

View file

@ -17,6 +17,7 @@
#include "../../model/world/commands.hpp" #include "../../model/world/commands.hpp"
#include "../../model/world/tablemimedata.hpp" #include "../../model/world/tablemimedata.hpp"
#include "../../model/world/commanddispatcher.hpp" #include "../../model/world/commanddispatcher.hpp"
#include "../widget/coloreditor.hpp"
#include "dialoguespinbox.hpp" #include "dialoguespinbox.hpp"
#include "scriptedit.hpp" #include "scriptedit.hpp"
@ -123,10 +124,19 @@ void CSVWorld::CommandDelegate::setModelDataImp (QWidget *editor, QAbstractItemM
if (!mCommandDispatcher) if (!mCommandDispatcher)
return; return;
QVariant new_;
// Color columns use a custom editor, so we need explicitly extract a data from it
CSVWidget::ColorEditor *colorEditor = qobject_cast<CSVWidget::ColorEditor *>(editor);
if (colorEditor != NULL)
{
new_ = colorEditor->color();
}
else
{
NastyTableModelHack hack (*model); NastyTableModelHack hack (*model);
QStyledItemDelegate::setModelData (editor, &hack, index); QStyledItemDelegate::setModelData (editor, &hack, index);
new_ = hack.getData();
QVariant new_ = hack.getData(); }
if ((model->data (index)!=new_) && (model->flags(index) & Qt::ItemIsEditable)) if ((model->data (index)!=new_) && (model->flags(index) & Qt::ItemIsEditable))
mCommandDispatcher->executeModify (model, index, new_); mCommandDispatcher->executeModify (model, index, new_);
@ -162,6 +172,12 @@ QWidget *CSVWorld::CommandDelegate::createEditor (QWidget *parent, const QStyleO
{ {
return QStyledItemDelegate::createEditor(parent, option, index); return QStyledItemDelegate::createEditor(parent, option, index);
} }
// For tables the pop-up of the color editor should appear immediately after the editor creation
// (the third parameter of ColorEditor's constructor)
else if (display == CSMWorld::ColumnBase::Display_Colour)
{
return new CSVWidget::ColorEditor(index.data().value<QColor>(), parent, true);
}
return createEditor (parent, option, index, display); return createEditor (parent, option, index, display);
} }
@ -184,7 +200,7 @@ QWidget *CSVWorld::CommandDelegate::createEditor (QWidget *parent, const QStyleO
{ {
case CSMWorld::ColumnBase::Display_Colour: case CSMWorld::ColumnBase::Display_Colour:
return new QLineEdit(parent); return new CSVWidget::ColorEditor(index.data().value<QColor>(), parent);
case CSMWorld::ColumnBase::Display_Integer: case CSMWorld::ColumnBase::Display_Integer:
{ {
@ -284,6 +300,14 @@ void CSVWorld::CommandDelegate::setEditorData (QWidget *editor, const QModelInde
} }
} }
// Color columns use a custom editor, so we need explicitly set a data for it
CSVWidget::ColorEditor *colorEditor = qobject_cast<CSVWidget::ColorEditor *>(editor);
if (colorEditor != NULL)
{
colorEditor->setColor(index.data().value<QColor>());
return;
}
QByteArray n = editor->metaObject()->userProperty().name(); QByteArray n = editor->metaObject()->userProperty().name();
if (n == "dateTime") { if (n == "dateTime") {

View file

@ -91,17 +91,6 @@ add_openmw_dir (mwbase
) )
# Main executable # Main executable
if (ANDROID)
set(BOOST_COMPONENTS system filesystem program_options thread wave atomic)
else ()
set(BOOST_COMPONENTS system filesystem program_options thread wave)
endif ()
if(WIN32)
set(BOOST_COMPONENTS ${BOOST_COMPONENTS} locale)
endif(WIN32)
find_package(Boost REQUIRED COMPONENTS ${BOOST_COMPONENTS})
if (NOT ANDROID) if (NOT ANDROID)
add_executable(openmw add_executable(openmw
@ -126,10 +115,14 @@ target_link_libraries(openmw
${OGRE_LIBRARIES} ${OGRE_LIBRARIES}
${OGRE_STATIC_PLUGINS} ${OGRE_STATIC_PLUGINS}
${SHINY_LIBRARIES} ${SHINY_LIBRARIES}
${Boost_LIBRARIES}
${OPENAL_LIBRARY} ${OPENAL_LIBRARY}
${SOUND_INPUT_LIBRARY} ${SOUND_INPUT_LIBRARY}
${BULLET_LIBRARIES} ${BULLET_LIBRARIES}
${Boost_SYSTEM_LIBRARY}
${Boost_THREAD_LIBRARY}
${Boost_FILESYSTEM_LIBRARY}
${Boost_PROGRAM_OPTIONS_LIBRARY}
${Boost_WAVE_LIBRARY}
${MYGUI_LIBRARIES} ${MYGUI_LIBRARIES}
${SDL2_LIBRARY} ${SDL2_LIBRARY}
${MYGUI_PLATFORM_LIBRARIES} ${MYGUI_PLATFORM_LIBRARIES}

View file

@ -677,44 +677,32 @@ namespace MWMechanics
return false; return false;
} }
void AiCombat::buildNewPath(const MWWorld::Ptr& actor, const MWWorld::Ptr& target) bool AiCombat::doesPathNeedRecalc(ESM::Pathgrid::Point dest, const ESM::Cell *cell)
{ {
Ogre::Vector3 newPathTarget = Ogre::Vector3(target.getRefData().getPosition().pos);
float dist;
if (!mPathFinder.getPath().empty()) if (!mPathFinder.getPath().empty())
{ {
ESM::Pathgrid::Point lastPt = mPathFinder.getPath().back(); Ogre::Vector3 currPathTarget(PathFinder::MakeOgreVector3(mPathFinder.getPath().back()));
Ogre::Vector3 currPathTarget(PathFinder::MakeOgreVector3(lastPt)); Ogre::Vector3 newPathTarget = PathFinder::MakeOgreVector3(dest);
dist = (newPathTarget - currPathTarget).length(); float dist = (newPathTarget - currPathTarget).length();
float targetPosThreshold = (cell->isExterior()) ? 300.0f : 100.0f;
return dist > targetPosThreshold;
} }
else dist = 1e+38F; // necessarily construct a new path
float targetPosThreshold = (actor.getCell()->getCell()->isExterior())? 300.0f : 100.0f;
//construct new path only if target has moved away more than on [targetPosThreshold]
if(dist > targetPosThreshold)
{
ESM::Position pos = actor.getRefData().getPosition();
ESM::Pathgrid::Point start(PathFinder::MakePathgridPoint(pos));
ESM::Pathgrid::Point dest(PathFinder::MakePathgridPoint(newPathTarget));
if(!mPathFinder.isPathConstructed())
mPathFinder.buildPath(start, dest, actor.getCell(), false);
else else
{ {
PathFinder newPathFinder; // necessarily construct a new path
newPathFinder.buildPath(start, dest, actor.getCell(), false); return true;
}
}
if(!mPathFinder.getPath().empty()) void AiCombat::buildNewPath(const MWWorld::Ptr& actor, const MWWorld::Ptr& target)
{ {
newPathFinder.syncStart(mPathFinder.getPath()); ESM::Pathgrid::Point newPathTarget = PathFinder::MakePathgridPoint(target.getRefData().getPosition());
mPathFinder = newPathFinder;
} //construct new path only if target has moved away more than on [targetPosThreshold]
} if (doesPathNeedRecalc(newPathTarget, actor.getCell()->getCell()))
{
ESM::Pathgrid::Point start(PathFinder::MakePathgridPoint(actor.getRefData().getPosition()));
mPathFinder.buildSyncedPath(start, newPathTarget, actor.getCell(), false);
} }
} }

View file

@ -53,6 +53,9 @@ namespace MWMechanics
virtual void writeState(ESM::AiSequence::AiSequence &sequence) const; virtual void writeState(ESM::AiSequence::AiSequence &sequence) const;
protected:
virtual bool doesPathNeedRecalc(ESM::Pathgrid::Point dest, const ESM::Cell *cell);
private: private:
int mTargetActorId; int mTargetActorId;

View file

@ -30,9 +30,9 @@ bool MWMechanics::AiPackage::pathTo(const MWWorld::Ptr& actor, ESM::Pathgrid::Po
ESM::Position pos = actor.getRefData().getPosition(); //position of the actor ESM::Position pos = actor.getRefData().getPosition(); //position of the actor
/// Stops the actor when it gets too close to a unloaded cell /// Stops the actor when it gets too close to a unloaded cell
const ESM::Cell *cell = actor.getCell()->getCell();
{ {
MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr();
const ESM::Cell *cell = actor.getCell()->getCell();
Movement &movement = actor.getClass().getMovementSettings(actor); Movement &movement = actor.getClass().getMovementSettings(actor);
//Ensure pursuer doesn't leave loaded cells //Ensure pursuer doesn't leave loaded cells
@ -67,8 +67,8 @@ bool MWMechanics::AiPackage::pathTo(const MWWorld::Ptr& actor, ESM::Pathgrid::Po
//*********************** //***********************
if(mTimer > 0.25) if(mTimer > 0.25)
{ {
if(distance(mPrevDest, dest) > 10) { //Only rebuild path if it's moved if (doesPathNeedRecalc(dest, cell)) { //Only rebuild path if it's moved
mPathFinder.buildPath(start, dest, actor.getCell(), true); //Rebuild path, in case the target has moved mPathFinder.buildSyncedPath(start, dest, actor.getCell(), true); //Rebuild path, in case the target has moved
mPrevDest = dest; mPrevDest = dest;
} }
@ -123,3 +123,8 @@ bool MWMechanics::AiPackage::pathTo(const MWWorld::Ptr& actor, ESM::Pathgrid::Po
return false; return false;
} }
bool MWMechanics::AiPackage::doesPathNeedRecalc(ESM::Pathgrid::Point dest, const ESM::Cell *cell)
{
return distance(mPrevDest, dest) > 10;
}

View file

@ -14,6 +14,7 @@ namespace MWWorld
namespace ESM namespace ESM
{ {
struct Cell;
namespace AiSequence namespace AiSequence
{ {
struct AiSequence; struct AiSequence;
@ -71,6 +72,8 @@ namespace MWMechanics
/** \return If the actor has arrived at his destination **/ /** \return If the actor has arrived at his destination **/
bool pathTo(const MWWorld::Ptr& actor, ESM::Pathgrid::Point dest, float duration); bool pathTo(const MWWorld::Ptr& actor, ESM::Pathgrid::Point dest, float duration);
virtual bool doesPathNeedRecalc(ESM::Pathgrid::Point dest, const ESM::Cell *cell);
// TODO: all this does not belong here, move into temporary storage // TODO: all this does not belong here, move into temporary storage
PathFinder mPathFinder; PathFinder mPathFinder;
ObstacleCheck mObstacleCheck; ObstacleCheck mObstacleCheck;

View file

@ -51,64 +51,31 @@ namespace MWMechanics
bool AiTravel::execute (const MWWorld::Ptr& actor, AiState& state, float duration) bool AiTravel::execute (const MWWorld::Ptr& actor, AiState& state, float duration)
{ {
MWBase::World *world = MWBase::Environment::get().getWorld();
ESM::Position pos = actor.getRefData().getPosition(); ESM::Position pos = actor.getRefData().getPosition();
Movement &movement = actor.getClass().getMovementSettings(actor);
const ESM::Cell *cell = actor.getCell()->getCell();
actor.getClass().getCreatureStats(actor).setMovementFlag(CreatureStats::Flag_Run, false); actor.getClass().getCreatureStats(actor).setMovementFlag(CreatureStats::Flag_Run, false);
actor.getClass().getCreatureStats(actor).setDrawState(DrawState_Nothing); actor.getClass().getCreatureStats(actor).setDrawState(DrawState_Nothing);
MWWorld::Ptr player = world->getPlayerPtr();
if(cell->mData.mX != player.getCell()->getCell()->mData.mX)
{
int sideX = PathFinder::sgn(cell->mData.mX - player.getCell()->getCell()->mData.mX);
//check if actor is near the border of an inactive cell. If so, stop walking.
if(sideX * (pos.pos[0] - cell->mData.mX*ESM::Land::REAL_SIZE) >
sideX * (ESM::Land::REAL_SIZE/2.0f - 200.0f))
{
movement.mPosition[1] = 0;
return false;
}
}
if(cell->mData.mY != player.getCell()->getCell()->mData.mY)
{
int sideY = PathFinder::sgn(cell->mData.mY - player.getCell()->getCell()->mData.mY);
//check if actor is near the border of an inactive cell. If so, stop walking.
if(sideY * (pos.pos[1] - cell->mData.mY*ESM::Land::REAL_SIZE) >
sideY * (ESM::Land::REAL_SIZE/2.0f - 200.0f))
{
movement.mPosition[1] = 0;
return false;
}
}
if (!isWithinMaxRange(Ogre::Vector3(mX, mY, mZ), Ogre::Vector3(pos.pos))) if (!isWithinMaxRange(Ogre::Vector3(mX, mY, mZ), Ogre::Vector3(pos.pos)))
return false; return false;
if (pathTo(actor, ESM::Pathgrid::Point(static_cast<int>(mX), static_cast<int>(mY), static_cast<int>(mZ)), duration))
{
actor.getClass().getMovementSettings(actor).mPosition[1] = 0;
return true;
}
return false;
}
bool AiTravel::doesPathNeedRecalc(ESM::Pathgrid::Point dest, const ESM::Cell *cell)
{
bool cellChange = cell->mData.mX != mCellX || cell->mData.mY != mCellY; bool cellChange = cell->mData.mX != mCellX || cell->mData.mY != mCellY;
if (!mPathFinder.isPathConstructed() || cellChange) if (!mPathFinder.isPathConstructed() || cellChange)
{ {
mCellX = cell->mData.mX; mCellX = cell->mData.mX;
mCellY = cell->mData.mY; mCellY = cell->mData.mY;
ESM::Pathgrid::Point dest(static_cast<int>(mX), static_cast<int>(mY), static_cast<int>(mZ));
ESM::Pathgrid::Point start(PathFinder::MakePathgridPoint(pos));
mPathFinder.buildPath(start, dest, actor.getCell(), true);
}
if(mPathFinder.checkPathCompleted(pos.pos[0], pos.pos[1]))
{
movement.mPosition[1] = 0;
return true; return true;
} }
zTurn(actor, Ogre::Degree(mPathFinder.getZAngleToNext(pos.pos[0], pos.pos[1])));
movement.mPosition[1] = 1;
return false; return false;
} }

View file

@ -34,6 +34,9 @@ namespace MWMechanics
virtual int getTypeId() const; virtual int getTypeId() const;
protected:
virtual bool doesPathNeedRecalc(ESM::Pathgrid::Point dest, const ESM::Cell *cell);
private: private:
float mX; float mX;
float mY; float mY;

View file

@ -651,6 +651,9 @@ namespace MWMechanics
if (mAllowedNodes.empty()) if (mAllowedNodes.empty())
return; return;
if (actor.getClass().isPureWaterCreature(actor))
return;
state.moveIn(new AiWanderStorage()); state.moveIn(new AiWanderStorage());
int index = OEngine::Misc::Rng::rollDice(mAllowedNodes.size()); int index = OEngine::Misc::Rng::rollDice(mAllowedNodes.size());
@ -669,6 +672,9 @@ namespace MWMechanics
MWBase::Environment::get().getWorld()->moveObject(actor, static_cast<float>(dest.mX), MWBase::Environment::get().getWorld()->moveObject(actor, static_cast<float>(dest.mX),
static_cast<float>(dest.mY), static_cast<float>(dest.mZ)); static_cast<float>(dest.mY), static_cast<float>(dest.mZ));
actor.getClass().adjustPosition(actor, false); actor.getClass().adjustPosition(actor, false);
// may have changed cell
mStoredAvailableNodes = false;
} }
void AiWander::getAllowedNodes(const MWWorld::Ptr& actor, const ESM::Cell* cell) void AiWander::getAllowedNodes(const MWWorld::Ptr& actor, const ESM::Cell* cell)

View file

@ -114,8 +114,7 @@ namespace MWMechanics
} }
PathFinder::PathFinder() PathFinder::PathFinder()
: mIsPathConstructed(false), : mPathgrid(NULL),
mPathgrid(NULL),
mCell(NULL) mCell(NULL)
{ {
} }
@ -124,7 +123,6 @@ namespace MWMechanics
{ {
if(!mPath.empty()) if(!mPath.empty())
mPath.clear(); mPath.clear();
mIsPathConstructed = false;
} }
/* /*
@ -180,7 +178,6 @@ namespace MWMechanics
static_cast<float>(endPoint.mX), static_cast<float>(endPoint.mY), static_cast<float>(endPoint.mZ))) static_cast<float>(endPoint.mX), static_cast<float>(endPoint.mY), static_cast<float>(endPoint.mZ)))
{ {
mPath.push_back(endPoint); mPath.push_back(endPoint);
mIsPathConstructed = true;
return; return;
} }
} }
@ -197,7 +194,6 @@ namespace MWMechanics
if(!mPathgrid || mPathgrid->mPoints.empty()) if(!mPathgrid || mPathgrid->mPoints.empty())
{ {
mPath.push_back(endPoint); mPath.push_back(endPoint);
mIsPathConstructed = true;
return; return;
} }
@ -235,7 +231,6 @@ namespace MWMechanics
if(startNode == endNode.first) if(startNode == endNode.first)
{ {
mPath.push_back(endPoint); mPath.push_back(endPoint);
mIsPathConstructed = true;
return; return;
} }
@ -243,7 +238,6 @@ namespace MWMechanics
if(!mPath.empty()) if(!mPath.empty())
{ {
mIsPathConstructed = true;
// Add the destination (which may be different to the closest // Add the destination (which may be different to the closest
// pathgrid point). However only add if endNode was the closest // pathgrid point). However only add if endNode was the closest
// point to endPoint. // point to endPoint.
@ -256,14 +250,8 @@ namespace MWMechanics
if(endNode.second) if(endNode.second)
mPath.push_back(endPoint); mPath.push_back(endPoint);
} }
else
mIsPathConstructed = false;
} }
else
mIsPathConstructed = false;
} }
else
mIsPathConstructed = false;
return; return;
} }
@ -271,7 +259,7 @@ namespace MWMechanics
float PathFinder::getZAngleToNext(float x, float y) const float PathFinder::getZAngleToNext(float x, float y) const
{ {
// This should never happen (programmers should have an if statement checking // This should never happen (programmers should have an if statement checking
// mIsPathConstructed that prevents this call if otherwise). // isPathConstructed that prevents this call if otherwise).
if(mPath.empty()) if(mPath.empty())
return 0.; return 0.;
@ -293,7 +281,6 @@ namespace MWMechanics
mPath.pop_front(); mPath.pop_front();
if(mPath.empty()) if(mPath.empty())
{ {
mIsPathConstructed = false;
return true; return true;
} }
} }
@ -301,23 +288,35 @@ namespace MWMechanics
return false; return false;
} }
// used by AiCombat, see header for the rationale // see header for the rationale
bool PathFinder::syncStart(const std::list<ESM::Pathgrid::Point> &path) void PathFinder::buildSyncedPath(const ESM::Pathgrid::Point &startPoint,
const ESM::Pathgrid::Point &endPoint,
const MWWorld::CellStore* cell,
bool allowShortcuts)
{ {
if (mPath.size() < 2) if (mPath.size() < 2)
return false; //nothing to pop {
// if path has one point, then it's the destination.
std::list<ESM::Pathgrid::Point>::const_iterator oldStart = path.begin(); // don't need to worry about bad path for this case
buildPath(startPoint, endPoint, cell, allowShortcuts);
}
else
{
const ESM::Pathgrid::Point oldStart(*getPath().begin());
buildPath(startPoint, endPoint, cell, allowShortcuts);
if (mPath.size() >= 2)
{
// if 2nd waypoint of new path == 1st waypoint of old,
// delete 1st waypoint of new path.
std::list<ESM::Pathgrid::Point>::iterator iter = ++mPath.begin(); std::list<ESM::Pathgrid::Point>::iterator iter = ++mPath.begin();
if (iter->mX == oldStart.mX
if( (*iter).mX == oldStart->mX && iter->mY == oldStart.mY
&& (*iter).mY == oldStart->mY && iter->mZ == oldStart.mZ)
&& (*iter).mZ == oldStart->mZ)
{ {
mPath.pop_front(); mPath.pop_front();
return true;
} }
return false; }
}
} }
} }

View file

@ -48,7 +48,7 @@ namespace MWMechanics
bool isPathConstructed() const bool isPathConstructed() const
{ {
return mIsPathConstructed; return !mPath.empty();
} }
int getPathSize() const int getPathSize() const
@ -63,13 +63,13 @@ namespace MWMechanics
/** Synchronize new path with old one to avoid visiting 1 waypoint 2 times /** Synchronize new path with old one to avoid visiting 1 waypoint 2 times
@note @note
If the first point is chosen as the nearest one BuildPath() takes closest PathGrid point to NPC as first point of path.
the situation can occur when the 1st point of the new path is undesirable This is undesireable if NPC has just passed a Pathgrid point, as this
(i.e. the 2nd point of new path == the 1st point of old path). makes the 2nd point of the new path == the 1st point of old path.
@param path - old path Which results in NPC "running in a circle" back to the just passed waypoint.
@return true if such point was found and deleted
*/ */
bool syncStart(const std::list<ESM::Pathgrid::Point> &path); void buildSyncedPath(const ESM::Pathgrid::Point &startPoint, const ESM::Pathgrid::Point &endPoint,
const MWWorld::CellStore* cell, bool allowShortcuts = true);
void addPointToPath(ESM::Pathgrid::Point &point) void addPointToPath(ESM::Pathgrid::Point &point)
{ {
@ -96,8 +96,6 @@ namespace MWMechanics
private: private:
bool mIsPathConstructed;
std::list<ESM::Pathgrid::Point> mPath; std::list<ESM::Pathgrid::Point> mPath;
const ESM::Pathgrid *mPathgrid; const ESM::Pathgrid *mPathgrid;

View file

@ -188,7 +188,7 @@ namespace MWWorld
const T *ptr = search(id); const T *ptr = search(id);
if (ptr == 0) { if (ptr == 0) {
std::ostringstream msg; std::ostringstream msg;
msg << "Object '" << id << "' not found (const)"; msg << T::getRecordType() << " '" << id << "' not found";
throw std::runtime_error(msg.str()); throw std::runtime_error(msg.str());
} }
return ptr; return ptr;
@ -202,7 +202,7 @@ namespace MWWorld
if(ptr == 0) if(ptr == 0)
{ {
std::ostringstream msg; std::ostringstream msg;
msg << "Object starting with '"<<id<<"' not found (const)"; msg << T::getRecordType() << " starting with '"<<id<<"' not found";
throw std::runtime_error(msg.str()); throw std::runtime_error(msg.str());
} }
return ptr; return ptr;
@ -989,7 +989,7 @@ namespace MWWorld
const T *ptr = search(index); const T *ptr = search(index);
if (ptr == 0) { if (ptr == 0) {
std::ostringstream msg; std::ostringstream msg;
msg << "Object with index " << index << " not found"; msg << T::getRecordType() << " with index " << index << " not found";
throw std::runtime_error(msg.str()); throw std::runtime_error(msg.str());
} }
return ptr; return ptr;

View file

@ -81,7 +81,6 @@ endif (OPENMW_USE_UNSHIELD)
source_group(wizard FILES ${WIZARD} ${WIZARD_HEADER}) source_group(wizard FILES ${WIZARD} ${WIZARD_HEADER})
find_package(Qt4 REQUIRED)
set(QT_USE_QTGUI 1) set(QT_USE_QTGUI 1)
# Set some platform specific settings # Set some platform specific settings
@ -90,12 +89,17 @@ if(WIN32)
set(QT_USE_QTMAIN TRUE) set(QT_USE_QTMAIN TRUE)
endif(WIN32) endif(WIN32)
if (DESIRED_QT_VERSION MATCHES 4)
include(${QT_USE_FILE})
QT4_ADD_RESOURCES(RCC_SRCS ${CMAKE_SOURCE_DIR}/files/wizard/wizard.qrc) QT4_ADD_RESOURCES(RCC_SRCS ${CMAKE_SOURCE_DIR}/files/wizard/wizard.qrc)
QT4_WRAP_CPP(MOC_SRCS ${WIZARD_HEADER_MOC}) QT4_WRAP_CPP(MOC_SRCS ${WIZARD_HEADER_MOC})
QT4_WRAP_UI(UI_HDRS ${WIZARD_UI}) QT4_WRAP_UI(UI_HDRS ${WIZARD_UI})
else()
QT5_ADD_RESOURCES(RCC_SRCS ${CMAKE_SOURCE_DIR}/files/wizard/wizard.qrc)
QT5_WRAP_CPP(MOC_SRCS ${WIZARD_HEADER_MOC})
QT5_WRAP_UI(UI_HDRS ${WIZARD_UI})
endif()
include(${QT_USE_FILE})
include_directories(${CMAKE_CURRENT_BINARY_DIR}) include_directories(${CMAKE_CURRENT_BINARY_DIR})
if (OPENMW_USE_UNSHIELD) if (OPENMW_USE_UNSHIELD)
@ -112,11 +116,24 @@ add_executable(openmw-wizard
) )
target_link_libraries(openmw-wizard target_link_libraries(openmw-wizard
${Boost_LIBRARIES}
${QT_LIBRARIES}
components components
) )
if (DESIRED_QT_VERSION MATCHES 4)
target_link_libraries(openmw-wizard
${QT_QTGUI_LIBRARY}
${QT_QTCORE_LIBRARY})
if (WIN32)
target_link_libraries(openmw-wizard ${QT_QTMAIN_LIBRARY})
endif()
else()
qt5_use_modules(openmw-wizard Widgets Core)
if (WIN32)
target_link_libraries(Qt5::WinMain)
endif()
endif()
if (OPENMW_USE_UNSHIELD) if (OPENMW_USE_UNSHIELD)
target_link_libraries(openmw-wizard ${LIBUNSHIELD_LIBRARY}) target_link_libraries(openmw-wizard ${LIBUNSHIELD_LIBRARY})
endif() endif()

View file

@ -38,9 +38,6 @@ int main(int argc, char *argv[])
QDir::setCurrent(dir.absolutePath()); QDir::setCurrent(dir.absolutePath());
// Support non-latin characters
QTextCodec::setCodecForCStrings(QTextCodec::codecForName("UTF-8"));
Wizard::MainWizard wizard; Wizard::MainWizard wizard;
wizard.show(); wizard.show();

View file

@ -6,7 +6,6 @@
#include <QWriteLocker> #include <QWriteLocker>
#include <QFileDialog> #include <QFileDialog>
#include <QFileInfo> #include <QFileInfo>
#include <QFileInfoListIterator>
#include <QStringList> #include <QStringList>
#include <QTextStream> #include <QTextStream>
#include <QTextCodec> #include <QTextCodec>

View file

@ -24,7 +24,6 @@ namespace Wizard
class UnshieldWorker : public QObject class UnshieldWorker : public QObject
{ {
Q_OBJECT Q_OBJECT
Q_ENUMS(Wizard::Component)
public: public:
UnshieldWorker(QObject *parent = 0); UnshieldWorker(QObject *parent = 0);

View file

@ -126,12 +126,6 @@ add_component_dir (version
set (ESM_UI ${CMAKE_SOURCE_DIR}/files/ui/contentselector.ui set (ESM_UI ${CMAKE_SOURCE_DIR}/files/ui/contentselector.ui
) )
find_package(Qt4 COMPONENTS QtCore QtGui)
if(MINGW)
find_package(Bullet REQUIRED COMPONENTS Collision)
endif()
if(QT_QTGUI_LIBRARY AND QT_QTCORE_LIBRARY)
add_component_qt_dir (contentselector add_component_qt_dir (contentselector
model/modelitem model/esmfile model/modelitem model/esmfile
model/naturalsort model/contentmodel model/naturalsort model/contentmodel
@ -148,10 +142,14 @@ if(QT_QTGUI_LIBRARY AND QT_QTCORE_LIBRARY)
processinvoker processinvoker
) )
if (DESIRED_QT_VERSION MATCHES 4)
include(${QT_USE_FILE}) include(${QT_USE_FILE})
QT4_WRAP_UI(ESM_UI_HDR ${ESM_UI}) QT4_WRAP_UI(ESM_UI_HDR ${ESM_UI})
QT4_WRAP_CPP(MOC_SRCS ${COMPONENT_MOC_FILES}) QT4_WRAP_CPP(MOC_SRCS ${COMPONENT_MOC_FILES})
endif(QT_QTGUI_LIBRARY AND QT_QTCORE_LIBRARY) else()
QT5_WRAP_UI(ESM_UI_HDR ${ESM_UI})
QT5_WRAP_CPP(MOC_SRCS ${COMPONENT_MOC_FILES})
endif()
if (CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang") if (CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang")
if("${CMAKE_SYSTEM_PROCESSOR}" STREQUAL "x86_64" AND NOT APPLE) if("${CMAKE_SYSTEM_PROCESSOR}" STREQUAL "x86_64" AND NOT APPLE)
@ -164,19 +162,33 @@ include_directories(${BULLET_INCLUDE_DIRS} ${CMAKE_CURRENT_BINARY_DIR})
add_library(components STATIC ${COMPONENT_FILES} ${MOC_SRCS} ${ESM_UI_HDR}) add_library(components STATIC ${COMPONENT_FILES} ${MOC_SRCS} ${ESM_UI_HDR})
target_link_libraries(components target_link_libraries(components
${Boost_LIBRARIES} ${Boost_SYSTEM_LIBRARY}
${Boost_FILESYSTEM_LIBRARY}
${Boost_THREAD_LIBRARY}
${Boost_PROGRAM_OPTIONS_LIBRARY}
${Boost_WAVE_LIBRARY}
${OGRE_LIBRARIES} ${OGRE_LIBRARIES}
${OENGINE_LIBRARY} ${OENGINE_LIBRARY}
${BULLET_LIBRARIES}
) )
if (WIN32)
target_link_libraries(components
${Boost_LOCALE_LIBRARY})
endif()
if (DESIRED_QT_VERSION MATCHES 4)
target_link_libraries(components
${QT_QTCORE_LIBRARY}
${QT_QTGUI_LIBRARY})
else()
qt5_use_modules(components Widgets Core)
endif()
if (GIT_CHECKOUT) if (GIT_CHECKOUT)
add_dependencies (components git-version) add_dependencies (components git-version)
endif (GIT_CHECKOUT) endif (GIT_CHECKOUT)
if(MINGW)
target_link_libraries(components ${QT_LIBRARIES} ${BULLET_LIBRARIES})
endif()
if (WIN32) if (WIN32)
target_link_libraries(components shlwapi) target_link_libraries(components shlwapi)
endif() endif()

View file

@ -174,16 +174,30 @@ bool Config::GameSettings::writeFile(QTextStream &stream)
return true; return true;
} }
bool Config::GameSettings::isOrderedLine(const QString& line) const
{
return line.contains(QRegExp("^\\s*fallback-archive\\s*="))
|| line.contains(QRegExp("^\\s*fallback\\s*="))
|| line.contains(QRegExp("^\\s*data\\s*="))
|| line.contains(QRegExp("^\\s*data-local\\s*="))
|| line.contains(QRegExp("^\\s*resources\\s*="))
|| line.contains(QRegExp("^\\s*content\\s*="));
}
// Policy: // Policy:
// //
// - Always ignore a line beginning with '#' or empty lines // - Always ignore a line beginning with '#' or empty lines; added above a config
// entry.
// //
// - If a line in file exists with matching key and first part of value (before ',', // - If a line in file exists with matching key and first part of value (before ',',
// '\n', etc) also matches, then replace the line with that of mUserSettings. // '\n', etc) also matches, then replace the line with that of mUserSettings.
// - else remove line (TODO: maybe replace the line with '#' in front instead?) // - else remove line
// //
// - If there is no corresponding line in file, add at the end // - If there is no corresponding line in file, add at the end
// //
// - Removed content items are saved as comments if the item had any comments.
// Content items prepended with '##' are considered previously removed.
//
bool Config::GameSettings::writeFileWithComments(QFile &file) bool Config::GameSettings::writeFileWithComments(QFile &file)
{ {
QTextStream stream(&file); QTextStream stream(&file);
@ -203,60 +217,124 @@ bool Config::GameSettings::writeFileWithComments(QFile &file)
if (fileCopy.empty()) if (fileCopy.empty())
return writeFile(stream); return writeFile(stream);
// Temp copy of settings to save, but with the keys appended with the first part of the value // start
// |
// | +----------------------------------------------------------+
// | | |
// v v |
// skip non-"ordered" lines (remove "ordered" lines) |
// | ^ |
// | | |
// | non-"ordered" line, write saved comments |
// | ^ |
// v | |
// blank or comment line, save in temp buffer <--------+ |
// | | | |
// | +------- comment line ------+ |
// v (special processing '##') |
// "ordered" line |
// | |
// v |
// save in a separate map of comments keyed by "ordered" line |
// | |
// +----------------------------------------------------------+
// //
// ATTENTION!
// //
// A hack to avoid looping through each line, makes use of the fact that fallbacks values
// are comma separated.
QMap<QString, QString> userSettingsCopy;
QRegExp settingRegex("^([^=]+)\\s*=\\s*([^,]+)(.*)$"); QRegExp settingRegex("^([^=]+)\\s*=\\s*([^,]+)(.*)$");
QString settingLine; std::vector<QString> comments;
QMap<QString, QString>::const_iterator settingsIter = mUserSettings.begin(); std::vector<QString>::iterator commentStart = fileCopy.end();
for (; settingsIter != mUserSettings.end(); ++settingsIter) std::map<QString, std::vector<QString> > commentsMap;
{
settingLine = settingsIter.key()+"="+settingsIter.value();
if (settingRegex.indexIn(settingLine) != -1)
{
userSettingsCopy[settingRegex.cap(1)+"="+settingRegex.cap(2)] =
(settingRegex.captureCount() < 3) ? "" : settingRegex.cap(3);
}
}
QString keyVal;
for (std::vector<QString>::iterator iter = fileCopy.begin(); iter != fileCopy.end(); ++iter) for (std::vector<QString>::iterator iter = fileCopy.begin(); iter != fileCopy.end(); ++iter)
{ {
// skip empty or comment lines if (isOrderedLine(*iter))
if ((*iter).isEmpty() || (*iter).contains(QRegExp("^\\s*#"))) {
continue; // save in a separate map of comments keyed by "ordered" line
if (!comments.empty())
{
if (settingRegex.indexIn(*iter) != -1)
{
commentsMap[settingRegex.cap(1)+"="+settingRegex.cap(2)] = comments;
comments.clear();
commentStart = fileCopy.end();
}
// else do nothing, malformed line
}
*iter = QString(); // "ordered" lines to be removed later
}
else if ((*iter).isEmpty() || (*iter).contains(QRegExp("^\\s*#")))
{
// comment line, save in temp buffer
if (comments.empty())
commentStart = iter;
// special removed content processing
if ((*iter).contains(QRegExp("^##content\\s*=")))
{
if (!comments.empty())
{
commentsMap[*iter] = comments;
comments.clear();
commentStart = fileCopy.end();
}
}
else
comments.push_back(*iter);
*iter = QString(); // assume to be deleted later
}
else
{
int index = settingRegex.indexIn(*iter);
// blank or non-"ordered" line, write saved comments
if (!comments.empty() && index != -1 && settingRegex.captureCount() >= 2 &&
mUserSettings.find(settingRegex.cap(1)) != mUserSettings.end())
{
for (std::vector<QString>::const_iterator it = comments.begin(); it != comments.end(); ++it)
{
*commentStart = *it;
++commentStart;
}
comments.clear();
commentStart = fileCopy.end();
}
// keep blank lines and non-"ordered" lines other than comments
// look for a key in the line // look for a key in the line
if (settingRegex.indexIn(*iter) == -1 || settingRegex.captureCount() < 2) if (index == -1 || settingRegex.captureCount() < 2)
{ {
// no key or first part of value found in line, replace with a null string which // no key or first part of value found in line, replace with a null string which
// will be remved later // will be remved later
*iter = QString(); *iter = QString();
comments.clear();
commentStart = fileCopy.end();
continue; continue;
} }
// look for a matching key in user settings // look for a matching key in user settings
keyVal = settingRegex.cap(1)+"="+settingRegex.cap(2); *iter = QString(); // assume no match
QMap<QString, QString>::iterator it = userSettingsCopy.find(keyVal); QString key = settingRegex.cap(1);
if (it == userSettingsCopy.end()) QString keyVal = settingRegex.cap(1)+"="+settingRegex.cap(2);
QMap<QString, QString>::const_iterator i = mUserSettings.find(key);
while (i != mUserSettings.end() && i.key() == key)
{ {
// no such key+valStart, replace with a null string which will be remved later QString settingLine = i.key() + "=" + i.value();
*iter = QString(); if (settingRegex.indexIn(settingLine) != -1)
{
if ((settingRegex.cap(1)+"="+settingRegex.cap(2)) == keyVal)
{
*iter = settingLine;
break;
}
}
++i;
} }
else
{
*iter = QString(it.key()+it.value());
userSettingsCopy.erase(it);
} }
} }
// write the new config file // comments at top of file
QString key;
QString value;
for (std::vector<QString>::iterator iter = fileCopy.begin(); iter != fileCopy.end(); ++iter) for (std::vector<QString>::iterator iter = fileCopy.begin(); iter != fileCopy.end(); ++iter)
{ {
if ((*iter).isNull()) if ((*iter).isNull())
@ -264,41 +342,82 @@ bool Config::GameSettings::writeFileWithComments(QFile &file)
// Below is based on readFile() code, if that changes corresponding change may be // Below is based on readFile() code, if that changes corresponding change may be
// required (for example duplicates may be inserted if the rules don't match) // required (for example duplicates may be inserted if the rules don't match)
if ((*iter).isEmpty() || (*iter).contains(QRegExp("^\\s*#"))) if (/*(*iter).isEmpty() ||*/ (*iter).contains(QRegExp("^\\s*#")))
{ {
stream << *iter << "\n"; stream << *iter << "\n";
continue; continue;
} }
}
if (settingRegex.indexIn(*iter) == -1 || settingRegex.captureCount() < 2) // Iterate in reverse order to preserve insertion order
continue; QString settingLine;
QMapIterator<QString, QString> it(mUserSettings);
it.toBack();
while (it.hasPrevious())
{
it.previous();
// Quote paths with spaces // Quote paths with spaces
key = settingRegex.cap(1); if ((it.key() == QLatin1String("data")
value = settingRegex.cap(2)+settingRegex.cap(3); || it.key() == QLatin1String("data-local")
if (key == QLatin1String("data") || it.key() == QLatin1String("resources")) && it.value().contains(QChar(' ')))
|| key == QLatin1String("data-local")
|| key == QLatin1String("resources"))
{ {
if (value.contains(QChar(' '))) QString stripped = it.value();
{ stripped.remove(QChar('\"')); // Remove quotes
value.remove(QChar('\"')); // Remove quotes
stream << key << "=\"" << value << "\"\n"; settingLine = it.key() + "=\"" + stripped + "\"";
continue;
} }
else
settingLine = it.key() + "=" + it.value();
if (settingRegex.indexIn(settingLine) != -1)
{
std::map<QString, std::vector<QString> >::iterator i =
commentsMap.find(settingRegex.cap(1)+"="+settingRegex.cap(2));
// check if previous removed content item with comments
if (i == commentsMap.end())
i = commentsMap.find("##"+settingRegex.cap(1)+"="+settingRegex.cap(2));
if (i != commentsMap.end())
{
std::vector<QString> cLines = i->second;
for (std::vector<QString>::const_iterator ci = cLines.begin(); ci != cLines.end(); ++ci)
stream << *ci << "\n";
commentsMap.erase(i);
} }
stream << key << "=" << value << "\n";
} }
if (!userSettingsCopy.empty()) stream << settingLine << "\n";
{
stream << "# new entries" << "\n";
QMap<QString, QString>::const_iterator it = userSettingsCopy.begin();
for (; it != userSettingsCopy.end(); ++it)
{
stream << it.key() << it.value() << "\n";
} }
// flush any removed settings
if (!commentsMap.empty())
{
std::map<QString, std::vector<QString> >::const_iterator i = commentsMap.begin();
for (; i != commentsMap.end(); ++i)
{
if (i->first.contains(QRegExp("^\\s*content\\s*=")))
{
std::vector<QString> cLines = i->second;
for (std::vector<QString>::const_iterator ci = cLines.begin(); ci != cLines.end(); ++ci)
stream << *ci << "\n";
// mark the content line entry for future preocessing
stream << "##" << i->first << "\n";
//commentsMap.erase(i);
}
}
}
// flush any end comments
if (!comments.empty())
{
for (std::vector<QString>::const_iterator ci = comments.begin(); ci != comments.end(); ++ci)
stream << *ci << "\n";
} }
file.resize(file.pos()); file.resize(file.pos());

View file

@ -83,6 +83,8 @@ namespace Config
QString mDataLocal; QString mDataLocal;
static const char sContentKey[]; static const char sContentKey[];
bool isOrderedLine(const QString& line) const;
}; };
} }
#endif // GAMESETTINGS_HPP #endif // GAMESETTINGS_HPP

View file

@ -30,17 +30,6 @@ ContentSelectorModel::ContentModel::~ContentModel()
void ContentSelectorModel::ContentModel::setEncoding(const QString &encoding) void ContentSelectorModel::ContentModel::setEncoding(const QString &encoding)
{ {
mEncoding = encoding; mEncoding = encoding;
if (encoding == QLatin1String("win1252"))
mCodec = QTextCodec::codecForName("windows-1252");
else if (encoding == QLatin1String("win1251"))
mCodec = QTextCodec::codecForName("windows-1251");
else if (encoding == QLatin1String("win1250"))
mCodec = QTextCodec::codecForName("windows-1250");
else
return; // This should never happen;
} }
int ContentSelectorModel::ContentModel::columnCount(const QModelIndex &parent) const int ContentSelectorModel::ContentModel::columnCount(const QModelIndex &parent) const
@ -484,6 +473,13 @@ void ContentSelectorModel::ContentModel::addFiles(const QString &path)
sortFiles(); sortFiles();
} }
void ContentSelectorModel::ContentModel::clearFiles()
{
beginRemoveRows(QModelIndex(), 0, mFiles.count()-1);
mFiles.clear();
endRemoveRows();
}
QStringList ContentSelectorModel::ContentModel::gameFiles() const QStringList ContentSelectorModel::ContentModel::gameFiles() const
{ {
QStringList gameFiles; QStringList gameFiles;

View file

@ -44,6 +44,7 @@ namespace ContentSelectorModel
bool dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent); bool dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent);
void addFiles(const QString &path); void addFiles(const QString &path);
void clearFiles();
QModelIndex indexFromItem(const EsmFile *item) const; QModelIndex indexFromItem(const EsmFile *item) const;
const EsmFile *item(const QString &name) const; const EsmFile *item(const QString &name) const;
@ -81,7 +82,6 @@ namespace ContentSelectorModel
ContentFileList mFiles; ContentFileList mFiles;
QHash<QString, Qt::CheckState> mCheckStates; QHash<QString, Qt::CheckState> mCheckStates;
QSet<QString> mPluginsWithLoadOrderError; QSet<QString> mPluginsWithLoadOrderError;
QTextCodec *mCodec;
QString mEncoding; QString mEncoding;
QIcon mWarningIcon; QIcon mWarningIcon;

View file

@ -150,6 +150,11 @@ void ContentSelectorView::ContentSelector::addFiles(const QString &path)
mContentModel->uncheckAll(); mContentModel->uncheckAll();
} }
void ContentSelectorView::ContentSelector::clearFiles()
{
mContentModel->clearFiles();
}
QString ContentSelectorView::ContentSelector::currentFile() const QString ContentSelectorView::ContentSelector::currentFile() const
{ {
QModelIndex currentIdx = ui.addonView->currentIndex(); QModelIndex currentIdx = ui.addonView->currentIndex();

View file

@ -29,6 +29,7 @@ namespace ContentSelectorView
QString currentFile() const; QString currentFile() const;
void addFiles(const QString &path); void addFiles(const QString &path);
void clearFiles();
void setProfileContent (const QStringList &fileList); void setProfileContent (const QStringList &fileList);
void clearCheckStates(); void clearCheckStates();

View file

@ -12,6 +12,8 @@ class ESMWriter;
struct Activator struct Activator
{ {
static unsigned int sRecordId; static unsigned int sRecordId;
/// Return a string descriptor for this record type. Currently used for debugging / error logs only.
static std::string getRecordType() { return "Activator"; }
std::string mId, mName, mScript, mModel; std::string mId, mName, mScript, mModel;

View file

@ -19,6 +19,9 @@ struct Potion
{ {
static unsigned int sRecordId; static unsigned int sRecordId;
/// Return a string descriptor for this record type. Currently used for debugging / error logs only.
static std::string getRecordType() { return "Potion"; }
struct ALDTstruct struct ALDTstruct
{ {
float mWeight; float mWeight;

View file

@ -16,6 +16,8 @@ class ESMWriter;
struct Apparatus struct Apparatus
{ {
static unsigned int sRecordId; static unsigned int sRecordId;
/// Return a string descriptor for this record type. Currently used for debugging / error logs only.
static std::string getRecordType() { return "Apparatus"; }
enum AppaType enum AppaType
{ {

View file

@ -66,6 +66,8 @@ struct PartReferenceList
struct Armor struct Armor
{ {
static unsigned int sRecordId; static unsigned int sRecordId;
/// Return a string descriptor for this record type. Currently used for debugging / error logs only.
static std::string getRecordType() { return "Armor"; }
enum Type enum Type
{ {

View file

@ -12,6 +12,8 @@ class ESMWriter;
struct BodyPart struct BodyPart
{ {
static unsigned int sRecordId; static unsigned int sRecordId;
/// Return a string descriptor for this record type. Currently used for debugging / error logs only.
static std::string getRecordType() { return "BodyPart"; }
enum MeshPart enum MeshPart
{ {

View file

@ -15,6 +15,8 @@ class ESMWriter;
struct Book struct Book
{ {
static unsigned int sRecordId; static unsigned int sRecordId;
/// Return a string descriptor for this record type. Currently used for debugging / error logs only.
static std::string getRecordType() { return "Book"; }
struct BKDTstruct struct BKDTstruct
{ {

View file

@ -14,6 +14,8 @@ class ESMWriter;
struct BirthSign struct BirthSign
{ {
static unsigned int sRecordId; static unsigned int sRecordId;
/// Return a string descriptor for this record type. Currently used for debugging / error logs only.
static std::string getRecordType() { return "BirthSign"; }
std::string mId, mName, mDescription, mTexture; std::string mId, mName, mDescription, mTexture;

View file

@ -56,6 +56,8 @@ typedef std::list<CellRef> CellRefTracker;
struct Cell struct Cell
{ {
static unsigned int sRecordId; static unsigned int sRecordId;
/// Return a string descriptor for this record type. Currently used for debugging / error logs only.
static std::string getRecordType() { return "Cell"; }
enum Flags enum Flags
{ {

View file

@ -18,6 +18,8 @@ class ESMWriter;
struct Class struct Class
{ {
static unsigned int sRecordId; static unsigned int sRecordId;
/// Return a string descriptor for this record type. Currently used for debugging / error logs only.
static std::string getRecordType() { return "Class"; }
enum AutoCalc enum AutoCalc
{ {

View file

@ -18,6 +18,8 @@ class ESMWriter;
struct Clothing struct Clothing
{ {
static unsigned int sRecordId; static unsigned int sRecordId;
/// Return a string descriptor for this record type. Currently used for debugging / error logs only.
static std::string getRecordType() { return "Clothing"; }
enum Type enum Type
{ {

View file

@ -36,6 +36,8 @@ struct InventoryList
struct Container struct Container
{ {
static unsigned int sRecordId; static unsigned int sRecordId;
/// Return a string descriptor for this record type. Currently used for debugging / error logs only.
static std::string getRecordType() { return "Container"; }
enum Flags enum Flags
{ {

View file

@ -22,6 +22,8 @@ class ESMWriter;
struct Creature struct Creature
{ {
static unsigned int sRecordId; static unsigned int sRecordId;
/// Return a string descriptor for this record type. Currently used for debugging / error logs only.
static std::string getRecordType() { return "Creature"; }
// Default is 0x48? // Default is 0x48?
enum Flags enum Flags

View file

@ -21,6 +21,8 @@ class ESMWriter;
struct Dialogue struct Dialogue
{ {
static unsigned int sRecordId; static unsigned int sRecordId;
/// Return a string descriptor for this record type. Currently used for debugging / error logs only.
static std::string getRecordType() { return "Dialogue"; }
enum Type enum Type
{ {

View file

@ -12,6 +12,8 @@ class ESMWriter;
struct Door struct Door
{ {
static unsigned int sRecordId; static unsigned int sRecordId;
/// Return a string descriptor for this record type. Currently used for debugging / error logs only.
static std::string getRecordType() { return "Door"; }
std::string mId, mName, mModel, mScript, mOpenSound, mCloseSound; std::string mId, mName, mModel, mScript, mOpenSound, mCloseSound;

View file

@ -18,6 +18,8 @@ class ESMWriter;
struct Enchantment struct Enchantment
{ {
static unsigned int sRecordId; static unsigned int sRecordId;
/// Return a string descriptor for this record type. Currently used for debugging / error logs only.
static std::string getRecordType() { return "Enchantment"; }
enum Type enum Type
{ {

View file

@ -30,6 +30,8 @@ struct RankData
struct Faction struct Faction
{ {
static unsigned int sRecordId; static unsigned int sRecordId;
/// Return a string descriptor for this record type. Currently used for debugging / error logs only.
static std::string getRecordType() { return "Faction"; }
std::string mId, mName; std::string mId, mName;

View file

@ -18,6 +18,8 @@ class ESMWriter;
struct Global struct Global
{ {
static unsigned int sRecordId; static unsigned int sRecordId;
/// Return a string descriptor for this record type. Currently used for debugging / error logs only.
static std::string getRecordType() { return "Global"; }
std::string mId; std::string mId;
Variant mValue; Variant mValue;

View file

@ -19,6 +19,8 @@ class ESMWriter;
struct GameSetting struct GameSetting
{ {
static unsigned int sRecordId; static unsigned int sRecordId;
/// Return a string descriptor for this record type. Currently used for debugging / error logs only.
static std::string getRecordType() { return "GameSetting"; }
std::string mId; std::string mId;

View file

@ -21,6 +21,8 @@ class ESMWriter;
struct DialInfo struct DialInfo
{ {
static unsigned int sRecordId; static unsigned int sRecordId;
/// Return a string descriptor for this record type. Currently used for debugging / error logs only.
static std::string getRecordType() { return "DialInfo"; }
enum Gender enum Gender
{ {

View file

@ -16,6 +16,8 @@ class ESMWriter;
struct Ingredient struct Ingredient
{ {
static unsigned int sRecordId; static unsigned int sRecordId;
/// Return a string descriptor for this record type. Currently used for debugging / error logs only.
static std::string getRecordType() { return "Ingredient"; }
struct IRDTstruct struct IRDTstruct
{ {

View file

@ -18,6 +18,8 @@ class ESMWriter;
struct Land struct Land
{ {
static unsigned int sRecordId; static unsigned int sRecordId;
/// Return a string descriptor for this record type. Currently used for debugging / error logs only.
static std::string getRecordType() { return "Land"; }
Land(); Land();
~Land(); ~Land();

View file

@ -46,6 +46,8 @@ struct LevelledListBase
struct CreatureLevList: LevelledListBase struct CreatureLevList: LevelledListBase
{ {
static unsigned int sRecordId; static unsigned int sRecordId;
/// Return a string descriptor for this record type. Currently used for debugging / error logs only.
static std::string getRecordType() { return "CreatureLevList"; }
enum Flags enum Flags
{ {
@ -64,6 +66,8 @@ struct CreatureLevList: LevelledListBase
struct ItemLevList: LevelledListBase struct ItemLevList: LevelledListBase
{ {
static unsigned int sRecordId; static unsigned int sRecordId;
/// Return a string descriptor for this record type. Currently used for debugging / error logs only.
static std::string getRecordType() { return "ItemLevList"; }
enum Flags enum Flags
{ {

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