Merge branch 'master' into videoplayback

Conflicts:
	apps/openmw/mwscript/docs/vmformat.txt
pull/16/head
scrawl 12 years ago
commit f1b138d0a8

@ -32,6 +32,7 @@ option(BOOST_STATIC "Link static build of Boost into the binaries" FALSE)
option(BUILD_ESMTOOL "build ESM inspector" ON)
option(BUILD_LAUNCHER "build Launcher" ON)
option(BUILD_MWINIIMPORTER "build MWiniImporter" ON)
option(BUILD_OPENCS "build OpenMW Construction Set" ON)
option(BUILD_WITH_CODE_COVERAGE "Enable code coverage with gconv" OFF)
option(BUILD_UNITTESTS "Enable Unittests with Google C++ Unittest ang GMock frameworks" OFF)
@ -103,7 +104,6 @@ set(OENGINE_OGRE
${LIBDIR}/openengine/ogre/renderer.cpp
${LIBDIR}/openengine/ogre/fader.cpp
${LIBDIR}/openengine/ogre/imagerotate.cpp
${LIBDIR}/openengine/ogre/atlas.cpp
${LIBDIR}/openengine/ogre/selectionbuffer.cpp
)
set(OENGINE_GUI
@ -385,7 +385,7 @@ if(DPKG_PROGRAM)
SET(CPACK_DEBIAN_PACKAGE_NAME "openmw")
SET(CPACK_DEBIAN_PACKAGE_VERSION "${VERSION_STRING}")
SET(CPACK_PACKAGE_EXECUTABLES "openmw;OpenMW esmtool;Esmtool omwlauncher;OMWLauncher mwiniimporter;MWiniImporter")
SET(CPACK_DEBIAN_PACKAGE_DEPENDS "libboost-filesystem1.46.1 (>= 1.46.1), libboost-program-options1.46.1 (>= 1.46.1), libboost-system1.46.1 (>= 1.46.1), libboost-thread1.46.1 (>= 1.46.1), libc6 (>= 2.11.2), libfreetype6 (>= 2.2.1), libgcc1 (>= 1:4.1.1), libmpg123-0 (>= 1.12.1), libois-1.3.0 (>= 1.3.0), libopenal1 (>= 1:1.12.854), libsndfile1 (>= 1.0.23), libstdc++6 (>= 4.4.5), libuuid1 (>= 2.17.2), libqtgui4 (>= 4.7.0)")
SET(CPACK_DEBIAN_PACKAGE_DEPENDS "libc6 (>= 2.11.2), libfreetype6 (>= 2.2.1), libgcc1 (>= 1:4.1.1), libmpg123-0 (>= 1.12.1), libois-1.3.0 (>= 1.3.0), libopenal1 (>= 1:1.12.854), libsndfile1 (>= 1.0.23), libstdc++6 (>= 4.4.5), libuuid1 (>= 2.17.2), libqtgui4 (>= 4.7.0)")
SET(CPACK_DEBIAN_PACKAGE_SECTION "Games")
@ -491,6 +491,10 @@ if (BUILD_MWINIIMPORTER)
add_subdirectory( apps/mwiniimporter )
endif()
if (BUILD_OPENCS)
add_subdirectory (apps/opencs)
endif()
# UnitTests
if (BUILD_UNITTESTS)
add_subdirectory( apps/openmw_test_suite )
@ -554,7 +558,9 @@ if (WIN32)
set_target_properties(omwlauncher PROPERTIES COMPILE_FLAGS ${WARNINGS})
endif (BUILD_LAUNCHER)
set_target_properties(openmw PROPERTIES COMPILE_FLAGS ${WARNINGS})
set_target_properties(esmtool PROPERTIES COMPILE_FLAGS ${WARNINGS})
if (BUILD_ESMTOOL)
set_target_properties(esmtool PROPERTIES COMPILE_FLAGS ${WARNINGS})
endif (BUILD_ESMTOOL)
endif(MSVC)
# Same for MinGW

@ -59,7 +59,7 @@ struct Arguments
std::string outname;
std::vector<std::string> types;
ESMData data;
ESM::ESMReader reader;
ESM::ESMWriter writer;
@ -74,7 +74,7 @@ bool parseOptions (int argc, char** argv, Arguments &info)
("version,v", "print version information and quit.")
("raw,r", "Show an unformatted list of all records and subrecords.")
// The intention is that this option would interact better
// with other modes including clone, dump, and raw.
// with other modes including clone, dump, and raw.
("type,t", bpo::value< std::vector<std::string> >(),
"Show only records of this type (four character record code). May "
"be specified multiple times. Only affects dump mode.")
@ -165,23 +165,12 @@ bool parseOptions (int argc, char** argv, Arguments &info)
// Font encoding settings
info.encoding = variables["encoding"].as<std::string>();
if (info.encoding == "win1250")
{
std::cout << "Using Central and Eastern European font encoding." << std::endl;
}
else if (info.encoding == "win1251")
{
std::cout << "Using Cyrillic font encoding." << std::endl;
}
else
if(info.encoding != "win1250" && info.encoding != "win1251" && info.encoding != "win1252")
{
if(info.encoding != "win1252")
{
std::cout << info.encoding << " is not a valid encoding option." << std::endl;
info.encoding = "win1252";
}
std::cout << "Using default (English) font encoding." << std::endl;
std::cout << info.encoding << " is not a valid encoding option." << std::endl;
info.encoding = "win1252";
}
std::cout << ToUTF8::encodingUsingMessage(info.encoding) << std::endl;
return true;
}
@ -262,7 +251,8 @@ void printRaw(ESM::ESMReader &esm)
int load(Arguments& info)
{
ESM::ESMReader& esm = info.reader;
esm.setEncoding(info.encoding);
ToUTF8::Utf8Encoder encoder (ToUTF8::calculateEncoding(info.encoding));
esm.setEncoder(&encoder);
std::string filename = info.filename;
std::cout << "Loading file: " << filename << std::endl;
@ -321,7 +311,7 @@ int load(Arguments& info)
if (info.types.size() > 0)
{
std::vector<std::string>::iterator match;
match = std::find(info.types.begin(), info.types.end(),
match = std::find(info.types.begin(), info.types.end(),
n.toString());
if (match == info.types.end()) interested = false;
}
@ -425,14 +415,15 @@ int clone(Arguments& info)
if (++i % 3 == 0)
std::cout << std::endl;
}
if (i % 3 != 0)
std::cout << std::endl;
std::cout << std::endl << "Saving records to: " << info.outname << "..." << std::endl;
ESM::ESMWriter& esm = info.writer;
esm.setEncoding(info.encoding);
ToUTF8::Utf8Encoder encoder (ToUTF8::calculateEncoding(info.encoding));
esm.setEncoder(&encoder);
esm.setAuthor(info.data.author);
esm.setDescription(info.data.description);
esm.setVersion(info.data.version);
@ -450,7 +441,7 @@ int clone(Arguments& info)
for (Records::iterator it = records.begin(); it != records.end() && i > 0; ++it)
{
EsmTool::RecordBase *record = *it;
name.val = record->getType().val;
esm.startRecord(name.toString(), record->getFlags());
@ -485,7 +476,7 @@ int clone(Arguments& info)
std::cerr << "\r" << perc << "%";
}
}
std::cout << "\rDone!" << std::endl;
esm.close();
@ -513,7 +504,7 @@ int comp(Arguments& info)
fileOne.encoding = info.encoding;
fileTwo.encoding = info.encoding;
fileOne.filename = info.filename;
fileTwo.filename = info.outname;
@ -534,9 +525,9 @@ int comp(Arguments& info)
std::cout << "Not equal, different amount of records." << std::endl;
return 1;
}
return 0;
}

@ -738,7 +738,6 @@ void Record<ESM::GameSetting>::print()
default:
std::cout << "unknown type";
}
std::cout << "\n Dirty: " << mData.mDirty << std::endl;
}
template<>

@ -272,7 +272,8 @@ void DataFilesModel::addMasters(const QString &path)
foreach (const QString &path, dir.entryList()) {
try {
ESM::ESMReader fileReader;
fileReader.setEncoding(mEncoding.toStdString());
ToUTF8::Utf8Encoder encoder (ToUTF8::calculateEncoding(mEncoding.toStdString()));
fileReader.setEncoder(&encoder);
fileReader.open(dir.absoluteFilePath(path).toStdString());
ESM::ESMReader::MasterList mlist = fileReader.getMasters();
@ -335,7 +336,8 @@ void DataFilesModel::addPlugins(const QString &path)
try {
ESM::ESMReader fileReader;
fileReader.setEncoding(mEncoding.toStdString());
ToUTF8::Utf8Encoder encoder (ToUTF8::calculateEncoding(mEncoding.toStdString()));
fileReader.setEncoder(&encoder);
fileReader.open(dir.absoluteFilePath(path).toStdString());
ESM::ESMReader::MasterList mlist = fileReader.getMasters();

@ -18,8 +18,609 @@ MwIniImporter::MwIniImporter()
{ 0, 0 }
};
const char *fallback[] = {
// light
"LightAttenuation:UseConstant",
"LightAttenuation:ConstantValue",
"LightAttenuation:UseLinear",
"LightAttenuation:LinearMethod",
"LightAttenuation:LinearValue",
"LightAttenuation:LinearRadiusMult",
"LightAttenuation:UseQuadratic",
"LightAttenuation:QuadraticMethod",
"LightAttenuation:QuadraticValue",
"LightAttenuation:QuadraticRadiusMult",
"LightAttenuation:OutQuadInLin",
// inventory
"Inventory:DirectionalDiffuseR",
"Inventory:DirectionalDiffuseG",
"Inventory:DirectionalDiffuseB",
"Inventory:DirectionalAmbientR",
"Inventory:DirectionalAmbientG",
"Inventory:DirectionalAmbientB",
"Inventory:DirectionalRotationX",
"Inventory:DirectionalRotationY",
"Inventory:UniformScaling",
// map
"Map:Travel Siltstrider Red",
"Map:Travel Siltstrider Green",
"Map:Travel Siltstrider Blue",
"Map:Travel Boat Red",
"Map:Travel Boat Green",
"Map:Travel Boat Blue",
"Map:Travel Magic Red",
"Map:Travel Magic Green",
"Map:Travel Magic Blue",
"Map:Show Travel Lines",
// water
"Water:Map Alpha",
"Water:World Alpha",
"Water:SurfaceTextureSize",
"Water:SurfaceTileCount",
"Water:SurfaceFPS",
"Water:SurfaceTexture",
"Water:SurfaceFrameCount",
"Water:TileTextureDivisor",
"Water:RippleTexture",
"Water:RippleFrameCount",
"Water:RippleLifetime",
"Water:MaxNumberRipples",
"Water:RippleScale",
"Water:RippleRotSpeed",
"Water:RippleAlphas",
"Water:PSWaterReflectTerrain",
"Water:PSWaterReflectUpdate",
"Water:NearWaterRadius",
"Water:NearWaterPoints",
"Water:NearWaterUnderwaterFreq",
"Water:NearWaterUnderwaterVolume",
"Water:NearWaterIndoorTolerance",
"Water:NearWaterOutdoorTolerance",
"Water:NearWaterIndoorID",
"Water:NearWaterOutdoorID",
"Water:UnderwaterSunriseFog",
"Water:UnderwaterDayFog",
"Water:UnderwaterSunsetFog",
"Water:UnderwaterNightFog",
"Water:UnderwaterIndoorFog",
"Water:UnderwaterColor",
"Water:UnderwaterColorWeight",
// pixelwater
"PixelWater:SurfaceFPS",
"PixelWater:TileCount",
"PixelWater:Resolution",
// fonts
"Fonts:Font 0",
"Fonts:Font 1",
"Fonts:Font 2",
// UI colors
"FontColor:color_normal",
"FontColor:color_normal_over",
"FontColor:color_normal_pressed",
"FontColor:color_active",
"FontColor:color_active_over",
"FontColor:color_active_pressed",
"FontColor:color_disabled",
"FontColor:color_disabled_over",
"FontColor:color_disabled_pressed",
"FontColor:color_link",
"FontColor:color_link_over",
"FontColor:color_link_pressed",
"FontColor:color_journal_link",
"FontColor:color_journal_link_over",
"FontColor:color_journal_link_pressed",
"FontColor:color_journal_topic",
"FontColor:color_journal_topic_over",
"FontColor:color_journal_topic_pressed",
"FontColor:color_answer",
"FontColor:color_answer_over",
"FontColor:color_answer_pressed",
"FontColor:color_header",
"FontColor:color_notify",
"FontColor:color_big_normal",
"FontColor:color_big_normal_over",
"FontColor:color_big_normal_pressed",
"FontColor:color_big_link",
"FontColor:color_big_link_over",
"FontColor:color_big_link_pressed",
"FontColor:color_big_answer",
"FontColor:color_big_answer_over",
"FontColor:color_big_answer_pressed",
"FontColor:color_big_header",
"FontColor:color_big_notify",
"FontColor:color_background",
"FontColor:color_focus",
"FontColor:color_health",
"FontColor:color_magic",
"FontColor:color_fatigue",
"FontColor:color_misc",
"FontColor:color_weapon_fill",
"FontColor:color_magic_fill",
"FontColor:color_positive",
"FontColor:color_negative",
"FontColor:color_count",
// level up messages
"Level Up:Level2",
"Level Up:Level3",
"Level Up:Level4",
"Level Up:Level5",
"Level Up:Level6",
"Level Up:Level7",
"Level Up:Level8",
"Level Up:Level9",
"Level Up:Level10",
"Level Up:Level11",
"Level Up:Level12",
"Level Up:Level13",
"Level Up:Level14",
"Level Up:Level15",
"Level Up:Level16",
"Level Up:Level17",
"Level Up:Level18",
"Level Up:Level19",
"Level Up:Level20",
"Level Up:Default",
// character creation multiple choice test
"Question 1:Question",
"Question 1:AnswerOne",
"Question 1:AnswerTwo",
"Question 1:AnswerThree",
"Question 1:Sound",
"Question 2:Question",
"Question 2:AnswerOne",
"Question 2:AnswerTwo",
"Question 2:AnswerThree",
"Question 2:Sound",
"Question 3:Question",
"Question 3:AnswerOne",
"Question 3:AnswerTwo",
"Question 3:AnswerThree",
"Question 3:Sound",
"Question 4:Question",
"Question 4:AnswerOne",
"Question 4:AnswerTwo",
"Question 4:AnswerThree",
"Question 4:Sound",
"Question 5:Question",
"Question 5:AnswerOne",
"Question 5:AnswerTwo",
"Question 5:AnswerThree",
"Question 5:Sound",
"Question 6:Question",
"Question 6:AnswerOne",
"Question 6:AnswerTwo",
"Question 6:AnswerThree",
"Question 6:Sound",
"Question 7:Question",
"Question 7:AnswerOne",
"Question 7:AnswerTwo",
"Question 7:AnswerThree",
"Question 7:Sound",
"Question 8:Question",
"Question 8:AnswerOne",
"Question 8:AnswerTwo",
"Question 8:AnswerThree",
"Question 8:Sound",
"Question 9:Question",
"Question 9:AnswerOne",
"Question 9:AnswerTwo",
"Question 9:AnswerThree",
"Question 9:Sound",
"Question 10:Question",
"Question 10:AnswerOne",
"Question 10:AnswerTwo",
"Question 10:AnswerThree",
"Question 10:Sound",
// blood textures and models
"Blood:Model 0",
"Blood:Model 1",
"Blood:Model 2",
"Blood:Texture 0",
"Blood:Texture 1",
"Blood:Texture 2",
"Blood:Texture Name 0",
"Blood:Texture Name 1",
"Blood:Texture Name 2",
// movies
"Movies:Company Logo",
"Movies:Morrowind Logo",
"Movies:New Game",
"Movies:Loading",
"Movies:Options Menu",
// weather related values
"Weather Thunderstorm:Thunder Sound ID 0",
"Weather Thunderstorm:Thunder Sound ID 1",
"Weather Thunderstorm:Thunder Sound ID 2",
"Weather Thunderstorm:Thunder Sound ID 3",
"Weather:Sunrise Time",
"Weather:Sunset Time",
"Weather:Sunrise Duration",
"Weather:Sunset Duration",
"Weather:Hours Between Weather Changes", // AKA weather update time
"Weather Thunderstorm:Thunder Frequency",
"Weather Thunderstorm:Thunder Threshold",
"Weather:EnvReduceColor",
"Weather:LerpCloseColor",
"Weather:BumpFadeColor",
"Weather:AlphaReduce",
"Weather:Minimum Time Between Environmental Sounds",
"Weather:Maximum Time Between Environmental Sounds",
"Weather:Sun Glare Fader Max",
"Weather:Sun Glare Fader Angle Max",
"Weather:Sun Glare Fader Color",
"Weather:Timescale Clouds",
"Weather:Precip Gravity",
"Weather:Rain Ripples",
"Weather:Rain Ripple Radius",
"Weather:Rain Ripples Per Drop",
"Weather:Rain Ripple Scale",
"Weather:Rain Ripple Speed",
"Weather:Fog Depth Change Speed",
"Weather:Sky Pre-Sunrise Time",
"Weather:Sky Post-Sunrise Time",
"Weather:Sky Pre-Sunset Time",
"Weather:Sky Post-Sunset Time",
"Weather:Ambient Pre-Sunrise Time",
"Weather:Ambient Post-Sunrise Time",
"Weather:Ambient Pre-Sunset Time",
"Weather:Ambient Post-Sunset Time",
"Weather:Fog Pre-Sunrise Time",
"Weather:Fog Post-Sunrise Time",
"Weather:Fog Pre-Sunset Time",
"Weather:Fog Post-Sunset Time",
"Weather:Sun Pre-Sunrise Time",
"Weather:Sun Post-Sunrise Time",
"Weather:Sun Pre-Sunset Time",
"Weather:Sun Post-Sunset Time",
"Weather:Stars Post-Sunset Start",
"Weather:Stars Pre-Sunrise Finish",
"Weather:Stars Fading Duration",
"Weather:Snow Ripples",
"Weather:Snow Ripple Radius",
"Weather:Snow Ripples Per Flake",
"Weather:Snow Ripple Scale",
"Weather:Snow Ripple Speed",
"Weather:Snow Gravity Scale",
"Weather:Snow High Kill",
"Weather:Snow Low Kill",
"Weather Clear:Cloud Texture",
"Weather Clear:Clouds Maximum Percent",
"Weather Clear:Transition Delta",
"Weather Clear:Sky Sunrise Color",
"Weather Clear:Sky Day Color",
"Weather Clear:Sky Sunset Color",
"Weather Clear:Sky Night Color",
"Weather Clear:Fog Sunrise Color",
"Weather Clear:Fog Day Color",
"Weather Clear:Fog Sunset Color",
"Weather Clear:Fog Night Color",
"Weather Clear:Ambient Sunrise Color",
"Weather Clear:Ambient Day Color",
"Weather Clear:Ambient Sunset Color",
"Weather Clear:Ambient Night Color",
"Weather Clear:Sun Sunrise Color",
"Weather Clear:Sun Day Color",
"Weather Clear:Sun Sunset Color",
"Weather Clear:Sun Night Color",
"Weather Clear:Sun Disc Sunset Color",
"Weather Clear:Land Fog Day Depth",
"Weather Clear:Land Fog Night Depth",
"Weather Clear:Wind Speed",
"Weather Clear:Cloud Speed",
"Weather Clear:Glare View",
"Weather Clear:Ambient Loop Sound ID",
"Weather Cloudy:Cloud Texture",
"Weather Cloudy:Clouds Maximum Percent",
"Weather Cloudy:Transition Delta",
"Weather Cloudy:Sky Sunrise Color",
"Weather Cloudy:Sky Day Color",
"Weather Cloudy:Sky Sunset Color",
"Weather Cloudy:Sky Night Color",
"Weather Cloudy:Fog Sunrise Color",
"Weather Cloudy:Fog Day Color",
"Weather Cloudy:Fog Sunset Color",
"Weather Cloudy:Fog Night Color",
"Weather Cloudy:Ambient Sunrise Color",
"Weather Cloudy:Ambient Day Color",
"Weather Cloudy:Ambient Sunset Color",
"Weather Cloudy:Ambient Night Color",
"Weather Cloudy:Sun Sunrise Color",
"Weather Cloudy:Sun Day Color",
"Weather Cloudy:Sun Sunset Color",
"Weather Cloudy:Sun Night Color",
"Weather Cloudy:Sun Disc Sunset Color",
"Weather Cloudy:Land Fog Day Depth",
"Weather Cloudy:Land Fog Night Depth",
"Weather Cloudy:Wind Speed",
"Weather Cloudy:Cloud Speed",
"Weather Cloudy:Glare View",
"Weather Cloudy:Ambient Loop Sound ID",
"Weather Foggy:Cloud Texture",
"Weather Foggy:Clouds Maximum Percent",
"Weather Foggy:Transition Delta",
"Weather Foggy:Sky Sunrise Color",
"Weather Foggy:Sky Day Color",
"Weather Foggy:Sky Sunset Color",
"Weather Foggy:Sky Night Color",
"Weather Foggy:Fog Sunrise Color",
"Weather Foggy:Fog Day Color",
"Weather Foggy:Fog Sunset Color",
"Weather Foggy:Fog Night Color",
"Weather Foggy:Ambient Sunrise Color",
"Weather Foggy:Ambient Day Color",
"Weather Foggy:Ambient Sunset Color",
"Weather Foggy:Ambient Night Color",
"Weather Foggy:Sun Sunrise Color",
"Weather Foggy:Sun Day Color",
"Weather Foggy:Sun Sunset Color",
"Weather Foggy:Sun Night Color",
"Weather Foggy:Sun Disc Sunset Color",
"Weather Foggy:Land Fog Day Depth",
"Weather Foggy:Land Fog Night Depth",
"Weather Foggy:Wind Speed",
"Weather Foggy:Cloud Speed",
"Weather Foggy:Glare View",
"Weather Foggy:Ambient Loop Sound ID",
"Weather Thunderstorm:Cloud Texture",
"Weather Thunderstorm:Clouds Maximum Percent",
"Weather Thunderstorm:Transition Delta",
"Weather Thunderstorm:Sky Sunrise Color",
"Weather Thunderstorm:Sky Day Color",
"Weather Thunderstorm:Sky Sunset Color",
"Weather Thunderstorm:Sky Night Color",
"Weather Thunderstorm:Fog Sunrise Color",
"Weather Thunderstorm:Fog Day Color",
"Weather Thunderstorm:Fog Sunset Color",
"Weather Thunderstorm:Fog Night Color",
"Weather Thunderstorm:Ambient Sunrise Color",
"Weather Thunderstorm:Ambient Day Color",
"Weather Thunderstorm:Ambient Sunset Color",
"Weather Thunderstorm:Ambient Night Color",
"Weather Thunderstorm:Sun Sunrise Color",
"Weather Thunderstorm:Sun Day Color",
"Weather Thunderstorm:Sun Sunset Color",
"Weather Thunderstorm:Sun Night Color",
"Weather Thunderstorm:Sun Disc Sunset Color",
"Weather Thunderstorm:Land Fog Day Depth",
"Weather Thunderstorm:Land Fog Night Depth",
"Weather Thunderstorm:Wind Speed",
"Weather Thunderstorm:Cloud Speed",
"Weather Thunderstorm:Glare View",
"Weather Thunderstorm:Rain Loop Sound ID",
"Weather Thunderstorm:Using Precip",
"Weather Thunderstorm:Rain Diameter",
"Weather Thunderstorm:Rain Height Min",
"Weather Thunderstorm:Rain Height Max",
"Weather Thunderstorm:Rain Threshold",
"Weather Thunderstorm:Max Raindrops",
"Weather Thunderstorm:Rain Entrance Speed",
"Weather Thunderstorm:Ambient Loop Sound ID",
"Weather Thunderstorm:Flash Decrement",
"Weather Rain:Cloud Texture",
"Weather Rain:Clouds Maximum Percent",
"Weather Rain:Transition Delta",
"Weather Rain:Sky Sunrise Color",
"Weather Rain:Sky Day Color",
"Weather Rain:Sky Sunset Color",
"Weather Rain:Sky Night Color",
"Weather Rain:Fog Sunrise Color",
"Weather Rain:Fog Day Color",
"Weather Rain:Fog Sunset Color",
"Weather Rain:Fog Night Color",
"Weather Rain:Ambient Sunrise Color",
"Weather Rain:Ambient Day Color",
"Weather Rain:Ambient Sunset Color",
"Weather Rain:Ambient Night Color",
"Weather Rain:Sun Sunrise Color",
"Weather Rain:Sun Day Color",
"Weather Rain:Sun Sunset Color",
"Weather Rain:Sun Night Color",
"Weather Rain:Sun Disc Sunset Color",
"Weather Rain:Land Fog Day Depth",
"Weather Rain:Land Fog Night Depth",
"Weather Rain:Wind Speed",
"Weather Rain:Cloud Speed",
"Weather Rain:Glare View",
"Weather Rain:Rain Loop Sound ID",
"Weather Rain:Using Precip",
"Weather Rain:Rain Diameter",
"Weather Rain:Rain Height Min",
"Weather Rain:Rain Height Max",
"Weather Rain:Rain Threshold",
"Weather Rain:Rain Entrance Speed",
"Weather Rain:Ambient Loop Sound ID",
"Weather Rain:Max Raindrops",
"Weather Overcast:Cloud Texture",
"Weather Overcast:Clouds Maximum Percent",
"Weather Overcast:Transition Delta",
"Weather Overcast:Sky Sunrise Color",
"Weather Overcast:Sky Day Color",
"Weather Overcast:Sky Sunset Color",
"Weather Overcast:Sky Night Color",
"Weather Overcast:Fog Sunrise Color",
"Weather Overcast:Fog Day Color",
"Weather Overcast:Fog Sunset Color",
"Weather Overcast:Fog Night Color",
"Weather Overcast:Ambient Sunrise Color",
"Weather Overcast:Ambient Day Color",
"Weather Overcast:Ambient Sunset Color",
"Weather Overcast:Ambient Night Color",
"Weather Overcast:Sun Sunrise Color",
"Weather Overcast:Sun Day Color",
"Weather Overcast:Sun Sunset Color",
"Weather Overcast:Sun Night Color",
"Weather Overcast:Sun Disc Sunset Color",
"Weather Overcast:Land Fog Day Depth",
"Weather Overcast:Land Fog Night Depth",
"Weather Overcast:Wind Speed",
"Weather Overcast:Cloud Speed",
"Weather Overcast:Glare View",
"Weather Overcast:Ambient Loop Sound ID",
"Weather Ashstorm:Cloud Texture",
"Weather Ashstorm:Clouds Maximum Percent",
"Weather Ashstorm:Transition Delta",
"Weather Ashstorm:Sky Sunrise Color",
"Weather Ashstorm:Sky Day Color",
"Weather Ashstorm:Sky Sunset Color",
"Weather Ashstorm:Sky Night Color",
"Weather Ashstorm:Fog Sunrise Color",
"Weather Ashstorm:Fog Day Color",
"Weather Ashstorm:Fog Sunset Color",
"Weather Ashstorm:Fog Night Color",
"Weather Ashstorm:Ambient Sunrise Color",
"Weather Ashstorm:Ambient Day Color",
"Weather Ashstorm:Ambient Sunset Color",
"Weather Ashstorm:Ambient Night Color",
"Weather Ashstorm:Sun Sunrise Color",
"Weather Ashstorm:Sun Day Color",
"Weather Ashstorm:Sun Sunset Color",
"Weather Ashstorm:Sun Night Color",
"Weather Ashstorm:Sun Disc Sunset Color",
"Weather Ashstorm:Land Fog Day Depth",
"Weather Ashstorm:Land Fog Night Depth",
"Weather Ashstorm:Wind Speed",
"Weather Ashstorm:Cloud Speed",
"Weather Ashstorm:Glare View",
"Weather Ashstorm:Ambient Loop Sound ID",
"Weather Ashstorm:Storm Threshold",
"Weather Blight:Cloud Texture",
"Weather Blight:Clouds Maximum Percent",
"Weather Blight:Transition Delta",
"Weather Blight:Sky Sunrise Color",
"Weather Blight:Sky Day Color",
"Weather Blight:Sky Sunset Color",
"Weather Blight:Sky Night Color",
"Weather Blight:Fog Sunrise Color",
"Weather Blight:Fog Day Color",
"Weather Blight:Fog Sunset Color",
"Weather Blight:Fog Night Color",
"Weather Blight:Ambient Sunrise Color",
"Weather Blight:Ambient Day Color",
"Weather Blight:Ambient Sunset Color",
"Weather Blight:Ambient Night Color",
"Weather Blight:Sun Sunrise Color",
"Weather Blight:Sun Day Color",
"Weather Blight:Sun Sunset Color",
"Weather Blight:Sun Night Color",
"Weather Blight:Sun Disc Sunset Color",
"Weather Blight:Land Fog Day Depth",
"Weather Blight:Land Fog Night Depth",
"Weather Blight:Wind Speed",
"Weather Blight:Cloud Speed",
"Weather Blight:Glare View",
"Weather Blight:Ambient Loop Sound ID",
"Weather Blight:Storm Threshold",
"Weather Blight:Disease Chance",
// for Bloodmoon
"Weather Snow:Cloud Texture",
"Weather Snow:Clouds Maximum Percent",
"Weather Snow:Transition Delta",
"Weather Snow:Sky Sunrise Color",
"Weather Snow:Sky Day Color",
"Weather Snow:Sky Sunset Color",
"Weather Snow:Sky Night Color",
"Weather Snow:Fog Sunrise Color",
"Weather Snow:Fog Day Color",
"Weather Snow:Fog Sunset Color",
"Weather Snow:Fog Night Color",
"Weather Snow:Ambient Sunrise Color",
"Weather Snow:Ambient Day Color",
"Weather Snow:Ambient Sunset Color",
"Weather Snow:Ambient Night Color",
"Weather Snow:Sun Sunrise Color",
"Weather Snow:Sun Day Color",
"Weather Snow:Sun Sunset Color",
"Weather Snow:Sun Night Color",
"Weather Snow:Sun Disc Sunset Color",
"Weather Snow:Land Fog Day Depth",
"Weather Snow:Land Fog Night Depth",
"Weather Snow:Wind Speed",
"Weather Snow:Cloud Speed",
"Weather Snow:Glare View",
"Weather Snow:Snow Diameter",
"Weather Snow:Snow Height Min",
"Weather Snow:Snow Height Max",
"Weather Snow:Snow Entrance Speed",
"Weather Snow:Max Snowflakes",
"Weather Snow:Ambient Loop Sound ID",
"Weather Snow:Snow Threshold",
// for Bloodmoon
"Weather Blizzard:Cloud Texture",
"Weather Blizzard:Clouds Maximum Percent",
"Weather Blizzard:Transition Delta",
"Weather Blizzard:Sky Sunrise Color",
"Weather Blizzard:Sky Day Color",
"Weather Blizzard:Sky Sunset Color",
"Weather Blizzard:Sky Night Color",
"Weather Blizzard:Fog Sunrise Color",
"Weather Blizzard:Fog Day Color",
"Weather Blizzard:Fog Sunset Color",
"Weather Blizzard:Fog Night Color",
"Weather Blizzard:Ambient Sunrise Color",
"Weather Blizzard:Ambient Day Color",
"Weather Blizzard:Ambient Sunset Color",
"Weather Blizzard:Ambient Night Color",
"Weather Blizzard:Sun Sunrise Color",
"Weather Blizzard:Sun Day Color",
"Weather Blizzard:Sun Sunset Color",
"Weather Blizzard:Sun Night Color",
"Weather Blizzard:Sun Disc Sunset Color",
"Weather Blizzard:Land Fog Day Depth",
"Weather Blizzard:Land Fog Night Depth",
"Weather Blizzard:Wind Speed",
"Weather Blizzard:Cloud Speed",
"Weather Blizzard:Glare View",
"Weather Blizzard:Ambient Loop Sound ID",
"Weather Blizzard:Storm Threshold",
// moons
"Moons:Secunda Size",
"Moons:Secunda Axis Offset",
"Moons:Secunda Speed",
"Moons:Secunda Daily Increment",
"Moons:Secunda Moon Shadow Early Fade Angle",
"Moons:Secunda Fade Start Angle",
"Moons:Secunda Fade End Angle",
"Moons:Secunda Fade In Start",
"Moons:Secunda Fade In Finish",
"Moons:Secunda Fade Out Start",
"Moons:Secunda Fade Out Finish",
"Moons:Masser Size",
"Moons:Masser Axis Offset",
"Moons:Masser Speed",
"Moons:Masser Daily Increment",
"Moons:Masser Moon Shadow Early Fade Angle",
"Moons:Masser Fade Start Angle",
"Moons:Masser Fade End Angle",
"Moons:Masser Fade In Start",
"Moons:Masser Fade In Finish",
"Moons:Masser Fade Out Start",
"Moons:Masser Fade Out Finish",
"Moons:Script Color",
0
};
@ -48,14 +649,26 @@ MwIniImporter::multistrmap MwIniImporter::loadIniFile(std::string filename) {
std::string section("");
MwIniImporter::multistrmap map;
boost::iostreams::stream<boost::iostreams::file_source>file(filename.c_str());
ToUTF8::Utf8Encoder encoder(mEncoding);
std::string line;
while (std::getline(file, line)) {
line = encoder.getUtf8(line);
// unify Unix-style and Windows file ending
if (!(line.empty()) && (line[line.length()-1]) == '\r') {
line = line.substr(0, line.length()-1);
}
if(line[0] == '[') {
if(line.length() > 2) {
section = line.substr(1, line.length()-3);
int pos = line.find(']');
if(pos < 2) {
std::cout << "Warning: ini file wrongly formatted (" << line << "). Line ignored." << std::endl;
continue;
}
section = line.substr(1, line.find(']')-1);
continue;
}
@ -147,7 +760,7 @@ void MwIniImporter::mergeFallback(multistrmap &cfg, multistrmap &ini) {
std::string value(*it);
std::replace( value.begin(), value.end(), ' ', '_' );
std::replace( value.begin(), value.end(), ':', '_' );
value.append(",").append(vc->substr(0,vc->length()-1));
value.append(",").append(vc->substr(0,vc->length()));
insertMultistrmap(cfg, "fallback", value);
}
}
@ -216,3 +829,8 @@ void MwIniImporter::writeToFile(boost::iostreams::stream<boost::iostreams::file_
}
}
}
void MwIniImporter::setInputEncoding(const ToUTF8::FromType &encoding)
{
mEncoding = encoding;
}

@ -8,12 +8,15 @@
#include <vector>
#include <exception>
#include <components/to_utf8/to_utf8.hpp>
class MwIniImporter {
public:
typedef std::map<std::string, std::string> strmap;
typedef std::map<std::string, std::vector<std::string> > multistrmap;
MwIniImporter();
void setInputEncoding(const ToUTF8::FromType& encoding);
void setVerbose(bool verbose);
multistrmap loadIniFile(std::string filename);
multistrmap loadCfgFile(std::string filename);
@ -25,9 +28,11 @@ class MwIniImporter {
private:
void insertMultistrmap(multistrmap &cfg, std::string key, std::string value);
std::string numberToString(int n);
std::string toUTF8(const std::string &str);
bool mVerbose;
strmap mMergeMap;
std::vector<std::string> mMergeFallback;
ToUTF8::FromType mEncoding;
};

@ -18,6 +18,11 @@ int main(int argc, char *argv[]) {
("cfg,c", bpo::value<std::string>(), "openmw.cfg file")
("output,o", bpo::value<std::string>()->default_value(""), "openmw.cfg file")
("game-files,g", "import esm and esp files")
("encoding,e", bpo::value<std::string>()-> default_value("win1252"),
"Character encoding used in OpenMW game messages:\n"
"\n\twin1250 - Central and Eastern European such as Polish, Czech, Slovak, Hungarian, Slovene, Bosnian, Croatian, Serbian (Latin script), Romanian and Albanian languages\n"
"\n\twin1251 - Cyrillic alphabet such as Russian, Bulgarian, Serbian Cyrillic and other languages\n"
"\n\twin1252 - Western European (Latin) alphabet, used by default")
;
p_desc.add("ini", 1).add("cfg", 1);
@ -57,6 +62,10 @@ int main(int argc, char *argv[]) {
MwIniImporter importer;
importer.setVerbose(vm.count("verbose"));
// Font encoding settings
std::string encoding(vm["encoding"].as<std::string>());
importer.setInputEncoding(ToUTF8::calculateEncoding(encoding));
MwIniImporter::multistrmap ini = importer.loadIniFile(iniFile);
MwIniImporter::multistrmap cfg = importer.loadCfgFile(cfgFile);

@ -0,0 +1,76 @@
set (OPENCS_SRC
main.cpp editor.cpp
model/doc/documentmanager.cpp model/doc/document.cpp
model/world/universalid.cpp model/world/idcollection.cpp model/world/data.cpp model/world/idtable.cpp
model/world/commands.cpp model/world/idtableproxymodel.cpp model/world/record.cpp
model/world/columnbase.cpp
model/tools/tools.cpp model/tools/operation.cpp model/tools/stage.cpp model/tools/verifier.cpp
model/tools/mandatoryid.cpp model/tools/reportmodel.cpp
view/doc/viewmanager.cpp view/doc/view.cpp view/doc/operations.cpp view/doc/operation.cpp view/doc/subviewfactory.cpp
view/doc/subview.cpp
view/world/table.cpp view/world/tablesubview.cpp view/world/subviews.cpp view/world/util.cpp
view/world/dialoguesubview.cpp
view/tools/reportsubview.cpp view/tools/subviews.cpp
)
set (OPENCS_HDR
editor.hpp
model/doc/documentmanager.hpp model/doc/document.hpp model/doc/state.hpp
model/world/universalid.hpp model/world/record.hpp model/world/idcollection.hpp model/world/data.hpp
model/world/idtable.hpp model/world/columns.hpp model/world/idtableproxymodel.hpp
model/world/commands.hpp model/world/columnbase.hpp
model/tools/tools.hpp model/tools/operation.hpp model/tools/stage.hpp model/tools/verifier.hpp
model/tools/mandatoryid.hpp model/tools/reportmodel.hpp
view/doc/viewmanager.hpp view/doc/view.hpp view/doc/operations.hpp view/doc/operation.hpp view/doc/subviewfactory.hpp
view/doc/subview.hpp view/doc/subviewfactoryimp.hpp
view/world/table.hpp view/world/tablesubview.hpp view/world/subviews.hpp view/world/util.hpp
view/world/dialoguesubview.hpp
view/tools/reportsubview.hpp view/tools/subviews.hpp
)
set (OPENCS_US
)
set (OPENCS_RES
)
source_group (opencs FILES ${OPENCS_SRC} ${OPENCS_HDR})
if(WIN32)
set(QT_USE_QTMAIN TRUE)
endif(WIN32)
find_package(Qt4 COMPONENTS QtCore QtGui QtXml QtXmlPatterns REQUIRED)
include(${QT_USE_FILE})
qt4_wrap_ui(OPENCS_UI_HDR ${OPENCS_UI})
qt4_wrap_cpp(OPENCS_MOC_SRC ${OPENCS_HDR})
qt4_add_resources(OPENCS_RES_SRC ${OPENCS_RES})
include_directories(${CMAKE_CURRENT_BINARY_DIR})
add_executable(opencs
${OPENCS_SRC}
${OPENCS_UI_HDR}
${OPENCS_MOC_SRC}
${OPENCS_RES_SRC}
)
target_link_libraries(opencs
${Boost_LIBRARIES}
${QT_LIBRARIES}
components
)

@ -0,0 +1,49 @@
#include "editor.hpp"
#include <sstream>
#include <QtGui/QApplication>
#include "model/doc/document.hpp"
#include "model/world/data.hpp"
CS::Editor::Editor() : mViewManager (mDocumentManager), mNewDocumentIndex (0)
{
connect (&mViewManager, SIGNAL (newDocumentRequest ()), this, SLOT (createDocument ()));
}
void CS::Editor::createDocument()
{
std::ostringstream stream;
stream << "NewDocument" << (++mNewDocumentIndex);
CSMDoc::Document *document = mDocumentManager.addDocument (stream.str());
static const char *sGlobals[] =
{
"Day", "DaysPassed", "GameHour", "Month", "PCRace", "PCVampire", "PCWerewolf", "PCYear", 0
};
for (int i=0; sGlobals[i]; ++i)
{
ESM::Global record;
record.mId = sGlobals[i];
record.mValue = i==0 ? 1 : 0;
record.mType = ESM::VT_Float;
document->getData().getGlobals().add (record);
}
document->getData().merge(); /// \todo remove once proper ESX loading is implemented
mViewManager.addView (document);
}
int CS::Editor::run()
{
/// \todo Instead of creating an empty document, open a small welcome dialogue window with buttons for new/load/recent projects
createDocument();
return QApplication::exec();
}

@ -0,0 +1,37 @@
#ifndef CS_EDITOR_H
#define CS_EDITOR_H
#include <QObject>
#include "model/doc/documentmanager.hpp"
#include "view/doc/viewmanager.hpp"
namespace CS
{
class Editor : public QObject
{
Q_OBJECT
int mNewDocumentIndex; ///< \todo remove when the proper new document dialogue is implemented.
CSMDoc::DocumentManager mDocumentManager;
CSVDoc::ViewManager mViewManager;
// not implemented
Editor (const Editor&);
Editor& operator= (const Editor&);
public:
Editor();
int run();
///< \return error status
public slots:
void createDocument();
};
}
#endif

@ -0,0 +1,39 @@
#include "editor.hpp"
#include <exception>
#include <iostream>
#include <QtGui/QApplication>
class Application : public QApplication
{
private:
bool notify (QObject *receiver, QEvent *event)
{
try
{
return QApplication::notify (receiver, event);
}
catch (const std::exception& exception)
{
std::cerr << "An exception has been caught: " << exception.what() << std::endl;
}
return false;
}
public:
Application (int& argc, char *argv[]) : QApplication (argc, argv) {}
};
int main(int argc, char *argv[])
{
Application mApplication (argc, argv);
CS::Editor editor;
return editor.run();
}

@ -0,0 +1,114 @@
#include "document.hpp"
CSMDoc::Document::Document (const std::string& name)
: mTools (mData)
{
mName = name; ///< \todo replace with ESX list
connect (&mUndoStack, SIGNAL (cleanChanged (bool)), this, SLOT (modificationStateChanged (bool)));
connect (&mTools, SIGNAL (progress (int, int, int)), this, SLOT (progress (int, int, int)));
connect (&mTools, SIGNAL (done (int)), this, SLOT (operationDone (int)));
// dummy implementation -> remove when proper save is implemented.
mSaveCount = 0;
connect (&mSaveTimer, SIGNAL(timeout()), this, SLOT (saving()));
}
QUndoStack& CSMDoc::Document::getUndoStack()
{
return mUndoStack;
}
int CSMDoc::Document::getState() const
{
int state = 0;
if (!mUndoStack.isClean())
state |= State_Modified;
if (mSaveCount)
state |= State_Locked | State_Saving | State_Operation;
if (int operations = mTools.getRunningOperations())
state |= State_Locked | State_Operation | operations;
return state;
}
const std::string& CSMDoc::Document::getName() const
{
return mName;
}
void CSMDoc::Document::save()
{
mSaveCount = 1;
mSaveTimer.start (500);
emit stateChanged (getState(), this);
emit progress (1, 16, State_Saving, 1, this);
}
CSMWorld::UniversalId CSMDoc::Document::verify()
{
CSMWorld::UniversalId id = mTools.runVerifier();
emit stateChanged (getState(), this);
return id;
}
void CSMDoc::Document::abortOperation (int type)
{
mTools.abortOperation (type);
if (type==State_Saving)
{
mSaveTimer.stop();
emit stateChanged (getState(), this);
}
}
void CSMDoc::Document::modificationStateChanged (bool clean)
{
emit stateChanged (getState(), this);
}
void CSMDoc::Document::operationDone (int type)
{
emit stateChanged (getState(), this);
}
void CSMDoc::Document::saving()
{
++mSaveCount;
emit progress (mSaveCount, 16, State_Saving, 1, this);
if (mSaveCount>15)
{
mSaveCount = 0;
mSaveTimer.stop();
mUndoStack.setClean();
emit stateChanged (getState(), this);
}
}
const CSMWorld::Data& CSMDoc::Document::getData() const
{
return mData;
}
CSMWorld::Data& CSMDoc::Document::getData()
{
return mData;
}
CSMTools::ReportModel *CSMDoc::Document::getReport (const CSMWorld::UniversalId& id)
{
return mTools.getReport (id);
}
void CSMDoc::Document::progress (int current, int max, int type)
{
emit progress (current, max, type, 1, this);
}

@ -0,0 +1,87 @@
#ifndef CSM_DOC_DOCUMENT_H
#define CSM_DOC_DOCUMENT_H
#include <string>
#include <QUndoStack>
#include <QObject>
#include <QTimer>
#include "../world/data.hpp"
#include "../tools/tools.hpp"
#include "state.hpp"
class QAbstractItemModel;
namespace CSMDoc
{
class Document : public QObject
{
Q_OBJECT
private:
std::string mName; ///< \todo replace name with ESX list
CSMWorld::Data mData;
CSMTools::Tools mTools;
// It is important that the undo stack is declared last, because on desctruction it fires a signal, that is connected to a slot, that is
// using other member variables. Unfortunately this connection is cut only in the QObject destructor, which is way too late.
QUndoStack mUndoStack;
int mSaveCount; ///< dummy implementation -> remove when proper save is implemented.
QTimer mSaveTimer; ///< dummy implementation -> remove when proper save is implemented.
// not implemented
Document (const Document&);
Document& operator= (const Document&);
public:
Document (const std::string& name);
///< \todo replace name with ESX list
QUndoStack& getUndoStack();
int getState() const;
const std::string& getName() const;
///< \todo replace with ESX list
void save();
CSMWorld::UniversalId verify();
void abortOperation (int type);
const CSMWorld::Data& getData() const;
CSMWorld::Data& getData();
CSMTools::ReportModel *getReport (const CSMWorld::UniversalId& id);
///< The ownership of the returned report is not transferred.
signals:
void stateChanged (int state, CSMDoc::Document *document);
void progress (int current, int max, int type, int threads, CSMDoc::Document *document);
private slots:
void modificationStateChanged (bool clean);
void operationDone (int type);
void saving();
///< dummy implementation -> remove when proper save is implemented.
public slots:
void progress (int current, int max, int type);
};
}
#endif

@ -0,0 +1,37 @@
#include "documentmanager.hpp"
#include <algorithm>
#include <stdexcept>
#include "document.hpp"
CSMDoc::DocumentManager::DocumentManager() {}
CSMDoc::DocumentManager::~DocumentManager()
{
for (std::vector<Document *>::iterator iter (mDocuments.begin()); iter!=mDocuments.end(); ++iter)
delete *iter;
}
CSMDoc::Document *CSMDoc::DocumentManager::addDocument (const std::string& name)
{
Document *document = new Document (name);
mDocuments.push_back (document);
return document;
}
bool CSMDoc::DocumentManager::removeDocument (Document *document)
{
std::vector<Document *>::iterator iter = std::find (mDocuments.begin(), mDocuments.end(), document);
if (iter==mDocuments.end())
throw std::runtime_error ("removing invalid document");
mDocuments.erase (iter);
delete document;
return mDocuments.empty();
}

@ -0,0 +1,32 @@
#ifndef CSM_DOC_DOCUMENTMGR_H
#define CSM_DOC_DOCUMENTMGR_H
#include <vector>
#include <string>
namespace CSMDoc
{
class Document;
class DocumentManager
{
std::vector<Document *> mDocuments;
DocumentManager (const DocumentManager&);
DocumentManager& operator= (const DocumentManager&);
public:
DocumentManager();
~DocumentManager();
Document *addDocument (const std::string& name);
///< The ownership of the returned document is not transferred to the caller.
bool removeDocument (Document *document);
///< \return last document removed?
};
}
#endif

@ -0,0 +1,19 @@
#ifndef CSM_DOC_STATE_H
#define CSM_DOC_STATE_H
namespace CSMDoc
{
enum State
{
State_Modified = 1,
State_Locked = 2,
State_Operation = 4,
State_Saving = 8,
State_Verifying = 16,
State_Compiling = 32, // not implemented yet
State_Searching = 64 // not implemented yet
};
}
#endif

@ -0,0 +1,21 @@
#include "mandatoryid.hpp"
#include "../world/idcollection.hpp"
CSMTools::MandatoryIdStage::MandatoryIdStage (const CSMWorld::IdCollectionBase& idCollection,
const CSMWorld::UniversalId& collectionId, const std::vector<std::string>& ids)
: mIdCollection (idCollection), mCollectionId (collectionId), mIds (ids)
{}
int CSMTools::MandatoryIdStage::setup()
{
return mIds.size();
}
void CSMTools::MandatoryIdStage::perform (int stage, std::vector<std::string>& messages)
{
if (mIdCollection.searchId (mIds.at (stage))==-1 ||
mIdCollection.getRecord (mIds.at (stage)).isDeleted())
messages.push_back (mCollectionId.toString() + "|Missing mandatory record: " + mIds.at (stage));
}

@ -0,0 +1,38 @@
#ifndef CSM_TOOLS_MANDATORYID_H
#define CSM_TOOLS_MANDATORYID_H
#include <string>
#include <vector>
#include "../world/universalid.hpp"
#include "stage.hpp"
namespace CSMWorld
{
class IdCollectionBase;
}
namespace CSMTools
{
/// \brief Verify stage: make sure that records with specific IDs exist.
class MandatoryIdStage : public Stage
{
const CSMWorld::IdCollectionBase& mIdCollection;
CSMWorld::UniversalId mCollectionId;
std::vector<std::string> mIds;
public:
MandatoryIdStage (const CSMWorld::IdCollectionBase& idCollection, const CSMWorld::UniversalId& collectionId,
const std::vector<std::string>& ids);
virtual int setup();
///< \return number of steps
virtual void perform (int stage, std::vector<std::string>& messages);
///< Messages resulting from this tage will be appended to \a messages.
};
}
#endif

@ -0,0 +1,84 @@
#include "operation.hpp"
#include <string>
#include <vector>
#include <QTimer>
#include "../doc/state.hpp"
#include "stage.hpp"
void CSMTools::Operation::prepareStages()
{
mCurrentStage = mStages.begin();
mCurrentStep = 0;
mCurrentStepTotal = 0;
mTotalSteps = 0;
for (std::vector<std::pair<Stage *, int> >::iterator iter (mStages.begin()); iter!=mStages.end(); ++iter)
{
iter->second = iter->first->setup();
mTotalSteps += iter->second;
}
}
CSMTools::Operation::Operation (int type) : mType (type) {}
CSMTools::Operation::~Operation()
{
for (std::vector<std::pair<Stage *, int> >::iterator iter (mStages.begin()); iter!=mStages.end(); ++iter)
delete iter->first;
}
void CSMTools::Operation::run()
{
prepareStages();
QTimer timer;
timer.connect (&timer, SIGNAL (timeout()), this, SLOT (verify()));
timer.start (0);
exec();
}
void CSMTools::Operation::appendStage (Stage *stage)
{
mStages.push_back (std::make_pair (stage, 0));
}
void CSMTools::Operation::abort()
{
exit();
}
void CSMTools::Operation::verify()
{
std::vector<std::string> messages;
while (mCurrentStage!=mStages.end())
{
if (mCurrentStep>=mCurrentStage->second)
{
mCurrentStep = 0;
++mCurrentStage;
}
else
{
mCurrentStage->first->perform (mCurrentStep++, messages);
++mCurrentStepTotal;
break;
}
}
emit progress (mCurrentStepTotal, mTotalSteps ? mTotalSteps : 1, mType);
for (std::vector<std::string>::const_iterator iter (messages.begin()); iter!=messages.end(); ++iter)
emit reportMessage (iter->c_str(), mType);
if (mCurrentStage==mStages.end())
exit();
}

@ -0,0 +1,54 @@
#ifndef CSM_TOOLS_OPERATION_H
#define CSM_TOOLS_OPERATION_H
#include <vector>
#include <QThread>
namespace CSMTools
{
class Stage;
class Operation : public QThread
{
Q_OBJECT
int mType;
std::vector<std::pair<Stage *, int> > mStages; // stage, number of steps
std::vector<std::pair<Stage *, int> >::iterator mCurrentStage;
int mCurrentStep;
int mCurrentStepTotal;
int mTotalSteps;
void prepareStages();
public:
Operation (int type);
virtual ~Operation();
virtual void run();
void appendStage (Stage *stage);
///< The ownership of \a stage is transferred to *this.
///
/// \attention Do no call this function while this Operation is running.
signals:
void progress (int current, int max, int type);
void reportMessage (const QString& message, int type);
public slots:
void abort();
private slots:
void verify();
};
}
#endif

@ -0,0 +1,71 @@
#include "reportmodel.hpp"
#include <stdexcept>
int CSMTools::ReportModel::rowCount (const QModelIndex & parent) const
{
if (parent.isValid())
return 0;
return mRows.size();
}
int CSMTools::ReportModel::columnCount (const QModelIndex & parent) const
{
if (parent.isValid())
return 0;
return 2;
}
QVariant CSMTools::ReportModel::data (const QModelIndex & index, int role) const
{
if (role!=Qt::DisplayRole)
return QVariant();
if (index.column()==0)
return static_cast<int> (mRows.at (index.row()).first.getType());
else
return mRows.at (index.row()).second.c_str();
}
QVariant CSMTools::ReportModel::headerData (int section, Qt::Orientation orientation, int role) const
{
if (role!=Qt::DisplayRole)
return QVariant();
if (orientation==Qt::Vertical)
return QVariant();
return tr (section==0 ? "Type" : "Description");
}
bool CSMTools::ReportModel::removeRows (int row, int count, const QModelIndex& parent)
{
if (parent.isValid())
return false;
mRows.erase (mRows.begin()+row, mRows.begin()+row+count);
return true;
}
void CSMTools::ReportModel::add (const std::string& row)
{
std::string::size_type index = row.find ('|');
if (index==std::string::npos)
throw std::logic_error ("invalid report message");
beginInsertRows (QModelIndex(), mRows.size(), mRows.size());
mRows.push_back (std::make_pair (row.substr (0, index), row.substr (index+1)));
endInsertRows();
}
const CSMWorld::UniversalId& CSMTools::ReportModel::getUniversalId (int row) const
{
return mRows.at (row).first;
}

@ -0,0 +1,37 @@
#ifndef CSM_TOOLS_REPORTMODEL_H
#define CSM_TOOLS_REPORTMODEL_H
#include <vector>
#include <string>
#include <QAbstractTableModel>
#include "../world/universalid.hpp"
namespace CSMTools
{
class ReportModel : public QAbstractTableModel
{
Q_OBJECT
std::vector<std::pair<CSMWorld::UniversalId, std::string> > mRows;
public:
virtual int rowCount (const QModelIndex & parent = QModelIndex()) const;
virtual int columnCount (const QModelIndex & parent = QModelIndex()) const;
virtual QVariant data (const QModelIndex & index, int role = Qt::DisplayRole) const;
virtual QVariant headerData (int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const;
virtual bool removeRows (int row, int count, const QModelIndex& parent = QModelIndex());
void add (const std::string& row);
const CSMWorld::UniversalId& getUniversalId (int row) const;
};
}
#endif

@ -0,0 +1,4 @@
#include "stage.hpp"
CSMTools::Stage::~Stage() {}

@ -0,0 +1,24 @@
#ifndef CSM_TOOLS_STAGE_H
#define CSM_TOOLS_STAGE_H
#include <vector>
#include <string>
namespace CSMTools
{
class Stage
{
public:
virtual ~Stage();
virtual int setup() = 0;
///< \return number of steps
virtual void perform (int stage, std::vector<std::string>& messages) = 0;
///< Messages resulting from this tage will be appended to \a messages.
};
}
#endif

@ -0,0 +1,123 @@
#include "tools.hpp"
#include <QThreadPool>
#include "verifier.hpp"
#include "../doc/state.hpp"
#include "../world/data.hpp"
#include "../world/universalid.hpp"
#include "reportmodel.hpp"
#include "mandatoryid.hpp"
CSMTools::Operation *CSMTools::Tools::get (int type)
{
switch (type)
{
case CSMDoc::State_Verifying: return mVerifier;
}
return 0;
}
const CSMTools::Operation *CSMTools::Tools::get (int type) const
{
return const_cast<Tools *> (this)->get (type);
}
CSMTools::Verifier *CSMTools::Tools::getVerifier()
{
if (!mVerifier)
{
mVerifier = new Verifier;
connect (mVerifier, SIGNAL (progress (int, int, int)), this, SIGNAL (progress (int, int, int)));
connect (mVerifier, SIGNAL (finished()), this, SLOT (verifierDone()));
connect (mVerifier, SIGNAL (reportMessage (const QString&, int)),
this, SLOT (verifierMessage (const QString&, int)));
std::vector<std::string> mandatoryIds; // I want C++11, damn it!
mandatoryIds.push_back ("Day");
mandatoryIds.push_back ("DaysPassed");
mandatoryIds.push_back ("GameHour");
mandatoryIds.push_back ("Month");
mandatoryIds.push_back ("PCRace");
mandatoryIds.push_back ("PCVampire");
mandatoryIds.push_back ("PCWerewolf");
mandatoryIds.push_back ("PCYear");
mVerifier->appendStage (new MandatoryIdStage (mData.getGlobals(),
CSMWorld::UniversalId (CSMWorld::UniversalId::Type_Globals), mandatoryIds));
}
return mVerifier;
}
CSMTools::Tools::Tools (CSMWorld::Data& data) : mData (data), mVerifier (0), mNextReportNumber (0)
{
for (std::map<int, ReportModel *>::iterator iter (mReports.begin()); iter!=mReports.end(); ++iter)
delete iter->second;
}
CSMTools::Tools::~Tools()
{
delete mVerifier;
}
CSMWorld::UniversalId CSMTools::Tools::runVerifier()
{
mReports.insert (std::make_pair (mNextReportNumber++, new ReportModel));
mActiveReports[CSMDoc::State_Verifying] = mNextReportNumber-1;
getVerifier()->start();
return CSMWorld::UniversalId (CSMWorld::UniversalId::Type_VerificationResults, mNextReportNumber-1);
}
void CSMTools::Tools::abortOperation (int type)
{
if (Operation *operation = get (type))
operation->abort();
}
int CSMTools::Tools::getRunningOperations() const
{
static const int sOperations[] =
{
CSMDoc::State_Verifying,
-1
};
int result = 0;
for (int i=0; sOperations[i]!=-1; ++i)
if (const Operation *operation = get (sOperations[i]))
if (operation->isRunning())
result |= sOperations[i];
return result;
}
CSMTools::ReportModel *CSMTools::Tools::getReport (const CSMWorld::UniversalId& id)
{
if (id.getType()!=CSMWorld::UniversalId::Type_VerificationResults)
throw std::logic_error ("invalid request for report model: " + id.toString());
return mReports.at (id.getIndex());
}
void CSMTools::Tools::verifierDone()
{
emit done (CSMDoc::State_Verifying);
}
void CSMTools::Tools::verifierMessage (const QString& message, int type)
{
std::map<int, int>::iterator iter = mActiveReports.find (type);
if (iter!=mActiveReports.end())
mReports[iter->second]->add (message.toStdString());
}

@ -0,0 +1,73 @@
#ifndef CSM_TOOLS_TOOLS_H
#define CSM_TOOLS_TOOLS_H
#include <QObject>
#include <map>
namespace CSMWorld
{
class Data;
class UniversalId;
}
namespace CSMTools
{
class Verifier;
class Operation;
class ReportModel;
class Tools : public QObject
{
Q_OBJECT
CSMWorld::Data& mData;
Verifier *mVerifier;
std::map<int, ReportModel *> mReports;
int mNextReportNumber;
std::map<int, int> mActiveReports; // type, report number
// not implemented
Tools (const Tools&);
Tools& operator= (const Tools&);
Verifier *getVerifier();
Operation *get (int type);
///< Returns a 0-pointer, if operation hasn't been used yet.
const Operation *get (int type) const;
///< Returns a 0-pointer, if operation hasn't been used yet.
public:
Tools (CSMWorld::Data& data);
virtual ~Tools();
CSMWorld::UniversalId runVerifier();
///< \return ID of the report for this verification run
void abortOperation (int type);
///< \attention The operation is not aborted immediately.
int getRunningOperations() const;
ReportModel *getReport (const CSMWorld::UniversalId& id);
///< The ownership of the returned report is not transferred.
private slots:
void verifierDone();
void verifierMessage (const QString& message, int type);
signals:
void progress (int current, int max, int type);
void done (int type);
};
}
#endif

@ -0,0 +1,7 @@
#include "verifier.hpp"
#include "../doc/state.hpp"
CSMTools::Verifier::Verifier() : Operation (CSMDoc::State_Verifying)
{}

@ -0,0 +1,17 @@
#ifndef CSM_TOOLS_VERIFIER_H
#define CSM_TOOLS_VERIFIER_H
#include "operation.hpp"
namespace CSMTools
{
class Verifier : public Operation
{
public:
Verifier();
};
}
#endif

@ -0,0 +1,13 @@
#include "columnbase.hpp"
CSMWorld::ColumnBase::ColumnBase (const std::string& title, int flags)
: mTitle (title), mFlags (flags)
{}
CSMWorld::ColumnBase::~ColumnBase() {}
bool CSMWorld::ColumnBase::isUserEditable() const
{
return isEditable();
}

@ -0,0 +1,57 @@
#ifndef CSM_WOLRD_COLUMNBASE_H
#define CSM_WOLRD_COLUMNBASE_H
#include <string>
#include <Qt>
#include <QVariant>
#include "record.hpp"
namespace CSMWorld
{
struct ColumnBase
{
enum Roles
{
Role_Flags = Qt::UserRole
};
enum Flags
{
Flag_Table = 1, // column should be displayed in table view
Flag_Dialogue = 2 // column should be displayed in dialogue view
};
std::string mTitle;
int mFlags;
ColumnBase (const std::string& title, int flag);
virtual ~ColumnBase();
virtual bool isEditable() const = 0;
virtual bool isUserEditable() const;
///< Can this column be edited directly by the user?
};
template<typename ESXRecordT>
struct Column : public ColumnBase
{
std::string mTitle;
int mFlags;
Column (const std::string& title, int flags = Flag_Table | Flag_Dialogue)
: ColumnBase (title, flags) {}
virtual QVariant get (const Record<ESXRecordT>& record) const = 0;
virtual void set (Record<ESXRecordT>& record, const QVariant& data)
{
throw std::logic_error ("Column " + mTitle + " is not editable");
}
};
}
#endif

@ -0,0 +1,95 @@
#ifndef CSM_WOLRD_COLUMNS_H
#define CSM_WOLRD_COLUMNS_H
#include "columnbase.hpp"
namespace CSMWorld
{
template<typename ESXRecordT>
struct FloatValueColumn : public Column<ESXRecordT>
{
FloatValueColumn() : Column<ESXRecordT> ("Value") {}
virtual QVariant get (const Record<ESXRecordT>& record) const
{
return record.get().mValue;
}
virtual void set (Record<ESXRecordT>& record, const QVariant& data)
{
ESXRecordT base = record.getBase();
base.mValue = data.toFloat();
record.setModified (base);
}
virtual bool isEditable() const
{
return true;
}
};
template<typename ESXRecordT>
struct StringIdColumn : public Column<ESXRecordT>
{
StringIdColumn() : Column<ESXRecordT> ("ID") {}
virtual QVariant get (const Record<ESXRecordT>& record) const
{
return record.get().mId.c_str();
}
virtual bool isEditable() const
{
return false;
}
};
template<typename ESXRecordT>
struct RecordStateColumn : public Column<ESXRecordT>
{
RecordStateColumn() : Column<ESXRecordT> ("*") {}
virtual QVariant get (const Record<ESXRecordT>& record) const
{
if (record.mState==Record<ESXRecordT>::State_Erased)
return static_cast<int> (Record<ESXRecordT>::State_Deleted);
return static_cast<int> (record.mState);
}
virtual void set (Record<ESXRecordT>& record, const QVariant& data)
{
record.mState = static_cast<RecordBase::State> (data.toInt());
}
virtual bool isEditable() const
{
return true;
}
virtual bool isUserEditable() const
{
return false;
}
};
template<typename ESXRecordT>
struct FixedRecordTypeColumn : public Column<ESXRecordT>
{
int mType;
FixedRecordTypeColumn (int type) : Column<ESXRecordT> ("Type", 0), mType (type) {}
virtual QVariant get (const Record<ESXRecordT>& record) const
{
return mType;
}
virtual bool isEditable() const
{
return false;
}
};
}
#endif

@ -0,0 +1,108 @@
#include "commands.hpp"
#include <QAbstractTableModel>
#include "idtableproxymodel.hpp"
#include "idtable.hpp"
CSMWorld::ModifyCommand::ModifyCommand (QAbstractItemModel& model, const QModelIndex& index,
const QVariant& new_, QUndoCommand *parent)
: QUndoCommand (parent), mModel (model), mIndex (index), mNew (new_)
{
mOld = mModel.data (mIndex, Qt::EditRole);
setText ("Modify " + mModel.headerData (mIndex.column(), Qt::Horizontal, Qt::DisplayRole).toString());
}
void CSMWorld::ModifyCommand::redo()
{
mModel.setData (mIndex, mNew);
}
void CSMWorld::ModifyCommand::undo()
{
mModel.setData (mIndex, mOld);
}
CSMWorld::CreateCommand::CreateCommand (IdTableProxyModel& model, const std::string& id, QUndoCommand *parent)
: QUndoCommand (parent), mModel (model), mId (id)
{
setText (("Create record " + id).c_str());
}
void CSMWorld::CreateCommand::redo()
{
mModel.addRecord (mId);
}
void CSMWorld::CreateCommand::undo()
{
mModel.removeRow (mModel.getModelIndex (mId, 0).row());
}
CSMWorld::RevertCommand::RevertCommand (IdTable& model, const std::string& id, QUndoCommand *parent)
: QUndoCommand (parent), mModel (model), mId (id), mOld (0)
{
setText (("Revert record " + id).c_str());
mOld = model.getRecord (id).clone();
}
CSMWorld::RevertCommand::~RevertCommand()
{
delete mOld;
}
void CSMWorld::RevertCommand::redo()
{
QModelIndex index = mModel.getModelIndex (mId, 1);
RecordBase::State state = static_cast<RecordBase::State> (mModel.data (index).toInt());
if (state==RecordBase::State_ModifiedOnly)
{
mModel.removeRows (index.row(), 1);
}
else
{
mModel.setData (index, static_cast<int> (RecordBase::State_BaseOnly));
}
}
void CSMWorld::RevertCommand::undo()
{
mModel.setRecord (*mOld);
}
CSMWorld::DeleteCommand::DeleteCommand (IdTable& model, const std::string& id, QUndoCommand *parent)
: QUndoCommand (parent), mModel (model), mId (id), mOld (0)
{
setText (("Delete record " + id).c_str());
mOld = model.getRecord (id).clone();
}
CSMWorld::DeleteCommand::~DeleteCommand()
{
delete mOld;
}
void CSMWorld::DeleteCommand::redo()
{
QModelIndex index = mModel.getModelIndex (mId, 1);
RecordBase::State state = static_cast<RecordBase::State> (mModel.data (index).toInt());
if (state==RecordBase::State_ModifiedOnly)
{
mModel.removeRows (index.row(), 1);
}
else
{
mModel.setData (index, static_cast<int> (RecordBase::State_Deleted));
}
}
void CSMWorld::DeleteCommand::undo()
{
mModel.setRecord (*mOld);
}

@ -0,0 +1,95 @@
#ifndef CSM_WOLRD_COMMANDS_H
#define CSM_WOLRD_COMMANDS_H
#include "record.hpp"
#include <string>
#include <QVariant>
#include <QUndoCommand>
#include <QModelIndex>
class QModelIndex;
class QAbstractItemModel;
namespace CSMWorld
{
class IdTableProxyModel;
class IdTable;
class RecordBase;
class ModifyCommand : public QUndoCommand
{
QAbstractItemModel& mModel;
QModelIndex mIndex;
QVariant mNew;
QVariant mOld;
public:
ModifyCommand (QAbstractItemModel& model, const QModelIndex& index, const QVariant& new_,
QUndoCommand *parent = 0);
virtual void redo();
virtual void undo();
};
class CreateCommand : public QUndoCommand
{
IdTableProxyModel& mModel;
std::string mId;
public:
CreateCommand (IdTableProxyModel& model, const std::string& id, QUndoCommand *parent = 0);
virtual void redo();
virtual void undo();
};
class RevertCommand : public QUndoCommand
{
IdTable& mModel;
std::string mId;
RecordBase *mOld;
// not implemented
RevertCommand (const RevertCommand&);
RevertCommand& operator= (const RevertCommand&);
public:
RevertCommand (IdTable& model, const std::string& id, QUndoCommand *parent = 0);
virtual ~RevertCommand();
virtual void redo();
virtual void undo();
};
class DeleteCommand : public QUndoCommand
{
IdTable& mModel;
std::string mId;
RecordBase *mOld;
// not implemented
DeleteCommand (const DeleteCommand&);
DeleteCommand& operator= (const DeleteCommand&);
public:
DeleteCommand (IdTable& model, const std::string& id, QUndoCommand *parent = 0);
virtual ~DeleteCommand();
virtual void redo();
virtual void undo();
};
}
#endif

@ -0,0 +1,62 @@
#include "data.hpp"
#include <stdexcept>
#include <QAbstractTableModel>
#include <components/esm/loadglob.hpp>
#include "idtable.hpp"
#include "columns.hpp"
void CSMWorld::Data::addModel (QAbstractTableModel *model, UniversalId::Type type1,
UniversalId::Type type2)
{
mModels.push_back (model);
mModelIndex.insert (std::make_pair (type1, model));
if (type2!=UniversalId::Type_None)
mModelIndex.insert (std::make_pair (type2, model));
}
CSMWorld::Data::Data()
{
mGlobals.addColumn (new StringIdColumn<ESM::Global>);
mGlobals.addColumn (new RecordStateColumn<ESM::Global>);
mGlobals.addColumn (new FixedRecordTypeColumn<ESM::Global> (UniversalId::Type_Global));
mGlobals.addColumn (new FloatValueColumn<ESM::Global>);
addModel (new IdTable (&mGlobals), UniversalId::Type_Globals, UniversalId::Type_Global);
}
CSMWorld::Data::~Data()
{
for (std::vector<QAbstractTableModel *>::iterator iter (mModels.begin()); iter!=mModels.end(); ++iter)
delete *iter;
}
const CSMWorld::IdCollection<ESM::Global>& CSMWorld::Data::getGlobals() const
{
return mGlobals;
}
CSMWorld::IdCollection<ESM::Global>& CSMWorld::Data::getGlobals()
{
return mGlobals;
}
QAbstractTableModel *CSMWorld::Data::getTableModel (const UniversalId& id)
{
std::map<UniversalId::Type, QAbstractTableModel *>::iterator iter = mModelIndex.find (id.getType());
if (iter==mModelIndex.end())
throw std::logic_error ("No table model available for " + id.toString());
return iter->second;
}
void CSMWorld::Data::merge()
{
mGlobals.merge();
}

@ -0,0 +1,50 @@
#ifndef CSM_WOLRD_DATA_H
#define CSM_WOLRD_DATA_H
#include <map>
#include <vector>
#include <components/esm/loadglob.hpp>
#include "idcollection.hpp"
#include "universalid.hpp"
class QAbstractTableModel;
namespace CSMWorld
{
class Data
{
IdCollection<ESM::Global> mGlobals;
std::vector<QAbstractTableModel *> mModels;
std::map<UniversalId::Type, QAbstractTableModel *> mModelIndex;
// not implemented
Data (const Data&);
Data& operator= (const Data&);
void addModel (QAbstractTableModel *model, UniversalId::Type type1,
UniversalId::Type type2 = UniversalId::Type_None);
public:
Data();
~Data();
const IdCollection<ESM::Global>& getGlobals() const;
IdCollection<ESM::Global>& getGlobals();
QAbstractTableModel *getTableModel (const UniversalId& id);
///< If no table model is available for \a id, an exception is thrown.
///
/// \note The returned table may either be the model for the ID itself or the model that
/// contains the record specified by the ID.
void merge();
///< Merge modified into base.
};
}
#endif

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

@ -0,0 +1,325 @@
#ifndef CSM_WOLRD_IDCOLLECTION_H
#define CSM_WOLRD_IDCOLLECTION_H
#include <vector>
#include <map>
#include <string>
#include <algorithm>
#include <cctype>
#include <stdexcept>
#include <functional>
#include <QVariant>
#include "columnbase.hpp"
namespace CSMWorld
{
class IdCollectionBase
{
// not implemented
IdCollectionBase (const IdCollectionBase&);
IdCollectionBase& operator= (const IdCollectionBase&);
public:
IdCollectionBase();
virtual ~IdCollectionBase();
virtual int getSize() const = 0;
virtual std::string getId (int index) const = 0;
virtual int getIndex (const std::string& id) const = 0;
virtual int getColumns() const = 0;
virtual const ColumnBase& getColumn (int column) const = 0;
virtual QVariant getData (int index, int column) const = 0;
virtual void setData (int index, int column, const QVariant& data) = 0;
virtual void merge() = 0;
///< Merge modified into base.
virtual void purge() = 0;
///< Remove records that are flagged as erased.
virtual void removeRows (int index, int count) = 0;
virtual void appendBlankRecord (const std::string& id) = 0;
virtual int searchId (const std::string& id) const = 0;
////< Search record with \a id.
/// \return index of record (if found) or -1 (not found)
virtual void replace (int index, const RecordBase& record) = 0;
///< If the record type does not match, an exception is thrown.
///
/// \attention \a record must not change the ID.
virtual void appendRecord (const RecordBase& record) = 0;
///< If the record type does not match, an exception is thrown.
virtual std::string getId (const RecordBase& record) const = 0;
///< Return ID for \a record.
///
/// \attention Throw san exception, if the type of \a record does not match.
virtual const RecordBase& getRecord (const std::string& id) const = 0;
};
///< \brief Collection of ID-based records
template<typename ESXRecordT>
class IdCollection : public IdCollectionBase
{
std::vector<Record<ESXRecordT> > mRecords;
std::map<std::string, int> mIndex;
std::vector<Column<ESXRecordT> *> mColumns;
// not implemented
IdCollection (const IdCollection&);
IdCollection& operator= (const IdCollection&);
public:
IdCollection();
virtual ~IdCollection();
void add (const ESXRecordT& record);
///< Add a new record (modified)
virtual int getSize() const;
virtual std::string getId (int index) const;
virtual int getIndex (const std::string& id) const;
virtual int getColumns() const;
virtual QVariant getData (int index, int column) const;
virtual void setData (int index, int column, const QVariant& data);
virtual const ColumnBase& getColumn (int column) const;
virtual void merge();
///< Merge modified into base.
virtual void purge();
///< Remove records that are flagged as erased.
virtual void removeRows (int index, int count) ;
virtual void appendBlankRecord (const std::string& id);
virtual int searchId (const std::string& id) const;
////< Search record with \a id.
/// \return index of record (if found) or -1 (not found)
virtual void replace (int index, const RecordBase& record);
///< If the record type does not match, an exception is thrown.
///
/// \attention \a record must not change the ID.
virtual void appendRecord (const RecordBase& record);
///< If the record type does not match, an exception is thrown.
virtual std::string getId (const RecordBase& record) const;
///< Return ID for \a record.
///
/// \attention Throw san exception, if the type of \a record does not match.
virtual const RecordBase& getRecord (const std::string& id) const;
void addColumn (Column<ESXRecordT> *column);
};
template<typename ESXRecordT>
IdCollection<ESXRecordT>::IdCollection()
{}
template<typename ESXRecordT>
IdCollection<ESXRecordT>::~IdCollection()
{
for (typename std::vector<Column<ESXRecordT> *>::iterator iter (mColumns.begin()); iter!=mColumns.end(); ++iter)
delete *iter;
}
template<typename ESXRecordT>
void IdCollection<ESXRecordT>::add (const ESXRecordT& record)
{
std::string id;
std::transform (record.mId.begin(), record.mId.end(), std::back_inserter (id),
(int(*)(int)) std::tolower);
std::map<std::string, int>::iterator iter = mIndex.find (id);
if (iter==mIndex.end())
{
Record<ESXRecordT> record2;
record2.mState = Record<ESXRecordT>::State_ModifiedOnly;
record2.mModified = record;
mRecords.push_back (record2);
mIndex.insert (std::make_pair (id, mRecords.size()-1));
}
else
{
mRecords[iter->second].setModified (record);
}
}
template<typename ESXRecordT>
int IdCollection<ESXRecordT>::getSize() const
{
return mRecords.size();
}
template<typename ESXRecordT>
std::string IdCollection<ESXRecordT>::getId (int index) const
{
return mRecords.at (index).get().mId;
}
template<typename ESXRecordT>
int IdCollection<ESXRecordT>::getIndex (const std::string& id) const
{
int index = searchId (id);
if (index==-1)
throw std::runtime_error ("invalid ID: " + id);
return index;
}
template<typename ESXRecordT>
int IdCollection<ESXRecordT>::getColumns() const
{
return mColumns.size();
}
template<typename ESXRecordT>
QVariant IdCollection<ESXRecordT>::getData (int index, int column) const
{
return mColumns.at (column)->get (mRecords.at (index));
}
template<typename ESXRecordT>
void IdCollection<ESXRecordT>::setData (int index, int column, const QVariant& data)
{
return mColumns.at (column)->set (mRecords.at (index), data);
}
template<typename ESXRecordT>
const ColumnBase& IdCollection<ESXRecordT>::getColumn (int column) const
{
return *mColumns.at (column);
}
template<typename ESXRecordT>
void IdCollection<ESXRecordT>::addColumn (Column<ESXRecordT> *column)
{
mColumns.push_back (column);
}
template<typename ESXRecordT>
void IdCollection<ESXRecordT>::merge()
{
for (typename std::vector<Record<ESXRecordT> >::iterator iter (mRecords.begin()); iter!=mRecords.end(); ++iter)
iter->merge();
purge();
}
template<typename ESXRecordT>
void IdCollection<ESXRecordT>::purge()
{
mRecords.erase (std::remove_if (mRecords.begin(), mRecords.end(),
std::mem_fun_ref (&Record<ESXRecordT>::isErased) // I want lambda :(
), mRecords.end());
}
template<typename ESXRecordT>
void IdCollection<ESXRecordT>::removeRows (int index, int count)
{
mRecords.erase (mRecords.begin()+index, mRecords.begin()+index+count);
typename std::map<std::string, int>::iterator iter = mIndex.begin();
while (iter!=mIndex.end())
{
if (iter->second>=index)
{
if (iter->second>=index+count)
{
iter->second -= count;
}
else
{
mIndex.erase (iter++);
}
}
++iter;
}
}
template<typename ESXRecordT>
void IdCollection<ESXRecordT>::appendBlankRecord (const std::string& id)
{
ESXRecordT record;
record.mId = id;
record.blank();
add (record);
}
template<typename ESXRecordT>
int IdCollection<ESXRecordT>::searchId (const std::string& id) const
{
std::string id2;
std::transform (id.begin(), id.end(), std::back_inserter (id2),
(int(*)(int)) std::tolower);
std::map<std::string, int>::const_iterator iter = mIndex.find (id2);
if (iter==mIndex.end())
return -1;
return iter->second;
}
template<typename ESXRecordT>
void IdCollection<ESXRecordT>::replace (int index, const RecordBase& record)
{
mRecords.at (index) = dynamic_cast<const Record<ESXRecordT>&> (record);
}
template<typename ESXRecordT>
void IdCollection<ESXRecordT>::appendRecord (const RecordBase& record)
{
mRecords.push_back (dynamic_cast<const Record<ESXRecordT>&> (record));
mIndex.insert (std::make_pair (getId (record), mRecords.size()-1));
}
template<typename ESXRecordT>
std::string IdCollection<ESXRecordT>::getId (const RecordBase& record) const
{
const Record<ESXRecordT>& record2 = dynamic_cast<const Record<ESXRecordT>&> (record);
return (record2.isModified() ? record2.mModified : record2.mBase).mId;
}
template<typename ESXRecordT>
const RecordBase& IdCollection<ESXRecordT>::getRecord (const std::string& id) const
{
int index = getIndex (id);
return mRecords.at (index);
}
}
#endif

@ -0,0 +1,137 @@
#include "idtable.hpp"
#include "idcollection.hpp"
CSMWorld::IdTable::IdTable (IdCollectionBase *idCollection) : mIdCollection (idCollection)
{
}
CSMWorld::IdTable::~IdTable()
{
}
int CSMWorld::IdTable::rowCount (const QModelIndex & parent) const
{
if (parent.isValid())
return 0;
return mIdCollection->getSize();
}
int CSMWorld::IdTable::columnCount (const QModelIndex & parent) const
{
if (parent.isValid())
return 0;
return mIdCollection->getColumns();
}
QVariant CSMWorld::IdTable::data (const QModelIndex & index, int role) const
{
if (role!=Qt::DisplayRole && role!=Qt::EditRole)
return QVariant();
if (role==Qt::EditRole && !mIdCollection->getColumn (index.column()).isEditable())
return QVariant();
return mIdCollection->getData (index.row(), index.column());
}
QVariant CSMWorld::IdTable::headerData (int section, Qt::Orientation orientation, int role) const
{
if (orientation==Qt::Vertical)
return QVariant();
if (role==Qt::DisplayRole)
return tr (mIdCollection->getColumn (section).mTitle.c_str());
if (role==ColumnBase::Role_Flags)
return mIdCollection->getColumn (section).mFlags;
return QVariant();
}
bool CSMWorld::IdTable::setData ( const QModelIndex &index, const QVariant &value, int role)
{
if (mIdCollection->getColumn (index.column()).isEditable() && role==Qt::EditRole)
{
mIdCollection->setData (index.row(), index.column(), value);
emit dataChanged (CSMWorld::IdTable::index (index.row(), 0),
CSMWorld::IdTable::index (index.row(), mIdCollection->getColumns()-1));
return true;
}
return false;
}
Qt::ItemFlags CSMWorld::IdTable::flags (const QModelIndex & index) const
{
Qt::ItemFlags flags = Qt::ItemIsSelectable | Qt::ItemIsEnabled;
if (mIdCollection->getColumn (index.column()).isUserEditable())
flags |= Qt::ItemIsEditable;
return flags;
}
bool CSMWorld::IdTable::removeRows (int row, int count, const QModelIndex& parent)
{
if (parent.isValid())
return false;
beginRemoveRows (parent, row, row+count-1);
mIdCollection->removeRows (row, count);
endRemoveRows();
return true;
}
void CSMWorld::IdTable::addRecord (const std::string& id)
{
int index = mIdCollection->getSize();
beginInsertRows (QModelIndex(), index, index);
mIdCollection->appendBlankRecord (id);
endInsertRows();
}
QModelIndex CSMWorld::IdTable::getModelIndex (const std::string& id, int column) const
{
return index (mIdCollection->getIndex (id), column);
}
void CSMWorld::IdTable::setRecord (const RecordBase& record)
{
int index = mIdCollection->searchId (mIdCollection->getId (record));
if (index==-1)
{
int index = mIdCollection->getSize();
beginInsertRows (QModelIndex(), index, index);
mIdCollection->appendRecord (record);
endInsertRows();
}
else
{
mIdCollection->replace (index, record);
emit dataChanged (CSMWorld::IdTable::index (index, 0),
CSMWorld::IdTable::index (index, mIdCollection->getColumns()-1));
}
}
const CSMWorld::RecordBase& CSMWorld::IdTable::getRecord (const std::string& id) const
{
return mIdCollection->getRecord (id);
}

@ -0,0 +1,53 @@
#ifndef CSM_WOLRD_IDTABLE_H
#define CSM_WOLRD_IDTABLE_H
#include <QAbstractTableModel>
namespace CSMWorld
{
class IdCollectionBase;
class RecordBase;
class IdTable : public QAbstractTableModel
{
Q_OBJECT
IdCollectionBase *mIdCollection;
// not implemented
IdTable (const IdTable&);
IdTable& operator= (const IdTable&);
public:
IdTable (IdCollectionBase *idCollection);
///< The ownership of \a idCollection is not transferred.
virtual ~IdTable();
virtual int rowCount (const QModelIndex & parent = QModelIndex()) const;
virtual int columnCount (const QModelIndex & parent = QModelIndex()) const;
virtual QVariant data (const QModelIndex & index, int role = Qt::DisplayRole) const;
virtual QVariant headerData (int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const;
virtual bool setData ( const QModelIndex &index, const QVariant &value, int role = Qt::EditRole);
virtual Qt::ItemFlags flags (const QModelIndex & index) const;
virtual bool removeRows (int row, int count, const QModelIndex& parent = QModelIndex());
void addRecord (const std::string& id);
QModelIndex getModelIndex (const std::string& id, int column) const;
void setRecord (const RecordBase& record);
///< Add record or overwrite existing recrod.
const RecordBase& getRecord (const std::string& id) const;
};
}
#endif

@ -0,0 +1,18 @@
#include "idtableproxymodel.hpp"
#include "idtable.hpp"
CSMWorld::IdTableProxyModel::IdTableProxyModel (QObject *parent)
: QSortFilterProxyModel (parent)
{}
void CSMWorld::IdTableProxyModel::addRecord (const std::string& id)
{
dynamic_cast<IdTable&> (*sourceModel()).addRecord (id);
}
QModelIndex CSMWorld::IdTableProxyModel::getModelIndex (const std::string& id, int column) const
{
return mapFromSource (dynamic_cast<IdTable&> (*sourceModel()).getModelIndex (id, column));
}

@ -0,0 +1,24 @@
#ifndef CSM_WOLRD_IDTABLEPROXYMODEL_H
#define CSM_WOLRD_IDTABLEPROXYMODEL_H
#include <QSortFilterProxyModel>
#include <string>
namespace CSMWorld
{
class IdTableProxyModel : public QSortFilterProxyModel
{
Q_OBJECT
public:
IdTableProxyModel (QObject *parent = 0);
virtual void addRecord (const std::string& id);
virtual QModelIndex getModelIndex (const std::string& id, int column) const;
};
}
#endif

@ -0,0 +1,21 @@
#include "record.hpp"
CSMWorld::RecordBase::~RecordBase() {}
bool CSMWorld::RecordBase::RecordBase::isDeleted() const
{
return mState==State_Deleted || mState==State_Erased;
}
bool CSMWorld::RecordBase::RecordBase::isErased() const
{
return mState==State_Erased;
}
bool CSMWorld::RecordBase::RecordBase::isModified() const
{
return mState==State_Modified || mState==State_ModifiedOnly;
}

@ -0,0 +1,104 @@
#ifndef CSM_WOLRD_RECORD_H
#define CSM_WOLRD_RECORD_H
#include <stdexcept>
namespace CSMWorld
{
struct RecordBase
{
enum State
{
State_BaseOnly = 0, // defined in base only
State_Modified = 1, // exists in base, but has been modified
State_ModifiedOnly = 2, // newly created in modified
State_Deleted = 3, // exists in base, but has been deleted
State_Erased = 4 // does not exist at all (we mostly treat that the same way as deleted)
};
State mState;
virtual ~RecordBase();
virtual RecordBase *clone() const = 0;
bool isDeleted() const;
bool isErased() const;
bool isModified() const;
};
template <typename ESXRecordT>
struct Record : public RecordBase
{
ESXRecordT mBase;
ESXRecordT mModified;
virtual RecordBase *clone() const;
const ESXRecordT& get() const;
///< Throws an exception, if the record is deleted.
const ESXRecordT& getBase() const;
///< Throws an exception, if the record is deleted. Returns modified, if there is no base.
void setModified (const ESXRecordT& modified);
///< Throws an exception, if the record is deleted.
void merge();
///< Merge modified into base.
};
template <typename ESXRecordT>
RecordBase *Record<ESXRecordT>::clone() const
{
return new Record<ESXRecordT> (*this);
}
template <typename ESXRecordT>
const ESXRecordT& Record<ESXRecordT>::get() const
{
if (mState==State_Erased)
throw std::logic_error ("attempt to access a deleted record");
return mState==State_BaseOnly ? mBase : mModified;
}
template <typename ESXRecordT>
const ESXRecordT& Record<ESXRecordT>::getBase() const
{
if (mState==State_Erased)
throw std::logic_error ("attempt to access a deleted record");
return mState==State_ModifiedOnly ? mModified : mBase;
}
template <typename ESXRecordT>
void Record<ESXRecordT>::setModified (const ESXRecordT& modified)
{
if (mState==State_Erased)
throw std::logic_error ("attempt to modify a deleted record");
mModified = modified;
if (mState!=State_ModifiedOnly)
mState = mBase==mModified ? State_BaseOnly : State_Modified;
}
template <typename ESXRecordT>
void Record<ESXRecordT>::merge()
{
if (isModified())
{
mBase = mModified;
mState = State_BaseOnly;
}
else if (mState==State_Deleted)
{
mState = State_Erased;
}
}
}
#endif

@ -0,0 +1,237 @@
#include "universalid.hpp"
#include <ostream>
#include <stdexcept>
#include <sstream>
namespace
{
struct TypeData
{
CSMWorld::UniversalId::Class mClass;
CSMWorld::UniversalId::Type mType;
const char *mName;
};
static const TypeData sNoArg[] =
{
{ CSMWorld::UniversalId::Class_None, CSMWorld::UniversalId::Type_None, "empty" },
{ CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Globals, "Global Variables" },
{ CSMWorld::UniversalId::Class_None, CSMWorld::UniversalId::Type_None, 0 } // end marker
};
static const TypeData sIdArg[] =
{
{ CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Global, "Global Variable" },
{ CSMWorld::UniversalId::Class_None, CSMWorld::UniversalId::Type_None, 0 } // end marker
};
static const TypeData sIndexArg[] =
{
{ CSMWorld::UniversalId::Class_Transient, CSMWorld::UniversalId::Type_VerificationResults, "Verification Results" },
{ CSMWorld::UniversalId::Class_None, CSMWorld::UniversalId::Type_None, 0 } // end marker
};
}
CSMWorld::UniversalId::UniversalId (const std::string& universalId)
{
std::string::size_type index = universalId.find (':');
if (index==std::string::npos)
{
std::string type = universalId.substr (0, index);
if (index==std::string::npos)
{
for (int i=0; sNoArg[i].mName; ++i)
if (type==sNoArg[i].mName)
{
mArgumentType = ArgumentType_None;
mType = sNoArg[i].mType;
mClass = sNoArg[i].mClass;
return;
}
}
else
{
for (int i=0; sIdArg[i].mName; ++i)
if (type==sIdArg[i].mName)
{
mArgumentType = ArgumentType_Id;
mType = sIdArg[i].mType;
mClass = sIdArg[i].mClass;
mId = universalId.substr (0, index);
return;
}
for (int i=0; sIndexArg[i].mName; ++i)
if (type==sIndexArg[i].mName)
{
mArgumentType = ArgumentType_Index;
mType = sIndexArg[i].mType;
mClass = sIndexArg[i].mClass;
std::istringstream stream (universalId.substr (0, index));
if (stream >> mIndex)
return;
break;
}
}
}
throw std::runtime_error ("invalid UniversalId: " + universalId);
}
CSMWorld::UniversalId::UniversalId (Type type) : mArgumentType (ArgumentType_None), mType (type), mIndex (0)
{
for (int i=0; sNoArg[i].mName; ++i)
if (type==sNoArg[i].mType)
{
mClass = sNoArg[i].mClass;
return;
}
throw std::logic_error ("invalid argument-less UniversalId type");
}
CSMWorld::UniversalId::UniversalId (Type type, const std::string& id)
: mArgumentType (ArgumentType_Id), mType (type), mId (id), mIndex (0)
{
for (int i=0; sIdArg[i].mName; ++i)
if (type==sIdArg[i].mType)
{
mClass = sIdArg[i].mClass;
return;
}
throw std::logic_error ("invalid ID argument UniversalId type");
}
CSMWorld::UniversalId::UniversalId (Type type, int index)
: mArgumentType (ArgumentType_Index), mType (type), mIndex (index)
{
for (int i=0; sIndexArg[i].mName; ++i)
if (type==sIndexArg[i].mType)
{
mClass = sIndexArg[i].mClass;
return;
}
throw std::logic_error ("invalid index argument UniversalId type");
}
CSMWorld::UniversalId::Class CSMWorld::UniversalId::getClass() const
{
return mClass;
}
CSMWorld::UniversalId::ArgumentType CSMWorld::UniversalId::getArgumentType() const
{
return mArgumentType;
}
CSMWorld::UniversalId::Type CSMWorld::UniversalId::getType() const
{
return mType;
}
const std::string& CSMWorld::UniversalId::getId() const
{
if (mArgumentType!=ArgumentType_Id)
throw std::logic_error ("invalid access to ID of non-ID UniversalId");
return mId;
}
int CSMWorld::UniversalId::getIndex() const
{
if (mArgumentType!=ArgumentType_Index)
throw std::logic_error ("invalid access to index of non-index UniversalId");
return mIndex;
}
bool CSMWorld::UniversalId::isEqual (const UniversalId& universalId) const
{
if (mClass!=universalId.mClass || mArgumentType!=universalId.mArgumentType || mType!=universalId.mType)
return false;
switch (mArgumentType)
{
case ArgumentType_Id: return mId==universalId.mId;
case ArgumentType_Index: return mIndex==universalId.mIndex;
default: return true;
}
}
bool CSMWorld::UniversalId::isLess (const UniversalId& universalId) const
{
if (mType<universalId.mType)
return true;
if (mType>universalId.mType)
return false;
switch (mArgumentType)
{
case ArgumentType_Id: return mId<universalId.mId;
case ArgumentType_Index: return mIndex<universalId.mIndex;
default: return false;
}
}
std::string CSMWorld::UniversalId::getTypeName() const
{
const TypeData *typeData = mArgumentType==ArgumentType_None ? sNoArg :
(mArgumentType==ArgumentType_Id ? sIdArg : sIndexArg);
for (int i=0; typeData[i].mName; ++i)
if (typeData[i].mType==mType)
return typeData[i].mName;
throw std::logic_error ("failed to retrieve UniversalId type name");
}
std::string CSMWorld::UniversalId::toString() const
{
std::ostringstream stream;
stream << getTypeName();
switch (mArgumentType)
{
case ArgumentType_None: break;
case ArgumentType_Id: stream << ": " << mId; break;
case ArgumentType_Index: stream << ": " << mIndex; break;
}
return stream.str();
}
bool CSMWorld::operator== (const CSMWorld::UniversalId& left, const CSMWorld::UniversalId& right)
{
return left.isEqual (right);
}
bool CSMWorld::operator!= (const CSMWorld::UniversalId& left, const CSMWorld::UniversalId& right)
{
return !left.isEqual (right);
}
bool CSMWorld::operator< (const UniversalId& left, const UniversalId& right)
{
return left.isLess (right);
}
std::ostream& CSMWorld::operator< (std::ostream& stream, const CSMWorld::UniversalId& universalId)
{
return stream << universalId.toString();
}

@ -0,0 +1,96 @@
#ifndef CSM_WOLRD_UNIVERSALID_H
#define CSM_WOLRD_UNIVERSALID_H
#include <string>
#include <iosfwd>
#include <QMetaType>
namespace CSMWorld
{
class UniversalId
{
public:
enum Class
{
Class_None = 0,
Class_Record,
Class_SubRecord,
Class_RecordList,
Class_Collection, // multiple types of records combined
Class_Transient, // not part of the world data or the project data
Class_NonRecord // record like data that is not part of the world
};
enum ArgumentType
{
ArgumentType_None,
ArgumentType_Id,
ArgumentType_Index
};
enum Type
{
Type_None,
Type_Globals,
Type_Global,
Type_VerificationResults
};
private:
Class mClass;
ArgumentType mArgumentType;
Type mType;
std::string mId;
int mIndex;
public:
UniversalId (const std::string& universalId);
UniversalId (Type type = Type_None);
///< Using a type for a non-argument-less UniversalId will throw an exception.
UniversalId (Type type, const std::string& id);
///< Using a type for a non-ID-argument UniversalId will throw an exception.
UniversalId (Type type, int index);
///< Using a type for a non-index-argument UniversalId will throw an exception.
Class getClass() const;
ArgumentType getArgumentType() const;
Type getType() const;
const std::string& getId() const;
///< Calling this function for a non-ID type will throw an exception.
int getIndex() const;
///< Calling this function for a non-index type will throw an exception.
bool isEqual (const UniversalId& universalId) const;
bool isLess (const UniversalId& universalId) const;
std::string getTypeName() const;
std::string toString() const;
};
bool operator== (const UniversalId& left, const UniversalId& right);
bool operator!= (const UniversalId& left, const UniversalId& right);
bool operator< (const UniversalId& left, const UniversalId& right);
std::ostream& operator< (std::ostream& stream, const UniversalId& universalId);
}
Q_DECLARE_METATYPE (CSMWorld::UniversalId)
#endif

@ -0,0 +1,54 @@
#include "operation.hpp"
#include <sstream>
#include "../../model/doc/document.hpp"
void CSVDoc::Operation::updateLabel (int threads)
{
if (threads==-1 || ((threads==0)!=mStalling))
{
std::string name ("unknown operation");
switch (mType)
{
case CSMDoc::State_Saving: name = "saving"; break;
case CSMDoc::State_Verifying: name = "verifying"; break;
}
std::ostringstream stream;
if ((mStalling = (threads<=0)))
{
stream << name << " (waiting for a free worker thread)";
}
else
{
stream << name << " (%p%)";
}
setFormat (stream.str().c_str());
}
}
CSVDoc::Operation::Operation (int type) : mType (type), mStalling (false)
{
/// \todo Add a cancel button or a pop up menu with a cancel item
updateLabel();
/// \todo assign different progress bar colours to allow the user to distinguish easily between operation types
}
void CSVDoc::Operation::setProgress (int current, int max, int threads)
{
updateLabel (threads);
setRange (0, max);
setValue (current);
}
int CSVDoc::Operation::getType() const
{
return mType;
}

@ -0,0 +1,31 @@
#ifndef CSV_DOC_OPERATION_H
#define CSV_DOC_OPERATION_H
#include <QProgressBar>
namespace CSVDoc
{
class Operation : public QProgressBar
{
Q_OBJECT
int mType;
bool mStalling;
// not implemented
Operation (const Operation&);
Operation& operator= (const Operation&);
void updateLabel (int threads = -1);
public:
Operation (int type);
void setProgress (int current, int max, int threads);
int getType() const;
};
}
#endif

@ -0,0 +1,47 @@
#include "operations.hpp"
#include <QVBoxLayout>
#include "operation.hpp"
CSVDoc::Operations::Operations()
{
/// \todo make widget height fixed (exactly the height required to display all operations)
setFeatures (QDockWidget::NoDockWidgetFeatures);
QWidget *widget = new QWidget;
setWidget (widget);
mLayout = new QVBoxLayout;
widget->setLayout (mLayout);
}
void CSVDoc::Operations::setProgress (int current, int max, int type, int threads)
{
for (std::vector<Operation *>::iterator iter (mOperations.begin()); iter!=mOperations.end(); ++iter)
if ((*iter)->getType()==type)
{
(*iter)->setProgress (current, max, threads);
return;
}
Operation *operation = new Operation (type);
mLayout->addWidget (operation);
mOperations.push_back (operation);
operation->setProgress (current, max, threads);
}
void CSVDoc::Operations::quitOperation (int type)
{
for (std::vector<Operation *>::iterator iter (mOperations.begin()); iter!=mOperations.end(); ++iter)
if ((*iter)->getType()==type)
{
delete *iter;
mOperations.erase (iter);
break;
}
}

@ -0,0 +1,37 @@
#ifndef CSV_DOC_OPERATIONS_H
#define CSV_DOC_OPERATIONS_H
#include <vector>
#include <QDockWidget>
class QVBoxLayout;
namespace CSVDoc
{
class Operation;
class Operations : public QDockWidget
{
Q_OBJECT
QVBoxLayout *mLayout;
std::vector<Operation *> mOperations;
// not implemented
Operations (const Operations&);
Operations& operator= (const Operations&);
public:
Operations();
void setProgress (int current, int max, int type, int threads);
///< Implicitly starts the operation, if it is not running already.
void quitOperation (int type);
///< Calling this function for an operation that is not running is a no-op.
};
}
#endif

@ -0,0 +1,18 @@
#include "subview.hpp"
CSVDoc::SubView::SubView (const CSMWorld::UniversalId& id) : mUniversalId (id)
{
/// \todo add a button to the title bar that clones this sub view
setWindowTitle (mUniversalId.toString().c_str());
/// \todo remove (for testing only)
setMinimumWidth (100);
setMinimumHeight (60);
}
CSMWorld::UniversalId CSVDoc::SubView::getUniversalId() const
{
return mUniversalId;
}

@ -0,0 +1,45 @@
#ifndef CSV_DOC_SUBVIEW_H
#define CSV_DOC_SUBVIEW_H
#include "../../model/doc/document.hpp"
#include "../../model/world/universalid.hpp"
#include "subviewfactory.hpp"
#include <QDockWidget>
class QUndoStack;
namespace CSMWorld
{
class Data;
}
namespace CSVDoc
{
class SubView : public QDockWidget
{
Q_OBJECT
CSMWorld::UniversalId mUniversalId;
// not implemented
SubView (const SubView&);
SubView& operator= (SubView&);
public:
SubView (const CSMWorld::UniversalId& id);
CSMWorld::UniversalId getUniversalId() const;
virtual void setEditLock (bool locked) = 0;
signals:
void focusId (const CSMWorld::UniversalId& universalId);
};
}
#endif

@ -0,0 +1,38 @@
#include "subviewfactory.hpp"
#include <cassert>
#include <stdexcept>
CSVDoc::SubViewFactoryBase::SubViewFactoryBase() {}
CSVDoc::SubViewFactoryBase::~SubViewFactoryBase() {}
CSVDoc::SubViewFactoryManager::SubViewFactoryManager() {}
CSVDoc::SubViewFactoryManager::~SubViewFactoryManager()
{
for (std::map<CSMWorld::UniversalId::Type, SubViewFactoryBase *>::iterator iter (mSubViewFactories.begin());
iter!=mSubViewFactories.end(); ++iter)
delete iter->second;
}
void CSVDoc::SubViewFactoryManager::add (const CSMWorld::UniversalId::Type& id, SubViewFactoryBase *factory)
{
assert (mSubViewFactories.find (id)==mSubViewFactories.end());
mSubViewFactories.insert (std::make_pair (id, factory));
}
CSVDoc::SubView *CSVDoc::SubViewFactoryManager::makeSubView (const CSMWorld::UniversalId& id,
CSMDoc::Document& document)
{
std::map<CSMWorld::UniversalId::Type, SubViewFactoryBase *>::iterator iter = mSubViewFactories.find (id.getType());
if (iter==mSubViewFactories.end())
throw std::runtime_error ("Failed to create a sub view for: " + id.toString());
return iter->second->makeSubView (id, document);
}

@ -0,0 +1,55 @@
#ifndef CSV_DOC_SUBVIEWFACTORY_H
#define CSV_DOC_SUBVIEWFACTORY_H
#include <map>
#include "../../model/world/universalid.hpp"
namespace CSMDoc
{
class Document;
}
namespace CSVDoc
{
class SubView;
class SubViewFactoryBase
{
// not implemented
SubViewFactoryBase (const SubViewFactoryBase&);
SubViewFactoryBase& operator= (const SubViewFactoryBase&);
public:
SubViewFactoryBase();
virtual ~SubViewFactoryBase();
virtual SubView *makeSubView (const CSMWorld::UniversalId& id, CSMDoc::Document& document) = 0;
///< The ownership of the returned sub view is not transferred.
};
class SubViewFactoryManager
{
std::map<CSMWorld::UniversalId::Type, SubViewFactoryBase *> mSubViewFactories;
// not implemented
SubViewFactoryManager (const SubViewFactoryManager&);
SubViewFactoryManager& operator= (const SubViewFactoryManager&);
public:
SubViewFactoryManager();
~SubViewFactoryManager();
void add (const CSMWorld::UniversalId::Type& id, SubViewFactoryBase *factory);
///< The ownership of \a factory is transferred to this.
SubView *makeSubView (const CSMWorld::UniversalId& id, CSMDoc::Document& document);
///< The ownership of the returned sub view is not transferred.
};
}
#endif

@ -0,0 +1,50 @@
#ifndef CSV_DOC_SUBVIEWFACTORYIMP_H
#define CSV_DOC_SUBVIEWFACTORYIMP_H
#include "../../model/doc/document.hpp"
#include "subviewfactory.hpp"
namespace CSVDoc
{
template<class SubViewT>
class SubViewFactory : public SubViewFactoryBase
{
public:
virtual CSVDoc::SubView *makeSubView (const CSMWorld::UniversalId& id, CSMDoc::Document& document);
};
template<class SubViewT>
CSVDoc::SubView *SubViewFactory<SubViewT>::makeSubView (const CSMWorld::UniversalId& id,
CSMDoc::Document& document)
{
return new SubViewT (id, document);
}
template<class SubViewT>
class SubViewFactoryWithCreateFlag : public SubViewFactoryBase
{
bool mCreateAndDelete;
public:
SubViewFactoryWithCreateFlag (bool createAndDelete);
virtual CSVDoc::SubView *makeSubView (const CSMWorld::UniversalId& id, CSMDoc::Document& document);
};
template<class SubViewT>
SubViewFactoryWithCreateFlag<SubViewT>::SubViewFactoryWithCreateFlag (bool createAndDelete)
: mCreateAndDelete (createAndDelete)
{}
template<class SubViewT>
CSVDoc::SubView *SubViewFactoryWithCreateFlag<SubViewT>::makeSubView (const CSMWorld::UniversalId& id,
CSMDoc::Document& document)
{
return new SubViewT (id, document, mCreateAndDelete);
}
}
#endif

@ -0,0 +1,216 @@
#include "view.hpp"
#include <sstream>
#include <stdexcept>
#include <QCloseEvent>
#include <QMenuBar>
#include <QMdiArea>
#include "../../model/doc/document.hpp"
#include "../world/subviews.hpp"
#include "../tools/subviews.hpp"
#include "viewmanager.hpp"
#include "operations.hpp"
#include "subview.hpp"
void CSVDoc::View::closeEvent (QCloseEvent *event)
{
if (!mViewManager.closeRequest (this))
event->ignore();
}
void CSVDoc::View::setupFileMenu()
{
QMenu *file = menuBar()->addMenu (tr ("&File"));
QAction *new_ = new QAction (tr ("New"), this);
connect (new_, SIGNAL (triggered()), this, SIGNAL (newDocumentRequest()));
file->addAction (new_);
mSave = new QAction (tr ("&Save"), this);
connect (mSave, SIGNAL (triggered()), this, SLOT (save()));
file->addAction (mSave);
}
void CSVDoc::View::setupEditMenu()
{
QMenu *edit = menuBar()->addMenu (tr ("&Edit"));
mUndo = mDocument->getUndoStack().createUndoAction (this, tr("&Undo"));
mUndo->setShortcuts (QKeySequence::Undo);
edit->addAction (mUndo);
mRedo= mDocument->getUndoStack().createRedoAction (this, tr("&Redo"));
mRedo->setShortcuts (QKeySequence::Redo);
edit->addAction (mRedo);
}
void CSVDoc::View::setupViewMenu()
{
QMenu *view = menuBar()->addMenu (tr ("&View"));
QAction *newWindow = new QAction (tr ("&New View"), this);
connect (newWindow, SIGNAL (triggered()), this, SLOT (newView()));
view->addAction (newWindow);
}
void CSVDoc::View::setupWorldMenu()
{
QMenu *world = menuBar()->addMenu (tr ("&World"));
QAction *globals = new QAction (tr ("Globals"), this);
connect (globals, SIGNAL (triggered()), this, SLOT (addGlobalsSubView()));
world->addAction (globals);
mVerify = new QAction (tr ("&Verify"), this);
connect (mVerify, SIGNAL (triggered()), this, SLOT (verify()));
world->addAction (mVerify);
}
void CSVDoc::View::setupUi()
{
setupFileMenu();
setupEditMenu();
setupViewMenu();
setupWorldMenu();
}
void CSVDoc::View::updateTitle()
{
std::ostringstream stream;
stream << mDocument->getName();
if (mDocument->getState() & CSMDoc::State_Modified)
stream << " *";
if (mViewTotal>1)
stream << " [" << (mViewIndex+1) << "/" << mViewTotal << "]";
setWindowTitle (stream.str().c_str());
}
void CSVDoc::View::updateActions()
{
bool editing = !(mDocument->getState() & CSMDoc::State_Locked);
for (std::vector<QAction *>::iterator iter (mEditingActions.begin()); iter!=mEditingActions.end(); ++iter)
(*iter)->setEnabled (editing);
mUndo->setEnabled (editing & mDocument->getUndoStack().canUndo());
mRedo->setEnabled (editing & mDocument->getUndoStack().canRedo());
mSave->setEnabled (!(mDocument->getState() & CSMDoc::State_Saving));
mVerify->setEnabled (!(mDocument->getState() & CSMDoc::State_Verifying));
}
CSVDoc::View::View (ViewManager& viewManager, CSMDoc::Document *document, int totalViews)
: mViewManager (viewManager), mDocument (document), mViewIndex (totalViews-1), mViewTotal (totalViews)
{
setDockOptions (QMainWindow::AllowNestedDocks);
resize (300, 300); /// \todo get default size from settings and set reasonable minimal size
mOperations = new Operations;
addDockWidget (Qt::BottomDockWidgetArea, mOperations);
updateTitle();
setupUi();
CSVWorld::addSubViewFactories (mSubViewFactory);
CSVTools::addSubViewFactories (mSubViewFactory);
}
CSVDoc::View::~View()
{
}
const CSMDoc::Document *CSVDoc::View::getDocument() const
{
return mDocument;
}
CSMDoc::Document *CSVDoc::View::getDocument()
{
return mDocument;
}
void CSVDoc::View::setIndex (int viewIndex, int totalViews)
{
mViewIndex = viewIndex;
mViewTotal = totalViews;
updateTitle();
}
void CSVDoc::View::updateDocumentState()
{
updateTitle();
updateActions();
static const int operations[] =
{
CSMDoc::State_Saving, CSMDoc::State_Verifying,
-1 // end marker
};
int state = mDocument->getState() ;
for (int i=0; operations[i]!=-1; ++i)
if (!(state & operations[i]))
mOperations->quitOperation (operations[i]);
QList<CSVDoc::SubView *> subViews = findChildren<CSVDoc::SubView *>();
for (QList<CSVDoc::SubView *>::iterator iter (subViews.begin()); iter!=subViews.end(); ++iter)
(*iter)->setEditLock (state & CSMDoc::State_Locked);
}
void CSVDoc::View::updateProgress (int current, int max, int type, int threads)
{
mOperations->setProgress (current, max, type, threads);
}
void CSVDoc::View::addSubView (const CSMWorld::UniversalId& id)
{
/// \todo add an user setting for limiting the number of sub views per top level view. Automatically open a new top level view if this
/// number is exceeded
/// \todo if the sub view limit setting is one, the sub view title bar should be hidden and the text in the main title bar adjusted
/// accordingly
/// \todo add an user setting to reuse sub views (on a per document basis or on a per top level view basis)
SubView *view = mSubViewFactory.makeSubView (id, *mDocument);
addDockWidget (Qt::TopDockWidgetArea, view);
connect (view, SIGNAL (focusId (const CSMWorld::UniversalId&)), this,
SLOT (addSubView (const CSMWorld::UniversalId&)));
view->show();
}
void CSVDoc::View::newView()
{
mViewManager.addView (mDocument);
}
void CSVDoc::View::save()
{
mDocument->save();
}
void CSVDoc::View::verify()
{
addSubView (mDocument->verify());
}
void CSVDoc::View::addGlobalsSubView()
{
addSubView (CSMWorld::UniversalId::Type_Globals);
}

@ -0,0 +1,103 @@
#ifndef CSV_DOC_VIEW_H
#define CSV_DOC_VIEW_H
#include <vector>
#include <map>
#include <QMainWindow>
#include "subviewfactory.hpp"
class QAction;
namespace CSMDoc
{
class Document;
}
namespace CSMWorld
{
class UniversalId;
}
namespace CSVDoc
{
class ViewManager;
class Operations;
class View : public QMainWindow
{
Q_OBJECT
ViewManager& mViewManager;
CSMDoc::Document *mDocument;
int mViewIndex;
int mViewTotal;
QAction *mUndo;
QAction *mRedo;
QAction *mSave;
QAction *mVerify;
std::vector<QAction *> mEditingActions;
Operations *mOperations;
SubViewFactoryManager mSubViewFactory;
// not implemented
View (const View&);
View& operator= (const View&);
private:
void closeEvent (QCloseEvent *event);
void setupFileMenu();
void setupEditMenu();
void setupViewMenu();
void setupWorldMenu();
void setupUi();
void updateTitle();
void updateActions();
public:
View (ViewManager& viewManager, CSMDoc::Document *document, int totalViews);
///< The ownership of \a document is not transferred to *this.
virtual ~View();
const CSMDoc::Document *getDocument() const;
CSMDoc::Document *getDocument();
void setIndex (int viewIndex, int totalViews);
void updateDocumentState();
void updateProgress (int current, int max, int type, int threads);
signals:
void newDocumentRequest();
public slots:
void addSubView (const CSMWorld::UniversalId& id);
private slots:
void newView();
void save();
void verify();
void addGlobalsSubView();
};
}
#endif

@ -0,0 +1,112 @@
#include "viewmanager.hpp"
#include <map>
#include "../../model/doc/documentmanager.hpp"
#include "../../model/doc/document.hpp"
#include "view.hpp"
void CSVDoc::ViewManager::updateIndices()
{
std::map<CSMDoc::Document *, std::pair<int, int> > documents;
for (std::vector<View *>::const_iterator iter (mViews.begin()); iter!=mViews.end(); ++iter)
{
std::map<CSMDoc::Document *, std::pair<int, int> >::iterator document = documents.find ((*iter)->getDocument());
if (document==documents.end())
document =
documents.insert (
std::make_pair ((*iter)->getDocument(), std::make_pair (0, countViews ((*iter)->getDocument())))).
first;
(*iter)->setIndex (document->second.first++, document->second.second);
}
}
CSVDoc::ViewManager::ViewManager (CSMDoc::DocumentManager& documentManager)
: mDocumentManager (documentManager)
{
}
CSVDoc::ViewManager::~ViewManager()
{
for (std::vector<View *>::iterator iter (mViews.begin()); iter!=mViews.end(); ++iter)
delete *iter;
}
CSVDoc::View *CSVDoc::ViewManager::addView (CSMDoc::Document *document)
{
if (countViews (document)==0)
{
// new document
connect (document, SIGNAL (stateChanged (int, CSMDoc::Document *)),
this, SLOT (documentStateChanged (int, CSMDoc::Document *)));
connect (document, SIGNAL (progress (int, int, int, int, CSMDoc::Document *)),
this, SLOT (progress (int, int, int, int, CSMDoc::Document *)));
}
View *view = new View (*this, document, countViews (document)+1);
mViews.push_back (view);
view->show();
connect (view, SIGNAL (newDocumentRequest ()), this, SIGNAL (newDocumentRequest()));
updateIndices();
return view;
}
int CSVDoc::ViewManager::countViews (const CSMDoc::Document *document) const
{
int count = 0;
for (std::vector<View *>::const_iterator iter (mViews.begin()); iter!=mViews.end(); ++iter)
if ((*iter)->getDocument()==document)
++count;
return count;
}
bool CSVDoc::ViewManager::closeRequest (View *view)
{
std::vector<View *>::iterator iter = std::find (mViews.begin(), mViews.end(), view);
if (iter!=mViews.end())
{
bool last = countViews (view->getDocument())<=1;
/// \todo check if save is in progress -> warn user about possible data loss
/// \todo check if document has not been saved -> return false and start close dialogue
mViews.erase (iter);
view->deleteLater();
if (last)
mDocumentManager.removeDocument (view->getDocument());
else
updateIndices();
}
return true;
}
void CSVDoc::ViewManager::documentStateChanged (int state, CSMDoc::Document *document)
{
for (std::vector<View *>::const_iterator iter (mViews.begin()); iter!=mViews.end(); ++iter)
if ((*iter)->getDocument()==document)
(*iter)->updateDocumentState();
}
void CSVDoc::ViewManager::progress (int current, int max, int type, int threads, CSMDoc::Document *document)
{
for (std::vector<View *>::const_iterator iter (mViews.begin()); iter!=mViews.end(); ++iter)
if ((*iter)->getDocument()==document)
(*iter)->updateProgress (current, max, type, threads);
}

@ -0,0 +1,58 @@
#ifndef CSV_DOC_VIEWMANAGER_H
#define CSV_DOC_VIEWMANAGER_H
#include <vector>
#include <QObject>
namespace CSMDoc
{
class Document;
class DocumentManager;
}
namespace CSVDoc
{
class View;
class ViewManager : public QObject
{
Q_OBJECT
CSMDoc::DocumentManager& mDocumentManager;
std::vector<View *> mViews;
// not implemented
ViewManager (const ViewManager&);
ViewManager& operator= (const ViewManager&);
void updateIndices();
public:
ViewManager (CSMDoc::DocumentManager& documentManager);
virtual ~ViewManager();
View *addView (CSMDoc::Document *document);
///< The ownership of the returned view is not transferred.
int countViews (const CSMDoc::Document *document) const;
///< Return number of views for \a document.
bool closeRequest (View *view);
signals:
void newDocumentRequest();
private slots:
void documentStateChanged (int state, CSMDoc::Document *document);
void progress (int current, int max, int type, int threads, CSMDoc::Document *document);
};
}
#endif

@ -0,0 +1,32 @@
#include "reportsubview.hpp"
#include <QTableView>
#include <QHeaderView>
#include "../../model/tools/reportmodel.hpp"
CSVTools::ReportSubView::ReportSubView (const CSMWorld::UniversalId& id, CSMDoc::Document& document)
: CSVDoc::SubView (id), mModel (document.getReport (id))
{
setWidget (mTable = new QTableView (this));
mTable->setModel (mModel);
mTable->horizontalHeader()->setResizeMode (QHeaderView::Interactive);
mTable->verticalHeader()->hide();
mTable->setSortingEnabled (true);
mTable->setSelectionBehavior (QAbstractItemView::SelectRows);
mTable->setSelectionMode (QAbstractItemView::ExtendedSelection);
connect (mTable, SIGNAL (doubleClicked (const QModelIndex&)), this, SLOT (show (const QModelIndex&)));
}
void CSVTools::ReportSubView::setEditLock (bool locked)
{
// ignored. We don't change document state anyway.
}
void CSVTools::ReportSubView::show (const QModelIndex& index)
{
focusId (mModel->getUniversalId (index.row()));
}

@ -0,0 +1,42 @@
#ifndef CSV_TOOLS_REPORTSUBVIEW_H
#define CSV_TOOLS_REPORTSUBVIEW_H
#include "../doc/subview.hpp"
class QTableView;
class QModelIndex;
namespace CSMDoc
{
class Document;
}
namespace CSMTools
{
class ReportModel;
}
namespace CSVTools
{
class Table;
class ReportSubView : public CSVDoc::SubView
{
Q_OBJECT
CSMTools::ReportModel *mModel;
QTableView *mTable;
public:
ReportSubView (const CSMWorld::UniversalId& id, CSMDoc::Document& document);
virtual void setEditLock (bool locked);
private slots:
void show (const QModelIndex& index);
};
}
#endif

@ -0,0 +1,12 @@
#include "subviews.hpp"
#include "../doc/subviewfactoryimp.hpp"
#include "reportsubview.hpp"
void CSVTools::addSubViewFactories (CSVDoc::SubViewFactoryManager& manager)
{
manager.add (CSMWorld::UniversalId::Type_VerificationResults,
new CSVDoc::SubViewFactory<ReportSubView>);
}

@ -0,0 +1,14 @@
#ifndef CSV_TOOLS_SUBVIEWS_H
#define CSV_TOOLS_SUBVIEWS_H
namespace CSVDoc
{
class SubViewFactoryManager;
}
namespace CSVTools
{
void addSubViewFactories (CSVDoc::SubViewFactoryManager& manager);
}
#endif

@ -0,0 +1,40 @@
#include "dialoguesubview.hpp"
#include <QGridLayout>
#include <QLabel>
#include <QAbstractTableModel>
#include "../../model/world/columnbase.hpp"
CSVWorld::DialogueSubView::DialogueSubView (const CSMWorld::UniversalId& id, CSMDoc::Document& document,
bool createAndDelete)
: SubView (id)
{
QWidget *widget = new QWidget (this);
setWidget (widget);
QGridLayout *layout = new QGridLayout;
widget->setLayout (layout);
QAbstractTableModel *model = document.getData().getTableModel (id);
int columns = model->columnCount();
for (int i=0; i<columns; ++i)
{
int flags = model->headerData (i, Qt::Horizontal, CSMWorld::ColumnBase::Role_Flags).toInt();
if (flags & CSMWorld::ColumnBase::Flag_Dialogue)
{
layout->addWidget (new QLabel (model->headerData (i, Qt::Horizontal).toString()), i, 0);
}
}
}
void CSVWorld::DialogueSubView::setEditLock (bool locked)
{
}

@ -0,0 +1,24 @@
#ifndef CSV_WORLD_DIALOGUESUBVIEW_H
#define CSV_WORLD_DIALOGUESUBVIEW_H
#include "../doc/subview.hpp"
namespace CSMDoc
{
class Document;
}
namespace CSVWorld
{
class DialogueSubView : public CSVDoc::SubView
{
public:
DialogueSubView (const CSMWorld::UniversalId& id, CSMDoc::Document& document, bool createAndDelete);
virtual void setEditLock (bool locked);
};
}
#endif

@ -0,0 +1,16 @@
#include "subviews.hpp"
#include "../doc/subviewfactoryimp.hpp"
#include "tablesubview.hpp"
#include "dialoguesubview.hpp"
void CSVWorld::addSubViewFactories (CSVDoc::SubViewFactoryManager& manager)
{
manager.add (CSMWorld::UniversalId::Type_Globals,
new CSVDoc::SubViewFactoryWithCreateFlag<TableSubView> (true));
manager.add (CSMWorld::UniversalId::Type_Global,
new CSVDoc::SubViewFactoryWithCreateFlag<DialogueSubView> (true));
}

@ -0,0 +1,14 @@
#ifndef CSV_WORLD_SUBVIEWS_H
#define CSV_WORLD_SUBVIEWS_H
namespace CSVDoc
{
class SubViewFactoryManager;
}
namespace CSVWorld
{
void addSubViewFactories (CSVDoc::SubViewFactoryManager& manager);
}
#endif

@ -0,0 +1,199 @@
#include "table.hpp"
#include <QHeaderView>
#include <QAction>
#include <QMenu>
#include <QContextMenuEvent>
#include "../../model/world/data.hpp"
#include "../../model/world/commands.hpp"
#include "../../model/world/idtableproxymodel.hpp"
#include "../../model/world/idtable.hpp"
#include "../../model/world/record.hpp"
#include "util.hpp"
void CSVWorld::Table::contextMenuEvent (QContextMenuEvent *event)
{
QModelIndexList selectedRows = selectionModel()->selectedRows();
QMenu menu (this);
/// \todo add menu items for select all and clear selection
if (!mEditLock)
{
if (mCreateAction)
menu.addAction (mCreateAction);
if (listRevertableSelectedIds().size()>0)
menu.addAction (mRevertAction);
if (listDeletableSelectedIds().size()>0)
menu.addAction (mDeleteAction);
}
menu.exec (event->globalPos());
}
std::vector<std::string> CSVWorld::Table::listRevertableSelectedIds() const
{
QModelIndexList selectedRows = selectionModel()->selectedRows();
std::vector<std::string> revertableIds;
for (QModelIndexList::const_iterator iter (selectedRows.begin()); iter!=selectedRows.end(); ++iter)
{
std::string id = mProxyModel->data (*iter).toString().toStdString();
CSMWorld::RecordBase::State state =
static_cast<CSMWorld::RecordBase::State> (mModel->data (mModel->getModelIndex (id, 1)).toInt());
if (state!=CSMWorld::RecordBase::State_BaseOnly)
revertableIds.push_back (id);
}
return revertableIds;
}
std::vector<std::string> CSVWorld::Table::listDeletableSelectedIds() const
{
QModelIndexList selectedRows = selectionModel()->selectedRows();
std::vector<std::string> deletableIds;
for (QModelIndexList::const_iterator iter (selectedRows.begin()); iter!=selectedRows.end(); ++iter)
{
std::string id = mProxyModel->data (*iter).toString().toStdString();
CSMWorld::RecordBase::State state =
static_cast<CSMWorld::RecordBase::State> (mModel->data (mModel->getModelIndex (id, 1)).toInt());
if (state!=CSMWorld::RecordBase::State_Deleted)
deletableIds.push_back (id);
}
return deletableIds;
}
CSVWorld::Table::Table (const CSMWorld::UniversalId& id, CSMWorld::Data& data, QUndoStack& undoStack,
bool createAndDelete)
: mUndoStack (undoStack), mCreateAction (0), mEditLock (false)
{
mModel = &dynamic_cast<CSMWorld::IdTable&> (*data.getTableModel (id));
mProxyModel = new CSMWorld::IdTableProxyModel (this);
mProxyModel->setSourceModel (mModel);
setModel (mProxyModel);
horizontalHeader()->setResizeMode (QHeaderView::Interactive);
verticalHeader()->hide();
setSortingEnabled (true);
setSelectionBehavior (QAbstractItemView::SelectRows);
setSelectionMode (QAbstractItemView::ExtendedSelection);
int columns = mModel->columnCount();
for (int i=0; i<columns; ++i)
{
int flags = mModel->headerData (i, Qt::Horizontal, CSMWorld::ColumnBase::Role_Flags).toInt();
if (flags & CSMWorld::ColumnBase::Flag_Table)
{
CommandDelegate *delegate = new CommandDelegate (undoStack, this);
mDelegates.push_back (delegate);
setItemDelegateForColumn (i, delegate);
}
else
hideColumn (i);
}
/// \todo make initial layout fill the whole width of the table
if (createAndDelete)
{
mCreateAction = new QAction (tr ("Add Record"), this);
connect (mCreateAction, SIGNAL (triggered()), this, SLOT (createRecord()));
addAction (mCreateAction);
}
mRevertAction = new QAction (tr ("Revert Record"), this);
connect (mRevertAction, SIGNAL (triggered()), this, SLOT (revertRecord()));
addAction (mRevertAction);
mDeleteAction = new QAction (tr ("Delete Record"), this);
connect (mDeleteAction, SIGNAL (triggered()), this, SLOT (deleteRecord()));
addAction (mDeleteAction);
}
void CSVWorld::Table::setEditLock (bool locked)
{
for (std::vector<CommandDelegate *>::iterator iter (mDelegates.begin()); iter!=mDelegates.end(); ++iter)
(*iter)->setEditLock (locked);
mEditLock = locked;
}
CSMWorld::UniversalId CSVWorld::Table::getUniversalId (int row) const
{
return CSMWorld::UniversalId (
static_cast<CSMWorld::UniversalId::Type> (mProxyModel->data (mProxyModel->index (row, 2)).toInt()),
mProxyModel->data (mProxyModel->index (row, 0)).toString().toStdString());
}
#include <sstream> /// \todo remove
void CSVWorld::Table::createRecord()
{
if (!mEditLock)
{
/// \todo ask the user for an ID instead.
static int index = 0;
std::ostringstream stream;
stream << "id" << index++;
mUndoStack.push (new CSMWorld::CreateCommand (*mProxyModel, stream.str()));
}
}
void CSVWorld::Table::revertRecord()
{
if (!mEditLock)
{
std::vector<std::string> revertableIds = listRevertableSelectedIds();
if (revertableIds.size()>0)
{
if (revertableIds.size()>1)
mUndoStack.beginMacro (tr ("Revert multiple records"));
for (std::vector<std::string>::const_iterator iter (revertableIds.begin()); iter!=revertableIds.end(); ++iter)
mUndoStack.push (new CSMWorld::RevertCommand (*mModel, *iter));
if (revertableIds.size()>1)
mUndoStack.endMacro();
}
}
}
void CSVWorld::Table::deleteRecord()
{
if (!mEditLock)
{
std::vector<std::string> deletableIds = listDeletableSelectedIds();
if (deletableIds.size()>0)
{
if (deletableIds.size()>1)
mUndoStack.beginMacro (tr ("Delete multiple records"));
for (std::vector<std::string>::const_iterator iter (deletableIds.begin()); iter!=deletableIds.end(); ++iter)
mUndoStack.push (new CSMWorld::DeleteCommand (*mModel, *iter));
if (deletableIds.size()>1)
mUndoStack.endMacro();
}
}
}

@ -0,0 +1,65 @@
#ifndef CSV_WORLD_TABLE_H
#define CSV_WORLD_TABLE_H
#include <vector>
#include <string>
#include <QTableView>
class QUndoStack;
class QAction;
namespace CSMWorld
{
class Data;
class UniversalId;
class IdTableProxyModel;
class IdTable;
}
namespace CSVWorld
{
class CommandDelegate;
///< Table widget
class Table : public QTableView
{
Q_OBJECT
std::vector<CommandDelegate *> mDelegates;
QUndoStack& mUndoStack;
QAction *mCreateAction;
QAction *mRevertAction;
QAction *mDeleteAction;
CSMWorld::IdTableProxyModel *mProxyModel;
CSMWorld::IdTable *mModel;
bool mEditLock;
private:
void contextMenuEvent (QContextMenuEvent *event);
std::vector<std::string> listRevertableSelectedIds() const;
std::vector<std::string> listDeletableSelectedIds() const;
public:
Table (const CSMWorld::UniversalId& id, CSMWorld::Data& data, QUndoStack& undoStack, bool createAndDelete);
///< \param createAndDelete Allow creation and deletion of records.
void setEditLock (bool locked);
CSMWorld::UniversalId getUniversalId (int row) const;
private slots:
void createRecord();
void revertRecord();
void deleteRecord();
};
}
#endif

@ -0,0 +1,25 @@
#include "tablesubview.hpp"
#include "../../model/doc/document.hpp"
#include "table.hpp"
CSVWorld::TableSubView::TableSubView (const CSMWorld::UniversalId& id, CSMDoc::Document& document,
bool createAndDelete)
: SubView (id)
{
setWidget (mTable = new Table (id, document.getData(), document.getUndoStack(), createAndDelete));
connect (mTable, SIGNAL (doubleClicked (const QModelIndex&)), this, SLOT (rowActivated (const QModelIndex&)));
}
void CSVWorld::TableSubView::setEditLock (bool locked)
{
mTable->setEditLock (locked);
}
void CSVWorld::TableSubView::rowActivated (const QModelIndex& index)
{
focusId (mTable->getUniversalId (index.row()));
}

@ -0,0 +1,35 @@
#ifndef CSV_WORLD_TABLESUBVIEW_H
#define CSV_WORLD_TABLESUBVIEW_H
#include "../doc/subview.hpp"
class QModelIndex;
namespace CSMDoc
{
class Document;
}
namespace CSVWorld
{
class Table;
class TableSubView : public CSVDoc::SubView
{
Q_OBJECT
Table *mTable;
public:
TableSubView (const CSMWorld::UniversalId& id, CSMDoc::Document& document, bool createAndDelete);
virtual void setEditLock (bool locked);
private slots:
void rowActivated (const QModelIndex& index);
};
}
#endif

@ -0,0 +1,57 @@
#include "util.hpp"
#include <QUndoStack>
#include "../../model/world/commands.hpp"
CSVWorld::NastyTableModelHack::NastyTableModelHack (QAbstractItemModel& model)
: mModel (model)
{}
int CSVWorld::NastyTableModelHack::rowCount (const QModelIndex & parent) const
{
return mModel.rowCount (parent);
}
int CSVWorld::NastyTableModelHack::columnCount (const QModelIndex & parent) const
{
return mModel.columnCount (parent);
}
QVariant CSVWorld::NastyTableModelHack::data (const QModelIndex & index, int role) const
{
return mModel.data (index, role);
}
bool CSVWorld::NastyTableModelHack::setData ( const QModelIndex &index, const QVariant &value, int role)
{
mData = value;
return true;
}
QVariant CSVWorld::NastyTableModelHack::getData() const
{
return mData;
}
CSVWorld::CommandDelegate::CommandDelegate (QUndoStack& undoStack, QObject *parent)
: QStyledItemDelegate (parent), mUndoStack (undoStack), mEditLock (false)
{}
void CSVWorld::CommandDelegate::setModelData (QWidget *editor, QAbstractItemModel *model,
const QModelIndex& index) const
{
if (!mEditLock)
{
NastyTableModelHack hack (*model);
QStyledItemDelegate::setModelData (editor, &hack, index);
mUndoStack.push (new CSMWorld::ModifyCommand (*model, index, hack.getData()));
}
///< \todo provide some kind of feedback to the user, indicating that editing is currently not possible.
}
void CSVWorld::CommandDelegate::setEditLock (bool locked)
{
mEditLock = locked;
}

@ -0,0 +1,50 @@
#ifndef CSV_WORLD_UTIL_H
#define CSV_WORLD_UTIL_H
#include <QAbstractTableModel>
#include <QStyledItemDelegate>
class QUndoStack;
namespace CSVWorld
{
///< \brief Getting the data out of an editor widget
///
/// Really, Qt? Really?
class NastyTableModelHack : public QAbstractTableModel
{
QAbstractItemModel& mModel;
QVariant mData;
public:
NastyTableModelHack (QAbstractItemModel& model);
int rowCount (const QModelIndex & parent = QModelIndex()) const;
int columnCount (const QModelIndex & parent = QModelIndex()) const;
QVariant data (const QModelIndex & index, int role = Qt::DisplayRole) const;
bool setData (const QModelIndex &index, const QVariant &value, int role = Qt::EditRole);
QVariant getData() const;
};
///< \brief Use commands instead of manipulating the model directly
class CommandDelegate : public QStyledItemDelegate
{
QUndoStack& mUndoStack;
bool mEditLock;
public:
CommandDelegate (QUndoStack& undoStack, QObject *parent);
void setModelData (QWidget *editor, QAbstractItemModel *model, const QModelIndex& index) const;
void setEditLock (bool locked);
};
}
#endif

@ -30,7 +30,7 @@ add_openmw_dir (mwgui
formatting inventorywindow container hud countdialog tradewindow settingswindow
confirmationdialog alchemywindow referenceinterface spellwindow mainmenu quickkeysmenu
itemselection spellbuyingwindow loadingscreen levelupdialog waitdialog spellcreationdialog
enchantingdialog trainingwindow travelwindow
enchantingdialog trainingwindow travelwindow imagebutton
)
add_openmw_dir (mwdialogue

@ -8,6 +8,7 @@
#include <components/bsa/bsa_archive.hpp>
#include <components/files/configurationmanager.hpp>
#include <components/translation/translation.hpp>
#include <components/nifoverrides/nifoverrides.hpp>
#include <components/nifbullet/bullet_nif_loader.hpp>
@ -330,16 +331,23 @@ void OMW::Engine::go()
// cursor replacer (converts the cursor from the bsa so they can be used by mygui)
MWGui::CursorReplace replacer;
// Create encoder
ToUTF8::Utf8Encoder encoder (mEncoding);
// Create the world
mEnvironment.setWorld (new MWWorld::World (*mOgre, mFileCollections, mMaster,
mResDir, mCfgMgr.getCachePath(), mNewGame, mEncoding, mFallbackMap));
mResDir, mCfgMgr.getCachePath(), mNewGame, &encoder, mFallbackMap));
//Load translation data
mTranslationDataStorage.setEncoder(&encoder);
mTranslationDataStorage.loadTranslationData(mFileCollections, mMaster);
// Create window manager - this manages all the MW-specific GUI windows
MWScript::registerExtensions (mExtensions);
mEnvironment.setWindowManager (new MWGui::WindowManager(
mExtensions, mFpsLevel, mNewGame, mOgre, mCfgMgr.getLogPath().string() + std::string("/"),
mCfgMgr.getCachePath ().string(), mScriptConsoleMode));
mCfgMgr.getCachePath ().string(), mScriptConsoleMode, mTranslationDataStorage));
// Create sound system
mEnvironment.setSoundManager (new MWSound::SoundManager(mUseSound));
@ -356,7 +364,7 @@ void OMW::Engine::go()
// Create dialog system
mEnvironment.setJournal (new MWDialogue::Journal);
mEnvironment.setDialogueManager (new MWDialogue::DialogueManager (mExtensions, mVerboseScripts));
mEnvironment.setDialogueManager (new MWDialogue::DialogueManager (mExtensions, mVerboseScripts, mTranslationDataStorage));
// Sets up the input system
mEnvironment.setInputManager (new MWInput::InputManager (*mOgre,
@ -487,7 +495,7 @@ void OMW::Engine::showFPS(int level)
mFpsLevel = level;
}
void OMW::Engine::setEncoding(const std::string& encoding)
void OMW::Engine::setEncoding(const ToUTF8::FromType& encoding)
{
mEncoding = encoding;
}

@ -5,6 +5,7 @@
#include <components/compiler/extensions.hpp>
#include <components/files/collections.hpp>
#include <components/translation/translation.hpp>
#include "mwbase/environment.hpp"
@ -59,7 +60,7 @@ namespace OMW
class Engine : private Ogre::FrameListener
{
MWBase::Environment mEnvironment;
std::string mEncoding;
ToUTF8::FromType mEncoding;
Files::PathContainer mDataDirs;
boost::filesystem::path mResDir;
OEngine::Render::OgreRenderer *mOgre;
@ -79,9 +80,9 @@ namespace OMW
Compiler::Extensions mExtensions;
Compiler::Context *mScriptContext;
Files::Collections mFileCollections;
bool mFSStrict;
Translation::Storage mTranslationDataStorage;
// not implemented
Engine (const Engine&);
@ -154,7 +155,7 @@ namespace OMW
void setCompileAll (bool all);
/// Font encoding
void setEncoding(const std::string& encoding);
void setEncoding(const ToUTF8::FromType& encoding);
void setAnimationVerbose(bool animverbose);

@ -181,21 +181,8 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat
// Font encoding settings
std::string encoding(variables["encoding"].as<std::string>());
if (encoding == "win1250")
{
std::cout << "Using Central and Eastern European font encoding." << std::endl;
engine.setEncoding(encoding);
}
else if (encoding == "win1251")
{
std::cout << "Using Cyrillic font encoding." << std::endl;
engine.setEncoding(encoding);
}
else
{
std::cout << "Using default (English) font encoding." << std::endl;
engine.setEncoding("win1252");
}
std::cout << ToUTF8::encodingUsingMessage(encoding) << std::endl;
engine.setEncoding(ToUTF8::calculateEncoding(encoding));
// directory settings
engine.enableFSStrict(variables["fs-strict"].as<bool>());

@ -7,6 +7,8 @@
#include <components/settings/settings.hpp>
#include <components/translation/translation.hpp>
#include "../mwmechanics/stat.hpp"
#include "../mwgui/mode.hpp"
@ -233,6 +235,8 @@ namespace MWBase
virtual void startSpellMaking(MWWorld::Ptr actor) = 0;
virtual void startEnchanting(MWWorld::Ptr actor) = 0;
virtual void startTraining(MWWorld::Ptr actor) = 0;
virtual const Translation::Storage& getTranslationDataStorage() const = 0;
};
}

@ -133,6 +133,10 @@ namespace MWBase
virtual char getGlobalVariableType (const std::string& name) const = 0;
///< Return ' ', if there is no global variable with this name.
virtual std::vector<std::string> getGlobals () const = 0;
virtual std::string getCurrentCellName() const = 0;
virtual MWWorld::Ptr getPtr (const std::string& name, bool activeOnly) = 0;
///< Return a pointer to a liveCellRef with the given name.

@ -204,33 +204,10 @@ namespace MWClass
std::string text;
const MWWorld::ESMStore& store = MWBase::Environment::get().getWorld()->getStore();
if (ref->mRef.mTeleport)
{
std::string dest;
if (ref->mRef.mDestCell != "")
{
// door leads to an interior, use interior name as tooltip
dest = ref->mRef.mDestCell;
}
else
{
// door leads to exterior, use cell name (if any), otherwise translated region name
int x,y;
MWBase::Environment::get().getWorld()->positionToIndex (ref->mRef.mDoorDest.pos[0], ref->mRef.mDoorDest.pos[1], x, y);
const ESM::Cell* cell = store.get<ESM::Cell>().find(x,y);
if (cell->mName != "")
dest = cell->mName;
else
{
const ESM::Region* region =
store.get<ESM::Region>().find(cell->mRegion);
dest = region->mName;
}
}
text += "\n#{sTo}";
text += "\n"+dest;
text += "\n" + getDestination(*ref);
}
if (ref->mRef.mLockLevel > 0)
@ -246,6 +223,37 @@ namespace MWClass
return info;
}
std::string Door::getDestination (const MWWorld::LiveCellRef<ESM::Door>& door)
{
const MWWorld::ESMStore& store = MWBase::Environment::get().getWorld()->getStore();
std::string dest;
if (door.mRef.mDestCell != "")
{
// door leads to an interior, use interior name as tooltip
dest = door.mRef.mDestCell;
}
else
{
// door leads to exterior, use cell name (if any), otherwise translated region name
int x,y;
MWBase::Environment::get().getWorld()->positionToIndex (door.mRef.mDoorDest.pos[0], door.mRef.mDoorDest.pos[1], x, y);
const ESM::Cell* cell = store.get<ESM::Cell>().find(x,y);
if (cell->mName != "")
dest = cell->mName;
else
{
const ESM::Region* region =
store.get<ESM::Region>().find(cell->mRegion);
//name as is, not a token
return region->mName;
}
}
return "#{sCell=" + dest + "}";
}
MWWorld::Ptr
Door::copyToCellImpl(const MWWorld::Ptr &ptr, MWWorld::CellStore &cell) const
{

@ -31,6 +31,9 @@ namespace MWClass
virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::Ptr& ptr) const;
///< @return the content of the tool tip to be displayed. raises exception if the object has no tooltip.
static std::string getDestination (const MWWorld::LiveCellRef<ESM::Door>& door);
///< @return destination cell name or token
virtual void lock (const MWWorld::Ptr& ptr, int lockLevel) const;
///< Lock object

@ -16,6 +16,7 @@
#include <components/compiler/scriptparser.hpp>
#include <components/interpreter/interpreter.hpp>
#include <components/interpreter/defines.hpp>
#include "../mwbase/environment.hpp"
#include "../mwbase/world.hpp"
@ -39,47 +40,14 @@
#include "filter.hpp"
namespace
{
std::string toLower (const std::string& name)
{
std::string lowerCase;
std::transform (name.begin(), name.end(), std::back_inserter (lowerCase),
(int(*)(int)) std::tolower);
return lowerCase;
}
bool stringCompareNoCase (std::string first, std::string second)
{
unsigned int i=0;
while ( (i<first.length()) && (i<second.length()) )
{
if (tolower(first[i])<tolower(second[i])) return true;
else if (tolower(first[i])>tolower(second[i])) return false;
++i;
}
if (first.length()<second.length())
return true;
else
return false;
}
//helper function
std::string::size_type find_str_ci(const std::string& str, const std::string& substr,size_t pos)
{
return toLower(str).find(toLower(substr),pos);
}
}
namespace MWDialogue
{
DialogueManager::DialogueManager (const Compiler::Extensions& extensions, bool scriptVerbose) :
DialogueManager::DialogueManager (const Compiler::Extensions& extensions, bool scriptVerbose, Translation::Storage& translationDataStorage) :
mCompilerContext (MWScript::CompilerContext::Type_Dialgoue),
mErrorStream(std::cout.rdbuf()),mErrorHandler(mErrorStream)
, mTemporaryDispositionChange(0.f)
, mPermanentDispositionChange(0.f), mScriptVerbose (scriptVerbose)
, mTranslationDataStorage(translationDataStorage)
{
mChoice = -1;
mIsInChoice = false;
@ -93,26 +61,55 @@ namespace MWDialogue
MWWorld::Store<ESM::Dialogue>::iterator it = dialogs.begin();
for (; it != dialogs.end(); ++it)
{
mDialogueMap[toLower(it->mId)] = *it;
mDialogueMap[Misc::StringUtils::lowerCase(it->mId)] = *it;
}
}
void DialogueManager::addTopic (const std::string& topic)
{
mKnownTopics[toLower(topic)] = true;
mKnownTopics[Misc::StringUtils::lowerCase(topic)] = true;
}
void DialogueManager::parseText (const std::string& text)
{
std::list<std::string>::iterator it;
for(it = mActorKnownTopics.begin();it != mActorKnownTopics.end();++it)
std::vector<HyperTextToken> hypertext = ParseHyperText(text);
//calculation of standard form fir all hyperlinks
for (size_t i = 0; i < hypertext.size(); ++i)
{
if (hypertext[i].mLink)
{
size_t asterisk_count = MWDialogue::RemovePseudoAsterisks(hypertext[i].mText);
for(; asterisk_count > 0; --asterisk_count)
hypertext[i].mText.append("*");
hypertext[i].mText = mTranslationDataStorage.topicStandardForm(hypertext[i].mText);
}
}
for (size_t i = 0; i < hypertext.size(); ++i)
{
size_t pos = find_str_ci(text,*it,0);
if(pos !=std::string::npos)
std::list<std::string>::iterator it;
for(it = mActorKnownTopics.begin(); it != mActorKnownTopics.end(); ++it)
{
mKnownTopics[*it] = true;
if (hypertext[i].mLink)
{
if( hypertext[i].mText == *it )
{
mKnownTopics[hypertext[i].mText] = true;
}
}
else if( !mTranslationDataStorage.hasTranslation() )
{
size_t pos = Misc::StringUtils::lowerCase(hypertext[i].mText).find(*it, 0);
if(pos !=std::string::npos)
{
mKnownTopics[*it] = true;
}
}
}
}
updateTopics();
}
@ -155,7 +152,9 @@ namespace MWDialogue
}
parseText (info->mResponse);
win->addText (info->mResponse);
MWScript::InterpreterContext interpreterContext(&mActor.getRefData().getLocals(),mActor);
win->addText (Interpreter::fixDefinesDialog(info->mResponse, interpreterContext));
executeScript (info->mResultScript);
mLastTopic = it->mId;
mLastDialogue = *info;
@ -267,7 +266,8 @@ namespace MWDialogue
else
win->addTitle (topic);
win->addText (info->mResponse);
MWScript::InterpreterContext interpreterContext(&mActor.getRefData().getLocals(),mActor);
win->addText (Interpreter::fixDefinesDialog(info->mResponse, interpreterContext));
executeScript (info->mResultScript);
@ -294,10 +294,11 @@ namespace MWDialogue
{
if (filter.search (*iter))
{
mActorKnownTopics.push_back (toLower (iter->mId));
std::string lower = Misc::StringUtils::lowerCase(iter->mId);
mActorKnownTopics.push_back (lower);
//does the player know the topic?
if (mKnownTopics.find (toLower (iter->mId)) != mKnownTopics.end())
if (mKnownTopics.find (lower) != mKnownTopics.end())
{
keywordList.push_back (iter->mId);
}
@ -355,7 +356,7 @@ namespace MWDialogue
win->setServices (windowServices);
// sort again, because the previous sort was case-sensitive
keywordList.sort(stringCompareNoCase);
keywordList.sort(Misc::StringUtils::ciEqual);
win->setKeywords(keywordList);
mChoice = choice;
@ -411,7 +412,9 @@ namespace MWDialogue
mIsInChoice = false;
std::string text = info->mResponse;
parseText (text);
MWBase::Environment::get().getWindowManager()->getDialogueWindow()->addText (text);
MWScript::InterpreterContext interpreterContext(&mActor.getRefData().getLocals(),mActor);
MWBase::Environment::get().getWindowManager()->getDialogueWindow()->addText (Interpreter::fixDefinesDialog(text, interpreterContext));
executeScript (info->mResultScript);
mLastTopic = mLastTopic;
mLastDialogue = *info;
@ -433,7 +436,7 @@ namespace MWDialogue
{
MWGui::DialogueWindow* win = MWBase::Environment::get().getWindowManager()->getDialogueWindow();
win->askQuestion(question);
mChoiceMap[toLower(question)] = choice;
mChoiceMap[Misc::StringUtils::lowerCase(question)] = choice;
mIsInChoice = true;
}
@ -493,4 +496,57 @@ namespace MWDialogue
{
mTemporaryDispositionChange += delta;
}
std::vector<HyperTextToken> ParseHyperText(const std::string& text)
{
std::vector<HyperTextToken> result;
MyGUI::UString utext(text);
size_t pos_begin, pos_end, iteration_pos = 0;
for(;;)
{
pos_begin = utext.find('@', iteration_pos);
if (pos_begin != std::string::npos)
pos_end = utext.find('#', pos_begin);
if (pos_begin != std::string::npos && pos_end != std::string::npos)
{
result.push_back( HyperTextToken(utext.substr(iteration_pos, pos_begin - iteration_pos), false) );
std::string link = utext.substr(pos_begin + 1, pos_end - pos_begin - 1);
result.push_back( HyperTextToken(link, true) );
iteration_pos = pos_end + 1;
}
else
{
result.push_back( HyperTextToken(utext.substr(iteration_pos), false) );
break;
}
}
return result;
}
size_t RemovePseudoAsterisks(std::string& phrase)
{
size_t pseudoAsterisksCount = 0;
const char specialPseudoAsteriskCharacter = 127;
if( !phrase.empty() )
{
std::string::reverse_iterator rit = phrase.rbegin();
while( rit != phrase.rend() && *rit == specialPseudoAsteriskCharacter )
{
pseudoAsterisksCount++;
++rit;
}
}
phrase = phrase.substr(0, phrase.length() - pseudoAsterisksCount);
return pseudoAsterisksCount;
}
}

@ -7,6 +7,7 @@
#include <list>
#include <components/compiler/streamerrorhandler.hpp>
#include <components/translation/translation.hpp>
#include "../mwworld/ptr.hpp"
@ -20,6 +21,7 @@ namespace MWDialogue
std::map<std::string, bool> mKnownTopics;// Those are the topics the player knows.
std::list<std::string> mActorKnownTopics;
Translation::Storage& mTranslationDataStorage;
MWScript::CompilerContext mCompilerContext;
std::ostream mErrorStream;
Compiler::StreamErrorHandler mErrorHandler;
@ -50,7 +52,7 @@ namespace MWDialogue
public:
DialogueManager (const Compiler::Extensions& extensions, bool scriptVerbose);
DialogueManager (const Compiler::Extensions& extensions, bool scriptVerbose, Translation::Storage& translationDataStorage);
virtual void startDialogue (const MWWorld::Ptr& actor);
@ -72,6 +74,21 @@ namespace MWDialogue
virtual int getTemporaryDispositionChange () const;
virtual void applyTemporaryDispositionChange (int delta);
};
struct HyperTextToken
{
HyperTextToken(const std::string& text, bool link) : mText(text), mLink(link) {}
std::string mText;
bool mLink;
};
// In translations (at least Russian) the links are marked with @#, so
// it should be a function to parse it
std::vector<HyperTextToken> ParseHyperText(const std::string& text);
size_t RemovePseudoAsterisks(std::string& phrase);
}
#endif

@ -88,7 +88,7 @@ void BookWindow::setTakeButtonShow(bool show)
mTakeButton->setVisible(show);
}
void BookWindow::onCloseButtonClicked (MyGUI::Widget* _sender)
void BookWindow::onCloseButtonClicked (MyGUI::Widget* sender)
{
// no 3d sounds because the object could be in a container.
MWBase::Environment::get().getSoundManager()->playSound ("book close", 1.0, 1.0);
@ -96,7 +96,7 @@ void BookWindow::onCloseButtonClicked (MyGUI::Widget* _sender)
mWindowManager.removeGuiMode(GM_Book);
}
void BookWindow::onTakeButtonClicked (MyGUI::Widget* _sender)
void BookWindow::onTakeButtonClicked (MyGUI::Widget* sender)
{
MWBase::Environment::get().getSoundManager()->playSound ("Item Book Up", 1.0, 1.0, MWBase::SoundManager::Play_NoTrack);
@ -106,7 +106,7 @@ void BookWindow::onTakeButtonClicked (MyGUI::Widget* _sender)
mWindowManager.removeGuiMode(GM_Book);
}
void BookWindow::onNextPageButtonClicked (MyGUI::Widget* _sender)
void BookWindow::onNextPageButtonClicked (MyGUI::Widget* sender)
{
if ((mCurrentPage+1)*2 < mPages.size())
{
@ -118,7 +118,7 @@ void BookWindow::onNextPageButtonClicked (MyGUI::Widget* _sender)
}
}
void BookWindow::onPrevPageButtonClicked (MyGUI::Widget* _sender)
void BookWindow::onPrevPageButtonClicked (MyGUI::Widget* sender)
{
if (mCurrentPage > 0)
{

@ -5,6 +5,8 @@
#include "../mwworld/ptr.hpp"
#include "imagebutton.hpp"
namespace MWGui
{
class BookWindow : public WindowBase
@ -16,19 +18,19 @@ namespace MWGui
void setTakeButtonShow(bool show);
protected:
void onNextPageButtonClicked (MyGUI::Widget* _sender);
void onPrevPageButtonClicked (MyGUI::Widget* _sender);
void onCloseButtonClicked (MyGUI::Widget* _sender);
void onTakeButtonClicked (MyGUI::Widget* _sender);
void onNextPageButtonClicked (MyGUI::Widget* sender);
void onPrevPageButtonClicked (MyGUI::Widget* sender);
void onCloseButtonClicked (MyGUI::Widget* sender);
void onTakeButtonClicked (MyGUI::Widget* sender);
void updatePages();
void clearPages();
private:
MyGUI::Button* mCloseButton;
MyGUI::Button* mTakeButton;
MyGUI::Button* mNextPageButton;
MyGUI::Button* mPrevPageButton;
MWGui::ImageButton* mCloseButton;
MWGui::ImageButton* mTakeButton;
MWGui::ImageButton* mNextPageButton;
MWGui::ImageButton* mPrevPageButton;
MyGUI::TextBox* mLeftPageNumber;
MyGUI::TextBox* mRightPageNumber;
MyGUI::Widget* mLeftPage;

@ -195,13 +195,13 @@ void ContainerBase::sellAlreadyBoughtItem(MyGUI::Widget* _sender, int count)
if (isInventory())
{
MWBase::Environment::get().getWindowManager()->getTradeWindow()->addItem(object, count);
MWBase::Environment::get().getWindowManager()->getTradeWindow()->buyFromNpc(object, count);
MWBase::Environment::get().getWindowManager()->getTradeWindow()->sellToNpc(object, count, true);
MWBase::Environment::get().getWindowManager()->getTradeWindow()->drawItems();
}
else
{
MWBase::Environment::get().getWindowManager()->getInventoryWindow()->addItem(object, count);
MWBase::Environment::get().getWindowManager()->getTradeWindow()->sellToNpc(object, count);
MWBase::Environment::get().getWindowManager()->getTradeWindow()->buyFromNpc(object, count, true);
MWBase::Environment::get().getWindowManager()->getInventoryWindow()->drawItems();
}
@ -218,13 +218,13 @@ void ContainerBase::sellItem(MyGUI::Widget* _sender, int count)
if (isInventory())
{
MWBase::Environment::get().getWindowManager()->getTradeWindow()->addBarteredItem(object, count);
MWBase::Environment::get().getWindowManager()->getTradeWindow()->buyFromNpc(object, count);
MWBase::Environment::get().getWindowManager()->getTradeWindow()->sellToNpc(object, count, false);
MWBase::Environment::get().getWindowManager()->getTradeWindow()->drawItems();
}
else
{
MWBase::Environment::get().getWindowManager()->getInventoryWindow()->addBarteredItem(object, count);
MWBase::Environment::get().getWindowManager()->getTradeWindow()->sellToNpc(object, count);
MWBase::Environment::get().getWindowManager()->getTradeWindow()->buyFromNpc(object, count, false);
MWBase::Environment::get().getWindowManager()->getInventoryWindow()->drawItems();
}

@ -2,7 +2,6 @@
#include <boost/filesystem.hpp>
#include <openengine/ogre/imagerotate.hpp>
#include <openengine/ogre/atlas.hpp>
#include <OgreResourceGroupManager.h>
#include <OgreRoot.h>
@ -14,7 +13,4 @@ CursorReplace::CursorReplace()
OEngine::Render::ImageRotate::rotate("textures\\tx_cursormove.dds", "mwpointer_vresize.png", 90);
OEngine::Render::ImageRotate::rotate("textures\\tx_cursormove.dds", "mwpointer_dresize1.png", -45);
OEngine::Render::ImageRotate::rotate("textures\\tx_cursormove.dds", "mwpointer_dresize2.png", 45);
OEngine::Render::Atlas::createFromFile("atlas1.cfg", "mwgui1", "textures\\");
OEngine::Render::Atlas::createFromFile("mainmenu.cfg", "mwgui2", "textures\\");
}

@ -16,6 +16,8 @@
#include "../mwmechanics/npcstats.hpp"
#include "../mwdialogue/dialoguemanagerimp.hpp"
#include "dialogue_history.hpp"
#include "widgets.hpp"
#include "list.hpp"
@ -52,7 +54,6 @@ bool sortByLength (const std::string& left, const std::string& right)
{
return left.size() > right.size();
}
}
@ -180,9 +181,30 @@ void DialogueWindow::onHistoryClicked(MyGUI::Widget* _sender)
if(color != "#B29154")
{
MyGUI::UString key = mHistory->getColorTextAt(cursorPosition);
if(color == "#686EBA") MWBase::Environment::get().getDialogueManager()->keywordSelected(lower_string(key));
if(color == "#572D21") MWBase::Environment::get().getDialogueManager()->questionAnswered(lower_string(key));
if(color == "#686EBA")
{
std::map<size_t, HyperLink>::iterator i = mHyperLinks.upper_bound(cursorPosition);
if( !mHyperLinks.empty() )
{
--i;
if( i->first + i->second.mLength > cursorPosition)
{
MWBase::Environment::get().getDialogueManager()->keywordSelected(i->second.mTrueValue);
}
}
else
{
// the link was colored, but it is not in mHyperLinks.
// It means that those liunks are not marked with @# and found
// by topic name search
MWBase::Environment::get().getDialogueManager()->keywordSelected(lower_string(key));
}
}
if(color == "#572D21")
MWBase::Environment::get().getDialogueManager()->questionAnswered(lower_string(key));
}
}
@ -258,6 +280,7 @@ void DialogueWindow::startDialogue(MWWorld::Ptr actor, std::string npcName)
setTitle(npcName);
mTopicsList->clear();
mHyperLinks.clear();
mHistory->setCaption("");
updateOptions();
}
@ -340,7 +363,7 @@ void addColorInString(std::string& str, const std::string& keyword,std::string c
}
}
std::string DialogueWindow::parseText(std::string text)
std::string DialogueWindow::parseText(const std::string& text)
{
bool separatorReached = false; // only parse topics that are below the separator (this prevents actions like "Barter" that are not topics from getting blue-colored)
@ -358,11 +381,56 @@ std::string DialogueWindow::parseText(std::string text)
// sort by length to make sure longer topics are replaced first
std::sort(topics.begin(), topics.end(), sortByLength);
for(std::vector<std::string>::const_iterator it = topics.begin(); it != topics.end(); ++it)
std::vector<MWDialogue::HyperTextToken> hypertext = MWDialogue::ParseHyperText(text);
size_t historySize = 0;
if(mHistory->getClient()->getSubWidgetText() != nullptr)
{
addColorInString(text,*it,"#686EBA","#B29154");
historySize = mHistory->getOnlyText().size();
}
return text;
std::string result;
size_t hypertextPos = 0;
for (size_t i = 0; i < hypertext.size(); ++i)
{
if (hypertext[i].mLink)
{
size_t asterisk_count = MWDialogue::RemovePseudoAsterisks(hypertext[i].mText);
std::string standardForm = hypertext[i].mText;
for(; asterisk_count > 0; --asterisk_count)
standardForm.append("*");
standardForm =
MWBase::Environment::get().getWindowManager()->
getTranslationDataStorage().topicStandardForm(standardForm);
if( std::find(topics.begin(), topics.end(), std::string(standardForm) ) != topics.end() )
{
result.append("#686EBA").append(hypertext[i].mText).append("#B29154");
mHyperLinks[historySize+hypertextPos].mLength = MyGUI::UString(hypertext[i].mText).length();
mHyperLinks[historySize+hypertextPos].mTrueValue = lower_string(standardForm);
}
else
result += hypertext[i].mText;
}
else
{
if( !mWindowManager.getTranslationDataStorage().hasTranslation() )
{
for(std::vector<std::string>::const_iterator it = topics.begin(); it != topics.end(); ++it)
{
addColorInString(hypertext[i].mText, *it, "#686EBA", "#B29154");
}
}
result += hypertext[i].mText;
}
hypertextPos += MyGUI::UString(hypertext[i].mText).length();
}
return result;
}
void DialogueWindow::addText(std::string text)
@ -370,6 +438,11 @@ void DialogueWindow::addText(std::string text)
mHistory->addDialogText("#B29154"+parseText(text)+"#B29154");
}
void DialogueWindow::addMessageBox(const std::string& text)
{
mHistory->addDialogText("\n#FFFFFF"+text+"#B29154");
}
void DialogueWindow::addTitle(std::string text)
{
// This is called from the dialogue manager, so text is
@ -394,6 +467,7 @@ void DialogueWindow::updateOptions()
{
//Clear the list of topics
mTopicsList->clear();
mHyperLinks.clear();
mHistory->eraseText(0, mHistory->getTextLength());
if (mPtr.getTypeName() == typeid(ESM::NPC).name())

@ -65,6 +65,7 @@ namespace MWGui
void setKeywords(std::list<std::string> keyWord);
void removeKeyword(std::string keyWord);
void addText(std::string text);
void addMessageBox(const std::string& text);
void addTitle(std::string text);
void askQuestion(std::string question);
void goodbye();
@ -92,12 +93,18 @@ namespace MWGui
virtual void onReferenceUnavailable();
struct HyperLink
{
size_t mLength;
std::string mTrueValue;
};
private:
void updateOptions();
/**
*Helper function that add topic keyword in blue in a text.
*/
std::string parseText(std::string text);
std::string parseText(const std::string& text);
int mServices;
@ -109,6 +116,8 @@ namespace MWGui
MyGUI::EditPtr mDispositionText;
PersuasionDialog mPersuasionDialog;
std::map<size_t, HyperLink> mHyperLinks;
};
}
#endif

@ -1,5 +1,10 @@
#include "formatting.hpp"
#include <components/interpreter/defines.hpp>
#include "../mwscript/interpretercontext.hpp"
#include "../mwworld/ptr.hpp"
#include <boost/algorithm/string/replace.hpp>
#include <boost/lexical_cast.hpp>
@ -68,6 +73,9 @@ std::vector<std::string> BookTextParser::split(std::string text, const int width
{
std::vector<std::string> result;
MWScript::InterpreterContext interpreterContext(NULL, MWWorld::Ptr()); // empty arguments, because there is no locals or actor
text = Interpreter::fixDefinesBook(text, interpreterContext);
boost::algorithm::replace_all(text, "<BR>", "\n");
boost::algorithm::replace_all(text, "<P>", "\n\n");
@ -167,6 +175,10 @@ std::vector<std::string> BookTextParser::split(std::string text, const int width
MyGUI::IntSize BookTextParser::parse(std::string text, MyGUI::Widget* parent, const int width)
{
MWScript::InterpreterContext interpreterContext(NULL, MWWorld::Ptr()); // empty arguments, because there is no locals or actor
text = Interpreter::fixDefinesBook(text, interpreterContext);
mParent = parent;
mWidth = width;
mHeight = 0;

@ -319,7 +319,7 @@ void HUD::setCellName(const std::string& cellName)
mCellNameTimer = 5.0f;
mCellName = cellName;
mCellNameBox->setCaption(mCellName);
mCellNameBox->setCaptionWithReplacing("#{sCell=" + mCellName + "}");
mCellNameBox->setVisible(mMapVisible);
}
}

@ -0,0 +1,63 @@
#include "imagebutton.hpp"
#include <OgreTextureManager.h>
namespace MWGui
{
void ImageButton::setPropertyOverride(const std::string &_key, const std::string &_value)
{
if (_key == "ImageHighlighted")
mImageHighlighted = _value;
else if (_key == "ImagePushed")
mImagePushed = _value;
else if (_key == "ImageNormal")
{
if (mImageNormal == "")
{
setImageTexture(_value);
}
mImageNormal = _value;
}
else
ImageBox::setPropertyOverride(_key, _value);
}
void ImageButton::onMouseSetFocus(Widget* _old)
{
setImageTexture(mImageHighlighted);
ImageBox::onMouseSetFocus(_old);
}
void ImageButton::onMouseLostFocus(Widget* _new)
{
setImageTexture(mImageNormal);
ImageBox::onMouseLostFocus(_new);
}
void ImageButton::onMouseButtonPressed(int _left, int _top, MyGUI::MouseButton _id)
{
if (_id == MyGUI::MouseButton::Left)
setImageTexture(mImagePushed);
ImageBox::onMouseButtonPressed(_left, _top, _id);
}
MyGUI::IntSize ImageButton::getRequestedSize()
{
Ogre::TexturePtr texture = Ogre::TextureManager::getSingleton().getByName(mImageNormal);
if (texture.isNull())
{
std::cerr << "ImageButton: can't find " << mImageNormal << std::endl;
return MyGUI::IntSize(0,0);
}
return MyGUI::IntSize (texture->getWidth(), texture->getHeight());
}
void ImageButton::onMouseButtonReleased(int _left, int _top, MyGUI::MouseButton _id)
{
if (_id == MyGUI::MouseButton::Left)
setImageTexture(mImageHighlighted);
ImageBox::onMouseButtonReleased(_left, _top, _id);
}
}

@ -0,0 +1,33 @@
#ifndef MWGUI_IMAGEBUTTON_H
#define MWGUI_IMAGEBUTTON_H
#include "MyGUI_ImageBox.h"
namespace MWGui
{
/**
* @brief allows using different image textures depending on the button state
*/
class ImageButton : public MyGUI::ImageBox
{
MYGUI_RTTI_DERIVED(ImageButton)
public:
MyGUI::IntSize getRequestedSize();
protected:
virtual void setPropertyOverride(const std::string& _key, const std::string& _value);
virtual void onMouseLostFocus(MyGUI::Widget* _new);
virtual void onMouseSetFocus(MyGUI::Widget* _old);
virtual void onMouseButtonPressed(int _left, int _top, MyGUI::MouseButton _id);
virtual void onMouseButtonReleased(int _left, int _top, MyGUI::MouseButton _id);
std::string mImageHighlighted;
std::string mImageNormal;
std::string mImagePushed;
};
}
#endif

@ -24,19 +24,6 @@
#include "scrollwindow.hpp"
#include "spellwindow.hpp"
namespace
{
std::string toLower (const std::string& name)
{
std::string lowerCase;
std::transform (name.begin(), name.end(), std::back_inserter (lowerCase),
(int(*)(int)) std::tolower);
return lowerCase;
}
}
namespace MWGui
{
@ -284,7 +271,7 @@ namespace MWGui
for (MWWorld::ContainerStoreIterator it = invStore.begin();
it != invStore.end(); ++it)
{
if (toLower(it->getCellRef().mRefID) == "gold_001")
if (Misc::StringUtils::ciEqual(it->getCellRef().mRefID, "gold_001"))
return it->getRefData().getCount();
}
return 0;

@ -83,10 +83,9 @@ book formatText(std::string text,book mBook,int maxLine, int lineSize)
MWGui::JournalWindow::JournalWindow (MWBase::WindowManager& parWindowManager)
: WindowBase("openmw_journal.layout", parWindowManager)
, mLastPos(0)
, mVisible(false)
, mPageNumber(0)
{
mMainWidget->setVisible(false);
//setCoord(0,0,498, 342);
center();
@ -115,20 +114,15 @@ MWGui::JournalWindow::JournalWindow (MWBase::WindowManager& parWindowManager)
//displayLeftText(list.front());
}
void MWGui::JournalWindow::setVisible(bool visible)
void MWGui::JournalWindow::close()
{
if (mVisible && !visible)
MWBase::Environment::get().getSoundManager()->playSound ("book close", 1.0, 1.0);
mVisible = visible;
mMainWidget->setVisible(visible);
MWBase::Environment::get().getSoundManager()->playSound ("book close", 1.0, 1.0);
}
void MWGui::JournalWindow::open()
{
mPageNumber = 0;
std::string journalOpenSound = "book open";
MWBase::Environment::get().getSoundManager()->playSound (journalOpenSound, 1.0, 1.0);
MWBase::Environment::get().getSoundManager()->playSound ("book open", 1.0, 1.0);
if(MWBase::Environment::get().getJournal()->begin()!=MWBase::Environment::get().getJournal()->end())
{
book journal;
@ -182,7 +176,7 @@ void MWGui::JournalWindow::displayRightText(std::string text)
}
void MWGui::JournalWindow::notifyNextPage(MyGUI::WidgetPtr _sender)
void MWGui::JournalWindow::notifyNextPage(MyGUI::Widget* _sender)
{
if(mPageNumber < int(mLeftPages.size())-1)
{
@ -194,7 +188,7 @@ void MWGui::JournalWindow::notifyNextPage(MyGUI::WidgetPtr _sender)
}
}
void MWGui::JournalWindow::notifyPrevPage(MyGUI::WidgetPtr _sender)
void MWGui::JournalWindow::notifyPrevPage(MyGUI::Widget* _sender)
{
if(mPageNumber > 0)
{

@ -7,6 +7,7 @@
#include <utility>
#include "window_base.hpp"
#include "imagebutton.hpp"
namespace MWGui
{
@ -15,8 +16,7 @@ namespace MWGui
public:
JournalWindow(MWBase::WindowManager& parWindowManager);
virtual void open();
virtual void setVisible(bool visible); // only used to play close sound
virtual void close();
private:
void displayLeftText(std::string text);
@ -26,22 +26,16 @@ namespace MWGui
/**
*Called when next/prev button is used.
*/
void notifyNextPage(MyGUI::WidgetPtr _sender);
void notifyPrevPage(MyGUI::WidgetPtr _sender);
static const int sLineHeight;
void notifyNextPage(MyGUI::Widget* _sender);
void notifyPrevPage(MyGUI::Widget* _sender);
MyGUI::WidgetPtr mSkillAreaWidget, mSkillClientWidget;
MyGUI::ScrollBar* mSkillScrollerWidget;
int mLastPos, mClientHeight;
MyGUI::EditPtr mLeftTextWidget;
MyGUI::EditPtr mRightTextWidget;
MyGUI::ButtonPtr mPrevBtn;
MyGUI::ButtonPtr mNextBtn;
MWGui::ImageButton* mPrevBtn;
MWGui::ImageButton* mNextBtn;
std::vector<std::string> mLeftPages;
std::vector<std::string> mRightPages;
int mPageNumber; //store the number of the current left page
bool mVisible;
};
}

@ -213,22 +213,26 @@ namespace MWGui
void LoadingScreen::changeWallpaper ()
{
std::vector<std::string> splash;
Ogre::StringVectorPtr resources = Ogre::ResourceGroupManager::getSingleton ().listResourceNames ("General", false);
for (Ogre::StringVector::const_iterator it = resources->begin(); it != resources->end(); ++it)
if (mResources.isNull ())
{
if (it->size() < 6)
continue;
std::string start = it->substr(0, 6);
boost::to_lower(start);
mResources = Ogre::StringVectorPtr (new Ogre::StringVector);
Ogre::StringVectorPtr resources = Ogre::ResourceGroupManager::getSingleton ().listResourceNames ("General", false);
for (Ogre::StringVector::const_iterator it = resources->begin(); it != resources->end(); ++it)
{
if (it->size() < 6)
continue;
std::string start = it->substr(0, 6);
boost::to_lower(start);
if (start == "splash")
splash.push_back (*it);
if (start == "splash")
mResources->push_back (*it);
}
}
if (splash.size())
if (mResources->size())
{
std::string randomSplash = splash[rand() % splash.size()];
std::string randomSplash = mResources->at (rand() % mResources->size());
Ogre::TexturePtr tex = Ogre::TextureManager::getSingleton ().load (randomSplash, "General");
mBackgroundImage->setImageTexture (randomSplash);

@ -42,6 +42,7 @@ namespace MWGui
Ogre::Rectangle2D* mRectangle;
Ogre::MaterialPtr mBackgroundMaterial;
Ogre::StringVectorPtr mResources;
bool mLoadingOn;

@ -20,65 +20,57 @@ namespace MWGui
{
setCoord(0,0,w,h);
int height = 64 * 3;
if (mButtonBox)
MyGUI::Gui::getInstance ().destroyWidget(mButtonBox);
mButtonBox = mMainWidget->createWidget<MyGUI::Widget>("", MyGUI::IntCoord(w/2 - 64, h/2 - height/2, 128, height), MyGUI::Align::Default);
mButtonBox = mMainWidget->createWidget<MyGUI::Widget>("", MyGUI::IntCoord(0, 0, 0, 0), MyGUI::Align::Default);
int curH = 0;
mReturn = mButtonBox->createWidget<MyGUI::Button> ("ButtonImage", MyGUI::IntCoord(0, curH, 128, 64), MyGUI::Align::Default);
mReturn->setImageResource ("Menu_Return");
mReturn->eventMouseButtonClick += MyGUI::newDelegate(this, &MainMenu::returnToGame);
curH += 64;
/*
mNewGame = mButtonBox->createWidget<MyGUI::Button> ("ButtonImage", MyGUI::IntCoord(0, curH, 128, 64), MyGUI::Align::Default);
mNewGame->setImageResource ("Menu_NewGame");
curH += 64;
mLoadGame = mButtonBox->createWidget<MyGUI::Button> ("ButtonImage", MyGUI::IntCoord(0, curH, 128, 64), MyGUI::Align::Default);
mLoadGame->setImageResource ("Menu_LoadGame");
curH += 64;
mSaveGame = mButtonBox->createWidget<MyGUI::Button> ("ButtonImage", MyGUI::IntCoord(0, curH, 128, 64), MyGUI::Align::Default);
mSaveGame->setImageResource ("Menu_SaveGame");
curH += 64;
*/
mOptions = mButtonBox->createWidget<MyGUI::Button> ("ButtonImage", MyGUI::IntCoord(0, curH, 128, 64), MyGUI::Align::Default);
mOptions->setImageResource ("Menu_Options");
mOptions->eventMouseButtonClick += MyGUI::newDelegate(this, &MainMenu::showOptions);
curH += 64;
/*
mCredits = mButtonBox->createWidget<MyGUI::Button> ("ButtonImage", MyGUI::IntCoord(0, curH, 128, 64), MyGUI::Align::Default);
mCredits->setImageResource ("Menu_Credits");
curH += 64;
*/
mExitGame = mButtonBox->createWidget<MyGUI::Button> ("ButtonImage", MyGUI::IntCoord(0, curH, 128, 64), MyGUI::Align::Default);
mExitGame->setImageResource ("Menu_ExitGame");
mExitGame->eventMouseButtonClick += MyGUI::newDelegate(this, &MainMenu::exitGame);
curH += 64;
}
void MainMenu::returnToGame(MyGUI::Widget* sender)
{
MWBase::Environment::get().getWindowManager ()->removeGuiMode (GM_MainMenu);
}
void MainMenu::showOptions(MyGUI::Widget* sender)
{
MWBase::Environment::get().getWindowManager ()->pushGuiMode (GM_Settings);
std::vector<std::string> buttons;
buttons.push_back("return");
//buttons.push_back("newgame");
//buttons.push_back("loadgame");
//buttons.push_back("savegame");
buttons.push_back("options");
//buttons.push_back("credits");
buttons.push_back("exitgame");
int maxwidth = 0;
mButtons.clear();
for (std::vector<std::string>::iterator it = buttons.begin(); it != buttons.end(); ++it)
{
MWGui::ImageButton* button = mButtonBox->createWidget<MWGui::ImageButton>
("ImageBox", MyGUI::IntCoord(0, curH, 0, 0), MyGUI::Align::Default);
button->setProperty("ImageHighlighted", "textures\\menu_" + *it + "_over.dds");
button->setProperty("ImageNormal", "textures\\menu_" + *it + ".dds");
button->setProperty("ImagePushed", "textures\\menu_" + *it + "_pressed.dds");
MyGUI::IntSize requested = button->getRequestedSize();
button->eventMouseButtonClick += MyGUI::newDelegate(this, &MainMenu::onButtonClicked);
mButtons[*it] = button;
curH += requested.height;
if (requested.width > maxwidth)
maxwidth = requested.width;
}
for (std::map<std::string, MWGui::ImageButton*>::iterator it = mButtons.begin(); it != mButtons.end(); ++it)
{
MyGUI::IntSize requested = it->second->getRequestedSize();
it->second->setCoord((maxwidth-requested.width) / 2, it->second->getTop(), requested.width, requested.height);
}
mButtonBox->setCoord (w/2 - maxwidth/2, h/2 - curH/2, maxwidth, curH);
}
void MainMenu::exitGame(MyGUI::Widget* sender)
void MainMenu::onButtonClicked(MyGUI::Widget *sender)
{
Ogre::Root::getSingleton ().queueEndRendering ();
if (sender == mButtons["return"])
MWBase::Environment::get().getWindowManager ()->removeGuiMode (GM_MainMenu);
else if (sender == mButtons["options"])
MWBase::Environment::get().getWindowManager ()->pushGuiMode (GM_Settings);
else if (sender == mButtons["exitgame"])
Ogre::Root::getSingleton ().queueEndRendering ();
}
}

@ -1,5 +1,7 @@
#include <openengine/gui/layout.hpp>
#include "imagebutton.hpp"
namespace MWGui
{
@ -11,19 +13,11 @@ namespace MWGui
void onResChange(int w, int h);
private:
MyGUI::Button* mReturn;
MyGUI::Button* mNewGame;
MyGUI::Button* mLoadGame;
MyGUI::Button* mSaveGame;
MyGUI::Button* mOptions;
MyGUI::Button* mCredits;
MyGUI::Button* mExitGame;
MyGUI::Widget* mButtonBox;
void returnToGame(MyGUI::Widget* sender);
void showOptions(MyGUI::Widget* sender);
void exitGame(MyGUI::Widget* sender);
std::map<std::string, MWGui::ImageButton*> mButtons;
void onButtonClicked (MyGUI::Widget* sender);
};
}

@ -299,7 +299,7 @@ MapWindow::~MapWindow()
void MapWindow::setCellName(const std::string& cellName)
{
setTitle(cellName);
setTitle("#{sCell=" + cellName + "}");
}
void MapWindow::addVisitedLocation(const std::string& name, int x, int y)

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

Loading…
Cancel
Save