Merge branch 'master' into HEAD
Conflicts: CMakeLists.txt apps/openmw/engine.cpp apps/openmw/mwgui/cursorreplace.cpp apps/openmw/mwgui/cursorreplace.hpp apps/openmw/mwgui/windowmanagerimp.cpp apps/openmw/mwgui/windowmanagerimp.hpp apps/openmw/mwinput/inputmanagerimp.cpp libs/openengine/ogre/renderer.cppactorid
commit
495aeb5d3b
@ -0,0 +1,40 @@
|
||||
language: cpp
|
||||
compiler:
|
||||
- gcc
|
||||
branches:
|
||||
only:
|
||||
- master
|
||||
- next
|
||||
before_install:
|
||||
- pwd
|
||||
- git submodule update --init --recursive
|
||||
- echo "yes" | sudo add-apt-repository "deb http://archive.ubuntu.com/ubuntu `lsb_release -sc` main universe restricted multiverse"
|
||||
- echo "yes" | sudo apt-add-repository ppa:openmw/deps
|
||||
- sudo apt-get update -qq
|
||||
- sudo apt-get install -qq libboost-all-dev libgtest-dev google-mock libzzip-dev
|
||||
- sudo apt-get install -qq libqt4-dev libxaw7-dev libxrandr-dev libfreeimage-dev libpng-dev
|
||||
- sudo apt-get install -qq libopenal-dev libmpg123-dev libsndfile1-dev
|
||||
- sudo apt-get install -qq libcg nvidia-cg-toolkit
|
||||
- sudo apt-get install -qq libavcodec-dev libavformat-dev libavdevice-dev libavutil-dev libswscale-dev libpostproc-dev
|
||||
- sudo apt-get install -qq libois-dev libbullet-dev libogre-static-dev libmygui-static-dev
|
||||
- sudo mkdir /usr/src/gtest/build
|
||||
- cd /usr/src/gtest/build
|
||||
- sudo cmake .. -DBUILD_SHARED_LIBS=1
|
||||
- sudo make -j4
|
||||
- sudo ln -s /usr/src/gtest/build/libgtest.so /usr/lib/libgtest.so
|
||||
- sudo ln -s /usr/src/gtest/build/libgtest_main.so /usr/lib/libgtest_main.so
|
||||
before_script:
|
||||
- cd -
|
||||
- mkdir build
|
||||
- cd build
|
||||
- cmake .. -DOGRE_STATIC=1 -DMYGUI_STATIC=1 -DBUILD_WITH_CODE_COVERAGE=1 -DBUILD_UNITTESTS=1
|
||||
script:
|
||||
- make -j4
|
||||
after_script:
|
||||
- ./openmw_test_suite
|
||||
notifications:
|
||||
recipients:
|
||||
- lgromanowski+travis.ci@gmail.com
|
||||
email:
|
||||
on_success: change
|
||||
on_failure: always
|
@ -1,123 +0,0 @@
|
||||
Bitstream Vera Fonts Copyright
|
||||
|
||||
The fonts have a generous copyright, allowing derivative works (as
|
||||
long as "Bitstream" or "Vera" are not in the names), and full
|
||||
redistribution (so long as they are not *sold* by themselves). They
|
||||
can be be bundled, redistributed and sold with any software.
|
||||
|
||||
The fonts are distributed under the following copyright:
|
||||
|
||||
Copyright
|
||||
=========
|
||||
|
||||
Copyright (c) 2003 by Bitstream, Inc. All Rights Reserved. Bitstream
|
||||
Vera is a trademark of Bitstream, Inc.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of the fonts accompanying this license ("Fonts") and associated
|
||||
documentation files (the "Font Software"), to reproduce and distribute
|
||||
the Font Software, including without limitation the rights to use,
|
||||
copy, merge, publish, distribute, and/or sell copies of the Font
|
||||
Software, and to permit persons to whom the Font Software is furnished
|
||||
to do so, subject to the following conditions:
|
||||
|
||||
The above copyright and trademark notices and this permission notice
|
||||
shall be included in all copies of one or more of the Font Software
|
||||
typefaces.
|
||||
|
||||
The Font Software may be modified, altered, or added to, and in
|
||||
particular the designs of glyphs or characters in the Fonts may be
|
||||
modified and additional glyphs or characters may be added to the
|
||||
Fonts, only if the fonts are renamed to names not containing either
|
||||
the words "Bitstream" or the word "Vera".
|
||||
|
||||
This License becomes null and void to the extent applicable to Fonts
|
||||
or Font Software that has been modified and is distributed under the
|
||||
"Bitstream Vera" names.
|
||||
|
||||
The Font Software may be sold as part of a larger software package but
|
||||
no copy of one or more of the Font Software typefaces may be sold by
|
||||
itself.
|
||||
|
||||
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
|
||||
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL
|
||||
BITSTREAM OR THE GNOME FOUNDATION BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
OTHER LIABILITY, INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL,
|
||||
OR CONSEQUENTIAL DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
||||
OTHERWISE, ARISING FROM, OUT OF THE USE OR INABILITY TO USE THE FONT
|
||||
SOFTWARE OR FROM OTHER DEALINGS IN THE FONT SOFTWARE.
|
||||
|
||||
Except as contained in this notice, the names of Gnome, the Gnome
|
||||
Foundation, and Bitstream Inc., shall not be used in advertising or
|
||||
otherwise to promote the sale, use or other dealings in this Font
|
||||
Software without prior written authorization from the Gnome Foundation
|
||||
or Bitstream Inc., respectively. For further information, contact:
|
||||
fonts at gnome dot org.
|
||||
|
||||
Copyright FAQ
|
||||
=============
|
||||
|
||||
1. I don't understand the resale restriction... What gives?
|
||||
|
||||
Bitstream is giving away these fonts, but wishes to ensure its
|
||||
competitors can't just drop the fonts as is into a font sale system
|
||||
and sell them as is. It seems fair that if Bitstream can't make money
|
||||
from the Bitstream Vera fonts, their competitors should not be able to
|
||||
do so either. You can sell the fonts as part of any software package,
|
||||
however.
|
||||
|
||||
2. I want to package these fonts separately for distribution and
|
||||
sale as part of a larger software package or system. Can I do so?
|
||||
|
||||
Yes. A RPM or Debian package is a "larger software package" to begin
|
||||
with, and you aren't selling them independently by themselves.
|
||||
See 1. above.
|
||||
|
||||
3. Are derivative works allowed?
|
||||
Yes!
|
||||
|
||||
4. Can I change or add to the font(s)?
|
||||
Yes, but you must change the name(s) of the font(s).
|
||||
|
||||
5. Under what terms are derivative works allowed?
|
||||
|
||||
You must change the name(s) of the fonts. This is to ensure the
|
||||
quality of the fonts, both to protect Bitstream and Gnome. We want to
|
||||
ensure that if an application has opened a font specifically of these
|
||||
names, it gets what it expects (though of course, using fontconfig,
|
||||
substitutions could still could have occurred during font
|
||||
opening). You must include the Bitstream copyright. Additional
|
||||
copyrights can be added, as per copyright law. Happy Font Hacking!
|
||||
|
||||
6. If I have improvements for Bitstream Vera, is it possible they might get
|
||||
adopted in future versions?
|
||||
|
||||
Yes. The contract between the Gnome Foundation and Bitstream has
|
||||
provisions for working with Bitstream to ensure quality additions to
|
||||
the Bitstream Vera font family. Please contact us if you have such
|
||||
additions. Note, that in general, we will want such additions for the
|
||||
entire family, not just a single font, and that you'll have to keep
|
||||
both Gnome and Jim Lyles, Vera's designer, happy! To make sense to add
|
||||
glyphs to the font, they must be stylistically in keeping with Vera's
|
||||
design. Vera cannot become a "ransom note" font. Jim Lyles will be
|
||||
providing a document describing the design elements used in Vera, as a
|
||||
guide and aid for people interested in contributing to Vera.
|
||||
|
||||
7. I want to sell a software package that uses these fonts: Can I do so?
|
||||
|
||||
Sure. Bundle the fonts with your software and sell your software
|
||||
with the fonts. That is the intent of the copyright.
|
||||
|
||||
8. If applications have built the names "Bitstream Vera" into them,
|
||||
can I override this somehow to use fonts of my choosing?
|
||||
|
||||
This depends on exact details of the software. Most open source
|
||||
systems and software (e.g., Gnome, KDE, etc.) are now converting to
|
||||
use fontconfig (see www.fontconfig.org) to handle font configuration,
|
||||
selection and substitution; it has provisions for overriding font
|
||||
names and subsituting alternatives. An example is provided by the
|
||||
supplied local.conf file, which chooses the family Bitstream Vera for
|
||||
"sans", "serif" and "monospace". Other software (e.g., the XFree86
|
||||
core server) has other mechanisms for font substitution.
|
@ -0,0 +1,99 @@
|
||||
Fonts are (c) Bitstream (see below). DejaVu changes are in public domain.
|
||||
Glyphs imported from Arev fonts are (c) Tavmjong Bah (see below)
|
||||
|
||||
Bitstream Vera Fonts Copyright
|
||||
------------------------------
|
||||
|
||||
Copyright (c) 2003 by Bitstream, Inc. All Rights Reserved. Bitstream Vera is
|
||||
a trademark of Bitstream, Inc.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of the fonts accompanying this license ("Fonts") and associated
|
||||
documentation files (the "Font Software"), to reproduce and distribute the
|
||||
Font Software, including without limitation the rights to use, copy, merge,
|
||||
publish, distribute, and/or sell copies of the Font Software, and to permit
|
||||
persons to whom the Font Software is furnished to do so, subject to the
|
||||
following conditions:
|
||||
|
||||
The above copyright and trademark notices and this permission notice shall
|
||||
be included in all copies of one or more of the Font Software typefaces.
|
||||
|
||||
The Font Software may be modified, altered, or added to, and in particular
|
||||
the designs of glyphs or characters in the Fonts may be modified and
|
||||
additional glyphs or characters may be added to the Fonts, only if the fonts
|
||||
are renamed to names not containing either the words "Bitstream" or the word
|
||||
"Vera".
|
||||
|
||||
This License becomes null and void to the extent applicable to Fonts or Font
|
||||
Software that has been modified and is distributed under the "Bitstream
|
||||
Vera" names.
|
||||
|
||||
The Font Software may be sold as part of a larger software package but no
|
||||
copy of one or more of the Font Software typefaces may be sold by itself.
|
||||
|
||||
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF COPYRIGHT, PATENT,
|
||||
TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL BITSTREAM OR THE GNOME
|
||||
FOUNDATION BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, INCLUDING
|
||||
ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES,
|
||||
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
|
||||
THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM OTHER DEALINGS IN THE
|
||||
FONT SOFTWARE.
|
||||
|
||||
Except as contained in this notice, the names of Gnome, the Gnome
|
||||
Foundation, and Bitstream Inc., shall not be used in advertising or
|
||||
otherwise to promote the sale, use or other dealings in this Font Software
|
||||
without prior written authorization from the Gnome Foundation or Bitstream
|
||||
Inc., respectively. For further information, contact: fonts at gnome dot
|
||||
org.
|
||||
|
||||
Arev Fonts Copyright
|
||||
------------------------------
|
||||
|
||||
Copyright (c) 2006 by Tavmjong Bah. All Rights Reserved.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of the fonts accompanying this license ("Fonts") and
|
||||
associated documentation files (the "Font Software"), to reproduce
|
||||
and distribute the modifications to the Bitstream Vera Font Software,
|
||||
including without limitation the rights to use, copy, merge, publish,
|
||||
distribute, and/or sell copies of the Font Software, and to permit
|
||||
persons to whom the Font Software is furnished to do so, subject to
|
||||
the following conditions:
|
||||
|
||||
The above copyright and trademark notices and this permission notice
|
||||
shall be included in all copies of one or more of the Font Software
|
||||
typefaces.
|
||||
|
||||
The Font Software may be modified, altered, or added to, and in
|
||||
particular the designs of glyphs or characters in the Fonts may be
|
||||
modified and additional glyphs or characters may be added to the
|
||||
Fonts, only if the fonts are renamed to names not containing either
|
||||
the words "Tavmjong Bah" or the word "Arev".
|
||||
|
||||
This License becomes null and void to the extent applicable to Fonts
|
||||
or Font Software that has been modified and is distributed under the
|
||||
"Tavmjong Bah Arev" names.
|
||||
|
||||
The Font Software may be sold as part of a larger software package but
|
||||
no copy of one or more of the Font Software typefaces may be sold by
|
||||
itself.
|
||||
|
||||
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
|
||||
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL
|
||||
TAVMJONG BAH BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
|
||||
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
|
||||
OTHER DEALINGS IN THE FONT SOFTWARE.
|
||||
|
||||
Except as contained in this notice, the name of Tavmjong Bah shall not
|
||||
be used in advertising or otherwise to promote the sale, use or other
|
||||
dealings in this Font Software without prior written authorization
|
||||
from Tavmjong Bah. For further information, contact: tavmjong @ free
|
||||
. fr.
|
||||
|
||||
$Id: LICENSE 2133 2007-11-28 02:46:28Z lechimp $
|
@ -0,0 +1,19 @@
|
||||
set(BSATOOL
|
||||
bsatool.cpp
|
||||
)
|
||||
source_group(apps\\bsatool FILES ${BSATOOL})
|
||||
|
||||
# Main executable
|
||||
add_executable(bsatool
|
||||
${BSATOOL}
|
||||
)
|
||||
|
||||
target_link_libraries(bsatool
|
||||
${Boost_LIBRARIES}
|
||||
components
|
||||
)
|
||||
|
||||
if (BUILD_WITH_CODE_COVERAGE)
|
||||
add_definitions (--coverage)
|
||||
target_link_libraries(bsatool gcov)
|
||||
endif()
|
@ -0,0 +1,288 @@
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
#include <exception>
|
||||
|
||||
#include <boost/program_options.hpp>
|
||||
#include <boost/filesystem.hpp>
|
||||
#include <boost/filesystem/fstream.hpp>
|
||||
|
||||
#include <components/bsa/bsa_file.hpp>
|
||||
|
||||
#define BSATOOL_VERSION 1.1
|
||||
|
||||
// Create local aliases for brevity
|
||||
namespace bpo = boost::program_options;
|
||||
namespace bfs = boost::filesystem;
|
||||
|
||||
struct Arguments
|
||||
{
|
||||
std::string mode;
|
||||
std::string filename;
|
||||
std::string extractfile;
|
||||
std::string outdir;
|
||||
|
||||
bool longformat;
|
||||
bool fullpath;
|
||||
};
|
||||
|
||||
void replaceAll(std::string& str, const std::string& needle, const std::string& substitute)
|
||||
{
|
||||
int pos = str.find(needle);
|
||||
while(pos != -1)
|
||||
{
|
||||
str.replace(pos, needle.size(), substitute);
|
||||
pos = str.find(needle);
|
||||
}
|
||||
}
|
||||
|
||||
bool parseOptions (int argc, char** argv, Arguments &info)
|
||||
{
|
||||
bpo::options_description desc("Inspect and extract files from Bethesda BSA archives\n\n"
|
||||
"Usages:\n"
|
||||
" bsatool list [-l] archivefile\n"
|
||||
" List the files presents in the input archive.\n\n"
|
||||
" bsatool extract [-f] archivefile [file_to_extract] [output_directory]\n"
|
||||
" Extract a file from the input archive.\n\n"
|
||||
" bsatool extractall archivefile [output_directory]\n"
|
||||
" Extract all files from the input archive.\n\n"
|
||||
"Allowed options");
|
||||
|
||||
desc.add_options()
|
||||
("help,h", "print help message.")
|
||||
("version,v", "print version information and quit.")
|
||||
("long,l", "Include extra information in archive listing.")
|
||||
("full-path,f", "Create diretory hierarchy on file extraction "
|
||||
"(always true for extractall).")
|
||||
;
|
||||
|
||||
// input-file is hidden and used as a positional argument
|
||||
bpo::options_description hidden("Hidden Options");
|
||||
|
||||
hidden.add_options()
|
||||
( "mode,m", bpo::value<std::string>(), "bsatool mode")
|
||||
( "input-file,i", bpo::value< std::vector<std::string> >(), "input file")
|
||||
;
|
||||
|
||||
bpo::positional_options_description p;
|
||||
p.add("mode", 1).add("input-file", 3);
|
||||
|
||||
// there might be a better way to do this
|
||||
bpo::options_description all;
|
||||
all.add(desc).add(hidden);
|
||||
|
||||
bpo::variables_map variables;
|
||||
try
|
||||
{
|
||||
bpo::parsed_options valid_opts = bpo::command_line_parser(argc, argv)
|
||||
.options(all).positional(p).run();
|
||||
bpo::store(valid_opts, variables);
|
||||
}
|
||||
catch(std::exception &e)
|
||||
{
|
||||
std::cout << "ERROR parsing arguments: " << e.what() << "\n\n"
|
||||
<< desc << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
bpo::notify(variables);
|
||||
|
||||
if (variables.count ("help"))
|
||||
{
|
||||
std::cout << desc << std::endl;
|
||||
return false;
|
||||
}
|
||||
if (variables.count ("version"))
|
||||
{
|
||||
std::cout << "BSATool version " << BSATOOL_VERSION << std::endl;
|
||||
return false;
|
||||
}
|
||||
if (!variables.count("mode"))
|
||||
{
|
||||
std::cout << "ERROR: no mode specified!\n\n"
|
||||
<< desc << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
info.mode = variables["mode"].as<std::string>();
|
||||
if (!(info.mode == "list" || info.mode == "extract" || info.mode == "extractall"))
|
||||
{
|
||||
std::cout << std::endl << "ERROR: invalid mode \"" << info.mode << "\"\n\n"
|
||||
<< desc << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!variables.count("input-file"))
|
||||
{
|
||||
std::cout << "\nERROR: missing BSA archive\n\n"
|
||||
<< desc << std::endl;
|
||||
return false;
|
||||
}
|
||||
info.filename = variables["input-file"].as< std::vector<std::string> >()[0];
|
||||
|
||||
// Default output to the working directory
|
||||
info.outdir = ".";
|
||||
|
||||
if (info.mode == "extract")
|
||||
{
|
||||
if (variables["input-file"].as< std::vector<std::string> >().size() < 2)
|
||||
{
|
||||
std::cout << "\nERROR: file to extract unspecified\n\n"
|
||||
<< desc << std::endl;
|
||||
return false;
|
||||
}
|
||||
if (variables["input-file"].as< std::vector<std::string> >().size() > 1)
|
||||
info.extractfile = variables["input-file"].as< std::vector<std::string> >()[1];
|
||||
if (variables["input-file"].as< std::vector<std::string> >().size() > 2)
|
||||
info.outdir = variables["input-file"].as< std::vector<std::string> >()[2];
|
||||
}
|
||||
else if (variables["input-file"].as< std::vector<std::string> >().size() > 1)
|
||||
info.outdir = variables["input-file"].as< std::vector<std::string> >()[1];
|
||||
|
||||
info.longformat = variables.count("long");
|
||||
info.fullpath = variables.count("full-path");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int list(Bsa::BSAFile& bsa, Arguments& info);
|
||||
int extract(Bsa::BSAFile& bsa, Arguments& info);
|
||||
int extractAll(Bsa::BSAFile& bsa, Arguments& info);
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
Arguments info;
|
||||
if(!parseOptions (argc, argv, info))
|
||||
return 1;
|
||||
|
||||
// Open file
|
||||
Bsa::BSAFile bsa;
|
||||
try
|
||||
{
|
||||
bsa.open(info.filename);
|
||||
}
|
||||
catch(std::exception &e)
|
||||
{
|
||||
std::cout << "ERROR reading BSA archive '" << info.filename
|
||||
<< "'\nDetails:\n" << e.what() << std::endl;
|
||||
return 2;
|
||||
}
|
||||
|
||||
if (info.mode == "list")
|
||||
return list(bsa, info);
|
||||
else if (info.mode == "extract")
|
||||
return extract(bsa, info);
|
||||
else if (info.mode == "extractall")
|
||||
return extractAll(bsa, info);
|
||||
else
|
||||
{
|
||||
std::cout << "Unsupported mode. That is not supposed to happen." << std::endl;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
int list(Bsa::BSAFile& bsa, Arguments& info)
|
||||
{
|
||||
// List all files
|
||||
const Bsa::BSAFile::FileList &files = bsa.getList();
|
||||
for(int i=0; i<files.size(); i++)
|
||||
{
|
||||
if(info.longformat)
|
||||
{
|
||||
// Long format
|
||||
std::cout << std::setw(50) << std::left << files[i].name;
|
||||
std::cout << std::setw(8) << std::left << std::dec << files[i].fileSize;
|
||||
std::cout << "@ 0x" << std::hex << files[i].offset << std::endl;
|
||||
}
|
||||
else
|
||||
std::cout << files[i].name << std::endl;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int extract(Bsa::BSAFile& bsa, Arguments& info)
|
||||
{
|
||||
std::string archivePath = info.extractfile;
|
||||
replaceAll(archivePath, "/", "\\");
|
||||
|
||||
std::string extractPath = info.extractfile;
|
||||
replaceAll(extractPath, "\\", "/");
|
||||
|
||||
if (!bsa.exists(archivePath.c_str()))
|
||||
{
|
||||
std::cout << "ERROR: file '" << archivePath << "' not found\n";
|
||||
std::cout << "In archive: " << info.filename << std::endl;
|
||||
return 3;
|
||||
}
|
||||
|
||||
// Get the target path (the path the file will be extracted to)
|
||||
bfs::path relPath (extractPath);
|
||||
bfs::path outdir (info.outdir);
|
||||
|
||||
bfs::path target;
|
||||
if (info.fullpath)
|
||||
target = outdir / relPath;
|
||||
else
|
||||
target = outdir / relPath.filename();
|
||||
|
||||
// Create the directory hierarchy
|
||||
bfs::create_directories(target.parent_path());
|
||||
|
||||
bfs::file_status s = bfs::status(target.parent_path());
|
||||
if (!bfs::is_directory(s))
|
||||
{
|
||||
std::cout << "ERROR: " << target.parent_path() << " is not a directory." << std::endl;
|
||||
return 3;
|
||||
}
|
||||
|
||||
// Get a stream for the file to extract
|
||||
Ogre::DataStreamPtr data = bsa.getFile(archivePath.c_str());
|
||||
bfs::ofstream out(target, std::ios::binary);
|
||||
|
||||
// Write the file to disk
|
||||
std::cout << "Extracting " << info.extractfile << " to " << target << std::endl;
|
||||
out.write(data->getAsString().c_str(), data->size());
|
||||
out.close();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int extractAll(Bsa::BSAFile& bsa, Arguments& info)
|
||||
{
|
||||
// Get the list of files present in the archive
|
||||
Bsa::BSAFile::FileList list = bsa.getList();
|
||||
|
||||
// Iter on the list
|
||||
for(Bsa::BSAFile::FileList::iterator it = list.begin(); it != list.end(); ++it) {
|
||||
const char* archivePath = it->name;
|
||||
|
||||
std::string extractPath (archivePath);
|
||||
replaceAll(extractPath, "\\", "/");
|
||||
|
||||
// Get the target path (the path the file will be extracted to)
|
||||
bfs::path target (info.outdir);
|
||||
target /= extractPath;
|
||||
|
||||
// Create the directory hierarchy
|
||||
bfs::create_directories(target.parent_path());
|
||||
|
||||
bfs::file_status s = bfs::status(target.parent_path());
|
||||
if (!bfs::is_directory(s))
|
||||
{
|
||||
std::cout << "ERROR: " << target.parent_path() << " is not a directory." << std::endl;
|
||||
return 3;
|
||||
}
|
||||
|
||||
// Get a stream for the file to extract
|
||||
// (inefficient because getFile iter on the list again)
|
||||
Ogre::DataStreamPtr data = bsa.getFile(archivePath);
|
||||
bfs::ofstream out(target, std::ios::binary);
|
||||
|
||||
// Write the file to disk
|
||||
std::cout << "Extracting " << target << std::endl;
|
||||
out.write(data->getAsString().c_str(), data->size());
|
||||
out.close();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -1 +0,0 @@
|
||||
IDI_ICON1 ICON DISCARDABLE "resources/images/openmw.ico"
|
@ -1,43 +1,43 @@
|
||||
#include <QtGui>
|
||||
|
||||
#include "playpage.hpp"
|
||||
|
||||
PlayPage::PlayPage(QWidget *parent) : QWidget(parent)
|
||||
{
|
||||
QWidget *playWidget = new QWidget(this);
|
||||
playWidget->setObjectName("PlayGroup");
|
||||
playWidget->setFixedSize(QSize(425, 375));
|
||||
#include <QListView>
|
||||
|
||||
mPlayButton = new QPushButton(tr("Play"), playWidget);
|
||||
mPlayButton->setObjectName("PlayButton");
|
||||
mPlayButton->setMinimumSize(QSize(200, 50));
|
||||
#ifdef Q_OS_MAC
|
||||
#include <QPlastiqueStyle>
|
||||
#endif
|
||||
|
||||
QLabel *profileLabel = new QLabel(tr("Current Profile:"), playWidget);
|
||||
profileLabel->setObjectName("ProfileLabel");
|
||||
PlayPage::PlayPage(QWidget *parent) : QWidget(parent)
|
||||
{
|
||||
setupUi(this);
|
||||
|
||||
// Hacks to get the stylesheet look properly
|
||||
#ifdef Q_OS_MAC
|
||||
QPlastiqueStyle *style = new QPlastiqueStyle;
|
||||
mProfilesComboBox = new QComboBox(playWidget);
|
||||
mProfilesComboBox->setObjectName("ProfilesComboBox");
|
||||
mProfilesComboBox->setStyle(style);
|
||||
profilesComboBox->setStyle(style);
|
||||
#endif
|
||||
profilesComboBox->setView(new QListView());
|
||||
|
||||
QGridLayout *playLayout = new QGridLayout(playWidget);
|
||||
connect(profilesComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(slotCurrentIndexChanged(int)));
|
||||
connect(playButton, SIGNAL(clicked()), this, SLOT(slotPlayClicked()));
|
||||
|
||||
QSpacerItem *hSpacer1 = new QSpacerItem(40, 20, QSizePolicy::Expanding, QSizePolicy::Minimum);
|
||||
QSpacerItem *hSpacer2 = new QSpacerItem(40, 20, QSizePolicy::Expanding, QSizePolicy::Minimum);
|
||||
}
|
||||
|
||||
QSpacerItem *vSpacer1 = new QSpacerItem(20, 40, QSizePolicy::Minimum, QSizePolicy::Expanding);
|
||||
QSpacerItem *vSpacer2 = new QSpacerItem(20, 40, QSizePolicy::Minimum, QSizePolicy::Expanding);
|
||||
|
||||
playLayout->addWidget(mPlayButton, 1, 1, 1, 1);
|
||||
playLayout->addWidget(profileLabel, 2, 1, 1, 1);
|
||||
playLayout->addWidget(mProfilesComboBox, 3, 1, 1, 1);
|
||||
playLayout->addItem(hSpacer1, 2, 0, 1, 1);
|
||||
playLayout->addItem(hSpacer2, 2, 2, 1, 1);
|
||||
playLayout->addItem(vSpacer1, 0, 1, 1, 1);
|
||||
playLayout->addItem(vSpacer2, 4, 1, 1, 1);
|
||||
void PlayPage::setProfilesComboBoxModel(QAbstractItemModel *model)
|
||||
{
|
||||
profilesComboBox->setModel(model);
|
||||
}
|
||||
|
||||
QHBoxLayout *pageLayout = new QHBoxLayout(this);
|
||||
void PlayPage::setProfilesComboBoxIndex(int index)
|
||||
{
|
||||
profilesComboBox->setCurrentIndex(index);
|
||||
}
|
||||
|
||||
pageLayout->addWidget(playWidget);
|
||||
void PlayPage::slotCurrentIndexChanged(int index)
|
||||
{
|
||||
emit profileChanged(index);
|
||||
}
|
||||
|
||||
}
|
||||
void PlayPage::slotPlayClicked()
|
||||
{
|
||||
emit playButtonClicked();
|
||||
}
|
||||
|
@ -1,21 +0,0 @@
|
||||
<!DOCTYPE RCC><RCC version="1.0">
|
||||
<qresource prefix="/images">
|
||||
<file alias="clear.png">resources/images/clear.png</file>
|
||||
<file alias="down.png">resources/images/down.png</file>
|
||||
<file alias="openmw.png">resources/images/openmw.png</file>
|
||||
<file alias="openmw-plugin.png">resources/images/openmw-plugin.png</file>
|
||||
<file alias="openmw-header.png">resources/images/openmw-header.png</file>
|
||||
<file alias="playpage-background.png">resources/images/playpage-background.png</file>
|
||||
</qresource>
|
||||
<qresource prefix="icons/tango">
|
||||
<file alias="index.theme">resources/icons/tango/index.theme</file>
|
||||
<file alias="video-display.png">resources/icons/tango/video-display.png</file>
|
||||
<file alias="16x16/document-new.png">resources/icons/tango/document-new.png</file>
|
||||
<file alias="16x16/edit-copy.png">resources/icons/tango/edit-copy.png</file>
|
||||
<file alias="16x16/edit-delete.png">resources/icons/tango/edit-delete.png</file>
|
||||
<file alias="16x16/go-bottom.png">resources/icons/tango/go-bottom.png</file>
|
||||
<file alias="16x16/go-down.png">resources/icons/tango/go-down.png</file>
|
||||
<file alias="16x16/go-top.png">resources/icons/tango/go-top.png</file>
|
||||
<file alias="16x16/go-up.png">resources/icons/tango/go-up.png</file>
|
||||
</qresource>
|
||||
</RCC>
|
Binary file not shown.
Before Width: | Height: | Size: 644 B |
@ -0,0 +1,177 @@
|
||||
#include "gamesettings.hpp"
|
||||
|
||||
#include <QTextStream>
|
||||
#include <QDir>
|
||||
#include <QString>
|
||||
#include <QRegExp>
|
||||
#include <QMap>
|
||||
|
||||
#include <QDebug>
|
||||
|
||||
#include <components/files/configurationmanager.hpp>
|
||||
|
||||
#include <boost/version.hpp>
|
||||
/**
|
||||
* Workaround for problems with whitespaces in paths in older versions of Boost library
|
||||
*/
|
||||
#if (BOOST_VERSION <= 104600)
|
||||
namespace boost
|
||||
{
|
||||
|
||||
template<>
|
||||
inline boost::filesystem::path lexical_cast<boost::filesystem::path, std::string>(const std::string& arg)
|
||||
{
|
||||
return boost::filesystem::path(arg);
|
||||
}
|
||||
|
||||
} /* namespace boost */
|
||||
#endif /* (BOOST_VERSION <= 104600) */
|
||||
|
||||
|
||||
GameSettings::GameSettings(Files::ConfigurationManager &cfg)
|
||||
: mCfgMgr(cfg)
|
||||
{
|
||||
}
|
||||
|
||||
GameSettings::~GameSettings()
|
||||
{
|
||||
}
|
||||
|
||||
void GameSettings::validatePaths()
|
||||
{
|
||||
if (mSettings.isEmpty() || !mDataDirs.isEmpty())
|
||||
return; // Don't re-validate paths if they are already parsed
|
||||
|
||||
QStringList paths = mSettings.values(QString("data"));
|
||||
Files::PathContainer dataDirs;
|
||||
|
||||
foreach (const QString &path, paths) {
|
||||
dataDirs.push_back(Files::PathContainer::value_type(path.toStdString()));
|
||||
}
|
||||
|
||||
// Parse the data dirs to convert the tokenized paths
|
||||
mCfgMgr.processPaths(dataDirs);
|
||||
mDataDirs.clear();
|
||||
|
||||
for (Files::PathContainer::iterator it = dataDirs.begin(); it != dataDirs.end(); ++it) {
|
||||
QString path = QString::fromStdString(it->string());
|
||||
path.remove(QChar('\"'));
|
||||
|
||||
QDir dir(path);
|
||||
if (dir.exists())
|
||||
mDataDirs.append(path);
|
||||
}
|
||||
|
||||
// Do the same for data-local
|
||||
QString local = mSettings.value(QString("data-local"));
|
||||
|
||||
if (local.isEmpty())
|
||||
return;
|
||||
|
||||
dataDirs.clear();
|
||||
dataDirs.push_back(Files::PathContainer::value_type(local.toStdString()));
|
||||
|
||||
mCfgMgr.processPaths(dataDirs);
|
||||
|
||||
if (!dataDirs.empty()) {
|
||||
QString path = QString::fromStdString(dataDirs.front().string());
|
||||
path.remove(QChar('\"'));
|
||||
|
||||
QDir dir(path);
|
||||
if (dir.exists())
|
||||
mDataLocal = path;
|
||||
}
|
||||
}
|
||||
|
||||
QStringList GameSettings::values(const QString &key, const QStringList &defaultValues)
|
||||
{
|
||||
if (!mSettings.values(key).isEmpty())
|
||||
return mSettings.values(key);
|
||||
return defaultValues;
|
||||
}
|
||||
|
||||
bool GameSettings::readFile(QTextStream &stream)
|
||||
{
|
||||
QMap<QString, QString> cache;
|
||||
QRegExp keyRe("^([^=]+)\\s*=\\s*(.+)$");
|
||||
|
||||
while (!stream.atEnd()) {
|
||||
QString line = stream.readLine();
|
||||
|
||||
if (line.isEmpty() || line.startsWith("#"))
|
||||
continue;
|
||||
|
||||
if (keyRe.indexIn(line) != -1) {
|
||||
|
||||
QString key = keyRe.cap(1);
|
||||
QString value = keyRe.cap(2);
|
||||
|
||||
// Don't remove existing data entries
|
||||
if (key != QLatin1String("data"))
|
||||
mSettings.remove(key);
|
||||
|
||||
QStringList values = cache.values(key);
|
||||
values.append(mSettings.values(key));
|
||||
|
||||
if (!values.contains(value)) {
|
||||
cache.insertMulti(key, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (mSettings.isEmpty()) {
|
||||
mSettings = cache; // This is the first time we read a file
|
||||
validatePaths();
|
||||
return true;
|
||||
}
|
||||
|
||||
// Merge the changed keys with those which didn't
|
||||
mSettings.unite(cache);
|
||||
validatePaths();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool GameSettings::writeFile(QTextStream &stream)
|
||||
{
|
||||
// Iterate in reverse order to preserve insertion order
|
||||
QMapIterator<QString, QString> i(mSettings);
|
||||
i.toBack();
|
||||
|
||||
while (i.hasPrevious()) {
|
||||
i.previous();
|
||||
|
||||
if (i.key() == QLatin1String("master") || i.key() == QLatin1String("plugin"))
|
||||
continue;
|
||||
|
||||
// Quote paths with spaces
|
||||
if (i.key() == QLatin1String("data")
|
||||
|| i.key() == QLatin1String("data-local")
|
||||
|| i.key() == QLatin1String("resources"))
|
||||
{
|
||||
if (i.value().contains(QChar(' ')))
|
||||
{
|
||||
QString stripped = i.value();
|
||||
stripped.remove(QChar('\"')); // Remove quotes
|
||||
|
||||
stream << i.key() << "=\"" << stripped << "\"\n";
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
stream << i.key() << "=" << i.value() << "\n";
|
||||
|
||||
}
|
||||
|
||||
QStringList masters = mSettings.values(QString("master"));
|
||||
for (int i = masters.count(); i--;) {
|
||||
stream << "master=" << masters.at(i) << "\n";
|
||||
}
|
||||
|
||||
QStringList plugins = mSettings.values(QString("plugin"));
|
||||
for (int i = plugins.count(); i--;) {
|
||||
stream << "plugin=" << plugins.at(i) << "\n";
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
@ -0,0 +1,61 @@
|
||||
#ifndef GAMESETTINGS_HPP
|
||||
#define GAMESETTINGS_HPP
|
||||
|
||||
#include <QTextStream>
|
||||
#include <QStringList>
|
||||
#include <QString>
|
||||
#include <QMap>
|
||||
|
||||
#include <boost/filesystem/path.hpp>
|
||||
|
||||
namespace Files { typedef std::vector<boost::filesystem::path> PathContainer;
|
||||
struct ConfigurationManager;}
|
||||
|
||||
class GameSettings
|
||||
{
|
||||
public:
|
||||
GameSettings(Files::ConfigurationManager &cfg);
|
||||
~GameSettings();
|
||||
|
||||
inline QString value(const QString &key, const QString &defaultValue = QString())
|
||||
{
|
||||
return mSettings.value(key).isEmpty() ? defaultValue : mSettings.value(key);
|
||||
}
|
||||
|
||||
|
||||
inline void setValue(const QString &key, const QString &value)
|
||||
{
|
||||
mSettings.insert(key, value);
|
||||
}
|
||||
|
||||
inline void setMultiValue(const QString &key, const QString &value)
|
||||
{
|
||||
QStringList values = mSettings.values(key);
|
||||
if (!values.contains(value))
|
||||
mSettings.insertMulti(key, value);
|
||||
}
|
||||
|
||||
inline void remove(const QString &key)
|
||||
{
|
||||
mSettings.remove(key);
|
||||
}
|
||||
|
||||
inline QStringList getDataDirs() { return mDataDirs; }
|
||||
inline void addDataDir(const QString &dir) { if(!dir.isEmpty()) mDataDirs.append(dir); }
|
||||
inline QString getDataLocal() {return mDataLocal; }
|
||||
|
||||
QStringList values(const QString &key, const QStringList &defaultValues = QStringList());
|
||||
bool readFile(QTextStream &stream);
|
||||
bool writeFile(QTextStream &stream);
|
||||
|
||||
private:
|
||||
Files::ConfigurationManager &mCfgMgr;
|
||||
|
||||
void validatePaths();
|
||||
QMap<QString, QString> mSettings;
|
||||
|
||||
QStringList mDataDirs;
|
||||
QString mDataLocal;
|
||||
};
|
||||
|
||||
#endif // GAMESETTINGS_HPP
|
@ -0,0 +1,44 @@
|
||||
#include "graphicssettings.hpp"
|
||||
|
||||
#include <QTextStream>
|
||||
#include <QString>
|
||||
#include <QRegExp>
|
||||
#include <QMap>
|
||||
|
||||
GraphicsSettings::GraphicsSettings()
|
||||
{
|
||||
}
|
||||
|
||||
GraphicsSettings::~GraphicsSettings()
|
||||
{
|
||||
}
|
||||
|
||||
bool GraphicsSettings::writeFile(QTextStream &stream)
|
||||
{
|
||||
QString sectionPrefix;
|
||||
QRegExp sectionRe("([^/]+)/(.+)$");
|
||||
QMap<QString, QString> settings = SettingsBase::getSettings();
|
||||
|
||||
QMapIterator<QString, QString> i(settings);
|
||||
while (i.hasNext()) {
|
||||
i.next();
|
||||
|
||||
QString prefix;
|
||||
QString key;
|
||||
|
||||
if (sectionRe.exactMatch(i.key())) {
|
||||
prefix = sectionRe.cap(1);
|
||||
key = sectionRe.cap(2);
|
||||
}
|
||||
|
||||
if (sectionPrefix != prefix) {
|
||||
sectionPrefix = prefix;
|
||||
stream << "\n[" << prefix << "]\n";
|
||||
}
|
||||
|
||||
stream << key << " = " << i.value() << "\n";
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
}
|
@ -0,0 +1,16 @@
|
||||
#ifndef GRAPHICSSETTINGS_HPP
|
||||
#define GRAPHICSSETTINGS_HPP
|
||||
|
||||
#include "settingsbase.hpp"
|
||||
|
||||
class GraphicsSettings : public SettingsBase<QMap<QString, QString> >
|
||||
{
|
||||
public:
|
||||
GraphicsSettings();
|
||||
~GraphicsSettings();
|
||||
|
||||
bool writeFile(QTextStream &stream);
|
||||
|
||||
};
|
||||
|
||||
#endif // GRAPHICSSETTINGS_HPP
|
@ -0,0 +1,101 @@
|
||||
#include "launchersettings.hpp"
|
||||
|
||||
#include <QTextStream>
|
||||
#include <QString>
|
||||
#include <QRegExp>
|
||||
#include <QMap>
|
||||
|
||||
LauncherSettings::LauncherSettings()
|
||||
{
|
||||
}
|
||||
|
||||
LauncherSettings::~LauncherSettings()
|
||||
{
|
||||
}
|
||||
|
||||
QStringList LauncherSettings::values(const QString &key, Qt::MatchFlags flags)
|
||||
{
|
||||
QMap<QString, QString> settings = SettingsBase::getSettings();
|
||||
|
||||
if (flags == Qt::MatchExactly)
|
||||
return settings.values(key);
|
||||
|
||||
QStringList result;
|
||||
|
||||
if (flags == Qt::MatchStartsWith) {
|
||||
QStringList keys = settings.keys();
|
||||
|
||||
foreach (const QString ¤tKey, keys) {
|
||||
if (currentKey.startsWith(key))
|
||||
result.append(settings.value(currentKey));
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
QStringList LauncherSettings::subKeys(const QString &key)
|
||||
{
|
||||
QMap<QString, QString> settings = SettingsBase::getSettings();
|
||||
QStringList keys = settings.uniqueKeys();
|
||||
|
||||
QRegExp keyRe("(.+)/");
|
||||
|
||||
QStringList result;
|
||||
|
||||
foreach (const QString ¤tKey, keys) {
|
||||
|
||||
if (keyRe.indexIn(currentKey) != -1) {
|
||||
|
||||
QString prefixedKey = keyRe.cap(1);
|
||||
if(prefixedKey.startsWith(key)) {
|
||||
|
||||
QString subKey = prefixedKey.remove(key);
|
||||
if (!subKey.isEmpty())
|
||||
result.append(subKey);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
result.removeDuplicates();
|
||||
return result;
|
||||
}
|
||||
|
||||
bool LauncherSettings::writeFile(QTextStream &stream)
|
||||
{
|
||||
QString sectionPrefix;
|
||||
QRegExp sectionRe("([^/]+)/(.+)$");
|
||||
QMap<QString, QString> settings = SettingsBase::getSettings();
|
||||
|
||||
QMapIterator<QString, QString> i(settings);
|
||||
i.toBack();
|
||||
|
||||
while (i.hasPrevious()) {
|
||||
i.previous();
|
||||
|
||||
QString prefix;
|
||||
QString key;
|
||||
|
||||
if (sectionRe.exactMatch(i.key())) {
|
||||
prefix = sectionRe.cap(1);
|
||||
key = sectionRe.cap(2);
|
||||
}
|
||||
|
||||
// Get rid of legacy settings
|
||||
if (key.contains(QChar('\\')))
|
||||
continue;
|
||||
|
||||
if (key == QLatin1String("CurrentProfile"))
|
||||
continue;
|
||||
|
||||
if (sectionPrefix != prefix) {
|
||||
sectionPrefix = prefix;
|
||||
stream << "\n[" << prefix << "]\n";
|
||||
}
|
||||
|
||||
stream << key << "=" << i.value() << "\n";
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
}
|
@ -0,0 +1,19 @@
|
||||
#ifndef LAUNCHERSETTINGS_HPP
|
||||
#define LAUNCHERSETTINGS_HPP
|
||||
|
||||
#include "settingsbase.hpp"
|
||||
|
||||
class LauncherSettings : public SettingsBase<QMap<QString, QString> >
|
||||
{
|
||||
public:
|
||||
LauncherSettings();
|
||||
~LauncherSettings();
|
||||
|
||||
QStringList subKeys(const QString &key);
|
||||
QStringList values(const QString &key, Qt::MatchFlags flags = Qt::MatchExactly);
|
||||
|
||||
bool writeFile(QTextStream &stream);
|
||||
|
||||
};
|
||||
|
||||
#endif // LAUNCHERSETTINGS_HPP
|
@ -0,0 +1,99 @@
|
||||
#ifndef SETTINGSBASE_HPP
|
||||
#define SETTINGSBASE_HPP
|
||||
|
||||
#include <QTextStream>
|
||||
#include <QStringList>
|
||||
#include <QString>
|
||||
#include <QRegExp>
|
||||
#include <QMap>
|
||||
|
||||
#include <QDebug>
|
||||
|
||||
template <class Map>
|
||||
class SettingsBase
|
||||
{
|
||||
|
||||
public:
|
||||
SettingsBase() {}
|
||||
~SettingsBase() {}
|
||||
|
||||
inline QString value(const QString &key, const QString &defaultValue = QString())
|
||||
{
|
||||
return mSettings.value(key).isEmpty() ? defaultValue : mSettings.value(key);
|
||||
}
|
||||
|
||||
inline void setValue(const QString &key, const QString &value)
|
||||
{
|
||||
QStringList values = mSettings.values(key);
|
||||
if (!values.contains(value))
|
||||
mSettings.insert(key, value);
|
||||
}
|
||||
|
||||
inline void setMultiValue(const QString &key, const QString &value)
|
||||
{
|
||||
QStringList values = mSettings.values(key);
|
||||
if (!values.contains(value))
|
||||
mSettings.insertMulti(key, value);
|
||||
}
|
||||
|
||||
inline void remove(const QString &key)
|
||||
{
|
||||
mSettings.remove(key);
|
||||
}
|
||||
|
||||
Map getSettings() {return mSettings;}
|
||||
|
||||
bool readFile(QTextStream &stream)
|
||||
{
|
||||
mCache.clear();
|
||||
|
||||
QString sectionPrefix;
|
||||
|
||||
QRegExp sectionRe("^\\[([^]]+)\\]");
|
||||
QRegExp keyRe("^([^=]+)\\s*=\\s*(.+)$");
|
||||
|
||||
while (!stream.atEnd()) {
|
||||
QString line = stream.readLine();
|
||||
|
||||
if (line.isEmpty() || line.startsWith("#"))
|
||||
continue;
|
||||
|
||||
if (sectionRe.exactMatch(line)) {
|
||||
sectionPrefix = sectionRe.cap(1);
|
||||
sectionPrefix.append("/");
|
||||
continue;
|
||||
}
|
||||
|
||||
if (keyRe.indexIn(line) != -1) {
|
||||
|
||||
QString key = keyRe.cap(1);
|
||||
QString value = keyRe.cap(2);
|
||||
|
||||
if (!sectionPrefix.isEmpty())
|
||||
key.prepend(sectionPrefix);
|
||||
|
||||
mSettings.remove(key);
|
||||
|
||||
QStringList values = mCache.values(key);
|
||||
if (!values.contains(value)) {
|
||||
mCache.insertMulti(key, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (mSettings.isEmpty()) {
|
||||
mSettings = mCache; // This is the first time we read a file
|
||||
return true;
|
||||
}
|
||||
|
||||
// Merge the changed keys with those which didn't
|
||||
mSettings.unite(mCache);
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
Map mSettings;
|
||||
Map mCache;
|
||||
};
|
||||
|
||||
#endif // SETTINGSBASE_HPP
|
@ -0,0 +1,269 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
|
||||
** Contact: http://www.qt-project.org/legal
|
||||
**
|
||||
** This file is part of Qt Creator.
|
||||
**
|
||||
** Commercial License Usage
|
||||
** Licensees holding valid commercial Qt licenses may use this file in
|
||||
** accordance with the commercial license agreement provided with the
|
||||
** Software or, alternatively, in accordance with the terms contained in
|
||||
** a written agreement between you and Digia. For licensing terms and
|
||||
** conditions see http://qt.digia.com/licensing. For further information
|
||||
** use the contact form at http://qt.digia.com/contact-us.
|
||||
**
|
||||
** GNU Lesser General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU Lesser
|
||||
** General Public License version 2.1 as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.LGPL included in the
|
||||
** packaging of this file. Please review the following information to
|
||||
** ensure the GNU Lesser General Public License version 2.1 requirements
|
||||
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||
**
|
||||
** In addition, as a special exception, Digia gives you certain additional
|
||||
** rights. These rights are described in the Digia Qt LGPL Exception
|
||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#include "checkablemessagebox.hpp"
|
||||
|
||||
#include <QVariant>
|
||||
|
||||
#include <QPushButton>
|
||||
#include <QAction>
|
||||
#include <QApplication>
|
||||
#include <QButtonGroup>
|
||||
#include <QCheckBox>
|
||||
#include <QDialog>
|
||||
#include <QDialogButtonBox>
|
||||
#include <QHBoxLayout>
|
||||
#include <QHeaderView>
|
||||
#include <QLabel>
|
||||
#include <QSpacerItem>
|
||||
#include <QVBoxLayout>
|
||||
|
||||
|
||||
/*!
|
||||
\class Utils::CheckableMessageBox
|
||||
|
||||
\brief A messagebox suitable for questions with a
|
||||
"Do not ask me again" checkbox.
|
||||
|
||||
Emulates the QMessageBox API with
|
||||
static conveniences. The message label can open external URLs.
|
||||
*/
|
||||
|
||||
class CheckableMessageBoxPrivate
|
||||
{
|
||||
public:
|
||||
CheckableMessageBoxPrivate(QDialog *q)
|
||||
: clickedButton(0)
|
||||
{
|
||||
QSizePolicy sizePolicy(QSizePolicy::Minimum, QSizePolicy::Preferred);
|
||||
|
||||
pixmapLabel = new QLabel(q);
|
||||
sizePolicy.setHorizontalStretch(0);
|
||||
sizePolicy.setVerticalStretch(0);
|
||||
sizePolicy.setHeightForWidth(pixmapLabel->sizePolicy().hasHeightForWidth());
|
||||
pixmapLabel->setSizePolicy(sizePolicy);
|
||||
pixmapLabel->setVisible(false);
|
||||
|
||||
QSpacerItem *pixmapSpacer =
|
||||
new QSpacerItem(0, 5, QSizePolicy::Minimum, QSizePolicy::MinimumExpanding);
|
||||
|
||||
messageLabel = new QLabel(q);
|
||||
messageLabel->setMinimumSize(QSize(300, 0));
|
||||
messageLabel->setWordWrap(true);
|
||||
messageLabel->setOpenExternalLinks(true);
|
||||
messageLabel->setTextInteractionFlags(Qt::LinksAccessibleByKeyboard|Qt::LinksAccessibleByMouse);
|
||||
|
||||
QSpacerItem *checkBoxRightSpacer =
|
||||
new QSpacerItem(1, 1, QSizePolicy::Expanding, QSizePolicy::Minimum);
|
||||
QSpacerItem *buttonSpacer =
|
||||
new QSpacerItem(0, 1, QSizePolicy::Minimum, QSizePolicy::Minimum);
|
||||
|
||||
checkBox = new QCheckBox(q);
|
||||
checkBox->setText(CheckableMessageBox::tr("Do not ask again"));
|
||||
|
||||
buttonBox = new QDialogButtonBox(q);
|
||||
buttonBox->setOrientation(Qt::Horizontal);
|
||||
buttonBox->setStandardButtons(QDialogButtonBox::Cancel|QDialogButtonBox::Ok);
|
||||
|
||||
QVBoxLayout *verticalLayout = new QVBoxLayout();
|
||||
verticalLayout->addWidget(pixmapLabel);
|
||||
verticalLayout->addItem(pixmapSpacer);
|
||||
|
||||
QHBoxLayout *horizontalLayout_2 = new QHBoxLayout();
|
||||
horizontalLayout_2->addLayout(verticalLayout);
|
||||
horizontalLayout_2->addWidget(messageLabel);
|
||||
|
||||
QHBoxLayout *horizontalLayout = new QHBoxLayout();
|
||||
horizontalLayout->addWidget(checkBox);
|
||||
horizontalLayout->addItem(checkBoxRightSpacer);
|
||||
|
||||
QVBoxLayout *verticalLayout_2 = new QVBoxLayout(q);
|
||||
verticalLayout_2->addLayout(horizontalLayout_2);
|
||||
verticalLayout_2->addLayout(horizontalLayout);
|
||||
verticalLayout_2->addItem(buttonSpacer);
|
||||
verticalLayout_2->addWidget(buttonBox);
|
||||
}
|
||||
|
||||
QLabel *pixmapLabel;
|
||||
QLabel *messageLabel;
|
||||
QCheckBox *checkBox;
|
||||
QDialogButtonBox *buttonBox;
|
||||
QAbstractButton *clickedButton;
|
||||
};
|
||||
|
||||
CheckableMessageBox::CheckableMessageBox(QWidget *parent) :
|
||||
QDialog(parent),
|
||||
d(new CheckableMessageBoxPrivate(this))
|
||||
{
|
||||
setModal(true);
|
||||
setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
|
||||
connect(d->buttonBox, SIGNAL(accepted()), SLOT(accept()));
|
||||
connect(d->buttonBox, SIGNAL(rejected()), SLOT(reject()));
|
||||
connect(d->buttonBox, SIGNAL(clicked(QAbstractButton*)),
|
||||
SLOT(slotClicked(QAbstractButton*)));
|
||||
}
|
||||
|
||||
CheckableMessageBox::~CheckableMessageBox()
|
||||
{
|
||||
delete d;
|
||||
}
|
||||
|
||||
void CheckableMessageBox::slotClicked(QAbstractButton *b)
|
||||
{
|
||||
d->clickedButton = b;
|
||||
}
|
||||
|
||||
QAbstractButton *CheckableMessageBox::clickedButton() const
|
||||
{
|
||||
return d->clickedButton;
|
||||
}
|
||||
|
||||
QDialogButtonBox::StandardButton CheckableMessageBox::clickedStandardButton() const
|
||||
{
|
||||
if (d->clickedButton)
|
||||
return d->buttonBox->standardButton(d->clickedButton);
|
||||
return QDialogButtonBox::NoButton;
|
||||
}
|
||||
|
||||
QString CheckableMessageBox::text() const
|
||||
{
|
||||
return d->messageLabel->text();
|
||||
}
|
||||
|
||||
void CheckableMessageBox::setText(const QString &t)
|
||||
{
|
||||
d->messageLabel->setText(t);
|
||||
}
|
||||
|
||||
QPixmap CheckableMessageBox::iconPixmap() const
|
||||
{
|
||||
if (const QPixmap *p = d->pixmapLabel->pixmap())
|
||||
return QPixmap(*p);
|
||||
return QPixmap();
|
||||
}
|
||||
|
||||
void CheckableMessageBox::setIconPixmap(const QPixmap &p)
|
||||
{
|
||||
d->pixmapLabel->setPixmap(p);
|
||||
d->pixmapLabel->setVisible(!p.isNull());
|
||||
}
|
||||
|
||||
bool CheckableMessageBox::isChecked() const
|
||||
{
|
||||
return d->checkBox->isChecked();
|
||||
}
|
||||
|
||||
void CheckableMessageBox::setChecked(bool s)
|
||||
{
|
||||
d->checkBox->setChecked(s);
|
||||
}
|
||||
|
||||
QString CheckableMessageBox::checkBoxText() const
|
||||
{
|
||||
return d->checkBox->text();
|
||||
}
|
||||
|
||||
void CheckableMessageBox::setCheckBoxText(const QString &t)
|
||||
{
|
||||
d->checkBox->setText(t);
|
||||
}
|
||||
|
||||
bool CheckableMessageBox::isCheckBoxVisible() const
|
||||
{
|
||||
return d->checkBox->isVisible();
|
||||
}
|
||||
|
||||
void CheckableMessageBox::setCheckBoxVisible(bool v)
|
||||
{
|
||||
d->checkBox->setVisible(v);
|
||||
}
|
||||
|
||||
QDialogButtonBox::StandardButtons CheckableMessageBox::standardButtons() const
|
||||
{
|
||||
return d->buttonBox->standardButtons();
|
||||
}
|
||||
|
||||
void CheckableMessageBox::setStandardButtons(QDialogButtonBox::StandardButtons s)
|
||||
{
|
||||
d->buttonBox->setStandardButtons(s);
|
||||
}
|
||||
|
||||
QPushButton *CheckableMessageBox::button(QDialogButtonBox::StandardButton b) const
|
||||
{
|
||||
return d->buttonBox->button(b);
|
||||
}
|
||||
|
||||
QPushButton *CheckableMessageBox::addButton(const QString &text, QDialogButtonBox::ButtonRole role)
|
||||
{
|
||||
return d->buttonBox->addButton(text, role);
|
||||
}
|
||||
|
||||
QDialogButtonBox::StandardButton CheckableMessageBox::defaultButton() const
|
||||
{
|
||||
foreach (QAbstractButton *b, d->buttonBox->buttons())
|
||||
if (QPushButton *pb = qobject_cast<QPushButton *>(b))
|
||||
if (pb->isDefault())
|
||||
return d->buttonBox->standardButton(pb);
|
||||
return QDialogButtonBox::NoButton;
|
||||
}
|
||||
|
||||
void CheckableMessageBox::setDefaultButton(QDialogButtonBox::StandardButton s)
|
||||
{
|
||||
if (QPushButton *b = d->buttonBox->button(s)) {
|
||||
b->setDefault(true);
|
||||
b->setFocus();
|
||||
}
|
||||
}
|
||||
|
||||
QDialogButtonBox::StandardButton
|
||||
CheckableMessageBox::question(QWidget *parent,
|
||||
const QString &title,
|
||||
const QString &question,
|
||||
const QString &checkBoxText,
|
||||
bool *checkBoxSetting,
|
||||
QDialogButtonBox::StandardButtons buttons,
|
||||
QDialogButtonBox::StandardButton defaultButton)
|
||||
{
|
||||
CheckableMessageBox mb(parent);
|
||||
mb.setWindowTitle(title);
|
||||
mb.setIconPixmap(QMessageBox::standardIcon(QMessageBox::Question));
|
||||
mb.setText(question);
|
||||
mb.setCheckBoxText(checkBoxText);
|
||||
mb.setChecked(*checkBoxSetting);
|
||||
mb.setStandardButtons(buttons);
|
||||
mb.setDefaultButton(defaultButton);
|
||||
mb.exec();
|
||||
*checkBoxSetting = mb.isChecked();
|
||||
return mb.clickedStandardButton();
|
||||
}
|
||||
|
||||
QMessageBox::StandardButton CheckableMessageBox::dialogButtonBoxToMessageBoxButton(QDialogButtonBox::StandardButton db)
|
||||
{
|
||||
return static_cast<QMessageBox::StandardButton>(int(db));
|
||||
}
|
@ -0,0 +1,100 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
|
||||
** Contact: http://www.qt-project.org/legal
|
||||
**
|
||||
** This file is part of Qt Creator.
|
||||
**
|
||||
** Commercial License Usage
|
||||
** Licensees holding valid commercial Qt licenses may use this file in
|
||||
** accordance with the commercial license agreement provided with the
|
||||
** Software or, alternatively, in accordance with the terms contained in
|
||||
** a written agreement between you and Digia. For licensing terms and
|
||||
** conditions see http://qt.digia.com/licensing. For further information
|
||||
** use the contact form at http://qt.digia.com/contact-us.
|
||||
**
|
||||
** GNU Lesser General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU Lesser
|
||||
** General Public License version 2.1 as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.LGPL included in the
|
||||
** packaging of this file. Please review the following information to
|
||||
** ensure the GNU Lesser General Public License version 2.1 requirements
|
||||
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||
**
|
||||
** In addition, as a special exception, Digia gives you certain additional
|
||||
** rights. These rights are described in the Digia Qt LGPL Exception
|
||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef CHECKABLEMESSAGEBOX_HPP
|
||||
#define CHECKABLEMESSAGEBOX_HPP
|
||||
|
||||
#include <QDialogButtonBox>
|
||||
#include <QMessageBox>
|
||||
#include <QDialog>
|
||||
|
||||
class CheckableMessageBoxPrivate;
|
||||
|
||||
class CheckableMessageBox : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(QString text READ text WRITE setText)
|
||||
Q_PROPERTY(QPixmap iconPixmap READ iconPixmap WRITE setIconPixmap)
|
||||
Q_PROPERTY(bool isChecked READ isChecked WRITE setChecked)
|
||||
Q_PROPERTY(QString checkBoxText READ checkBoxText WRITE setCheckBoxText)
|
||||
Q_PROPERTY(QDialogButtonBox::StandardButtons buttons READ standardButtons WRITE setStandardButtons)
|
||||
Q_PROPERTY(QDialogButtonBox::StandardButton defaultButton READ defaultButton WRITE setDefaultButton)
|
||||
|
||||
public:
|
||||
explicit CheckableMessageBox(QWidget *parent);
|
||||
virtual ~CheckableMessageBox();
|
||||
|
||||
static QDialogButtonBox::StandardButton
|
||||
question(QWidget *parent,
|
||||
const QString &title,
|
||||
const QString &question,
|
||||
const QString &checkBoxText,
|
||||
bool *checkBoxSetting,
|
||||
QDialogButtonBox::StandardButtons buttons = QDialogButtonBox::Yes|QDialogButtonBox::No,
|
||||
QDialogButtonBox::StandardButton defaultButton = QDialogButtonBox::No);
|
||||
|
||||
QString text() const;
|
||||
void setText(const QString &);
|
||||
|
||||
bool isChecked() const;
|
||||
void setChecked(bool s);
|
||||
|
||||
QString checkBoxText() const;
|
||||
void setCheckBoxText(const QString &);
|
||||
|
||||
bool isCheckBoxVisible() const;
|
||||
void setCheckBoxVisible(bool);
|
||||
|
||||
QDialogButtonBox::StandardButtons standardButtons() const;
|
||||
void setStandardButtons(QDialogButtonBox::StandardButtons s);
|
||||
QPushButton *button(QDialogButtonBox::StandardButton b) const;
|
||||
QPushButton *addButton(const QString &text, QDialogButtonBox::ButtonRole role);
|
||||
|
||||
QDialogButtonBox::StandardButton defaultButton() const;
|
||||
void setDefaultButton(QDialogButtonBox::StandardButton s);
|
||||
|
||||
// See static QMessageBox::standardPixmap()
|
||||
QPixmap iconPixmap() const;
|
||||
void setIconPixmap (const QPixmap &p);
|
||||
|
||||
// Query the result
|
||||
QAbstractButton *clickedButton() const;
|
||||
QDialogButtonBox::StandardButton clickedStandardButton() const;
|
||||
|
||||
// Conversion convenience
|
||||
static QMessageBox::StandardButton dialogButtonBoxToMessageBoxButton(QDialogButtonBox::StandardButton);
|
||||
|
||||
private slots:
|
||||
void slotClicked(QAbstractButton *b);
|
||||
|
||||
private:
|
||||
CheckableMessageBoxPrivate *d;
|
||||
};
|
||||
|
||||
#endif // CHECKABLEMESSAGEBOX_HPP
|
@ -1,57 +0,0 @@
|
||||
#include "filedialog.hpp"
|
||||
#include <QDialogButtonBox>
|
||||
#include <QPushButton>
|
||||
|
||||
FileDialog::FileDialog(QWidget *parent)
|
||||
: QFileDialog(parent)
|
||||
{
|
||||
// Remove the default Choose button to prevent it being updated elsewhere
|
||||
QDialogButtonBox *box = qFindChild<QDialogButtonBox*>(this);
|
||||
Q_ASSERT(box);
|
||||
box->removeButton(box->button(QDialogButtonBox::Open));
|
||||
|
||||
// Add our own button so we can disable/enable it
|
||||
mChooseButton = new QPushButton(tr("&Choose"));
|
||||
mChooseButton->setIcon(QIcon::fromTheme("document-open"));
|
||||
mChooseButton->setEnabled(false);
|
||||
box->addButton(mChooseButton, QDialogButtonBox::AcceptRole);
|
||||
|
||||
connect(this, SIGNAL(directoryEntered(const QString&)), this, SLOT(updateChooseButton(const QString&)));
|
||||
emit directoryEntered(QDir::currentPath());
|
||||
}
|
||||
|
||||
QString FileDialog::getExistingDirectory(QWidget *parent,
|
||||
const QString &caption,
|
||||
const QString &dir,
|
||||
Options options)
|
||||
{
|
||||
// create a non-native file dialog
|
||||
FileDialog dialog;
|
||||
dialog.setFileMode(DirectoryOnly);
|
||||
dialog.setOptions(options |= QFileDialog::DontUseNativeDialog | QFileDialog::ShowDirsOnly | QFileDialog::ReadOnly);
|
||||
|
||||
if (!caption.isEmpty())
|
||||
dialog.setWindowTitle(caption);
|
||||
|
||||
if (!dir.isEmpty())
|
||||
dialog.setDirectory(dir);
|
||||
|
||||
if (dialog.exec() == QDialog::Accepted) {
|
||||
return dialog.selectedFiles().value(0);
|
||||
}
|
||||
return QString();
|
||||
}
|
||||
|
||||
void FileDialog::updateChooseButton(const QString &directory)
|
||||
{
|
||||
QDir currentDir = QDir(directory);
|
||||
currentDir.setFilter(QDir::Files | QDir::Hidden | QDir::NoSymLinks);
|
||||
currentDir.setNameFilters(QStringList() << "*.esm" << "*.esp");
|
||||
|
||||
if (!currentDir.entryList().isEmpty()) {
|
||||
// There are data files in the current dir
|
||||
mChooseButton->setEnabled(true);
|
||||
} else {
|
||||
mChooseButton->setEnabled(false);
|
||||
}
|
||||
}
|
@ -1,28 +0,0 @@
|
||||
#ifndef FILEDIALOG_HPP
|
||||
#define FILEDIALOG_HPP
|
||||
|
||||
#include <QFileDialog>
|
||||
|
||||
class QPushButton;
|
||||
|
||||
class FileDialog : public QFileDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
FileDialog(QWidget *parent = 0);
|
||||
|
||||
static QString getExistingDirectory(QWidget *parent = 0,
|
||||
const QString &caption = QString(),
|
||||
const QString &dir = QString(),
|
||||
Options options = ShowDirsOnly);
|
||||
|
||||
private slots:
|
||||
void updateChooseButton(const QString &directory);
|
||||
|
||||
private:
|
||||
QPushButton *mChooseButton;
|
||||
};
|
||||
|
||||
|
||||
#endif // FILEDIALOG_HPP
|
@ -1,52 +0,0 @@
|
||||
#include <QRegExpValidator>
|
||||
#include <QLineEdit>
|
||||
#include <QString>
|
||||
|
||||
#include "profilescombobox.hpp"
|
||||
|
||||
ProfilesComboBox::ProfilesComboBox(QWidget *parent) :
|
||||
QComboBox(parent)
|
||||
{
|
||||
mValidator = new QRegExpValidator(QRegExp("^[a-zA-Z0-9_]*$"), this); // Alpha-numeric + underscore
|
||||
|
||||
setEditable(true);
|
||||
setValidator(mValidator);
|
||||
setCompleter(0);
|
||||
|
||||
connect(this, SIGNAL(currentIndexChanged(int)), this,
|
||||
SLOT(slotIndexChanged(int)));
|
||||
connect(lineEdit(), SIGNAL(returnPressed()), this,
|
||||
SLOT(slotReturnPressed()));
|
||||
}
|
||||
|
||||
void ProfilesComboBox::setEditEnabled(bool editable)
|
||||
{
|
||||
if (!editable)
|
||||
return setEditable(false);
|
||||
|
||||
// Reset the completer and validator
|
||||
setEditable(true);
|
||||
setValidator(mValidator);
|
||||
setCompleter(0);
|
||||
}
|
||||
|
||||
void ProfilesComboBox::slotReturnPressed()
|
||||
{
|
||||
QString current = currentText();
|
||||
QString previous = itemText(currentIndex());
|
||||
|
||||
if (findText(current) != -1)
|
||||
return;
|
||||
|
||||
setItemText(currentIndex(), current);
|
||||
emit(profileRenamed(previous, current));
|
||||
}
|
||||
|
||||
void ProfilesComboBox::slotIndexChanged(int index)
|
||||
{
|
||||
if (index == -1)
|
||||
return;
|
||||
|
||||
emit(profileChanged(mOldProfile, currentText()));
|
||||
mOldProfile = itemText(index);
|
||||
}
|
@ -1,49 +1,119 @@
|
||||
|
||||
#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)
|
||||
CS::Editor::Editor() : mViewManager (mDocumentManager)
|
||||
{
|
||||
connect (&mViewManager, SIGNAL (newDocumentRequest ()), this, SLOT (createDocument ()));
|
||||
connect (&mViewManager, SIGNAL (loadDocumentRequest ()), this, SLOT (loadDocument ()));
|
||||
|
||||
connect (&mStartup, SIGNAL (createDocument()), this, SLOT (createDocument ()));
|
||||
connect (&mStartup, SIGNAL (loadDocument()), this, SLOT (loadDocument ()));
|
||||
|
||||
connect (&mFileDialog, SIGNAL(openFiles()), this, SLOT(openFiles()));
|
||||
connect (&mFileDialog, SIGNAL(createNewFile()), this, SLOT(createNewFile()));
|
||||
|
||||
setupDataFiles();
|
||||
}
|
||||
|
||||
void CS::Editor::createDocument()
|
||||
void CS::Editor::setupDataFiles()
|
||||
{
|
||||
std::ostringstream stream;
|
||||
boost::program_options::variables_map variables;
|
||||
boost::program_options::options_description desc;
|
||||
|
||||
stream << "NewDocument" << (++mNewDocumentIndex);
|
||||
desc.add_options()
|
||||
("data", boost::program_options::value<Files::PathContainer>()->default_value(Files::PathContainer(), "data")->multitoken())
|
||||
("data-local", boost::program_options::value<std::string>()->default_value(""))
|
||||
("fs-strict", boost::program_options::value<bool>()->implicit_value(true)->default_value(false))
|
||||
("encoding", boost::program_options::value<std::string>()->default_value("win1252"));
|
||||
|
||||
CSMDoc::Document *document = mDocumentManager.addDocument (stream.str());
|
||||
boost::program_options::notify(variables);
|
||||
|
||||
static const char *sGlobals[] =
|
||||
{
|
||||
"Day", "DaysPassed", "GameHour", "Month", "PCRace", "PCVampire", "PCWerewolf", "PCYear", 0
|
||||
};
|
||||
mCfgMgr.readConfiguration(variables, desc);
|
||||
|
||||
Files::PathContainer mDataDirs, mDataLocal;
|
||||
if (!variables["data"].empty()) {
|
||||
mDataDirs = Files::PathContainer(variables["data"].as<Files::PathContainer>());
|
||||
}
|
||||
|
||||
std::string local = variables["data-local"].as<std::string>();
|
||||
if (!local.empty()) {
|
||||
mDataLocal.push_back(Files::PathContainer::value_type(local));
|
||||
}
|
||||
|
||||
for (int i=0; sGlobals[i]; ++i)
|
||||
mCfgMgr.processPaths(mDataDirs);
|
||||
mCfgMgr.processPaths(mDataLocal);
|
||||
|
||||
// Set the charset for reading the esm/esp files
|
||||
QString encoding = QString::fromStdString(variables["encoding"].as<std::string>());
|
||||
mFileDialog.setEncoding(encoding);
|
||||
|
||||
Files::PathContainer dataDirs;
|
||||
dataDirs.insert(dataDirs.end(), mDataDirs.begin(), mDataDirs.end());
|
||||
dataDirs.insert(dataDirs.end(), mDataLocal.begin(), mDataLocal.end());
|
||||
|
||||
for (Files::PathContainer::const_iterator iter = dataDirs.begin(); iter != dataDirs.end(); ++iter)
|
||||
{
|
||||
ESM::Global record;
|
||||
record.mId = sGlobals[i];
|
||||
record.mValue = i==0 ? 1 : 0;
|
||||
record.mType = ESM::VT_Float;
|
||||
document->getData().getGlobals().add (record);
|
||||
QString path = QString::fromStdString(iter->string());
|
||||
mFileDialog.addFiles(path);
|
||||
}
|
||||
}
|
||||
|
||||
void CS::Editor::createDocument()
|
||||
{
|
||||
mStartup.hide();
|
||||
|
||||
mFileDialog.newFile();
|
||||
}
|
||||
|
||||
void CS::Editor::loadDocument()
|
||||
{
|
||||
mStartup.hide();
|
||||
|
||||
mFileDialog.openFile();
|
||||
}
|
||||
|
||||
void CS::Editor::openFiles()
|
||||
{
|
||||
std::vector<boost::filesystem::path> files;
|
||||
QStringList paths = mFileDialog.checkedItemsPaths();
|
||||
|
||||
foreach (const QString &path, paths) {
|
||||
files.push_back(path.toStdString());
|
||||
}
|
||||
|
||||
document->getData().merge(); /// \todo remove once proper ESX loading is implemented
|
||||
CSMDoc::Document *document = mDocumentManager.addDocument(files, false);
|
||||
|
||||
mViewManager.addView (document);
|
||||
mFileDialog.hide();
|
||||
}
|
||||
|
||||
void CS::Editor::createNewFile()
|
||||
{
|
||||
std::vector<boost::filesystem::path> files;
|
||||
QStringList paths = mFileDialog.checkedItemsPaths();
|
||||
|
||||
foreach (const QString &path, paths) {
|
||||
files.push_back(path.toStdString());
|
||||
}
|
||||
|
||||
files.push_back(mFileDialog.fileName().toStdString());
|
||||
|
||||
CSMDoc::Document *document = mDocumentManager.addDocument (files, true);
|
||||
|
||||
mViewManager.addView (document);
|
||||
mFileDialog.hide();
|
||||
}
|
||||
|
||||
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();
|
||||
mStartup.show();
|
||||
|
||||
QApplication::setQuitOnLastWindowClosed (true);
|
||||
|
||||
return QApplication::exec();
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,82 @@
|
||||
#include "settingcontainer.hpp"
|
||||
|
||||
#include <QStringList>
|
||||
|
||||
CSMSettings::SettingContainer::SettingContainer(QObject *parent) :
|
||||
QObject(parent), mValue (0), mValues (0)
|
||||
{
|
||||
}
|
||||
|
||||
CSMSettings::SettingContainer::SettingContainer(const QString &value, QObject *parent) :
|
||||
QObject(parent), mValue (new QString (value)), mValues (0)
|
||||
{
|
||||
}
|
||||
|
||||
void CSMSettings::SettingContainer::insert (const QString &value)
|
||||
{
|
||||
if (mValue)
|
||||
{
|
||||
mValues = new QStringList;
|
||||
mValues->push_back (*mValue);
|
||||
mValues->push_back (value);
|
||||
|
||||
delete mValue;
|
||||
mValue = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
delete mValue;
|
||||
mValue = new QString (value);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void CSMSettings::SettingContainer::update (const QString &value, int index)
|
||||
{
|
||||
if (isEmpty())
|
||||
mValue = new QString(value);
|
||||
|
||||
else if (mValue)
|
||||
*mValue = value;
|
||||
|
||||
else if (mValues)
|
||||
mValues->replace(index, value);
|
||||
}
|
||||
|
||||
QString CSMSettings::SettingContainer::getValue (int index) const
|
||||
{
|
||||
QString retVal("");
|
||||
|
||||
//if mValue is valid, it's a single-value property.
|
||||
//ignore the index and return the value
|
||||
if (mValue)
|
||||
retVal = *mValue;
|
||||
|
||||
//otherwise, if it's a multivalued property
|
||||
//return the appropriate value at the index
|
||||
else if (mValues)
|
||||
{
|
||||
if (index == -1)
|
||||
retVal = mValues->at(0);
|
||||
|
||||
else if (index < mValues->size())
|
||||
retVal = mValues->at(index);
|
||||
}
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
||||
int CSMSettings::SettingContainer::count () const
|
||||
{
|
||||
int retVal = 0;
|
||||
|
||||
if (!isEmpty())
|
||||
{
|
||||
if (mValues)
|
||||
retVal = mValues->size();
|
||||
else
|
||||
retVal = 1;
|
||||
}
|
||||
|
||||
return retVal;
|
||||
}
|
@ -0,0 +1,37 @@
|
||||
#ifndef SETTINGCONTAINER_HPP
|
||||
#define SETTINGCONTAINER_HPP
|
||||
|
||||
#include <QObject>
|
||||
|
||||
class QStringList;
|
||||
|
||||
namespace CSMSettings
|
||||
{
|
||||
class SettingContainer : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
QString *mValue;
|
||||
QStringList *mValues;
|
||||
|
||||
public:
|
||||
explicit SettingContainer (QObject *parent = 0);
|
||||
explicit SettingContainer (const QString &value, QObject *parent = 0);
|
||||
|
||||
virtual QString getName() const {return "";}
|
||||
|
||||
void insert (const QString &value);
|
||||
void update (const QString &value, int index = 0);
|
||||
|
||||
QString getValue (int index = -1) const;
|
||||
inline QStringList *getValues() const { return mValues; }
|
||||
int count() const;
|
||||
|
||||
//test for empty container
|
||||
//useful for default-constructed containers returned by QMap when invalid key is passed
|
||||
inline bool isEmpty() const { return (!mValue && !mValues); }
|
||||
inline bool isMultiValue() const { return (mValues); }
|
||||
};
|
||||
}
|
||||
|
||||
#endif // SETTINGCONTAINER_HPP
|
@ -0,0 +1,102 @@
|
||||
#include "settingsitem.hpp"
|
||||
|
||||
bool CSMSettings::SettingsItem::updateItem (const QStringList *values)
|
||||
{
|
||||
QStringList::ConstIterator it = values->begin();
|
||||
|
||||
//if the item is not multivalued,
|
||||
//save the last value passed in the container
|
||||
if (!mIsMultiValue)
|
||||
{
|
||||
it = values->end();
|
||||
it--;
|
||||
}
|
||||
|
||||
bool isValid = true;
|
||||
QString value ("");
|
||||
|
||||
for (; it != values->end(); ++it)
|
||||
{
|
||||
value = *it;
|
||||
isValid = validate(value);
|
||||
|
||||
//skip only the invalid values
|
||||
if (!isValid)
|
||||
continue;
|
||||
|
||||
insert(value);
|
||||
}
|
||||
|
||||
return isValid;
|
||||
}
|
||||
|
||||
bool CSMSettings::SettingsItem::updateItem (const QString &value)
|
||||
{
|
||||
//takes a value or a SettingsContainer and updates itself accordingly
|
||||
//after validating the data against it's own definition
|
||||
|
||||
QString newValue = value;
|
||||
|
||||
if (!validate (newValue))
|
||||
newValue = mDefaultValue;
|
||||
|
||||
bool success = (getValue() != newValue);
|
||||
|
||||
if (success)
|
||||
{
|
||||
if (mIsMultiValue)
|
||||
insert (newValue);
|
||||
else
|
||||
update (newValue);
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
bool CSMSettings::SettingsItem::updateItem(int valueListIndex)
|
||||
{
|
||||
bool success = false;
|
||||
|
||||
if (mValueList)
|
||||
{
|
||||
if (mValueList->size() > valueListIndex)
|
||||
success = updateItem (mValueList->at(valueListIndex));
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
bool CSMSettings::SettingsItem::validate (const QString &value)
|
||||
{
|
||||
bool isValid = true;
|
||||
|
||||
//validation required only if a value list or min/max value pair has been provided
|
||||
if (mValueList->size()>0)
|
||||
{
|
||||
for (QStringList::ConstIterator it = mValueList->begin(); it !=mValueList->end(); ++it)
|
||||
{
|
||||
isValid = ( value == *it);
|
||||
|
||||
if (isValid)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
else if (mValuePair)
|
||||
{
|
||||
int numVal = value.toInt();
|
||||
|
||||
isValid = (numVal > mValuePair->left.toInt() && numVal < mValuePair->right.toInt());
|
||||
}
|
||||
|
||||
return isValid;
|
||||
}
|
||||
|
||||
void CSMSettings::SettingsItem::setDefaultValue (const QString &value)
|
||||
{
|
||||
mDefaultValue = value;
|
||||
update (value);
|
||||
}
|
||||
|
||||
QString CSMSettings::SettingsItem::getDefaultValue() const
|
||||
{
|
||||
return mDefaultValue;
|
||||
}
|
@ -0,0 +1,47 @@
|
||||
#ifndef SETTINGSITEM_HPP
|
||||
#define SETTINGSITEM_HPP
|
||||
|
||||
#include <QObject>
|
||||
#include "support.hpp"
|
||||
#include "settingcontainer.hpp"
|
||||
|
||||
namespace CSMSettings
|
||||
{
|
||||
class SettingsItem : public SettingContainer
|
||||
{
|
||||
QStringPair *mValuePair;
|
||||
QStringList *mValueList;
|
||||
bool mIsMultiValue;
|
||||
QString mName;
|
||||
QString mDefaultValue;
|
||||
|
||||
public:
|
||||
explicit SettingsItem(QString name, bool isMultiValue,
|
||||
const QString& defaultValue, QObject *parent = 0)
|
||||
: SettingContainer(defaultValue, parent),
|
||||
mIsMultiValue (isMultiValue), mValueList (0),
|
||||
mName (name), mValuePair (0), mDefaultValue (defaultValue)
|
||||
{}
|
||||
|
||||
bool updateItem (const QStringList *values);
|
||||
bool updateItem (const QString &value);
|
||||
bool updateItem (int valueListIndex);
|
||||
|
||||
inline QStringList *getValueList() { return mValueList; }
|
||||
inline void setValueList (QStringList *valueList) { mValueList = valueList; }
|
||||
|
||||
inline QStringPair *getValuePair() { return mValuePair; }
|
||||
inline void setValuePair (QStringPair valuePair) { mValuePair = new QStringPair(valuePair); }
|
||||
|
||||
inline QString getName () const { return mName; }
|
||||
inline bool isMultivalue () { return mIsMultiValue; }
|
||||
|
||||
void setDefaultValue (const QString &value);
|
||||
QString getDefaultValue () const;
|
||||
|
||||
private:
|
||||
bool validate (const QString &value);
|
||||
};
|
||||
}
|
||||
#endif // SETTINGSITEM_HPP
|
||||
|
@ -0,0 +1 @@
|
||||
#include "support.hpp"
|
@ -0,0 +1,39 @@
|
||||
#ifndef MODEL_SUPPORT_HPP
|
||||
#define MODEL_SUPPORT_HPP
|
||||
|
||||
#include <QObject>
|
||||
#include <QStringList>
|
||||
|
||||
class QLayout;
|
||||
class QWidget;
|
||||
class QListWidgetItem;
|
||||
|
||||
namespace CSMSettings
|
||||
{
|
||||
class SettingContainer;
|
||||
|
||||
typedef QList<SettingContainer *> SettingList;
|
||||
typedef QMap<QString, SettingContainer *> SettingMap;
|
||||
typedef QMap<QString, SettingMap *> SectionMap;
|
||||
|
||||
struct QStringPair
|
||||
{
|
||||
QStringPair(): left (""), right ("")
|
||||
{}
|
||||
|
||||
QStringPair (const QString &leftValue, const QString &rightValue)
|
||||
: left (leftValue), right(rightValue)
|
||||
{}
|
||||
|
||||
QStringPair (const QStringPair &pair)
|
||||
: left (pair.left), right (pair.right)
|
||||
{}
|
||||
|
||||
QString left;
|
||||
QString right;
|
||||
|
||||
bool isEmpty() const
|
||||
{ return (left.isEmpty() && right.isEmpty()); }
|
||||
};
|
||||
}
|
||||
#endif // MODEL_SUPPORT_HPP
|
@ -0,0 +1,137 @@
|
||||
#include "usersettings.hpp"
|
||||
|
||||
#include <QTextStream>
|
||||
#include <QDir>
|
||||
#include <QString>
|
||||
#include <QRegExp>
|
||||
#include <QMap>
|
||||
#include <QMessageBox>
|
||||
#include <QTextCodec>
|
||||
|
||||
#include <components/files/configurationmanager.hpp>
|
||||
|
||||
#include "settingcontainer.hpp"
|
||||
|
||||
#include <boost/version.hpp>
|
||||
/**
|
||||
* Workaround for problems with whitespaces in paths in older versions of Boost library
|
||||
*/
|
||||
#if (BOOST_VERSION <= 104600)
|
||||
namespace boost
|
||||
{
|
||||
|
||||
template<>
|
||||
inline boost::filesystem::path lexical_cast<boost::filesystem::path, std::string>(const std::string& arg)
|
||||
{
|
||||
return boost::filesystem::path(arg);
|
||||
}
|
||||
|
||||
} /* namespace boost */
|
||||
#endif /* (BOOST_VERSION <= 104600) */
|
||||
|
||||
|
||||
CSMSettings::UserSettings::UserSettings()
|
||||
{
|
||||
mUserSettingsInstance = this;
|
||||
}
|
||||
|
||||
CSMSettings::UserSettings::~UserSettings()
|
||||
{
|
||||
}
|
||||
|
||||
QFile *CSMSettings::UserSettings::openFile (const QString &filename)
|
||||
{
|
||||
QFile *file = new QFile(filename);
|
||||
|
||||
bool success = (file->open(QIODevice::ReadWrite | QIODevice::Text | QIODevice::Truncate)) ;
|
||||
|
||||
if (!success)
|
||||
{
|
||||
// File cannot be opened or created
|
||||
QMessageBox msgBox;
|
||||
msgBox.setWindowTitle(QObject::tr("Error writing OpenMW configuration file"));
|
||||
msgBox.setIcon(QMessageBox::Critical);
|
||||
msgBox.setStandardButtons(QMessageBox::Ok);
|
||||
msgBox.setText(QObject::tr("<br><b>Could not open or create %0 for writing</b><br><br> \
|
||||
Please make sure you have the right permissions \
|
||||
and try again.<br>").arg(file->fileName()));
|
||||
msgBox.exec();
|
||||
delete file;
|
||||
file = 0;
|
||||
}
|
||||
|
||||
return file;
|
||||
}
|
||||
|
||||
bool CSMSettings::UserSettings::writeFile(QFile *file, QMap<QString, CSMSettings::SettingList *> &settings)
|
||||
{
|
||||
if (!file)
|
||||
return false;
|
||||
|
||||
QTextStream stream(file);
|
||||
stream.setCodec(QTextCodec::codecForName("UTF-8"));
|
||||
|
||||
QList<QString> keyList = settings.keys();
|
||||
|
||||
foreach (QString key, keyList)
|
||||
{
|
||||
SettingList *sectionSettings = settings[key];
|
||||
|
||||
stream << "[" << key << "]" << '\n';
|
||||
|
||||
foreach (SettingContainer *item, *sectionSettings)
|
||||
stream << item->getName() << " = " << item->getValue() << '\n';
|
||||
}
|
||||
|
||||
file->close();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void CSMSettings::UserSettings::getSettings(QTextStream &stream, SectionMap §ions)
|
||||
{
|
||||
//looks for a square bracket, "'\\["
|
||||
//that has one or more "not nothing" in it, "([^]]+)"
|
||||
//and is closed with a square bracket, "\\]"
|
||||
|
||||
QRegExp sectionRe("^\\[([^]]+)\\]");
|
||||
|
||||
//Find any character(s) that is/are not equal sign(s), "[^=]+"
|
||||
//followed by an optional whitespace, an equal sign, and another optional whirespace, "\\s*=\\s*"
|
||||
//and one or more periods, "(.+)"
|
||||
|
||||
QRegExp keyRe("^([^=]+)\\s*=\\s*(.+)$");
|
||||
|
||||
CSMSettings::SettingMap *settings = 0;
|
||||
QString section = "none";
|
||||
|
||||
while (!stream.atEnd())
|
||||
{
|
||||
QString line = stream.readLine().simplified();
|
||||
|
||||
if (line.isEmpty() || line.startsWith("#"))
|
||||
continue;
|
||||
|
||||
//if a section is found, push it onto a new QStringList
|
||||
//and push the QStringList onto
|
||||
if (sectionRe.exactMatch(line))
|
||||
{
|
||||
//add the previous section's settings to the member map
|
||||
if (settings)
|
||||
sections.insert(section, settings);
|
||||
|
||||
//save new section and create a new list
|
||||
section = sectionRe.cap(1);
|
||||
settings = new SettingMap;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (keyRe.indexIn(line) != -1)
|
||||
{
|
||||
SettingContainer *sc = new SettingContainer (keyRe.cap(2).simplified());
|
||||
(*settings)[keyRe.cap(1).simplified()] = sc;
|
||||
}
|
||||
|
||||
}
|
||||
sections.insert(section, settings);
|
||||
}
|
@ -0,0 +1,52 @@
|
||||
#ifndef USERSETTINGS_HPP
|
||||
#define USERSETTINGS_HPP
|
||||
|
||||
#include <QTextStream>
|
||||
#include <QStringList>
|
||||
#include <QString>
|
||||
#include <QMap>
|
||||
|
||||
#include <boost/filesystem/path.hpp>
|
||||
|
||||
#include "support.hpp"
|
||||
|
||||
namespace Files { typedef std::vector<boost::filesystem::path> PathContainer;
|
||||
struct ConfigurationManager;}
|
||||
|
||||
class QFile;
|
||||
|
||||
namespace CSMSettings {
|
||||
|
||||
struct UserSettings: public QObject
|
||||
{
|
||||
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
static UserSettings &instance()
|
||||
{
|
||||
static UserSettings instance;
|
||||
|
||||
return instance;
|
||||
}
|
||||
|
||||
QFile *openFile (const QString &);
|
||||
bool writeFile(QFile *file, QMap<QString, SettingList *> §ions);
|
||||
void getSettings (QTextStream &stream, SectionMap &settings);
|
||||
|
||||
private:
|
||||
|
||||
UserSettings *mUserSettingsInstance;
|
||||
UserSettings();
|
||||
~UserSettings();
|
||||
|
||||
UserSettings (UserSettings const &); //not implemented
|
||||
void operator= (UserSettings const &); //not implemented
|
||||
|
||||
signals:
|
||||
void signalUpdateEditorSetting (const QString &settingName, const QString &settingValue);
|
||||
|
||||
};
|
||||
}
|
||||
#endif // USERSETTINGS_HPP
|
@ -0,0 +1,39 @@
|
||||
|
||||
#include "birthsigncheck.hpp"
|
||||
|
||||
#include <sstream>
|
||||
#include <map>
|
||||
|
||||
#include <components/esm/loadbsgn.hpp>
|
||||
|
||||
#include "../world/universalid.hpp"
|
||||
|
||||
CSMTools::BirthsignCheckStage::BirthsignCheckStage (const CSMWorld::IdCollection<ESM::BirthSign>& birthsigns)
|
||||
: mBirthsigns (birthsigns)
|
||||
{}
|
||||
|
||||
int CSMTools::BirthsignCheckStage::setup()
|
||||
{
|
||||
return mBirthsigns.getSize();
|
||||
}
|
||||
|
||||
void CSMTools::BirthsignCheckStage::perform (int stage, std::vector<std::string>& messages)
|
||||
{
|
||||
const ESM::BirthSign& birthsign = mBirthsigns.getRecord (stage).get();
|
||||
|
||||
CSMWorld::UniversalId id (CSMWorld::UniversalId::Type_Birthsign, birthsign.mId);
|
||||
|
||||
// test for empty name, description and texture
|
||||
if (birthsign.mName.empty())
|
||||
messages.push_back (id.toString() + "|" + birthsign.mId + " has an empty name");
|
||||
|
||||
if (birthsign.mDescription.empty())
|
||||
messages.push_back (id.toString() + "|" + birthsign.mId + " has an empty description");
|
||||
|
||||
if (birthsign.mTexture.empty())
|
||||
messages.push_back (id.toString() + "|" + birthsign.mId + " is missing a texture");
|
||||
|
||||
/// \todo test if the texture exists
|
||||
|
||||
/// \todo check data members that can't be edited in the table view
|
||||
}
|
@ -0,0 +1,29 @@
|
||||
#ifndef CSM_TOOLS_BIRTHSIGNCHECK_H
|
||||
#define CSM_TOOLS_BIRTHSIGNCHECK_H
|
||||
|
||||
#include <components/esm/loadbsgn.hpp>
|
||||
|
||||
#include "../world/idcollection.hpp"
|
||||
|
||||
#include "stage.hpp"
|
||||
|
||||
namespace CSMTools
|
||||
{
|
||||
/// \brief VerifyStage: make sure that birthsign records are internally consistent
|
||||
class BirthsignCheckStage : public Stage
|
||||
{
|
||||
const CSMWorld::IdCollection<ESM::BirthSign>& mBirthsigns;
|
||||
|
||||
public:
|
||||
|
||||
BirthsignCheckStage (const CSMWorld::IdCollection<ESM::BirthSign>& birthsigns);
|
||||
|
||||
virtual int setup();
|
||||
///< \return number of steps
|
||||
|
||||
virtual void perform (int stage, std::vector<std::string>& messages);
|
||||
///< Messages resulting from this tage will be appended to \a messages.
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
@ -0,0 +1,72 @@
|
||||
|
||||
#include "classcheck.hpp"
|
||||
|
||||
#include <sstream>
|
||||
#include <map>
|
||||
|
||||
#include <components/esm/loadclas.hpp>
|
||||
#include <components/esm/loadskil.hpp>
|
||||
|
||||
#include "../world/universalid.hpp"
|
||||
|
||||
CSMTools::ClassCheckStage::ClassCheckStage (const CSMWorld::IdCollection<ESM::Class>& classes)
|
||||
: mClasses (classes)
|
||||
{}
|
||||
|
||||
int CSMTools::ClassCheckStage::setup()
|
||||
{
|
||||
return mClasses.getSize();
|
||||
}
|
||||
|
||||
void CSMTools::ClassCheckStage::perform (int stage, std::vector<std::string>& messages)
|
||||
{
|
||||
const ESM::Class& class_= mClasses.getRecord (stage).get();
|
||||
|
||||
CSMWorld::UniversalId id (CSMWorld::UniversalId::Type_Class, class_.mId);
|
||||
|
||||
// test for empty name and description
|
||||
if (class_.mName.empty())
|
||||
messages.push_back (id.toString() + "|" + class_.mId + " has an empty name");
|
||||
|
||||
if (class_.mDescription.empty())
|
||||
messages.push_back (id.toString() + "|" + class_.mId + " has an empty description");
|
||||
|
||||
// test for invalid attributes
|
||||
for (int i=0; i<2; ++i)
|
||||
if (class_.mData.mAttribute[i]==-1)
|
||||
{
|
||||
std::ostringstream stream;
|
||||
|
||||
stream << id.toString() << "|Attribute #" << i << " of " << class_.mId << " is not set";
|
||||
|
||||
messages.push_back (stream.str());
|
||||
}
|
||||
|
||||
if (class_.mData.mAttribute[0]==class_.mData.mAttribute[1] && class_.mData.mAttribute[0]!=-1)
|
||||
{
|
||||
std::ostringstream stream;
|
||||
|
||||
stream << id.toString() << "|Class lists same attribute twice";
|
||||
|
||||
messages.push_back (stream.str());
|
||||
}
|
||||
|
||||
// test for non-unique skill
|
||||
std::map<int, int> skills; // ID, number of occurrences
|
||||
|
||||
for (int i=0; i<5; ++i)
|
||||
for (int i2=0; i2<2; ++i2)
|
||||
++skills[class_.mData.mSkills[i][i2]];
|
||||
|
||||
for (std::map<int, int>::const_iterator iter (skills.begin()); iter!=skills.end(); ++iter)
|
||||
if (iter->second>1)
|
||||
{
|
||||
std::ostringstream stream;
|
||||
|
||||
stream
|
||||
<< id.toString() << "|"
|
||||
<< ESM::Skill::indexToId (iter->first) << " is listed more than once";
|
||||
|
||||
messages.push_back (stream.str());
|
||||
}
|
||||
}
|
@ -0,0 +1,29 @@
|
||||
#ifndef CSM_TOOLS_CLASSCHECK_H
|
||||
#define CSM_TOOLS_CLASSCHECK_H
|
||||
|
||||
#include <components/esm/loadclas.hpp>
|
||||
|
||||
#include "../world/idcollection.hpp"
|
||||
|
||||
#include "stage.hpp"
|
||||
|
||||
namespace CSMTools
|
||||
{
|
||||
/// \brief VerifyStage: make sure that class records are internally consistent
|
||||
class ClassCheckStage : public Stage
|
||||
{
|
||||
const CSMWorld::IdCollection<ESM::Class>& mClasses;
|
||||
|
||||
public:
|
||||
|
||||
ClassCheckStage (const CSMWorld::IdCollection<ESM::Class>& classes);
|
||||
|
||||
virtual int setup();
|
||||
///< \return number of steps
|
||||
|
||||
virtual void perform (int stage, std::vector<std::string>& messages);
|
||||
///< Messages resulting from this tage will be appended to \a messages.
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
@ -0,0 +1,61 @@
|
||||
|
||||
#include "factioncheck.hpp"
|
||||
|
||||
#include <sstream>
|
||||
#include <map>
|
||||
|
||||
#include <components/esm/loadfact.hpp>
|
||||
#include <components/esm/loadskil.hpp>
|
||||
|
||||
#include "../world/universalid.hpp"
|
||||
|
||||
CSMTools::FactionCheckStage::FactionCheckStage (const CSMWorld::IdCollection<ESM::Faction>& factions)
|
||||
: mFactions (factions)
|
||||
{}
|
||||
|
||||
int CSMTools::FactionCheckStage::setup()
|
||||
{
|
||||
return mFactions.getSize();
|
||||
}
|
||||
|
||||
void CSMTools::FactionCheckStage::perform (int stage, std::vector<std::string>& messages)
|
||||
{
|
||||
const ESM::Faction& faction = mFactions.getRecord (stage).get();
|
||||
|
||||
CSMWorld::UniversalId id (CSMWorld::UniversalId::Type_Faction, faction.mId);
|
||||
|
||||
// test for empty name
|
||||
if (faction.mName.empty())
|
||||
messages.push_back (id.toString() + "|" + faction.mId + " has an empty name");
|
||||
|
||||
// test for invalid attributes
|
||||
if (faction.mData.mAttribute[0]==faction.mData.mAttribute[1] && faction.mData.mAttribute[0]!=-1)
|
||||
{
|
||||
std::ostringstream stream;
|
||||
|
||||
stream << id.toString() << "|Faction lists same attribute twice";
|
||||
|
||||
messages.push_back (stream.str());
|
||||
}
|
||||
|
||||
// test for non-unique skill
|
||||
std::map<int, int> skills; // ID, number of occurrences
|
||||
|
||||
for (int i=0; i<6; ++i)
|
||||
if (faction.mData.mSkills[i]!=-1)
|
||||
++skills[faction.mData.mSkills[i]];
|
||||
|
||||
for (std::map<int, int>::const_iterator iter (skills.begin()); iter!=skills.end(); ++iter)
|
||||
if (iter->second>1)
|
||||
{
|
||||
std::ostringstream stream;
|
||||
|
||||
stream
|
||||
<< id.toString() << "|"
|
||||
<< ESM::Skill::indexToId (iter->first) << " is listed more than once";
|
||||
|
||||
messages.push_back (stream.str());
|
||||
}
|
||||
|
||||
/// \todo check data members that can't be edited in the table view
|
||||
}
|
@ -0,0 +1,29 @@
|
||||
#ifndef CSM_TOOLS_FACTIONCHECK_H
|
||||
#define CSM_TOOLS_FACTIONCHECK_H
|
||||
|
||||
#include <components/esm/loadfact.hpp>
|
||||
|
||||
#include "../world/idcollection.hpp"
|
||||
|
||||
#include "stage.hpp"
|
||||
|
||||
namespace CSMTools
|
||||
{
|
||||
/// \brief VerifyStage: make sure that faction records are internally consistent
|
||||
class FactionCheckStage : public Stage
|
||||
{
|
||||
const CSMWorld::IdCollection<ESM::Faction>& mFactions;
|
||||
|
||||
public:
|
||||
|
||||
FactionCheckStage (const CSMWorld::IdCollection<ESM::Faction>& factions);
|
||||
|
||||
virtual int setup();
|
||||
///< \return number of steps
|
||||
|
||||
virtual void perform (int stage, std::vector<std::string>& messages);
|
||||
///< Messages resulting from this tage will be appended to \a messages.
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
@ -0,0 +1,68 @@
|
||||
|
||||
#include "racecheck.hpp"
|
||||
|
||||
#include <sstream>
|
||||
|
||||
#include <components/esm/loadrace.hpp>
|
||||
|
||||
#include "../world/universalid.hpp"
|
||||
|
||||
void CSMTools::RaceCheckStage::performPerRecord (int stage, std::vector<std::string>& messages)
|
||||
{
|
||||
const ESM::Race& race = mRaces.getRecord (stage).get();
|
||||
|
||||
CSMWorld::UniversalId id (CSMWorld::UniversalId::Type_Race, race.mId);
|
||||
|
||||
// test for empty name and description
|
||||
if (race.mName.empty())
|
||||
messages.push_back (id.toString() + "|" + race.mId + " has an empty name");
|
||||
|
||||
if (race.mDescription.empty())
|
||||
messages.push_back (id.toString() + "|" + race.mId + " has an empty description");
|
||||
|
||||
// test for positive height
|
||||
if (race.mData.mHeight.mMale<=0)
|
||||
messages.push_back (id.toString() + "|male " + race.mId + " has non-positive height");
|
||||
|
||||
if (race.mData.mHeight.mFemale<=0)
|
||||
messages.push_back (id.toString() + "|female " + race.mId + " has non-positive height");
|
||||
|
||||
// test for non-negative weight
|
||||
if (race.mData.mWeight.mMale<0)
|
||||
messages.push_back (id.toString() + "|male " + race.mId + " has negative weight");
|
||||
|
||||
if (race.mData.mWeight.mFemale<0)
|
||||
messages.push_back (id.toString() + "|female " + race.mId + " has negative weight");
|
||||
|
||||
// remember playable flag
|
||||
if (race.mData.mFlags & 0x1)
|
||||
mPlayable = true;
|
||||
|
||||
/// \todo check data members that can't be edited in the table view
|
||||
}
|
||||
|
||||
void CSMTools::RaceCheckStage::performFinal (std::vector<std::string>& messages)
|
||||
{
|
||||
CSMWorld::UniversalId id (CSMWorld::UniversalId::Type_Races);
|
||||
|
||||
if (!mPlayable)
|
||||
messages.push_back (id.toString() + "|No playable race");
|
||||
}
|
||||
|
||||
CSMTools::RaceCheckStage::RaceCheckStage (const CSMWorld::IdCollection<ESM::Race>& races)
|
||||
: mRaces (races), mPlayable (false)
|
||||
{}
|
||||
|
||||
int CSMTools::RaceCheckStage::setup()
|
||||
{
|
||||
mPlayable = false;
|
||||
return mRaces.getSize()+1;
|
||||
}
|
||||
|
||||
void CSMTools::RaceCheckStage::perform (int stage, std::vector<std::string>& messages)
|
||||
{
|
||||
if (stage==mRaces.getSize())
|
||||
performFinal (messages);
|
||||
else
|
||||
performPerRecord (stage, messages);
|
||||
}
|
@ -0,0 +1,34 @@
|
||||
#ifndef CSM_TOOLS_RACECHECK_H
|
||||
#define CSM_TOOLS_RACECHECK_H
|
||||
|
||||
#include <components/esm/loadrace.hpp>
|
||||
|
||||
#include "../world/idcollection.hpp"
|
||||
|
||||
#include "stage.hpp"
|
||||
|
||||
namespace CSMTools
|
||||
{
|
||||
/// \brief VerifyStage: make sure that race records are internally consistent
|
||||
class RaceCheckStage : public Stage
|
||||
{
|
||||
const CSMWorld::IdCollection<ESM::Race>& mRaces;
|
||||
bool mPlayable;
|
||||
|
||||
void performPerRecord (int stage, std::vector<std::string>& messages);
|
||||
|
||||
void performFinal (std::vector<std::string>& messages);
|
||||
|
||||
public:
|
||||
|
||||
RaceCheckStage (const CSMWorld::IdCollection<ESM::Race>& races);
|
||||
|
||||
virtual int setup();
|
||||
///< \return number of steps
|
||||
|
||||
virtual void perform (int stage, std::vector<std::string>& messages);
|
||||
///< Messages resulting from this tage will be appended to \a messages.
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
@ -0,0 +1,33 @@
|
||||
|
||||
#include "regioncheck.hpp"
|
||||
|
||||
#include <sstream>
|
||||
#include <map>
|
||||
|
||||
#include <components/esm/loadregn.hpp>
|
||||
|
||||
#include "../world/universalid.hpp"
|
||||
|
||||
CSMTools::RegionCheckStage::RegionCheckStage (const CSMWorld::IdCollection<ESM::Region>& regions)
|
||||
: mRegions (regions)
|
||||
{}
|
||||
|
||||
int CSMTools::RegionCheckStage::setup()
|
||||
{
|
||||
return mRegions.getSize();
|
||||
}
|
||||
|
||||
void CSMTools::RegionCheckStage::perform (int stage, std::vector<std::string>& messages)
|
||||
{
|
||||
const ESM::Region& region = mRegions.getRecord (stage).get();
|
||||
|
||||
CSMWorld::UniversalId id (CSMWorld::UniversalId::Type_Region, region.mId);
|
||||
|
||||
// test for empty name
|
||||
if (region.mName.empty())
|
||||
messages.push_back (id.toString() + "|" + region.mId + " has an empty name");
|
||||
|
||||
/// \todo test that the ID in mSleeplist exists
|
||||
|
||||
/// \todo check data members that can't be edited in the table view
|
||||
}
|
@ -0,0 +1,29 @@
|
||||
#ifndef CSM_TOOLS_REGIONCHECK_H
|
||||
#define CSM_TOOLS_REGIONCHECK_H
|
||||
|
||||
#include <components/esm/loadregn.hpp>
|
||||
|
||||
#include "../world/idcollection.hpp"
|
||||
|
||||
#include "stage.hpp"
|
||||
|
||||
namespace CSMTools
|
||||
{
|
||||
/// \brief VerifyStage: make sure that region records are internally consistent
|
||||
class RegionCheckStage : public Stage
|
||||
{
|
||||
const CSMWorld::IdCollection<ESM::Region>& mRegions;
|
||||
|
||||
public:
|
||||
|
||||
RegionCheckStage (const CSMWorld::IdCollection<ESM::Region>& regions);
|
||||
|
||||
virtual int setup();
|
||||
///< \return number of steps
|
||||
|
||||
virtual void perform (int stage, std::vector<std::string>& messages);
|
||||
///< Messages resulting from this tage will be appended to \a messages.
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
@ -0,0 +1,37 @@
|
||||
|
||||
#include "skillcheck.hpp"
|
||||
|
||||
#include <sstream>
|
||||
|
||||
#include <components/esm/loadskil.hpp>
|
||||
|
||||
#include "../world/universalid.hpp"
|
||||
|
||||
CSMTools::SkillCheckStage::SkillCheckStage (const CSMWorld::IdCollection<ESM::Skill>& skills)
|
||||
: mSkills (skills)
|
||||
{}
|
||||
|
||||
int CSMTools::SkillCheckStage::setup()
|
||||
{
|
||||
return mSkills.getSize();
|
||||
}
|
||||
|
||||
void CSMTools::SkillCheckStage::perform (int stage, std::vector<std::string>& messages)
|
||||
{
|
||||
const ESM::Skill& skill = mSkills.getRecord (stage).get();
|
||||
|
||||
CSMWorld::UniversalId id (CSMWorld::UniversalId::Type_Skill, skill.mId);
|
||||
|
||||
for (int i=0; i<4; ++i)
|
||||
if (skill.mData.mUseValue[i]<0)
|
||||
{
|
||||
std::ostringstream stream;
|
||||
|
||||
stream << id.toString() << "|Use value #" << i << " of " << skill.mId << " is negative";
|
||||
|
||||
messages.push_back (stream.str());
|
||||
}
|
||||
|
||||
if (skill.mDescription.empty())
|
||||
messages.push_back (id.toString() + "|" + skill.mId + " has an empty description");
|
||||
}
|
@ -0,0 +1,29 @@
|
||||
#ifndef CSM_TOOLS_SKILLCHECK_H
|
||||
#define CSM_TOOLS_SKILLCHECK_H
|
||||
|
||||
#include <components/esm/loadskil.hpp>
|
||||
|
||||
#include "../world/idcollection.hpp"
|
||||
|
||||
#include "stage.hpp"
|
||||
|
||||
namespace CSMTools
|
||||
{
|
||||
/// \brief VerifyStage: make sure that skill records are internally consistent
|
||||
class SkillCheckStage : public Stage
|
||||
{
|
||||
const CSMWorld::IdCollection<ESM::Skill>& mSkills;
|
||||
|
||||
public:
|
||||
|
||||
SkillCheckStage (const CSMWorld::IdCollection<ESM::Skill>& skills);
|
||||
|
||||
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,29 @@
|
||||
|
||||
#include "soundcheck.hpp"
|
||||
|
||||
#include <sstream>
|
||||
|
||||
#include <components/esm/loadskil.hpp>
|
||||
|
||||
#include "../world/universalid.hpp"
|
||||
|
||||
CSMTools::SoundCheckStage::SoundCheckStage (const CSMWorld::IdCollection<ESM::Sound>& sounds)
|
||||
: mSounds (sounds)
|
||||
{}
|
||||
|
||||
int CSMTools::SoundCheckStage::setup()
|
||||
{
|
||||
return mSounds.getSize();
|
||||
}
|
||||
|
||||
void CSMTools::SoundCheckStage::perform (int stage, std::vector<std::string>& messages)
|
||||
{
|
||||
const ESM::Sound& sound = mSounds.getRecord (stage).get();
|
||||
|
||||
CSMWorld::UniversalId id (CSMWorld::UniversalId::Type_Sound, sound.mId);
|
||||
|
||||
if (sound.mData.mMinRange>sound.mData.mMaxRange)
|
||||
messages.push_back (id.toString() + "|Maximum range larger than minimum range");
|
||||
|
||||
/// \todo check, if the sound file exists
|
||||
}
|
@ -0,0 +1,29 @@
|
||||
#ifndef CSM_TOOLS_SOUNDCHECK_H
|
||||
#define CSM_TOOLS_SOUNDCHECK_H
|
||||
|
||||
#include <components/esm/loadsoun.hpp>
|
||||
|
||||
#include "../world/idcollection.hpp"
|
||||
|
||||
#include "stage.hpp"
|
||||
|
||||
namespace CSMTools
|
||||
{
|
||||
/// \brief VerifyStage: make sure that sound records are internally consistent
|
||||
class SoundCheckStage : public Stage
|
||||
{
|
||||
const CSMWorld::IdCollection<ESM::Sound>& mSounds;
|
||||
|
||||
public:
|
||||
|
||||
SoundCheckStage (const CSMWorld::IdCollection<ESM::Sound>& sounds);
|
||||
|
||||
virtual int setup();
|
||||
///< \return number of steps
|
||||
|
||||
virtual void perform (int stage, std::vector<std::string>& messages);
|
||||
///< Messages resulting from this tage will be appended to \a messages.
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
@ -0,0 +1,35 @@
|
||||
|
||||
#include "spellcheck.hpp"
|
||||
|
||||
#include <sstream>
|
||||
#include <map>
|
||||
|
||||
#include <components/esm/loadspel.hpp>
|
||||
|
||||
#include "../world/universalid.hpp"
|
||||
|
||||
CSMTools::SpellCheckStage::SpellCheckStage (const CSMWorld::IdCollection<ESM::Spell>& spells)
|
||||
: mSpells (spells)
|
||||
{}
|
||||
|
||||
int CSMTools::SpellCheckStage::setup()
|
||||
{
|
||||
return mSpells.getSize();
|
||||
}
|
||||
|
||||
void CSMTools::SpellCheckStage::perform (int stage, std::vector<std::string>& messages)
|
||||
{
|
||||
const ESM::Spell& spell = mSpells.getRecord (stage).get();
|
||||
|
||||
CSMWorld::UniversalId id (CSMWorld::UniversalId::Type_Spell, spell.mId);
|
||||
|
||||
// test for empty name and description
|
||||
if (spell.mName.empty())
|
||||
messages.push_back (id.toString() + "|" + spell.mId + " has an empty name");
|
||||
|
||||
// test for invalid cost values
|
||||
if (spell.mData.mCost<0)
|
||||
messages.push_back (id.toString() + "|" + spell.mId + " has a negative spell costs");
|
||||
|
||||
/// \todo check data members that can't be edited in the table view
|
||||
}
|
@ -0,0 +1,29 @@
|
||||
#ifndef CSM_TOOLS_SPELLCHECK_H
|
||||
#define CSM_TOOLS_SPELLCHECK_H
|
||||
|
||||
#include <components/esm/loadspel.hpp>
|
||||
|
||||
#include "../world/idcollection.hpp"
|
||||
|
||||
#include "stage.hpp"
|
||||
|
||||
namespace CSMTools
|
||||
{
|
||||
/// \brief VerifyStage: make sure that spell records are internally consistent
|
||||
class SpellCheckStage : public Stage
|
||||
{
|
||||
const CSMWorld::IdCollection<ESM::Spell>& mSpells;
|
||||
|
||||
public:
|
||||
|
||||
SpellCheckStage (const CSMWorld::IdCollection<ESM::Spell>& spells);
|
||||
|
||||
virtual int setup();
|
||||
///< \return number of steps
|
||||
|
||||
virtual void perform (int stage, std::vector<std::string>& messages);
|
||||
///< Messages resulting from this tage will be appended to \a messages.
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
@ -0,0 +1,20 @@
|
||||
|
||||
#include "cell.hpp"
|
||||
|
||||
#include <sstream>
|
||||
|
||||
void CSMWorld::Cell::load (ESM::ESMReader &esm)
|
||||
{
|
||||
mName = mId;
|
||||
|
||||
ESM::Cell::load (esm, true); /// \todo set this to false, once the bug in ESM::Cell::load is fixed
|
||||
|
||||
if (!(mData.mFlags & Interior))
|
||||
{
|
||||
std::ostringstream stream;
|
||||
|
||||
stream << "#" << mData.mX << " " << mData.mY;
|
||||
|
||||
mId = stream.str();
|
||||
}
|
||||
}
|
@ -0,0 +1,17 @@
|
||||
#ifndef CSM_WOLRD_CELL_H
|
||||
#define CSM_WOLRD_CELL_H
|
||||
|
||||
#include <components/esm/loadcell.hpp>
|
||||
|
||||
namespace CSMWorld
|
||||
{
|
||||
/// \brief Wrapper for Cell record
|
||||
struct Cell : public ESM::Cell
|
||||
{
|
||||
std::string mId;
|
||||
|
||||
void load (ESM::ESMReader &esm);
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
@ -0,0 +1,6 @@
|
||||
|
||||
#include "refidadapter.hpp"
|
||||
|
||||
CSMWorld::RefIdAdapter::RefIdAdapter() {}
|
||||
|
||||
CSMWorld::RefIdAdapter::~RefIdAdapter() {}
|
@ -0,0 +1,37 @@
|
||||
#ifndef CSM_WOLRD_REFIDADAPTER_H
|
||||
#define CSM_WOLRD_REFIDADAPTER_H
|
||||
|
||||
#include <string>
|
||||
|
||||
class QVariant;
|
||||
|
||||
namespace CSMWorld
|
||||
{
|
||||
class RefIdColumn;
|
||||
class RefIdData;
|
||||
class RecordBase;
|
||||
|
||||
class RefIdAdapter
|
||||
{
|
||||
// not implemented
|
||||
RefIdAdapter (const RefIdAdapter&);
|
||||
RefIdAdapter& operator= (const RefIdAdapter&);
|
||||
|
||||
public:
|
||||
|
||||
RefIdAdapter();
|
||||
|
||||
virtual ~RefIdAdapter();
|
||||
|
||||
virtual QVariant getData (const RefIdColumn *column, const RefIdData& data, int idnex)
|
||||
const = 0;
|
||||
|
||||
virtual void setData (const RefIdColumn *column, RefIdData& data, int index,
|
||||
const QVariant& value) const = 0;
|
||||
///< If the data type does not match an exception is thrown.
|
||||
|
||||
virtual std::string getId (const RecordBase& record) const = 0;
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
@ -0,0 +1,575 @@
|
||||
|
||||
#include "refidadapterimp.hpp"
|
||||
|
||||
CSMWorld::PotionRefIdAdapter::PotionRefIdAdapter (const InventoryColumns& columns,
|
||||
const RefIdColumn *autoCalc)
|
||||
: InventoryRefIdAdapter<ESM::Potion> (UniversalId::Type_Potion, columns),
|
||||
mAutoCalc (autoCalc)
|
||||
{}
|
||||
|
||||
QVariant CSMWorld::PotionRefIdAdapter::getData (const RefIdColumn *column, const RefIdData& data,
|
||||
int index) const
|
||||
{
|
||||
const Record<ESM::Potion>& record = static_cast<const Record<ESM::Potion>&> (
|
||||
data.getRecord (RefIdData::LocalIndex (index, UniversalId::Type_Potion)));
|
||||
|
||||
if (column==mAutoCalc)
|
||||
return record.get().mData.mAutoCalc!=0;
|
||||
|
||||
return InventoryRefIdAdapter<ESM::Potion>::getData (column, data, index);
|
||||
}
|
||||
|
||||
void CSMWorld::PotionRefIdAdapter::setData (const RefIdColumn *column, RefIdData& data, int index,
|
||||
const QVariant& value) const
|
||||
{
|
||||
Record<ESM::Potion>& record = static_cast<Record<ESM::Potion>&> (
|
||||
data.getRecord (RefIdData::LocalIndex (index, UniversalId::Type_Potion)));
|
||||
|
||||
if (column==mAutoCalc)
|
||||
record.get().mData.mAutoCalc = value.toInt();
|
||||
else
|
||||
InventoryRefIdAdapter<ESM::Potion>::setData (column, data, index, value);
|
||||
}
|
||||
|
||||
|
||||
CSMWorld::ApparatusRefIdAdapter::ApparatusRefIdAdapter (const InventoryColumns& columns,
|
||||
const RefIdColumn *type, const RefIdColumn *quality)
|
||||
: InventoryRefIdAdapter<ESM::Apparatus> (UniversalId::Type_Apparatus, columns),
|
||||
mType (type), mQuality (quality)
|
||||
{}
|
||||
|
||||
QVariant CSMWorld::ApparatusRefIdAdapter::getData (const RefIdColumn *column,
|
||||
const RefIdData& data, int index) const
|
||||
{
|
||||
const Record<ESM::Apparatus>& record = static_cast<const Record<ESM::Apparatus>&> (
|
||||
data.getRecord (RefIdData::LocalIndex (index, UniversalId::Type_Apparatus)));
|
||||
|
||||
if (column==mType)
|
||||
return record.get().mData.mType;
|
||||
|
||||
if (column==mQuality)
|
||||
return record.get().mData.mQuality;
|
||||
|
||||
return InventoryRefIdAdapter<ESM::Apparatus>::getData (column, data, index);
|
||||
}
|
||||
|
||||
void CSMWorld::ApparatusRefIdAdapter::setData (const RefIdColumn *column, RefIdData& data, int index,
|
||||
const QVariant& value) const
|
||||
{
|
||||
Record<ESM::Apparatus>& record = static_cast<Record<ESM::Apparatus>&> (
|
||||
data.getRecord (RefIdData::LocalIndex (index, UniversalId::Type_Apparatus)));
|
||||
|
||||
if (column==mType)
|
||||
record.get().mData.mType = value.toInt();
|
||||
else if (column==mQuality)
|
||||
record.get().mData.mQuality = value.toFloat();
|
||||
else
|
||||
InventoryRefIdAdapter<ESM::Apparatus>::setData (column, data, index, value);
|
||||
}
|
||||
|
||||
|
||||
CSMWorld::ArmorRefIdAdapter::ArmorRefIdAdapter (const EnchantableColumns& columns,
|
||||
const RefIdColumn *type, const RefIdColumn *health, const RefIdColumn *armor)
|
||||
: EnchantableRefIdAdapter<ESM::Armor> (UniversalId::Type_Armor, columns),
|
||||
mType (type), mHealth (health), mArmor (armor)
|
||||
{}
|
||||
|
||||
QVariant CSMWorld::ArmorRefIdAdapter::getData (const RefIdColumn *column,
|
||||
const RefIdData& data, int index) const
|
||||
{
|
||||
const Record<ESM::Armor>& record = static_cast<const Record<ESM::Armor>&> (
|
||||
data.getRecord (RefIdData::LocalIndex (index, UniversalId::Type_Armor)));
|
||||
|
||||
if (column==mType)
|
||||
return record.get().mData.mType;
|
||||
|
||||
if (column==mHealth)
|
||||
return record.get().mData.mHealth;
|
||||
|
||||
if (column==mArmor)
|
||||
return record.get().mData.mArmor;
|
||||
|
||||
return EnchantableRefIdAdapter<ESM::Armor>::getData (column, data, index);
|
||||
}
|
||||
|
||||
void CSMWorld::ArmorRefIdAdapter::setData (const RefIdColumn *column, RefIdData& data, int index,
|
||||
const QVariant& value) const
|
||||
{
|
||||
Record<ESM::Armor>& record = static_cast<Record<ESM::Armor>&> (
|
||||
data.getRecord (RefIdData::LocalIndex (index, UniversalId::Type_Armor)));
|
||||
|
||||
if (column==mType)
|
||||
record.get().mData.mType = value.toInt();
|
||||
else if (column==mHealth)
|
||||
record.get().mData.mHealth = value.toInt();
|
||||
else if (column==mArmor)
|
||||
record.get().mData.mArmor = value.toInt();
|
||||
else
|
||||
EnchantableRefIdAdapter<ESM::Armor>::setData (column, data, index, value);
|
||||
}
|
||||
|
||||
CSMWorld::BookRefIdAdapter::BookRefIdAdapter (const EnchantableColumns& columns,
|
||||
const RefIdColumn *scroll, const RefIdColumn *skill)
|
||||
: EnchantableRefIdAdapter<ESM::Book> (UniversalId::Type_Book, columns),
|
||||
mScroll (scroll), mSkill (skill)
|
||||
{}
|
||||
|
||||
QVariant CSMWorld::BookRefIdAdapter::getData (const RefIdColumn *column,
|
||||
const RefIdData& data, int index) const
|
||||
{
|
||||
const Record<ESM::Book>& record = static_cast<const Record<ESM::Book>&> (
|
||||
data.getRecord (RefIdData::LocalIndex (index, UniversalId::Type_Book)));
|
||||
|
||||
if (column==mScroll)
|
||||
return record.get().mData.mIsScroll!=0;
|
||||
|
||||
if (column==mSkill)
|
||||
return record.get().mData.mSkillID;
|
||||
|
||||
return EnchantableRefIdAdapter<ESM::Book>::getData (column, data, index);
|
||||
}
|
||||
|
||||
void CSMWorld::BookRefIdAdapter::setData (const RefIdColumn *column, RefIdData& data, int index,
|
||||
const QVariant& value) const
|
||||
{
|
||||
Record<ESM::Book>& record = static_cast<Record<ESM::Book>&> (
|
||||
data.getRecord (RefIdData::LocalIndex (index, UniversalId::Type_Book)));
|
||||
|
||||
if (column==mScroll)
|
||||
record.get().mData.mIsScroll = value.toInt();
|
||||
else if (column==mSkill)
|
||||
record.get().mData.mSkillID = value.toInt();
|
||||
else
|
||||
EnchantableRefIdAdapter<ESM::Book>::setData (column, data, index, value);
|
||||
}
|
||||
|
||||
CSMWorld::ClothingRefIdAdapter::ClothingRefIdAdapter (const EnchantableColumns& columns,
|
||||
const RefIdColumn *type)
|
||||
: EnchantableRefIdAdapter<ESM::Clothing> (UniversalId::Type_Clothing, columns), mType (type)
|
||||
{}
|
||||
|
||||
QVariant CSMWorld::ClothingRefIdAdapter::getData (const RefIdColumn *column,
|
||||
const RefIdData& data, int index) const
|
||||
{
|
||||
const Record<ESM::Clothing>& record = static_cast<const Record<ESM::Clothing>&> (
|
||||
data.getRecord (RefIdData::LocalIndex (index, UniversalId::Type_Clothing)));
|
||||
|
||||
if (column==mType)
|
||||
return record.get().mData.mType;
|
||||
|
||||
return EnchantableRefIdAdapter<ESM::Clothing>::getData (column, data, index);
|
||||
}
|
||||
|
||||
void CSMWorld::ClothingRefIdAdapter::setData (const RefIdColumn *column, RefIdData& data, int index,
|
||||
const QVariant& value) const
|
||||
{
|
||||
Record<ESM::Clothing>& record = static_cast<Record<ESM::Clothing>&> (
|
||||
data.getRecord (RefIdData::LocalIndex (index, UniversalId::Type_Clothing)));
|
||||
|
||||
if (column==mType)
|
||||
record.get().mData.mType = value.toInt();
|
||||
else
|
||||
EnchantableRefIdAdapter<ESM::Clothing>::setData (column, data, index, value);
|
||||
}
|
||||
|
||||
CSMWorld::ContainerRefIdAdapter::ContainerRefIdAdapter (const NameColumns& columns,
|
||||
const RefIdColumn *weight, const RefIdColumn *organic, const RefIdColumn *respawn)
|
||||
: NameRefIdAdapter<ESM::Container> (UniversalId::Type_Container, columns), mWeight (weight),
|
||||
mOrganic (organic), mRespawn (respawn)
|
||||
{}
|
||||
|
||||
QVariant CSMWorld::ContainerRefIdAdapter::getData (const RefIdColumn *column, const RefIdData& data,
|
||||
int index) const
|
||||
{
|
||||
const Record<ESM::Container>& record = static_cast<const Record<ESM::Container>&> (
|
||||
data.getRecord (RefIdData::LocalIndex (index, UniversalId::Type_Container)));
|
||||
|
||||
if (column==mWeight)
|
||||
return record.get().mWeight;
|
||||
|
||||
if (column==mOrganic)
|
||||
return (record.get().mFlags & ESM::Container::Organic)!=0;
|
||||
|
||||
if (column==mRespawn)
|
||||
return (record.get().mFlags & ESM::Container::Respawn)!=0;
|
||||
|
||||
return NameRefIdAdapter<ESM::Container>::getData (column, data, index);
|
||||
}
|
||||
|
||||
void CSMWorld::ContainerRefIdAdapter::setData (const RefIdColumn *column, RefIdData& data, int index,
|
||||
const QVariant& value) const
|
||||
{
|
||||
Record<ESM::Container>& record = static_cast<Record<ESM::Container>&> (
|
||||
data.getRecord (RefIdData::LocalIndex (index, UniversalId::Type_Container)));
|
||||
|
||||
if (column==mWeight)
|
||||
record.get().mWeight = value.toFloat();
|
||||
else if (column==mOrganic)
|
||||
{
|
||||
if (value.toInt())
|
||||
record.get().mFlags |= ESM::Container::Organic;
|
||||
else
|
||||
record.get().mFlags &= ~ESM::Container::Organic;
|
||||
}
|
||||
else if (column==mRespawn)
|
||||
{
|
||||
if (value.toInt())
|
||||
record.get().mFlags |= ESM::Container::Respawn;
|
||||
else
|
||||
record.get().mFlags &= ~ESM::Container::Respawn;
|
||||
}
|
||||
else
|
||||
NameRefIdAdapter<ESM::Container>::setData (column, data, index, value);
|
||||
}
|
||||
|
||||
CSMWorld::CreatureColumns::CreatureColumns (const ActorColumns& actorColumns)
|
||||
: ActorColumns (actorColumns)
|
||||
{}
|
||||
|
||||
CSMWorld::CreatureRefIdAdapter::CreatureRefIdAdapter (const CreatureColumns& columns)
|
||||
: ActorRefIdAdapter<ESM::Creature> (UniversalId::Type_Creature, columns), mColumns (columns)
|
||||
{}
|
||||
|
||||
QVariant CSMWorld::CreatureRefIdAdapter::getData (const RefIdColumn *column, const RefIdData& data,
|
||||
int index) const
|
||||
{
|
||||
const Record<ESM::Creature>& record = static_cast<const Record<ESM::Creature>&> (
|
||||
data.getRecord (RefIdData::LocalIndex (index, UniversalId::Type_Creature)));
|
||||
|
||||
if (column==mColumns.mType)
|
||||
return record.get().mData.mType;
|
||||
|
||||
if (column==mColumns.mSoul)
|
||||
return record.get().mData.mSoul;
|
||||
|
||||
if (column==mColumns.mScale)
|
||||
return record.get().mScale;
|
||||
|
||||
if (column==mColumns.mOriginal)
|
||||
return QString::fromUtf8 (record.get().mOriginal.c_str());
|
||||
|
||||
std::map<const RefIdColumn *, unsigned int>::const_iterator iter =
|
||||
mColumns.mFlags.find (column);
|
||||
|
||||
if (iter!=mColumns.mFlags.end())
|
||||
return (record.get().mFlags & iter->second)!=0;
|
||||
|
||||
return ActorRefIdAdapter<ESM::Creature>::getData (column, data, index);
|
||||
}
|
||||
|
||||
void CSMWorld::CreatureRefIdAdapter::setData (const RefIdColumn *column, RefIdData& data, int index,
|
||||
const QVariant& value) const
|
||||
{
|
||||
Record<ESM::Creature>& record = static_cast<Record<ESM::Creature>&> (
|
||||
data.getRecord (RefIdData::LocalIndex (index, UniversalId::Type_Creature)));
|
||||
|
||||
if (column==mColumns.mType)
|
||||
record.get().mData.mType = value.toInt();
|
||||
else if (column==mColumns.mSoul)
|
||||
record.get().mData.mSoul = value.toInt();
|
||||
else if (column==mColumns.mScale)
|
||||
record.get().mScale = value.toFloat();
|
||||
else if (column==mColumns.mOriginal)
|
||||
record.get().mOriginal = value.toString().toUtf8().constData();
|
||||
else
|
||||
{
|
||||
std::map<const RefIdColumn *, unsigned int>::const_iterator iter =
|
||||
mColumns.mFlags.find (column);
|
||||
|
||||
if (iter!=mColumns.mFlags.end())
|
||||
{
|
||||
if (value.toInt()!=0)
|
||||
record.get().mFlags |= iter->second;
|
||||
else
|
||||
record.get().mFlags &= ~iter->second;
|
||||
}
|
||||
else
|
||||
ActorRefIdAdapter<ESM::Creature>::setData (column, data, index, value);
|
||||
}
|
||||
}
|
||||
|
||||
CSMWorld::DoorRefIdAdapter::DoorRefIdAdapter (const NameColumns& columns,
|
||||
const RefIdColumn *openSound, const RefIdColumn *closeSound)
|
||||
: NameRefIdAdapter<ESM::Door> (UniversalId::Type_Door, columns), mOpenSound (openSound),
|
||||
mCloseSound (closeSound)
|
||||
{}
|
||||
|
||||
QVariant CSMWorld::DoorRefIdAdapter::getData (const RefIdColumn *column, const RefIdData& data,
|
||||
int index) const
|
||||
{
|
||||
const Record<ESM::Door>& record = static_cast<const Record<ESM::Door>&> (
|
||||
data.getRecord (RefIdData::LocalIndex (index, UniversalId::Type_Door)));
|
||||
|
||||
if (column==mOpenSound)
|
||||
return QString::fromUtf8 (record.get().mOpenSound.c_str());
|
||||
|
||||
if (column==mCloseSound)
|
||||
return QString::fromUtf8 (record.get().mCloseSound.c_str());
|
||||
|
||||
return NameRefIdAdapter<ESM::Door>::getData (column, data, index);
|
||||
}
|
||||
|
||||
void CSMWorld::DoorRefIdAdapter::setData (const RefIdColumn *column, RefIdData& data, int index,
|
||||
const QVariant& value) const
|
||||
{
|
||||
Record<ESM::Door>& record = static_cast<Record<ESM::Door>&> (
|
||||
data.getRecord (RefIdData::LocalIndex (index, UniversalId::Type_Door)));
|
||||
|
||||
if (column==mOpenSound)
|
||||
record.get().mOpenSound = value.toString().toUtf8().constData();
|
||||
else if (column==mCloseSound)
|
||||
record.get().mCloseSound = value.toString().toUtf8().constData();
|
||||
else
|
||||
NameRefIdAdapter<ESM::Door>::setData (column, data, index, value);
|
||||
}
|
||||
|
||||
CSMWorld::LightColumns::LightColumns (const InventoryColumns& columns)
|
||||
: InventoryColumns (columns) {}
|
||||
|
||||
CSMWorld::LightRefIdAdapter::LightRefIdAdapter (const LightColumns& columns)
|
||||
: InventoryRefIdAdapter<ESM::Light> (UniversalId::Type_Light, columns), mColumns (columns)
|
||||
{}
|
||||
|
||||
QVariant CSMWorld::LightRefIdAdapter::getData (const RefIdColumn *column, const RefIdData& data,
|
||||
int index) const
|
||||
{
|
||||
const Record<ESM::Light>& record = static_cast<const Record<ESM::Light>&> (
|
||||
data.getRecord (RefIdData::LocalIndex (index, UniversalId::Type_Light)));
|
||||
|
||||
if (column==mColumns.mTime)
|
||||
return record.get().mData.mTime;
|
||||
|
||||
if (column==mColumns.mRadius)
|
||||
return record.get().mData.mRadius;
|
||||
|
||||
if (column==mColumns.mColor)
|
||||
return record.get().mData.mColor;
|
||||
|
||||
if (column==mColumns.mSound)
|
||||
return QString::fromUtf8 (record.get().mSound.c_str());
|
||||
|
||||
std::map<const RefIdColumn *, unsigned int>::const_iterator iter =
|
||||
mColumns.mFlags.find (column);
|
||||
|
||||
if (iter!=mColumns.mFlags.end())
|
||||
return (record.get().mData.mFlags & iter->second)!=0;
|
||||
|
||||
return InventoryRefIdAdapter<ESM::Light>::getData (column, data, index);
|
||||
}
|
||||
|
||||
void CSMWorld::LightRefIdAdapter::setData (const RefIdColumn *column, RefIdData& data, int index,
|
||||
const QVariant& value) const
|
||||
{
|
||||
Record<ESM::Light>& record = static_cast<Record<ESM::Light>&> (
|
||||
data.getRecord (RefIdData::LocalIndex (index, UniversalId::Type_Light)));
|
||||
|
||||
if (column==mColumns.mTime)
|
||||
record.get().mData.mTime = value.toInt();
|
||||
else if (column==mColumns.mRadius)
|
||||
record.get().mData.mRadius = value.toInt();
|
||||
else if (column==mColumns.mColor)
|
||||
record.get().mData.mColor = value.toInt();
|
||||
else if (column==mColumns.mSound)
|
||||
record.get().mSound = value.toString().toUtf8().constData();
|
||||
else
|
||||
{
|
||||
std::map<const RefIdColumn *, unsigned int>::const_iterator iter =
|
||||
mColumns.mFlags.find (column);
|
||||
|
||||
if (iter!=mColumns.mFlags.end())
|
||||
{
|
||||
if (value.toInt()!=0)
|
||||
record.get().mData.mFlags |= iter->second;
|
||||
else
|
||||
record.get().mData.mFlags &= ~iter->second;
|
||||
}
|
||||
else
|
||||
InventoryRefIdAdapter<ESM::Light>::setData (column, data, index, value);
|
||||
}
|
||||
}
|
||||
|
||||
CSMWorld::MiscRefIdAdapter::MiscRefIdAdapter (const InventoryColumns& columns, const RefIdColumn *key)
|
||||
: InventoryRefIdAdapter<ESM::Miscellaneous> (UniversalId::Type_Miscellaneous, columns), mKey (key)
|
||||
{}
|
||||
|
||||
QVariant CSMWorld::MiscRefIdAdapter::getData (const RefIdColumn *column, const RefIdData& data,
|
||||
int index) const
|
||||
{
|
||||
const Record<ESM::Miscellaneous>& record = static_cast<const Record<ESM::Miscellaneous>&> (
|
||||
data.getRecord (RefIdData::LocalIndex (index, UniversalId::Type_Miscellaneous)));
|
||||
|
||||
if (column==mKey)
|
||||
return record.get().mData.mIsKey!=0;
|
||||
|
||||
return InventoryRefIdAdapter<ESM::Miscellaneous>::getData (column, data, index);
|
||||
}
|
||||
|
||||
void CSMWorld::MiscRefIdAdapter::setData (const RefIdColumn *column, RefIdData& data, int index,
|
||||
const QVariant& value) const
|
||||
{
|
||||
Record<ESM::Miscellaneous>& record = static_cast<Record<ESM::Miscellaneous>&> (
|
||||
data.getRecord (RefIdData::LocalIndex (index, UniversalId::Type_Miscellaneous)));
|
||||
|
||||
if (column==mKey)
|
||||
record.get().mData.mIsKey = value.toInt();
|
||||
else
|
||||
InventoryRefIdAdapter<ESM::Miscellaneous>::setData (column, data, index, value);
|
||||
}
|
||||
|
||||
CSMWorld::NpcColumns::NpcColumns (const ActorColumns& actorColumns) : ActorColumns (actorColumns) {}
|
||||
|
||||
CSMWorld::NpcRefIdAdapter::NpcRefIdAdapter (const NpcColumns& columns)
|
||||
: ActorRefIdAdapter<ESM::NPC> (UniversalId::Type_Npc, columns), mColumns (columns)
|
||||
{}
|
||||
|
||||
QVariant CSMWorld::NpcRefIdAdapter::getData (const RefIdColumn *column, const RefIdData& data, int index)
|
||||
const
|
||||
{
|
||||
const Record<ESM::NPC>& record = static_cast<const Record<ESM::NPC>&> (
|
||||
data.getRecord (RefIdData::LocalIndex (index, UniversalId::Type_Npc)));
|
||||
|
||||
if (column==mColumns.mRace)
|
||||
return QString::fromUtf8 (record.get().mRace.c_str());
|
||||
|
||||
if (column==mColumns.mClass)
|
||||
return QString::fromUtf8 (record.get().mClass.c_str());
|
||||
|
||||
if (column==mColumns.mFaction)
|
||||
return QString::fromUtf8 (record.get().mFaction.c_str());
|
||||
|
||||
if (column==mColumns.mHair)
|
||||
return QString::fromUtf8 (record.get().mHair.c_str());
|
||||
|
||||
if (column==mColumns.mHead)
|
||||
return QString::fromUtf8 (record.get().mHead.c_str());
|
||||
|
||||
std::map<const RefIdColumn *, unsigned int>::const_iterator iter =
|
||||
mColumns.mFlags.find (column);
|
||||
|
||||
if (iter!=mColumns.mFlags.end())
|
||||
return (record.get().mFlags & iter->second)!=0;
|
||||
|
||||
return ActorRefIdAdapter<ESM::NPC>::getData (column, data, index);
|
||||
}
|
||||
|
||||
void CSMWorld::NpcRefIdAdapter::setData (const RefIdColumn *column, RefIdData& data, int index,
|
||||
const QVariant& value) const
|
||||
{
|
||||
Record<ESM::NPC>& record = static_cast<Record<ESM::NPC>&> (
|
||||
data.getRecord (RefIdData::LocalIndex (index, UniversalId::Type_Npc)));
|
||||
|
||||
if (column==mColumns.mRace)
|
||||
record.get().mRace = value.toString().toUtf8().constData();
|
||||
else if (column==mColumns.mClass)
|
||||
record.get().mClass = value.toString().toUtf8().constData();
|
||||
else if (column==mColumns.mFaction)
|
||||
record.get().mFaction = value.toString().toUtf8().constData();
|
||||
else if (column==mColumns.mHair)
|
||||
record.get().mHair = value.toString().toUtf8().constData();
|
||||
else if (column==mColumns.mHead)
|
||||
record.get().mHead = value.toString().toUtf8().constData();
|
||||
else
|
||||
{
|
||||
std::map<const RefIdColumn *, unsigned int>::const_iterator iter =
|
||||
mColumns.mFlags.find (column);
|
||||
|
||||
if (iter!=mColumns.mFlags.end())
|
||||
{
|
||||
if (value.toInt()!=0)
|
||||
record.get().mFlags |= iter->second;
|
||||
else
|
||||
record.get().mFlags &= ~iter->second;
|
||||
}
|
||||
else
|
||||
ActorRefIdAdapter<ESM::NPC>::setData (column, data, index, value);
|
||||
}
|
||||
}
|
||||
|
||||
CSMWorld::WeaponColumns::WeaponColumns (const EnchantableColumns& columns)
|
||||
: EnchantableColumns (columns) {}
|
||||
|
||||
CSMWorld::WeaponRefIdAdapter::WeaponRefIdAdapter (const WeaponColumns& columns)
|
||||
: EnchantableRefIdAdapter<ESM::Weapon> (UniversalId::Type_Weapon, columns), mColumns (columns)
|
||||
{}
|
||||
|
||||
QVariant CSMWorld::WeaponRefIdAdapter::getData (const RefIdColumn *column, const RefIdData& data,
|
||||
int index) const
|
||||
{
|
||||
const Record<ESM::Weapon>& record = static_cast<const Record<ESM::Weapon>&> (
|
||||
data.getRecord (RefIdData::LocalIndex (index, UniversalId::Type_Weapon)));
|
||||
|
||||
if (column==mColumns.mType)
|
||||
return record.get().mData.mType;
|
||||
|
||||
if (column==mColumns.mHealth)
|
||||
return record.get().mData.mHealth;
|
||||
|
||||
if (column==mColumns.mSpeed)
|
||||
return record.get().mData.mSpeed;
|
||||
|
||||
if (column==mColumns.mReach)
|
||||
return record.get().mData.mReach;
|
||||
|
||||
for (int i=0; i<2; ++i)
|
||||
{
|
||||
if (column==mColumns.mChop[i])
|
||||
return record.get().mData.mChop[i];
|
||||
|
||||
if (column==mColumns.mSlash[i])
|
||||
return record.get().mData.mSlash[i];
|
||||
|
||||
if (column==mColumns.mThrust[i])
|
||||
return record.get().mData.mThrust[i];
|
||||
}
|
||||
|
||||
std::map<const RefIdColumn *, unsigned int>::const_iterator iter =
|
||||
mColumns.mFlags.find (column);
|
||||
|
||||
if (iter!=mColumns.mFlags.end())
|
||||
return (record.get().mData.mFlags & iter->second)!=0;
|
||||
|
||||
return EnchantableRefIdAdapter<ESM::Weapon>::getData (column, data, index);
|
||||
}
|
||||
|
||||
void CSMWorld::WeaponRefIdAdapter::setData (const RefIdColumn *column, RefIdData& data, int index,
|
||||
const QVariant& value) const
|
||||
{
|
||||
Record<ESM::Weapon>& record = static_cast<Record<ESM::Weapon>&> (
|
||||
data.getRecord (RefIdData::LocalIndex (index, UniversalId::Type_Weapon)));
|
||||
|
||||
if (column==mColumns.mType)
|
||||
record.get().mData.mType = value.toInt();
|
||||
else if (column==mColumns.mHealth)
|
||||
record.get().mData.mHealth = value.toInt();
|
||||
else if (column==mColumns.mSpeed)
|
||||
record.get().mData.mSpeed = value.toFloat();
|
||||
else if (column==mColumns.mReach)
|
||||
record.get().mData.mReach = value.toFloat();
|
||||
else if (column==mColumns.mChop[0])
|
||||
record.get().mData.mChop[0] = value.toInt();
|
||||
else if (column==mColumns.mChop[1])
|
||||
record.get().mData.mChop[1] = value.toInt();
|
||||
else if (column==mColumns.mSlash[0])
|
||||
record.get().mData.mSlash[0] = value.toInt();
|
||||
else if (column==mColumns.mSlash[1])
|
||||
record.get().mData.mSlash[1] = value.toInt();
|
||||
else if (column==mColumns.mThrust[0])
|
||||
record.get().mData.mThrust[0] = value.toInt();
|
||||
else if (column==mColumns.mThrust[1])
|
||||
record.get().mData.mThrust[1] = value.toInt();
|
||||
else
|
||||
{
|
||||
std::map<const RefIdColumn *, unsigned int>::const_iterator iter =
|
||||
mColumns.mFlags.find (column);
|
||||
|
||||
if (iter!=mColumns.mFlags.end())
|
||||
{
|
||||
if (value.toInt()!=0)
|
||||
record.get().mData.mFlags |= iter->second;
|
||||
else
|
||||
record.get().mData.mFlags &= ~iter->second;
|
||||
}
|
||||
else
|
||||
EnchantableRefIdAdapter<ESM::Weapon>::setData (column, data, index, value);
|
||||
}
|
||||
}
|
@ -0,0 +1,766 @@
|
||||
#ifndef CSM_WOLRD_REFIDADAPTERIMP_H
|
||||
#define CSM_WOLRD_REFIDADAPTERIMP_H
|
||||
|
||||
#include <map>
|
||||
|
||||
#include <QVariant>
|
||||
|
||||
#include <components/esm/loadalch.hpp>
|
||||
#include <components/esm/loadappa.hpp>
|
||||
|
||||
#include "record.hpp"
|
||||
#include "refiddata.hpp"
|
||||
#include "universalid.hpp"
|
||||
#include "refidadapter.hpp"
|
||||
|
||||
namespace CSMWorld
|
||||
{
|
||||
struct BaseColumns
|
||||
{
|
||||
const RefIdColumn *mId;
|
||||
const RefIdColumn *mModified;
|
||||
const RefIdColumn *mType;
|
||||
};
|
||||
|
||||
/// \brief Base adapter for all refereceable record types
|
||||
template<typename RecordT>
|
||||
class BaseRefIdAdapter : public RefIdAdapter
|
||||
{
|
||||
UniversalId::Type mType;
|
||||
BaseColumns mBase;
|
||||
|
||||
public:
|
||||
|
||||
BaseRefIdAdapter (UniversalId::Type type, const BaseColumns& base);
|
||||
|
||||
virtual std::string getId (const RecordBase& record) const;
|
||||
|
||||
virtual QVariant getData (const RefIdColumn *column, const RefIdData& data, int index)
|
||||
const;
|
||||
|
||||
virtual void setData (const RefIdColumn *column, RefIdData& data, int index,
|
||||
const QVariant& value) const;
|
||||
///< If the data type does not match an exception is thrown.
|
||||
|
||||
UniversalId::Type getType() const;
|
||||
};
|
||||
|
||||
template<typename RecordT>
|
||||
BaseRefIdAdapter<RecordT>::BaseRefIdAdapter (UniversalId::Type type, const BaseColumns& base)
|
||||
: mType (type), mBase (base)
|
||||
{}
|
||||
|
||||
template<typename RecordT>
|
||||
std::string BaseRefIdAdapter<RecordT>::getId (const RecordBase& record) const
|
||||
{
|
||||
return dynamic_cast<const Record<RecordT>&> (record).get().mId;
|
||||
}
|
||||
|
||||
template<typename RecordT>
|
||||
QVariant BaseRefIdAdapter<RecordT>::getData (const RefIdColumn *column, const RefIdData& data,
|
||||
int index) const
|
||||
{
|
||||
const Record<RecordT>& record = static_cast<const Record<RecordT>&> (
|
||||
data.getRecord (RefIdData::LocalIndex (index, mType)));
|
||||
|
||||
if (column==mBase.mId)
|
||||
return QString::fromUtf8 (record.get().mId.c_str());
|
||||
|
||||
if (column==mBase.mModified)
|
||||
{
|
||||
if (record.mState==Record<RecordT>::State_Erased)
|
||||
return static_cast<int> (Record<RecordT>::State_Deleted);
|
||||
|
||||
return static_cast<int> (record.mState);
|
||||
}
|
||||
|
||||
if (column==mBase.mType)
|
||||
return static_cast<int> (mType);
|
||||
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
template<typename RecordT>
|
||||
void BaseRefIdAdapter<RecordT>::setData (const RefIdColumn *column, RefIdData& data, int index,
|
||||
const QVariant& value) const
|
||||
{
|
||||
Record<RecordT>& record = static_cast<Record<RecordT>&> (
|
||||
data.getRecord (RefIdData::LocalIndex (index, mType)));
|
||||
|
||||
if (column==mBase.mModified)
|
||||
record.mState = static_cast<RecordBase::State> (value.toInt());
|
||||
}
|
||||
|
||||
template<typename RecordT>
|
||||
UniversalId::Type BaseRefIdAdapter<RecordT>::getType() const
|
||||
{
|
||||
return mType;
|
||||
}
|
||||
|
||||
|
||||
struct ModelColumns : public BaseColumns
|
||||
{
|
||||
const RefIdColumn *mModel;
|
||||
|
||||
ModelColumns (const BaseColumns& base) : BaseColumns (base) {}
|
||||
};
|
||||
|
||||
/// \brief Adapter for IDs with models (all but levelled lists)
|
||||
template<typename RecordT>
|
||||
class ModelRefIdAdapter : public BaseRefIdAdapter<RecordT>
|
||||
{
|
||||
ModelColumns mModel;
|
||||
|
||||
public:
|
||||
|
||||
ModelRefIdAdapter (UniversalId::Type type, const ModelColumns& columns);
|
||||
|
||||
virtual QVariant getData (const RefIdColumn *column, const RefIdData& data, int index)
|
||||
const;
|
||||
|
||||
virtual void setData (const RefIdColumn *column, RefIdData& data, int index,
|
||||
const QVariant& value) const;
|
||||
///< If the data type does not match an exception is thrown.
|
||||
};
|
||||
|
||||
template<typename RecordT>
|
||||
ModelRefIdAdapter<RecordT>::ModelRefIdAdapter (UniversalId::Type type, const ModelColumns& columns)
|
||||
: BaseRefIdAdapter<RecordT> (type, columns), mModel (columns)
|
||||
{}
|
||||
|
||||
template<typename RecordT>
|
||||
QVariant ModelRefIdAdapter<RecordT>::getData (const RefIdColumn *column, const RefIdData& data,
|
||||
int index) const
|
||||
{
|
||||
const Record<RecordT>& record = static_cast<const Record<RecordT>&> (
|
||||
data.getRecord (RefIdData::LocalIndex (index, BaseRefIdAdapter<RecordT>::getType())));
|
||||
|
||||
if (column==mModel.mModel)
|
||||
return QString::fromUtf8 (record.get().mModel.c_str());
|
||||
|
||||
return BaseRefIdAdapter<RecordT>::getData (column, data, index);
|
||||
}
|
||||
|
||||
template<typename RecordT>
|
||||
void ModelRefIdAdapter<RecordT>::setData (const RefIdColumn *column, RefIdData& data, int index,
|
||||
const QVariant& value) const
|
||||
{
|
||||
Record<RecordT>& record = static_cast<Record<RecordT>&> (
|
||||
data.getRecord (RefIdData::LocalIndex (index, BaseRefIdAdapter<RecordT>::getType())));
|
||||
|
||||
if (column==mModel.mModel)
|
||||
record.get().mModel = value.toString().toUtf8().constData();
|
||||
else
|
||||
BaseRefIdAdapter<RecordT>::setData (column, data, index, value);
|
||||
}
|
||||
|
||||
struct NameColumns : public ModelColumns
|
||||
{
|
||||
const RefIdColumn *mName;
|
||||
const RefIdColumn *mScript;
|
||||
|
||||
NameColumns (const ModelColumns& base) : ModelColumns (base) {}
|
||||
};
|
||||
|
||||
/// \brief Adapter for IDs with names (all but levelled lists and statics)
|
||||
template<typename RecordT>
|
||||
class NameRefIdAdapter : public ModelRefIdAdapter<RecordT>
|
||||
{
|
||||
NameColumns mName;
|
||||
|
||||
public:
|
||||
|
||||
NameRefIdAdapter (UniversalId::Type type, const NameColumns& columns);
|
||||
|
||||
virtual QVariant getData (const RefIdColumn *column, const RefIdData& data, int index)
|
||||
const;
|
||||
|
||||
virtual void setData (const RefIdColumn *column, RefIdData& data, int index,
|
||||
const QVariant& value) const;
|
||||
///< If the data type does not match an exception is thrown.
|
||||
};
|
||||
|
||||
template<typename RecordT>
|
||||
NameRefIdAdapter<RecordT>::NameRefIdAdapter (UniversalId::Type type, const NameColumns& columns)
|
||||
: ModelRefIdAdapter<RecordT> (type, columns), mName (columns)
|
||||
{}
|
||||
|
||||
template<typename RecordT>
|
||||
QVariant NameRefIdAdapter<RecordT>::getData (const RefIdColumn *column, const RefIdData& data,
|
||||
int index) const
|
||||
{
|
||||
const Record<RecordT>& record = static_cast<const Record<RecordT>&> (
|
||||
data.getRecord (RefIdData::LocalIndex (index, BaseRefIdAdapter<RecordT>::getType())));
|
||||
|
||||
if (column==mName.mName)
|
||||
return QString::fromUtf8 (record.get().mName.c_str());
|
||||
|
||||
if (column==mName.mScript)
|
||||
return QString::fromUtf8 (record.get().mScript.c_str());
|
||||
|
||||
return ModelRefIdAdapter<RecordT>::getData (column, data, index);
|
||||
}
|
||||
|
||||
template<typename RecordT>
|
||||
void NameRefIdAdapter<RecordT>::setData (const RefIdColumn *column, RefIdData& data, int index,
|
||||
const QVariant& value) const
|
||||
{
|
||||
Record<RecordT>& record = static_cast<Record<RecordT>&> (
|
||||
data.getRecord (RefIdData::LocalIndex (index, BaseRefIdAdapter<RecordT>::getType())));
|
||||
|
||||
if (column==mName.mName)
|
||||
record.get().mName = value.toString().toUtf8().constData();
|
||||
else if (column==mName.mScript)
|
||||
record.get().mScript = value.toString().toUtf8().constData();
|
||||
else
|
||||
ModelRefIdAdapter<RecordT>::setData (column, data, index, value);
|
||||
}
|
||||
|
||||
struct InventoryColumns : public NameColumns
|
||||
{
|
||||
const RefIdColumn *mIcon;
|
||||
const RefIdColumn *mWeight;
|
||||
const RefIdColumn *mValue;
|
||||
|
||||
InventoryColumns (const NameColumns& base) : NameColumns (base) {}
|
||||
};
|
||||
|
||||
/// \brief Adapter for IDs that can go into an inventory
|
||||
template<typename RecordT>
|
||||
class InventoryRefIdAdapter : public NameRefIdAdapter<RecordT>
|
||||
{
|
||||
InventoryColumns mInventory;
|
||||
|
||||
public:
|
||||
|
||||
InventoryRefIdAdapter (UniversalId::Type type, const InventoryColumns& columns);
|
||||
|
||||
virtual QVariant getData (const RefIdColumn *column, const RefIdData& data, int index)
|
||||
const;
|
||||
|
||||
virtual void setData (const RefIdColumn *column, RefIdData& data, int index,
|
||||
const QVariant& value) const;
|
||||
///< If the data type does not match an exception is thrown.
|
||||
};
|
||||
|
||||
template<typename RecordT>
|
||||
InventoryRefIdAdapter<RecordT>::InventoryRefIdAdapter (UniversalId::Type type,
|
||||
const InventoryColumns& columns)
|
||||
: NameRefIdAdapter<RecordT> (type, columns), mInventory (columns)
|
||||
{}
|
||||
|
||||
template<typename RecordT>
|
||||
QVariant InventoryRefIdAdapter<RecordT>::getData (const RefIdColumn *column, const RefIdData& data,
|
||||
int index) const
|
||||
{
|
||||
const Record<RecordT>& record = static_cast<const Record<RecordT>&> (
|
||||
data.getRecord (RefIdData::LocalIndex (index, BaseRefIdAdapter<RecordT>::getType())));
|
||||
|
||||
if (column==mInventory.mIcon)
|
||||
return QString::fromUtf8 (record.get().mIcon.c_str());
|
||||
|
||||
if (column==mInventory.mWeight)
|
||||
return record.get().mData.mWeight;
|
||||
|
||||
if (column==mInventory.mValue)
|
||||
return record.get().mData.mValue;
|
||||
|
||||
return NameRefIdAdapter<RecordT>::getData (column, data, index);
|
||||
}
|
||||
|
||||
template<typename RecordT>
|
||||
void InventoryRefIdAdapter<RecordT>::setData (const RefIdColumn *column, RefIdData& data, int index,
|
||||
const QVariant& value) const
|
||||
{
|
||||
Record<RecordT>& record = static_cast<Record<RecordT>&> (
|
||||
data.getRecord (RefIdData::LocalIndex (index, BaseRefIdAdapter<RecordT>::getType())));
|
||||
|
||||
if (column==mInventory.mIcon)
|
||||
record.get().mIcon = value.toString().toUtf8().constData();
|
||||
else if (column==mInventory.mWeight)
|
||||
record.get().mData.mWeight = value.toFloat();
|
||||
else if (column==mInventory.mValue)
|
||||
record.get().mData.mValue = value.toInt();
|
||||
else
|
||||
NameRefIdAdapter<RecordT>::setData (column, data, index, value);
|
||||
}
|
||||
|
||||
class PotionRefIdAdapter : public InventoryRefIdAdapter<ESM::Potion>
|
||||
{
|
||||
const RefIdColumn *mAutoCalc;
|
||||
|
||||
public:
|
||||
|
||||
PotionRefIdAdapter (const InventoryColumns& columns, const RefIdColumn *autoCalc);
|
||||
|
||||
virtual QVariant getData (const RefIdColumn *column, const RefIdData& data, int index)
|
||||
const;
|
||||
|
||||
virtual void setData (const RefIdColumn *column, RefIdData& data, int index,
|
||||
const QVariant& value) const;
|
||||
///< If the data type does not match an exception is thrown.
|
||||
};
|
||||
|
||||
struct EnchantableColumns : public InventoryColumns
|
||||
{
|
||||
const RefIdColumn *mEnchantment;
|
||||
const RefIdColumn *mEnchantmentPoints;
|
||||
|
||||
EnchantableColumns (const InventoryColumns& base) : InventoryColumns (base) {}
|
||||
};
|
||||
|
||||
/// \brief Adapter for enchantable IDs
|
||||
template<typename RecordT>
|
||||
class EnchantableRefIdAdapter : public InventoryRefIdAdapter<RecordT>
|
||||
{
|
||||
EnchantableColumns mEnchantable;
|
||||
|
||||
public:
|
||||
|
||||
EnchantableRefIdAdapter (UniversalId::Type type, const EnchantableColumns& columns);
|
||||
|
||||
virtual QVariant getData (const RefIdColumn *column, const RefIdData& data, int index)
|
||||
const;
|
||||
|
||||
virtual void setData (const RefIdColumn *column, RefIdData& data, int index,
|
||||
const QVariant& value) const;
|
||||
///< If the data type does not match an exception is thrown.
|
||||
};
|
||||
|
||||
template<typename RecordT>
|
||||
EnchantableRefIdAdapter<RecordT>::EnchantableRefIdAdapter (UniversalId::Type type,
|
||||
const EnchantableColumns& columns)
|
||||
: InventoryRefIdAdapter<RecordT> (type, columns), mEnchantable (columns)
|
||||
{}
|
||||
|
||||
template<typename RecordT>
|
||||
QVariant EnchantableRefIdAdapter<RecordT>::getData (const RefIdColumn *column, const RefIdData& data,
|
||||
int index) const
|
||||
{
|
||||
const Record<RecordT>& record = static_cast<const Record<RecordT>&> (
|
||||
data.getRecord (RefIdData::LocalIndex (index, BaseRefIdAdapter<RecordT>::getType())));
|
||||
|
||||
if (column==mEnchantable.mEnchantment)
|
||||
return QString::fromUtf8 (record.get().mEnchant.c_str());
|
||||
|
||||
if (column==mEnchantable.mEnchantmentPoints)
|
||||
return static_cast<int> (record.get().mData.mEnchant);
|
||||
|
||||
return InventoryRefIdAdapter<RecordT>::getData (column, data, index);
|
||||
}
|
||||
|
||||
template<typename RecordT>
|
||||
void EnchantableRefIdAdapter<RecordT>::setData (const RefIdColumn *column, RefIdData& data,
|
||||
int index, const QVariant& value) const
|
||||
{
|
||||
Record<RecordT>& record = static_cast<Record<RecordT>&> (
|
||||
data.getRecord (RefIdData::LocalIndex (index, BaseRefIdAdapter<RecordT>::getType())));
|
||||
|
||||
if (column==mEnchantable.mEnchantment)
|
||||
record.get().mEnchant = value.toString().toUtf8().constData();
|
||||
else if (column==mEnchantable.mEnchantmentPoints)
|
||||
record.get().mData.mEnchant = value.toInt();
|
||||
else
|
||||
InventoryRefIdAdapter<RecordT>::setData (column, data, index, value);
|
||||
}
|
||||
|
||||
struct ToolColumns : public InventoryColumns
|
||||
{
|
||||
const RefIdColumn *mQuality;
|
||||
const RefIdColumn *mUses;
|
||||
|
||||
ToolColumns (const InventoryColumns& base) : InventoryColumns (base) {}
|
||||
};
|
||||
|
||||
/// \brief Adapter for tools with limited uses IDs (lockpick, repair, probes)
|
||||
template<typename RecordT>
|
||||
class ToolRefIdAdapter : public InventoryRefIdAdapter<RecordT>
|
||||
{
|
||||
ToolColumns mTools;
|
||||
|
||||
public:
|
||||
|
||||
ToolRefIdAdapter (UniversalId::Type type, const ToolColumns& columns);
|
||||
|
||||
virtual QVariant getData (const RefIdColumn *column, const RefIdData& data, int index)
|
||||
const;
|
||||
|
||||
virtual void setData (const RefIdColumn *column, RefIdData& data, int index,
|
||||
const QVariant& value) const;
|
||||
///< If the data type does not match an exception is thrown.
|
||||
};
|
||||
|
||||
template<typename RecordT>
|
||||
ToolRefIdAdapter<RecordT>::ToolRefIdAdapter (UniversalId::Type type, const ToolColumns& columns)
|
||||
: InventoryRefIdAdapter<RecordT> (type, columns), mTools (columns)
|
||||
{}
|
||||
|
||||
template<typename RecordT>
|
||||
QVariant ToolRefIdAdapter<RecordT>::getData (const RefIdColumn *column, const RefIdData& data,
|
||||
int index) const
|
||||
{
|
||||
const Record<RecordT>& record = static_cast<const Record<RecordT>&> (
|
||||
data.getRecord (RefIdData::LocalIndex (index, BaseRefIdAdapter<RecordT>::getType())));
|
||||
|
||||
if (column==mTools.mQuality)
|
||||
return record.get().mData.mQuality;
|
||||
|
||||
if (column==mTools.mUses)
|
||||
return record.get().mData.mUses;
|
||||
|
||||
return InventoryRefIdAdapter<RecordT>::getData (column, data, index);
|
||||
}
|
||||
|
||||
template<typename RecordT>
|
||||
void ToolRefIdAdapter<RecordT>::setData (const RefIdColumn *column, RefIdData& data,
|
||||
int index, const QVariant& value) const
|
||||
{
|
||||
Record<RecordT>& record = static_cast<Record<RecordT>&> (
|
||||
data.getRecord (RefIdData::LocalIndex (index, BaseRefIdAdapter<RecordT>::getType())));
|
||||
|
||||
if (column==mTools.mQuality)
|
||||
record.get().mData.mQuality = value.toFloat();
|
||||
else if (column==mTools.mUses)
|
||||
record.get().mData.mUses = value.toInt();
|
||||
else
|
||||
InventoryRefIdAdapter<RecordT>::setData (column, data, index, value);
|
||||
}
|
||||
|
||||
struct ActorColumns : public NameColumns
|
||||
{
|
||||
const RefIdColumn *mHasAi;
|
||||
const RefIdColumn *mHello;
|
||||
const RefIdColumn *mFlee;
|
||||
const RefIdColumn *mFight;
|
||||
const RefIdColumn *mAlarm;
|
||||
std::map<const RefIdColumn *, unsigned int> mServices;
|
||||
|
||||
ActorColumns (const NameColumns& base) : NameColumns (base) {}
|
||||
};
|
||||
|
||||
/// \brief Adapter for actor IDs (handles common AI functionality)
|
||||
template<typename RecordT>
|
||||
class ActorRefIdAdapter : public NameRefIdAdapter<RecordT>
|
||||
{
|
||||
ActorColumns mActors;
|
||||
|
||||
public:
|
||||
|
||||
ActorRefIdAdapter (UniversalId::Type type, const ActorColumns& columns);
|
||||
|
||||
virtual QVariant getData (const RefIdColumn *column, const RefIdData& data, int index)
|
||||
const;
|
||||
|
||||
virtual void setData (const RefIdColumn *column, RefIdData& data, int index,
|
||||
const QVariant& value) const;
|
||||
///< If the data type does not match an exception is thrown.
|
||||
};
|
||||
|
||||
template<typename RecordT>
|
||||
ActorRefIdAdapter<RecordT>::ActorRefIdAdapter (UniversalId::Type type,
|
||||
const ActorColumns& columns)
|
||||
: NameRefIdAdapter<RecordT> (type, columns), mActors (columns)
|
||||
{}
|
||||
|
||||
template<typename RecordT>
|
||||
QVariant ActorRefIdAdapter<RecordT>::getData (const RefIdColumn *column, const RefIdData& data,
|
||||
int index) const
|
||||
{
|
||||
const Record<RecordT>& record = static_cast<const Record<RecordT>&> (
|
||||
data.getRecord (RefIdData::LocalIndex (index, BaseRefIdAdapter<RecordT>::getType())));
|
||||
|
||||
if (column==mActors.mHasAi)
|
||||
return record.get().mHasAI!=0;
|
||||
|
||||
if (column==mActors.mHello)
|
||||
return record.get().mAiData.mHello;
|
||||
|
||||
if (column==mActors.mFlee)
|
||||
return record.get().mAiData.mFlee;
|
||||
|
||||
if (column==mActors.mFight)
|
||||
return record.get().mAiData.mFight;
|
||||
|
||||
if (column==mActors.mAlarm)
|
||||
return record.get().mAiData.mAlarm;
|
||||
|
||||
std::map<const RefIdColumn *, unsigned int>::const_iterator iter =
|
||||
mActors.mServices.find (column);
|
||||
|
||||
if (iter!=mActors.mServices.end())
|
||||
return (record.get().mAiData.mServices & iter->second)!=0;
|
||||
|
||||
return NameRefIdAdapter<RecordT>::getData (column, data, index);
|
||||
}
|
||||
|
||||
template<typename RecordT>
|
||||
void ActorRefIdAdapter<RecordT>::setData (const RefIdColumn *column, RefIdData& data, int index,
|
||||
const QVariant& value) const
|
||||
{
|
||||
Record<RecordT>& record = static_cast<Record<RecordT>&> (
|
||||
data.getRecord (RefIdData::LocalIndex (index, BaseRefIdAdapter<RecordT>::getType())));
|
||||
|
||||
if (column==mActors.mHasAi)
|
||||
record.get().mHasAI = value.toInt();
|
||||
else if (column==mActors.mHello)
|
||||
record.get().mAiData.mHello = value.toInt();
|
||||
else if (column==mActors.mFlee)
|
||||
record.get().mAiData.mFlee = value.toInt();
|
||||
else if (column==mActors.mFight)
|
||||
record.get().mAiData.mFight = value.toInt();
|
||||
else if (column==mActors.mAlarm)
|
||||
record.get().mAiData.mAlarm = value.toInt();
|
||||
else
|
||||
{
|
||||
typename std::map<const RefIdColumn *, unsigned int>::const_iterator iter =
|
||||
mActors.mServices.find (column);
|
||||
if (iter!=mActors.mServices.end())
|
||||
{
|
||||
if (value.toInt()!=0)
|
||||
record.get().mAiData.mServices |= iter->second;
|
||||
else
|
||||
record.get().mAiData.mServices &= ~iter->second;
|
||||
}
|
||||
else
|
||||
NameRefIdAdapter<RecordT>::setData (column, data, index, value);
|
||||
}
|
||||
}
|
||||
|
||||
class ApparatusRefIdAdapter : public InventoryRefIdAdapter<ESM::Apparatus>
|
||||
{
|
||||
const RefIdColumn *mType;
|
||||
const RefIdColumn *mQuality;
|
||||
|
||||
public:
|
||||
|
||||
ApparatusRefIdAdapter (const InventoryColumns& columns, const RefIdColumn *type,
|
||||
const RefIdColumn *quality);
|
||||
|
||||
virtual QVariant getData (const RefIdColumn *column, const RefIdData& data, int index)
|
||||
const;
|
||||
|
||||
virtual void setData (const RefIdColumn *column, RefIdData& data, int index,
|
||||
const QVariant& value) const;
|
||||
///< If the data type does not match an exception is thrown.
|
||||
};
|
||||
|
||||
class ArmorRefIdAdapter : public EnchantableRefIdAdapter<ESM::Armor>
|
||||
{
|
||||
const RefIdColumn *mType;
|
||||
const RefIdColumn *mHealth;
|
||||
const RefIdColumn *mArmor;
|
||||
|
||||
public:
|
||||
|
||||
ArmorRefIdAdapter (const EnchantableColumns& columns, const RefIdColumn *type,
|
||||
const RefIdColumn *health, const RefIdColumn *armor);
|
||||
|
||||
virtual QVariant getData (const RefIdColumn *column, const RefIdData& data, int index)
|
||||
const;
|
||||
|
||||
virtual void setData (const RefIdColumn *column, RefIdData& data, int index,
|
||||
const QVariant& value) const;
|
||||
///< If the data type does not match an exception is thrown.
|
||||
};
|
||||
|
||||
class BookRefIdAdapter : public EnchantableRefIdAdapter<ESM::Book>
|
||||
{
|
||||
const RefIdColumn *mScroll;
|
||||
const RefIdColumn *mSkill;
|
||||
|
||||
public:
|
||||
|
||||
BookRefIdAdapter (const EnchantableColumns& columns, const RefIdColumn *scroll,
|
||||
const RefIdColumn *skill);
|
||||
|
||||
virtual QVariant getData (const RefIdColumn *column, const RefIdData& data, int index)
|
||||
const;
|
||||
|
||||
virtual void setData (const RefIdColumn *column, RefIdData& data, int index,
|
||||
const QVariant& value) const;
|
||||
///< If the data type does not match an exception is thrown.
|
||||
};
|
||||
|
||||
class ClothingRefIdAdapter : public EnchantableRefIdAdapter<ESM::Clothing>
|
||||
{
|
||||
const RefIdColumn *mType;
|
||||
|
||||
public:
|
||||
|
||||
ClothingRefIdAdapter (const EnchantableColumns& columns, const RefIdColumn *type);
|
||||
|
||||
virtual QVariant getData (const RefIdColumn *column, const RefIdData& data, int index)
|
||||
const;
|
||||
|
||||
virtual void setData (const RefIdColumn *column, RefIdData& data, int index,
|
||||
const QVariant& value) const;
|
||||
///< If the data type does not match an exception is thrown.
|
||||
};
|
||||
|
||||
class ContainerRefIdAdapter : public NameRefIdAdapter<ESM::Container>
|
||||
{
|
||||
const RefIdColumn *mWeight;
|
||||
const RefIdColumn *mOrganic;
|
||||
const RefIdColumn *mRespawn;
|
||||
|
||||
public:
|
||||
|
||||
ContainerRefIdAdapter (const NameColumns& columns, const RefIdColumn *weight,
|
||||
const RefIdColumn *organic, const RefIdColumn *respawn);
|
||||
|
||||
virtual QVariant getData (const RefIdColumn *column, const RefIdData& data, int index)
|
||||
const;
|
||||
|
||||
virtual void setData (const RefIdColumn *column, RefIdData& data, int index,
|
||||
const QVariant& value) const;
|
||||
///< If the data type does not match an exception is thrown.
|
||||
};
|
||||
|
||||
struct CreatureColumns : public ActorColumns
|
||||
{
|
||||
std::map<const RefIdColumn *, unsigned int> mFlags;
|
||||
const RefIdColumn *mType;
|
||||
const RefIdColumn *mSoul;
|
||||
const RefIdColumn *mScale;
|
||||
const RefIdColumn *mOriginal;
|
||||
|
||||
CreatureColumns (const ActorColumns& actorColumns);
|
||||
};
|
||||
|
||||
class CreatureRefIdAdapter : public ActorRefIdAdapter<ESM::Creature>
|
||||
{
|
||||
CreatureColumns mColumns;
|
||||
|
||||
public:
|
||||
|
||||
CreatureRefIdAdapter (const CreatureColumns& columns);
|
||||
|
||||
virtual QVariant getData (const RefIdColumn *column, const RefIdData& data, int index)
|
||||
const;
|
||||
|
||||
virtual void setData (const RefIdColumn *column, RefIdData& data, int index,
|
||||
const QVariant& value) const;
|
||||
///< If the data type does not match an exception is thrown.
|
||||
};
|
||||
|
||||
class DoorRefIdAdapter : public NameRefIdAdapter<ESM::Door>
|
||||
{
|
||||
const RefIdColumn *mOpenSound;
|
||||
const RefIdColumn *mCloseSound;
|
||||
|
||||
public:
|
||||
|
||||
DoorRefIdAdapter (const NameColumns& columns, const RefIdColumn *openSound,
|
||||
const RefIdColumn *closeSound);
|
||||
|
||||
virtual QVariant getData (const RefIdColumn *column, const RefIdData& data, int index)
|
||||
const;
|
||||
|
||||
virtual void setData (const RefIdColumn *column, RefIdData& data, int index,
|
||||
const QVariant& value) const;
|
||||
///< If the data type does not match an exception is thrown.
|
||||
};
|
||||
|
||||
struct LightColumns : public InventoryColumns
|
||||
{
|
||||
const RefIdColumn *mTime;
|
||||
const RefIdColumn *mRadius;
|
||||
const RefIdColumn *mColor;
|
||||
const RefIdColumn *mSound;
|
||||
std::map<const RefIdColumn *, unsigned int> mFlags;
|
||||
|
||||
LightColumns (const InventoryColumns& columns);
|
||||
};
|
||||
|
||||
class LightRefIdAdapter : public InventoryRefIdAdapter<ESM::Light>
|
||||
{
|
||||
LightColumns mColumns;
|
||||
|
||||
public:
|
||||
|
||||
LightRefIdAdapter (const LightColumns& columns);
|
||||
|
||||
virtual QVariant getData (const RefIdColumn *column, const RefIdData& data, int index)
|
||||
const;
|
||||
|
||||
virtual void setData (const RefIdColumn *column, RefIdData& data, int index,
|
||||
const QVariant& value) const;
|
||||
///< If the data type does not match an exception is thrown.
|
||||
};
|
||||
|
||||
class MiscRefIdAdapter : public InventoryRefIdAdapter<ESM::Miscellaneous>
|
||||
{
|
||||
const RefIdColumn *mKey;
|
||||
|
||||
public:
|
||||
|
||||
MiscRefIdAdapter (const InventoryColumns& columns, const RefIdColumn *key);
|
||||
|
||||
virtual QVariant getData (const RefIdColumn *column, const RefIdData& data, int index)
|
||||
const;
|
||||
|
||||
virtual void setData (const RefIdColumn *column, RefIdData& data, int index,
|
||||
const QVariant& value) const;
|
||||
///< If the data type does not match an exception is thrown.
|
||||
};
|
||||
|
||||
struct NpcColumns : public ActorColumns
|
||||
{
|
||||
std::map<const RefIdColumn *, unsigned int> mFlags;
|
||||
const RefIdColumn *mRace;
|
||||
const RefIdColumn *mClass;
|
||||
const RefIdColumn *mFaction;
|
||||
const RefIdColumn *mHair;
|
||||
const RefIdColumn *mHead;
|
||||
|
||||
NpcColumns (const ActorColumns& actorColumns);
|
||||
};
|
||||
|
||||
class NpcRefIdAdapter : public ActorRefIdAdapter<ESM::NPC>
|
||||
{
|
||||
NpcColumns mColumns;
|
||||
|
||||
public:
|
||||
|
||||
NpcRefIdAdapter (const NpcColumns& columns);
|
||||
|
||||
virtual QVariant getData (const RefIdColumn *column, const RefIdData& data, int index)
|
||||
const;
|
||||
|
||||
virtual void setData (const RefIdColumn *column, RefIdData& data, int index,
|
||||
const QVariant& value) const;
|
||||
///< If the data type does not match an exception is thrown.
|
||||
};
|
||||
|
||||
struct WeaponColumns : public EnchantableColumns
|
||||
{
|
||||
const RefIdColumn *mType;
|
||||
const RefIdColumn *mHealth;
|
||||
const RefIdColumn *mSpeed;
|
||||
const RefIdColumn *mReach;
|
||||
const RefIdColumn *mChop[2];
|
||||
const RefIdColumn *mSlash[2];
|
||||
const RefIdColumn *mThrust[2];
|
||||
std::map<const RefIdColumn *, unsigned int> mFlags;
|
||||
|
||||
WeaponColumns (const EnchantableColumns& columns);
|
||||
};
|
||||
|
||||
class WeaponRefIdAdapter : public EnchantableRefIdAdapter<ESM::Weapon>
|
||||
{
|
||||
WeaponColumns mColumns;
|
||||
|
||||
public:
|
||||
|
||||
WeaponRefIdAdapter (const WeaponColumns& columns);
|
||||
|
||||
virtual QVariant getData (const RefIdColumn *column, const RefIdData& data, int index)
|
||||
const;
|
||||
|
||||
virtual void setData (const RefIdColumn *column, RefIdData& data, int index,
|
||||
const QVariant& value) const;
|
||||
///< If the data type does not match an exception is thrown.
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
@ -0,0 +1,540 @@
|
||||
|
||||
#include "refidcollection.hpp"
|
||||
|
||||
#include <stdexcept>
|
||||
|
||||
#include "refidadapter.hpp"
|
||||
#include "refidadapterimp.hpp"
|
||||
|
||||
CSMWorld::RefIdColumn::RefIdColumn (const std::string& title, Display displayType, int flag,
|
||||
bool editable, bool userEditable)
|
||||
: ColumnBase (title, displayType, flag), mEditable (editable), mUserEditable (userEditable)
|
||||
{}
|
||||
|
||||
bool CSMWorld::RefIdColumn::isEditable() const
|
||||
{
|
||||
return mEditable;
|
||||
}
|
||||
|
||||
bool CSMWorld::RefIdColumn::isUserEditable() const
|
||||
{
|
||||
return mUserEditable;
|
||||
}
|
||||
|
||||
|
||||
const CSMWorld::RefIdAdapter& CSMWorld::RefIdCollection::findAdaptor (UniversalId::Type type) const
|
||||
{
|
||||
std::map<UniversalId::Type, RefIdAdapter *>::const_iterator iter = mAdapters.find (type);
|
||||
|
||||
if (iter==mAdapters.end())
|
||||
throw std::logic_error ("unsupported type in RefIdCollection");
|
||||
|
||||
return *iter->second;
|
||||
}
|
||||
|
||||
CSMWorld::RefIdCollection::RefIdCollection()
|
||||
{
|
||||
BaseColumns baseColumns;
|
||||
|
||||
mColumns.push_back (RefIdColumn ("ID", ColumnBase::Display_String,
|
||||
ColumnBase::Flag_Table | ColumnBase::Flag_Dialogue, false, false));
|
||||
baseColumns.mId = &mColumns.back();
|
||||
mColumns.push_back (RefIdColumn ("*", ColumnBase::Display_Integer,
|
||||
ColumnBase::Flag_Table | ColumnBase::Flag_Dialogue, false, false));
|
||||
baseColumns.mModified = &mColumns.back();
|
||||
mColumns.push_back (RefIdColumn ("Type", ColumnBase::Display_Integer,
|
||||
ColumnBase::Flag_Table | ColumnBase::Flag_Dialogue, false, false));
|
||||
baseColumns.mType = &mColumns.back();
|
||||
|
||||
ModelColumns modelColumns (baseColumns);
|
||||
|
||||
mColumns.push_back (RefIdColumn ("Model", ColumnBase::Display_String));
|
||||
modelColumns.mModel = &mColumns.back();
|
||||
|
||||
NameColumns nameColumns (modelColumns);
|
||||
|
||||
mColumns.push_back (RefIdColumn ("Name", ColumnBase::Display_String));
|
||||
nameColumns.mName = &mColumns.back();
|
||||
mColumns.push_back (RefIdColumn ("Script", ColumnBase::Display_String));
|
||||
nameColumns.mScript = &mColumns.back();
|
||||
|
||||
InventoryColumns inventoryColumns (nameColumns);
|
||||
|
||||
mColumns.push_back (RefIdColumn ("Icon", ColumnBase::Display_String));
|
||||
inventoryColumns.mIcon = &mColumns.back();
|
||||
mColumns.push_back (RefIdColumn ("Weight", ColumnBase::Display_Float));
|
||||
inventoryColumns.mWeight = &mColumns.back();
|
||||
mColumns.push_back (RefIdColumn ("Value", ColumnBase::Display_Integer));
|
||||
inventoryColumns.mValue = &mColumns.back();
|
||||
|
||||
EnchantableColumns enchantableColumns (inventoryColumns);
|
||||
|
||||
mColumns.push_back (RefIdColumn ("Enchantment", ColumnBase::Display_String));
|
||||
enchantableColumns.mEnchantment = &mColumns.back();
|
||||
mColumns.push_back (RefIdColumn ("Enchantment Points", ColumnBase::Display_Integer));
|
||||
enchantableColumns.mEnchantmentPoints = &mColumns.back();
|
||||
|
||||
ToolColumns toolsColumns (inventoryColumns);
|
||||
|
||||
mColumns.push_back (RefIdColumn ("Quality", ColumnBase::Display_Float));
|
||||
toolsColumns.mQuality = &mColumns.back();
|
||||
mColumns.push_back (RefIdColumn ("Uses", ColumnBase::Display_Integer));
|
||||
toolsColumns.mUses = &mColumns.back();
|
||||
|
||||
ActorColumns actorsColumns (nameColumns);
|
||||
|
||||
mColumns.push_back (RefIdColumn ("AI", ColumnBase::Display_Boolean));
|
||||
actorsColumns.mHasAi = &mColumns.back();
|
||||
mColumns.push_back (RefIdColumn ("AI Hello", ColumnBase::Display_Integer));
|
||||
actorsColumns.mHello = &mColumns.back();
|
||||
mColumns.push_back (RefIdColumn ("AI Flee", ColumnBase::Display_Integer));
|
||||
actorsColumns.mFlee = &mColumns.back();
|
||||
mColumns.push_back (RefIdColumn ("AI Fight", ColumnBase::Display_Integer));
|
||||
actorsColumns.mFight = &mColumns.back();
|
||||
mColumns.push_back (RefIdColumn ("AI Alarm", ColumnBase::Display_Integer));
|
||||
actorsColumns.mAlarm = &mColumns.back();
|
||||
|
||||
static const struct
|
||||
{
|
||||
const char *mName;
|
||||
unsigned int mFlag;
|
||||
} sServiceTable[] =
|
||||
{
|
||||
{ "Buys Weapons", ESM::NPC::Weapon},
|
||||
{ "Buys Armor", ESM::NPC::Armor},
|
||||
{ "Buys Clothing", ESM::NPC::Clothing},
|
||||
{ "Buys Books", ESM::NPC::Books},
|
||||
{ "Buys Ingredients", ESM::NPC::Ingredients},
|
||||
{ "Buys Lockpicks", ESM::NPC::Picks},
|
||||
{ "Buys Probes", ESM::NPC::Probes},
|
||||
{ "Buys Lights", ESM::NPC::Lights},
|
||||
{ "Buys Apparati", ESM::NPC::Apparatus},
|
||||
{ "Buys Repair Items", ESM::NPC::RepairItem},
|
||||
{ "Buys Misc Items", ESM::NPC::Misc},
|
||||
{ "Buys Potions", ESM::NPC::Potions},
|
||||
{ "Buys Magic Items", ESM::NPC::MagicItems},
|
||||
{ "Sells Spells", ESM::NPC::Spells},
|
||||
{ "Trainer", ESM::NPC::Training},
|
||||
{ "Spellmaking", ESM::NPC::Spellmaking},
|
||||
{ "Enchanting Service", ESM::NPC::Enchanting},
|
||||
{ "Repair Serivce", ESM::NPC::Repair},
|
||||
{ 0, 0 }
|
||||
};
|
||||
|
||||
for (int i=0; sServiceTable[i].mName; ++i)
|
||||
{
|
||||
mColumns.push_back (RefIdColumn (sServiceTable[i].mName, ColumnBase::Display_Boolean));
|
||||
actorsColumns.mServices.insert (std::make_pair (&mColumns.back(), sServiceTable[i].mFlag));
|
||||
}
|
||||
|
||||
mColumns.push_back (RefIdColumn ("Auto Calc", ColumnBase::Display_Boolean));
|
||||
const RefIdColumn *autoCalc = &mColumns.back();
|
||||
|
||||
mColumns.push_back (RefIdColumn ("Apparatus Type", ColumnBase::Display_ApparatusType));
|
||||
const RefIdColumn *apparatusType = &mColumns.back();
|
||||
|
||||
mColumns.push_back (RefIdColumn ("Armor Type", ColumnBase::Display_ArmorType));
|
||||
const RefIdColumn *armorType = &mColumns.back();
|
||||
|
||||
mColumns.push_back (RefIdColumn ("Health", ColumnBase::Display_Integer));
|
||||
const RefIdColumn *health = &mColumns.back();
|
||||
|
||||
mColumns.push_back (RefIdColumn ("Armor Value", ColumnBase::Display_Integer));
|
||||
const RefIdColumn *armor = &mColumns.back();
|
||||
|
||||
mColumns.push_back (RefIdColumn ("Scroll", ColumnBase::Display_Boolean));
|
||||
const RefIdColumn *scroll = &mColumns.back();
|
||||
|
||||
mColumns.push_back (RefIdColumn ("Attribute", ColumnBase::Display_Attribute));
|
||||
const RefIdColumn *attribute = &mColumns.back();
|
||||
|
||||
mColumns.push_back (RefIdColumn ("Clothing Type", ColumnBase::Display_ClothingType));
|
||||
const RefIdColumn *clothingType = &mColumns.back();
|
||||
|
||||
mColumns.push_back (RefIdColumn ("Weight Capacity", ColumnBase::Display_Float));
|
||||
const RefIdColumn *weightCapacity = &mColumns.back();
|
||||
|
||||
mColumns.push_back (RefIdColumn ("Organic Container", ColumnBase::Display_Boolean));
|
||||
const RefIdColumn *organic = &mColumns.back();
|
||||
|
||||
mColumns.push_back (RefIdColumn ("Respawn", ColumnBase::Display_Boolean));
|
||||
const RefIdColumn *respawn = &mColumns.back();
|
||||
|
||||
CreatureColumns creatureColumns (actorsColumns);
|
||||
|
||||
mColumns.push_back (RefIdColumn ("Creature Type", ColumnBase::Display_CreatureType));
|
||||
creatureColumns.mType = &mColumns.back();
|
||||
mColumns.push_back (RefIdColumn ("Soul Points", ColumnBase::Display_Integer));
|
||||
creatureColumns.mSoul = &mColumns.back();
|
||||
mColumns.push_back (RefIdColumn ("Scale", ColumnBase::Display_Float));
|
||||
creatureColumns.mScale = &mColumns.back();
|
||||
mColumns.push_back (RefIdColumn ("Original Creature", ColumnBase::Display_String));
|
||||
creatureColumns.mOriginal = &mColumns.back();
|
||||
|
||||
static const struct
|
||||
{
|
||||
const char *mName;
|
||||
unsigned int mFlag;
|
||||
} sCreatureFlagTable[] =
|
||||
{
|
||||
{ "Biped", ESM::Creature::Biped },
|
||||
{ "Has Weapon", ESM::Creature::Weapon },
|
||||
{ "No Movement", ESM::Creature::None },
|
||||
{ "Swims", ESM::Creature::Swims },
|
||||
{ "Flies", ESM::Creature::Flies },
|
||||
{ "Walks", ESM::Creature::Walks },
|
||||
{ "Essential", ESM::Creature::Essential },
|
||||
{ "Skeleton Blood", ESM::Creature::Skeleton },
|
||||
{ "Metal Blood", ESM::Creature::Metal },
|
||||
{ 0, 0 }
|
||||
};
|
||||
|
||||
// for re-use in NPC records
|
||||
const RefIdColumn *essential = 0;
|
||||
const RefIdColumn *skeletonBlood = 0;
|
||||
const RefIdColumn *metalBlood = 0;
|
||||
|
||||
for (int i=0; sCreatureFlagTable[i].mName; ++i)
|
||||
{
|
||||
mColumns.push_back (RefIdColumn (sCreatureFlagTable[i].mName, ColumnBase::Display_Boolean));
|
||||
creatureColumns.mFlags.insert (std::make_pair (&mColumns.back(), sCreatureFlagTable[i].mFlag));
|
||||
|
||||
switch (sCreatureFlagTable[i].mFlag)
|
||||
{
|
||||
case ESM::Creature::Essential: essential = &mColumns.back(); break;
|
||||
case ESM::Creature::Skeleton: skeletonBlood = &mColumns.back(); break;
|
||||
case ESM::Creature::Metal: metalBlood = &mColumns.back(); break;
|
||||
}
|
||||
}
|
||||
|
||||
creatureColumns.mFlags.insert (std::make_pair (respawn, ESM::Creature::Respawn));
|
||||
|
||||
mColumns.push_back (RefIdColumn ("Open Sound", ColumnBase::Display_String));
|
||||
const RefIdColumn *openSound = &mColumns.back();
|
||||
|
||||
mColumns.push_back (RefIdColumn ("Close Sound", ColumnBase::Display_String));
|
||||
const RefIdColumn *closeSound = &mColumns.back();
|
||||
|
||||
LightColumns lightColumns (inventoryColumns);
|
||||
|
||||
mColumns.push_back (RefIdColumn ("Duration", ColumnBase::Display_Integer));
|
||||
lightColumns.mTime = &mColumns.back();
|
||||
|
||||
mColumns.push_back (RefIdColumn ("Radius", ColumnBase::Display_Integer));
|
||||
lightColumns.mRadius = &mColumns.back();
|
||||
|
||||
mColumns.push_back (RefIdColumn ("Colour", ColumnBase::Display_Integer));
|
||||
lightColumns.mColor = &mColumns.back();
|
||||
|
||||
mColumns.push_back (RefIdColumn ("Sound", ColumnBase::Display_String));
|
||||
lightColumns.mSound = &mColumns.back();
|
||||
|
||||
static const struct
|
||||
{
|
||||
const char *mName;
|
||||
unsigned int mFlag;
|
||||
} sLightFlagTable[] =
|
||||
{
|
||||
{ "Dynamic", ESM::Light::Dynamic },
|
||||
{ "Portable", ESM::Light::Carry },
|
||||
{ "Negative Light", ESM::Light::Negative },
|
||||
{ "Flickering", ESM::Light::Flicker },
|
||||
{ "Slow Flickering", ESM::Light::Flicker },
|
||||
{ "Pulsing", ESM::Light::Pulse },
|
||||
{ "Slow Pulsing", ESM::Light::PulseSlow },
|
||||
{ "Fire", ESM::Light::Fire },
|
||||
{ "Off by default", ESM::Light::OffDefault },
|
||||
{ 0, 0 }
|
||||
};
|
||||
|
||||
for (int i=0; sLightFlagTable[i].mName; ++i)
|
||||
{
|
||||
mColumns.push_back (RefIdColumn (sLightFlagTable[i].mName, ColumnBase::Display_Boolean));
|
||||
lightColumns.mFlags.insert (std::make_pair (&mColumns.back(), sLightFlagTable[i].mFlag));
|
||||
}
|
||||
|
||||
mColumns.push_back (RefIdColumn ("Key", ColumnBase::Display_Boolean));
|
||||
const RefIdColumn *key = &mColumns.back();
|
||||
|
||||
NpcColumns npcColumns (actorsColumns);
|
||||
|
||||
mColumns.push_back (RefIdColumn ("Race", ColumnBase::Display_String));
|
||||
npcColumns.mRace = &mColumns.back();
|
||||
|
||||
mColumns.push_back (RefIdColumn ("Class", ColumnBase::Display_String));
|
||||
npcColumns.mClass = &mColumns.back();
|
||||
|
||||
mColumns.push_back (RefIdColumn ("Faction", ColumnBase::Display_String));
|
||||
npcColumns.mFaction = &mColumns.back();
|
||||
|
||||
mColumns.push_back (RefIdColumn ("Hair", ColumnBase::Display_String));
|
||||
npcColumns.mHair = &mColumns.back();
|
||||
|
||||
mColumns.push_back (RefIdColumn ("Head", ColumnBase::Display_String));
|
||||
npcColumns.mHead = &mColumns.back();
|
||||
|
||||
mColumns.push_back (RefIdColumn ("Female", ColumnBase::Display_Boolean));
|
||||
npcColumns.mFlags.insert (std::make_pair (&mColumns.back(), ESM::NPC::Female));
|
||||
|
||||
npcColumns.mFlags.insert (std::make_pair (essential, ESM::NPC::Essential));
|
||||
|
||||
npcColumns.mFlags.insert (std::make_pair (respawn, ESM::NPC::Respawn));
|
||||
|
||||
npcColumns.mFlags.insert (std::make_pair (autoCalc, ESM::NPC::Autocalc));
|
||||
|
||||
npcColumns.mFlags.insert (std::make_pair (skeletonBlood, ESM::NPC::Skeleton));
|
||||
|
||||
npcColumns.mFlags.insert (std::make_pair (metalBlood, ESM::NPC::Metal));
|
||||
|
||||
WeaponColumns weaponColumns (enchantableColumns);
|
||||
|
||||
mColumns.push_back (RefIdColumn ("Weapon Type", ColumnBase::Display_WeaponType));
|
||||
weaponColumns.mType = &mColumns.back();
|
||||
|
||||
weaponColumns.mHealth = health;
|
||||
|
||||
mColumns.push_back (RefIdColumn ("Weapon Speed", ColumnBase::Display_Float));
|
||||
weaponColumns.mSpeed = &mColumns.back();
|
||||
|
||||
mColumns.push_back (RefIdColumn ("Weapon Reach", ColumnBase::Display_Float));
|
||||
weaponColumns.mReach = &mColumns.back();
|
||||
|
||||
for (int i=0; i<2; ++i)
|
||||
{
|
||||
std::string suffix = i==0 ? "Min " : "Max ";
|
||||
|
||||
mColumns.push_back (RefIdColumn ("Chop" + suffix, ColumnBase::Display_Integer));
|
||||
weaponColumns.mChop[i] = &mColumns.back();
|
||||
|
||||
mColumns.push_back (RefIdColumn ("Slash" + suffix, ColumnBase::Display_Integer));
|
||||
weaponColumns.mSlash[i] = &mColumns.back();
|
||||
|
||||
mColumns.push_back (RefIdColumn ("Thrust" + suffix, ColumnBase::Display_Integer));
|
||||
weaponColumns.mThrust[i] = &mColumns.back();
|
||||
}
|
||||
|
||||
static const struct
|
||||
{
|
||||
const char *mName;
|
||||
unsigned int mFlag;
|
||||
} sWeaponFlagTable[] =
|
||||
{
|
||||
{ "Magical", ESM::Weapon::Magical },
|
||||
{ "Silver", ESM::Weapon::Silver },
|
||||
{ 0, 0 }
|
||||
};
|
||||
|
||||
for (int i=0; sWeaponFlagTable[i].mName; ++i)
|
||||
{
|
||||
mColumns.push_back (RefIdColumn (sWeaponFlagTable[i].mName, ColumnBase::Display_Boolean));
|
||||
weaponColumns.mFlags.insert (std::make_pair (&mColumns.back(), sWeaponFlagTable[i].mFlag));
|
||||
}
|
||||
|
||||
mAdapters.insert (std::make_pair (UniversalId::Type_Activator,
|
||||
new NameRefIdAdapter<ESM::Activator> (UniversalId::Type_Activator, nameColumns)));
|
||||
mAdapters.insert (std::make_pair (UniversalId::Type_Potion,
|
||||
new PotionRefIdAdapter (inventoryColumns, autoCalc)));
|
||||
mAdapters.insert (std::make_pair (UniversalId::Type_Apparatus,
|
||||
new ApparatusRefIdAdapter (inventoryColumns, apparatusType, toolsColumns.mQuality)));
|
||||
mAdapters.insert (std::make_pair (UniversalId::Type_Armor,
|
||||
new ArmorRefIdAdapter (enchantableColumns, armorType, health, armor)));
|
||||
mAdapters.insert (std::make_pair (UniversalId::Type_Book,
|
||||
new BookRefIdAdapter (enchantableColumns, scroll, attribute)));
|
||||
mAdapters.insert (std::make_pair (UniversalId::Type_Clothing,
|
||||
new ClothingRefIdAdapter (enchantableColumns, clothingType)));
|
||||
mAdapters.insert (std::make_pair (UniversalId::Type_Container,
|
||||
new ContainerRefIdAdapter (nameColumns, weightCapacity, organic, respawn)));
|
||||
mAdapters.insert (std::make_pair (UniversalId::Type_Creature,
|
||||
new CreatureRefIdAdapter (creatureColumns)));
|
||||
mAdapters.insert (std::make_pair (UniversalId::Type_Door,
|
||||
new DoorRefIdAdapter (nameColumns, openSound, closeSound)));
|
||||
mAdapters.insert (std::make_pair (UniversalId::Type_Ingredient,
|
||||
new InventoryRefIdAdapter<ESM::Ingredient> (UniversalId::Type_Ingredient, inventoryColumns)));
|
||||
mAdapters.insert (std::make_pair (UniversalId::Type_CreatureLevelledList,
|
||||
new BaseRefIdAdapter<ESM::CreatureLevList> (
|
||||
UniversalId::Type_CreatureLevelledList, baseColumns)));
|
||||
mAdapters.insert (std::make_pair (UniversalId::Type_ItemLevelledList,
|
||||
new BaseRefIdAdapter<ESM::ItemLevList> (UniversalId::Type_ItemLevelledList, baseColumns)));
|
||||
mAdapters.insert (std::make_pair (UniversalId::Type_Light,
|
||||
new LightRefIdAdapter (lightColumns)));
|
||||
mAdapters.insert (std::make_pair (UniversalId::Type_Lockpick,
|
||||
new ToolRefIdAdapter<ESM::Lockpick> (UniversalId::Type_Lockpick, toolsColumns)));
|
||||
mAdapters.insert (std::make_pair (UniversalId::Type_Miscellaneous,
|
||||
new MiscRefIdAdapter (inventoryColumns, key)));
|
||||
mAdapters.insert (std::make_pair (UniversalId::Type_Npc,
|
||||
new NpcRefIdAdapter (npcColumns)));
|
||||
mAdapters.insert (std::make_pair (UniversalId::Type_Probe,
|
||||
new ToolRefIdAdapter<ESM::Probe> (UniversalId::Type_Probe, toolsColumns)));
|
||||
mAdapters.insert (std::make_pair (UniversalId::Type_Repair,
|
||||
new ToolRefIdAdapter<ESM::Repair> (UniversalId::Type_Repair, toolsColumns)));
|
||||
mAdapters.insert (std::make_pair (UniversalId::Type_Static,
|
||||
new ModelRefIdAdapter<ESM::Static> (UniversalId::Type_Static, modelColumns)));
|
||||
mAdapters.insert (std::make_pair (UniversalId::Type_Weapon,
|
||||
new WeaponRefIdAdapter (weaponColumns)));
|
||||
}
|
||||
|
||||
CSMWorld::RefIdCollection::~RefIdCollection()
|
||||
{
|
||||
for (std::map<UniversalId::Type, RefIdAdapter *>::iterator iter (mAdapters.begin());
|
||||
iter!=mAdapters.end(); ++iter)
|
||||
delete iter->second;
|
||||
}
|
||||
|
||||
int CSMWorld::RefIdCollection::getSize() const
|
||||
{
|
||||
return mData.getSize();
|
||||
}
|
||||
|
||||
std::string CSMWorld::RefIdCollection::getId (int index) const
|
||||
{
|
||||
return getData (index, 0).toString().toUtf8().constData();
|
||||
}
|
||||
|
||||
int CSMWorld::RefIdCollection::getIndex (const std::string& id) const
|
||||
{
|
||||
int index = searchId (id);
|
||||
|
||||
if (index==-1)
|
||||
throw std::runtime_error ("invalid ID: " + id);
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
int CSMWorld::RefIdCollection::getColumns() const
|
||||
{
|
||||
return mColumns.size();
|
||||
}
|
||||
|
||||
const CSMWorld::ColumnBase& CSMWorld::RefIdCollection::getColumn (int column) const
|
||||
{
|
||||
return mColumns.at (column);
|
||||
}
|
||||
|
||||
QVariant CSMWorld::RefIdCollection::getData (int index, int column) const
|
||||
{
|
||||
RefIdData::LocalIndex localIndex = mData.globalToLocalIndex (index);
|
||||
|
||||
const RefIdAdapter& adaptor = findAdaptor (localIndex.second);
|
||||
|
||||
return adaptor.getData (&mColumns.at (column), mData, localIndex.first);
|
||||
}
|
||||
|
||||
void CSMWorld::RefIdCollection::setData (int index, int column, const QVariant& data)
|
||||
{
|
||||
RefIdData::LocalIndex localIndex = mData.globalToLocalIndex (index);
|
||||
|
||||
const RefIdAdapter& adaptor = findAdaptor (localIndex.second);
|
||||
|
||||
adaptor.setData (&mColumns.at (column), mData, localIndex.first, data);
|
||||
}
|
||||
|
||||
void CSMWorld::RefIdCollection::removeRows (int index, int count)
|
||||
{
|
||||
mData.erase (index, count);
|
||||
}
|
||||
|
||||
void CSMWorld::RefIdCollection::appendBlankRecord (const std::string& id, UniversalId::Type type)
|
||||
{
|
||||
mData.appendRecord (type, id);
|
||||
}
|
||||
|
||||
int CSMWorld::RefIdCollection::searchId (const std::string& id) const
|
||||
{
|
||||
RefIdData::LocalIndex localIndex = mData.searchId (id);
|
||||
|
||||
if (localIndex.first==-1)
|
||||
return -1;
|
||||
|
||||
return mData.localToGlobalIndex (localIndex);
|
||||
}
|
||||
|
||||
void CSMWorld::RefIdCollection::replace (int index, const RecordBase& record)
|
||||
{
|
||||
mData.getRecord (mData.globalToLocalIndex (index)).assign (record);
|
||||
}
|
||||
|
||||
void CSMWorld::RefIdCollection::appendRecord (const RecordBase& record,
|
||||
UniversalId::Type type)
|
||||
{
|
||||
std::string id = findAdaptor (type).getId (record);
|
||||
|
||||
int index = mData.getAppendIndex (type);
|
||||
|
||||
mData.appendRecord (type, id);
|
||||
|
||||
mData.getRecord (mData.globalToLocalIndex (index)).assign (record);
|
||||
}
|
||||
|
||||
const CSMWorld::RecordBase& CSMWorld::RefIdCollection::getRecord (const std::string& id) const
|
||||
{
|
||||
return mData.getRecord (mData.searchId (id));
|
||||
}
|
||||
|
||||
const CSMWorld::RecordBase& CSMWorld::RefIdCollection::getRecord (int index) const
|
||||
{
|
||||
return mData.getRecord (mData.globalToLocalIndex (index));
|
||||
}
|
||||
|
||||
void CSMWorld::RefIdCollection::load (ESM::ESMReader& reader, bool base, UniversalId::Type type)
|
||||
{
|
||||
std::string id = reader.getHNOString ("NAME");
|
||||
|
||||
int index = searchId (id);
|
||||
|
||||
if (reader.isNextSub ("DELE"))
|
||||
{
|
||||
reader.skipRecord();
|
||||
|
||||
if (index==-1)
|
||||
{
|
||||
// deleting a record that does not exist
|
||||
|
||||
// ignore it for now
|
||||
|
||||
/// \todo report the problem to the user
|
||||
}
|
||||
else if (base)
|
||||
{
|
||||
mData.erase (index, 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
mData.getRecord (mData.globalToLocalIndex (index)).mState = RecordBase::State_Deleted;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (index==-1)
|
||||
{
|
||||
// new record
|
||||
int index = mData.getAppendIndex (type);
|
||||
mData.appendRecord (type, id);
|
||||
|
||||
RefIdData::LocalIndex localIndex = mData.globalToLocalIndex (index);
|
||||
|
||||
mData.load (localIndex, reader, base);
|
||||
|
||||
mData.getRecord (localIndex).mState =
|
||||
base ? RecordBase::State_BaseOnly : RecordBase::State_ModifiedOnly;
|
||||
}
|
||||
else
|
||||
{
|
||||
// old record
|
||||
RefIdData::LocalIndex localIndex = mData.globalToLocalIndex (index);
|
||||
|
||||
if (!base)
|
||||
if (mData.getRecord (localIndex).mState==RecordBase::State_Erased)
|
||||
throw std::logic_error ("attempt to access a deleted record");
|
||||
|
||||
mData.load (localIndex, reader, base);
|
||||
|
||||
if (!base)
|
||||
mData.getRecord (localIndex).mState = RecordBase::State_Modified;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int CSMWorld::RefIdCollection::getAppendIndex (UniversalId::Type type) const
|
||||
{
|
||||
return mData.getAppendIndex (type);
|
||||
}
|
@ -0,0 +1,95 @@
|
||||
#ifndef CSM_WOLRD_REFIDCOLLECTION_H
|
||||
#define CSM_WOLRD_REFIDCOLLECTION_H
|
||||
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include <deque>
|
||||
|
||||
#include "columnbase.hpp"
|
||||
#include "idcollection.hpp"
|
||||
#include "refiddata.hpp"
|
||||
|
||||
namespace CSMWorld
|
||||
{
|
||||
class RefIdAdapter;
|
||||
|
||||
class RefIdColumn : public ColumnBase
|
||||
{
|
||||
bool mEditable;
|
||||
bool mUserEditable;
|
||||
|
||||
public:
|
||||
|
||||
RefIdColumn (const std::string& title, Display displayType,
|
||||
int flag = Flag_Table | Flag_Dialogue, bool editable = true,
|
||||
bool userEditable = true);
|
||||
|
||||
virtual bool isEditable() const;
|
||||
|
||||
virtual bool isUserEditable() const;
|
||||
};
|
||||
|
||||
class RefIdCollection : public IdCollectionBase
|
||||
{
|
||||
private:
|
||||
|
||||
RefIdData mData;
|
||||
std::deque<RefIdColumn> mColumns;
|
||||
std::map<UniversalId::Type, RefIdAdapter *> mAdapters;
|
||||
|
||||
private:
|
||||
|
||||
const RefIdAdapter& findAdaptor (UniversalId::Type) const;
|
||||
///< Throws an exception if no adaptor for \a Type can be found.
|
||||
|
||||
public:
|
||||
|
||||
RefIdCollection();
|
||||
|
||||
virtual ~RefIdCollection();
|
||||
|
||||
virtual int getSize() const;
|
||||
|
||||
virtual std::string getId (int index) const;
|
||||
|
||||
virtual int getIndex (const std::string& id) const;
|
||||
|
||||
virtual int getColumns() const;
|
||||
|
||||
virtual const ColumnBase& getColumn (int column) const;
|
||||
|
||||
virtual QVariant getData (int index, int column) const;
|
||||
|
||||
virtual void setData (int index, int column, const QVariant& data);
|
||||
|
||||
virtual void removeRows (int index, int count);
|
||||
|
||||
virtual void appendBlankRecord (const std::string& id, UniversalId::Type type);
|
||||
///< \param type Will be ignored, unless the collection supports multiple record types
|
||||
|
||||
virtual int searchId (const std::string& id) const;
|
||||
////< Search record with \a id.
|
||||
/// \return index of record (if found) or -1 (not found)
|
||||
|
||||
virtual void replace (int index, const RecordBase& record);
|
||||
///< If the record type does not match, an exception is thrown.
|
||||
///
|
||||
/// \attention \a record must not change the ID.
|
||||
|
||||
virtual void appendRecord (const RecordBase& record, UniversalId::Type type);
|
||||
///< If the record type does not match, an exception is thrown.
|
||||
///
|
||||
///< \param type Will be ignored, unless the collection supports multiple record types
|
||||
|
||||
virtual const RecordBase& getRecord (const std::string& id) const;
|
||||
|
||||
virtual const RecordBase& getRecord (int index) const;
|
||||
|
||||
virtual void load (ESM::ESMReader& reader, bool base, UniversalId::Type type);
|
||||
|
||||
virtual int getAppendIndex (UniversalId::Type type) const;
|
||||
///< \param type Will be ignored, unless the collection supports multiple record types
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
@ -0,0 +1,198 @@
|
||||
|
||||
#include "refiddata.hpp"
|
||||
|
||||
#include <cassert>
|
||||
|
||||
#include <components/misc/stringops.hpp>
|
||||
|
||||
CSMWorld::RefIdDataContainerBase::~RefIdDataContainerBase() {}
|
||||
|
||||
CSMWorld::RefIdData::RefIdData()
|
||||
{
|
||||
mRecordContainers.insert (std::make_pair (UniversalId::Type_Activator, &mActivators));
|
||||
mRecordContainers.insert (std::make_pair (UniversalId::Type_Potion, &mPotions));
|
||||
mRecordContainers.insert (std::make_pair (UniversalId::Type_Apparatus, &mApparati));
|
||||
mRecordContainers.insert (std::make_pair (UniversalId::Type_Armor, &mArmors));
|
||||
mRecordContainers.insert (std::make_pair (UniversalId::Type_Book, &mBooks));
|
||||
mRecordContainers.insert (std::make_pair (UniversalId::Type_Clothing, &mClothing));
|
||||
mRecordContainers.insert (std::make_pair (UniversalId::Type_Container, &mContainers));
|
||||
mRecordContainers.insert (std::make_pair (UniversalId::Type_Creature, &mCreatures));
|
||||
mRecordContainers.insert (std::make_pair (UniversalId::Type_Door, &mDoors));
|
||||
mRecordContainers.insert (std::make_pair (UniversalId::Type_Ingredient, &mIngredients));
|
||||
mRecordContainers.insert (std::make_pair (UniversalId::Type_CreatureLevelledList,
|
||||
&mCreatureLevelledLists));
|
||||
mRecordContainers.insert (std::make_pair (UniversalId::Type_ItemLevelledList, &mItemLevelledLists));
|
||||
mRecordContainers.insert (std::make_pair (UniversalId::Type_Light, &mLights));
|
||||
mRecordContainers.insert (std::make_pair (UniversalId::Type_Lockpick, &mLockpicks));
|
||||
mRecordContainers.insert (std::make_pair (UniversalId::Type_Miscellaneous, &mMiscellaneous));
|
||||
mRecordContainers.insert (std::make_pair (UniversalId::Type_Npc, &mNpcs));
|
||||
mRecordContainers.insert (std::make_pair (UniversalId::Type_Probe, &mProbes));
|
||||
mRecordContainers.insert (std::make_pair (UniversalId::Type_Repair, &mRepairs));
|
||||
mRecordContainers.insert (std::make_pair (UniversalId::Type_Static, &mStatics));
|
||||
mRecordContainers.insert (std::make_pair (UniversalId::Type_Weapon, &mWeapons));
|
||||
}
|
||||
|
||||
CSMWorld::RefIdData::LocalIndex CSMWorld::RefIdData::globalToLocalIndex (int index) const
|
||||
{
|
||||
for (std::map<UniversalId::Type, RefIdDataContainerBase *>::const_iterator iter (
|
||||
mRecordContainers.begin()); iter!=mRecordContainers.end(); ++iter)
|
||||
{
|
||||
if (index<iter->second->getSize())
|
||||
return LocalIndex (index, iter->first);
|
||||
|
||||
index -= iter->second->getSize();
|
||||
}
|
||||
|
||||
throw std::runtime_error ("RefIdData index out of range");
|
||||
}
|
||||
|
||||
int CSMWorld::RefIdData::localToGlobalIndex (const LocalIndex& index)
|
||||
const
|
||||
{
|
||||
std::map<UniversalId::Type, RefIdDataContainerBase *>::const_iterator end =
|
||||
mRecordContainers.find (index.second);
|
||||
|
||||
if (end==mRecordContainers.end())
|
||||
throw std::logic_error ("invalid local index type");
|
||||
|
||||
int globalIndex = index.first;
|
||||
|
||||
for (std::map<UniversalId::Type, RefIdDataContainerBase *>::const_iterator iter (
|
||||
mRecordContainers.begin()); iter!=end; ++iter)
|
||||
globalIndex += iter->second->getSize();
|
||||
|
||||
return globalIndex;
|
||||
}
|
||||
|
||||
CSMWorld::RefIdData::LocalIndex CSMWorld::RefIdData::searchId (
|
||||
const std::string& id) const
|
||||
{
|
||||
std::string id2 = Misc::StringUtils::lowerCase (id);
|
||||
|
||||
std::map<std::string, std::pair<int, UniversalId::Type> >::const_iterator iter = mIndex.find (id2);
|
||||
|
||||
if (iter==mIndex.end())
|
||||
return std::make_pair (-1, CSMWorld::UniversalId::Type_None);
|
||||
|
||||
return iter->second;
|
||||
}
|
||||
|
||||
void CSMWorld::RefIdData::erase (int index, int count)
|
||||
{
|
||||
LocalIndex localIndex = globalToLocalIndex (index);
|
||||
|
||||
std::map<UniversalId::Type, RefIdDataContainerBase *>::const_iterator iter =
|
||||
mRecordContainers.find (localIndex.second);
|
||||
|
||||
while (count>0 && iter!=mRecordContainers.end())
|
||||
{
|
||||
int size = iter->second->getSize();
|
||||
|
||||
if (localIndex.first+count>size)
|
||||
{
|
||||
erase (localIndex, size-localIndex.first);
|
||||
count -= size-localIndex.first;
|
||||
|
||||
++iter;
|
||||
|
||||
if (iter==mRecordContainers.end())
|
||||
throw std::runtime_error ("invalid count value for erase operation");
|
||||
|
||||
localIndex.first = 0;
|
||||
localIndex.second = iter->first;
|
||||
}
|
||||
else
|
||||
{
|
||||
erase (localIndex, count);
|
||||
count = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const CSMWorld::RecordBase& CSMWorld::RefIdData::getRecord (const LocalIndex& index) const
|
||||
{
|
||||
std::map<UniversalId::Type, RefIdDataContainerBase *>::const_iterator iter =
|
||||
mRecordContainers.find (index.second);
|
||||
|
||||
if (iter==mRecordContainers.end())
|
||||
throw std::logic_error ("invalid local index type");
|
||||
|
||||
return iter->second->getRecord (index.first);
|
||||
}
|
||||
|
||||
CSMWorld::RecordBase& CSMWorld::RefIdData::getRecord (const LocalIndex& index)
|
||||
{
|
||||
std::map<UniversalId::Type, RefIdDataContainerBase *>::iterator iter =
|
||||
mRecordContainers.find (index.second);
|
||||
|
||||
if (iter==mRecordContainers.end())
|
||||
throw std::logic_error ("invalid local index type");
|
||||
|
||||
return iter->second->getRecord (index.first);
|
||||
}
|
||||
|
||||
void CSMWorld::RefIdData::appendRecord (UniversalId::Type type, const std::string& id)
|
||||
{
|
||||
std::map<UniversalId::Type, RefIdDataContainerBase *>::iterator iter =
|
||||
mRecordContainers.find (type);
|
||||
|
||||
if (iter==mRecordContainers.end())
|
||||
throw std::logic_error ("invalid local index type");
|
||||
|
||||
iter->second->appendRecord (id);
|
||||
|
||||
mIndex.insert (std::make_pair (Misc::StringUtils::lowerCase (id),
|
||||
LocalIndex (iter->second->getSize()-1, type)));
|
||||
}
|
||||
|
||||
int CSMWorld::RefIdData::getAppendIndex (UniversalId::Type type) const
|
||||
{
|
||||
int index = 0;
|
||||
|
||||
for (std::map<UniversalId::Type, RefIdDataContainerBase *>::const_iterator iter (
|
||||
mRecordContainers.begin()); iter!=mRecordContainers.end(); ++iter)
|
||||
{
|
||||
index += iter->second->getSize();
|
||||
|
||||
if (type==iter->first)
|
||||
break;
|
||||
}
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
void CSMWorld::RefIdData::load (const LocalIndex& index, ESM::ESMReader& reader, bool base)
|
||||
{
|
||||
std::map<UniversalId::Type, RefIdDataContainerBase *>::iterator iter =
|
||||
mRecordContainers.find (index.second);
|
||||
|
||||
if (iter==mRecordContainers.end())
|
||||
throw std::logic_error ("invalid local index type");
|
||||
|
||||
iter->second->load (index.first, reader, base);
|
||||
}
|
||||
|
||||
void CSMWorld::RefIdData::erase (const LocalIndex& index, int count)
|
||||
{
|
||||
std::map<UniversalId::Type, RefIdDataContainerBase *>::iterator iter =
|
||||
mRecordContainers.find (index.second);
|
||||
|
||||
if (iter==mRecordContainers.end())
|
||||
throw std::logic_error ("invalid local index type");
|
||||
|
||||
for (int i=index.first; i<index.first+count; ++i)
|
||||
{
|
||||
std::map<std::string, LocalIndex>::iterator result =
|
||||
mIndex.find (Misc::StringUtils::lowerCase (iter->second->getId (i)));
|
||||
|
||||
if (result!=mIndex.end())
|
||||
mIndex.erase (result);
|
||||
}
|
||||
|
||||
iter->second->erase (index.first, count);
|
||||
}
|
||||
|
||||
int CSMWorld::RefIdData::getSize() const
|
||||
{
|
||||
return mIndex.size();
|
||||
}
|
@ -0,0 +1,188 @@
|
||||
#ifndef CSM_WOLRD_REFIDDATA_H
|
||||
#define CSM_WOLRD_REFIDDATA_H
|
||||
|
||||
#include <vector>
|
||||
#include <map>
|
||||
|
||||
#include <components/esm/loadacti.hpp>
|
||||
#include <components/esm/loadalch.hpp>
|
||||
#include <components/esm/loadappa.hpp>
|
||||
#include <components/esm/loadarmo.hpp>
|
||||
#include <components/esm/loadbook.hpp>
|
||||
#include <components/esm/loadclot.hpp>
|
||||
#include <components/esm/loadcont.hpp>
|
||||
#include <components/esm/loadcrea.hpp>
|
||||
#include <components/esm/loaddoor.hpp>
|
||||
#include <components/esm/loadingr.hpp>
|
||||
#include <components/esm/loadlevlist.hpp>
|
||||
#include <components/esm/loadligh.hpp>
|
||||
#include <components/esm/loadlock.hpp>
|
||||
#include <components/esm/loadprob.hpp>
|
||||
#include <components/esm/loadrepa.hpp>
|
||||
#include <components/esm/loadstat.hpp>
|
||||
#include <components/esm/loadweap.hpp>
|
||||
#include <components/esm/loadnpc.hpp>
|
||||
#include <components/esm/loadmisc.hpp>
|
||||
|
||||
#include "record.hpp"
|
||||
#include "universalid.hpp"
|
||||
|
||||
namespace ESM
|
||||
{
|
||||
class ESMReader;
|
||||
}
|
||||
|
||||
namespace CSMWorld
|
||||
{
|
||||
struct RefIdDataContainerBase
|
||||
{
|
||||
virtual ~RefIdDataContainerBase();
|
||||
|
||||
virtual int getSize() const = 0;
|
||||
|
||||
virtual const RecordBase& getRecord (int index) const = 0;
|
||||
|
||||
virtual RecordBase& getRecord (int index)= 0;
|
||||
|
||||
virtual void appendRecord (const std::string& id) = 0;
|
||||
|
||||
virtual void load (int index, ESM::ESMReader& reader, bool base) = 0;
|
||||
|
||||
virtual void erase (int index, int count) = 0;
|
||||
|
||||
virtual std::string getId (int index) const = 0;
|
||||
};
|
||||
|
||||
template<typename RecordT>
|
||||
struct RefIdDataContainer : public RefIdDataContainerBase
|
||||
{
|
||||
std::vector<Record<RecordT> > mContainer;
|
||||
|
||||
virtual int getSize() const;
|
||||
|
||||
virtual const RecordBase& getRecord (int index) const;
|
||||
|
||||
virtual RecordBase& getRecord (int index);
|
||||
|
||||
virtual void appendRecord (const std::string& id);
|
||||
|
||||
virtual void load (int index, ESM::ESMReader& reader, bool base);
|
||||
|
||||
virtual void erase (int index, int count);
|
||||
|
||||
virtual std::string getId (int index) const;
|
||||
};
|
||||
|
||||
template<typename RecordT>
|
||||
int RefIdDataContainer<RecordT>::getSize() const
|
||||
{
|
||||
return static_cast<int> (mContainer.size());
|
||||
}
|
||||
|
||||
template<typename RecordT>
|
||||
const RecordBase& RefIdDataContainer<RecordT>::getRecord (int index) const
|
||||
{
|
||||
return mContainer.at (index);
|
||||
}
|
||||
|
||||
template<typename RecordT>
|
||||
RecordBase& RefIdDataContainer<RecordT>::getRecord (int index)
|
||||
{
|
||||
return mContainer.at (index);
|
||||
}
|
||||
|
||||
template<typename RecordT>
|
||||
void RefIdDataContainer<RecordT>::appendRecord (const std::string& id)
|
||||
{
|
||||
Record<RecordT> record;
|
||||
record.mModified.mId = id;
|
||||
record.mModified.blank();
|
||||
record.mState = RecordBase::State_ModifiedOnly;
|
||||
|
||||
mContainer.push_back (record);
|
||||
}
|
||||
|
||||
template<typename RecordT>
|
||||
void RefIdDataContainer<RecordT>::load (int index, ESM::ESMReader& reader, bool base)
|
||||
{
|
||||
(base ? mContainer.at (index).mBase : mContainer.at (index).mModified).load (reader);
|
||||
}
|
||||
|
||||
template<typename RecordT>
|
||||
void RefIdDataContainer<RecordT>::erase (int index, int count)
|
||||
{
|
||||
if (index<0 || index+count>=getSize())
|
||||
throw std::runtime_error ("invalid RefIdDataContainer index");
|
||||
|
||||
mContainer.erase (mContainer.begin()+index, mContainer.begin()+index+count);
|
||||
}
|
||||
|
||||
template<typename RecordT>
|
||||
std::string RefIdDataContainer<RecordT>::getId (int index) const
|
||||
{
|
||||
return mContainer.at (index).get().mId;
|
||||
}
|
||||
|
||||
class RefIdData
|
||||
{
|
||||
public:
|
||||
|
||||
typedef std::pair<int, UniversalId::Type> LocalIndex;
|
||||
|
||||
private:
|
||||
|
||||
RefIdDataContainer<ESM::Activator> mActivators;
|
||||
RefIdDataContainer<ESM::Potion> mPotions;
|
||||
RefIdDataContainer<ESM::Apparatus> mApparati;
|
||||
RefIdDataContainer<ESM::Armor> mArmors;
|
||||
RefIdDataContainer<ESM::Book> mBooks;
|
||||
RefIdDataContainer<ESM::Clothing> mClothing;
|
||||
RefIdDataContainer<ESM::Container> mContainers;
|
||||
RefIdDataContainer<ESM::Creature> mCreatures;
|
||||
RefIdDataContainer<ESM::Door> mDoors;
|
||||
RefIdDataContainer<ESM::Ingredient> mIngredients;
|
||||
RefIdDataContainer<ESM::CreatureLevList> mCreatureLevelledLists;
|
||||
RefIdDataContainer<ESM::ItemLevList> mItemLevelledLists;
|
||||
RefIdDataContainer<ESM::Light> mLights;
|
||||
RefIdDataContainer<ESM::Lockpick> mLockpicks;
|
||||
RefIdDataContainer<ESM::Miscellaneous> mMiscellaneous;
|
||||
RefIdDataContainer<ESM::NPC> mNpcs;
|
||||
RefIdDataContainer<ESM::Probe> mProbes;
|
||||
RefIdDataContainer<ESM::Repair> mRepairs;
|
||||
RefIdDataContainer<ESM::Static> mStatics;
|
||||
RefIdDataContainer<ESM::Weapon> mWeapons;
|
||||
|
||||
std::map<std::string, LocalIndex> mIndex;
|
||||
|
||||
std::map<UniversalId::Type, RefIdDataContainerBase *> mRecordContainers;
|
||||
|
||||
void erase (const LocalIndex& index, int count);
|
||||
///< Must not spill over into another type.
|
||||
|
||||
public:
|
||||
|
||||
RefIdData();
|
||||
|
||||
LocalIndex globalToLocalIndex (int index) const;
|
||||
|
||||
int localToGlobalIndex (const LocalIndex& index) const;
|
||||
|
||||
LocalIndex searchId (const std::string& id) const;
|
||||
|
||||
void erase (int index, int count);
|
||||
|
||||
const RecordBase& getRecord (const LocalIndex& index) const;
|
||||
|
||||
RecordBase& getRecord (const LocalIndex& index);
|
||||
|
||||
void appendRecord (UniversalId::Type type, const std::string& id);
|
||||
|
||||
int getAppendIndex (UniversalId::Type type) const;
|
||||
|
||||
void load (const LocalIndex& index, ESM::ESMReader& reader, bool base);
|
||||
|
||||
int getSize() const;
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
@ -0,0 +1,22 @@
|
||||
|
||||
#include "scriptcontext.hpp"
|
||||
|
||||
bool CSMWorld::ScriptContext::canDeclareLocals() const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
char CSMWorld::ScriptContext::getGlobalType (const std::string& name) const
|
||||
{
|
||||
return ' ';
|
||||
}
|
||||
|
||||
char CSMWorld::ScriptContext::getMemberType (const std::string& name, const std::string& id) const
|
||||
{
|
||||
return ' ';
|
||||
}
|
||||
|
||||
bool CSMWorld::ScriptContext::isId (const std::string& name) const
|
||||
{
|
||||
return false;
|
||||
}
|
@ -0,0 +1,26 @@
|
||||
#ifndef CSM_WORLD_SCRIPTCONTEXT_H
|
||||
#define CSM_WORLD_SCRIPTCONTEXT_H
|
||||
|
||||
#include <components/compiler/context.hpp>
|
||||
|
||||
namespace CSMWorld
|
||||
{
|
||||
class ScriptContext : public Compiler::Context
|
||||
{
|
||||
public:
|
||||
|
||||
virtual bool canDeclareLocals() const;
|
||||
///< Is the compiler allowed to declare local variables?
|
||||
|
||||
virtual char getGlobalType (const std::string& name) const;
|
||||
///< 'l: long, 's': short, 'f': float, ' ': does not exist.
|
||||
|
||||
virtual char getMemberType (const std::string& name, const std::string& id) const;
|
||||
///< 'l: long, 's': short, 'f': float, ' ': does not exist.
|
||||
|
||||
virtual bool isId (const std::string& name) const;
|
||||
///< Does \a name match an ID, that can be referenced?
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue