commit
58add97676
@ -1,24 +1,55 @@
|
||||
build
|
||||
*~
|
||||
Doxygen
|
||||
prebuilt
|
||||
apps/openmw/config.hpp
|
||||
Docs/mainpage.hpp
|
||||
## make
|
||||
CMakeFiles
|
||||
*/CMakeFiles
|
||||
CMakeCache.txt
|
||||
moc_*.cxx
|
||||
cmake_install.cmake
|
||||
*.[ao]
|
||||
Makefile
|
||||
makefile
|
||||
data
|
||||
build
|
||||
prebuilt
|
||||
|
||||
## doxygen
|
||||
Doxygen
|
||||
|
||||
## ides/editors
|
||||
*~
|
||||
*.kdev4
|
||||
CMakeLists.txt.user
|
||||
*.swp
|
||||
*.swo
|
||||
*.kate-swp
|
||||
.cproject
|
||||
.project
|
||||
.settings/
|
||||
.settings
|
||||
.directory
|
||||
## qt-creator
|
||||
CMakeLists.txt.user*
|
||||
|
||||
## resources
|
||||
data
|
||||
resources
|
||||
/*.cfg
|
||||
/*.desktop
|
||||
/*.install
|
||||
|
||||
## binaries
|
||||
/esmtool
|
||||
/mwiniimport
|
||||
/omwlauncher
|
||||
/openmw
|
||||
/opencs
|
||||
|
||||
## generated objects
|
||||
apps/openmw/config.hpp
|
||||
components/version/version.hpp
|
||||
Docs/mainpage.hpp
|
||||
moc_*.cxx
|
||||
*.cxx_parameters
|
||||
*qrc_launcher.cxx
|
||||
*qrc_resources.cxx
|
||||
*__*
|
||||
*ui_datafilespage.h
|
||||
*ui_graphicspage.h
|
||||
*ui_mainwindow.h
|
||||
*ui_playpage.h
|
||||
*.[ao]
|
||||
*.so
|
||||
|
@ -1,10 +0,0 @@
|
||||
Dongle's Oblivion Daedric font set
|
||||
http://www.uesp.net/wiki/Lore:Daedric_Alphabet#Daedric_Font
|
||||
|
||||
---------------------------------------------------
|
||||
|
||||
This was done entirely as a personal project. Bethesda Softworks graciously granted me the permission for it. I am not connected with them in any way.
|
||||
You may freely use these fonts to create anything you'd like. You may re-distribute the fonts freely, over the Internet, or by any other means. Always keep the .zip file intact, and this read me included.
|
||||
Please do not modify and redistribute the fonts without my permission.
|
||||
You may NOT sell any of these fonts under any circumstances. This includes putting them on compilation font CDs for sale, putting them in a "members only" pay-area of a website, or any other means of financial gain connected in ANY way with the redistribution of any of these fonts.
|
||||
You have my permission to create and sell any artwork made with these fonts, however you may need to contact Bethesda Softworks before doing so.
|
@ -1,160 +0,0 @@
|
||||
#Getting OpenMW Working on OS X
|
||||
|
||||
## Initial setup
|
||||
First of all, clone OpenMW repo.
|
||||
|
||||
$ git clone github.com/zinnschlag/openmw
|
||||
|
||||
Or use your github url if you forked.
|
||||
|
||||
About dependencies: I prefer not to install them globally (i. e. in /usr/local/), so I'm installing them in directory in my home directory. If OpenMW sources is in $HOME/path/openmw, I'm using $HOME/path/libs/root as prefix for boost and other libs.
|
||||
|
||||
It's useful to create env var for lib install prefix:
|
||||
|
||||
$ export OMW_LIB_PREFIX=$HOME/path/libs/root`
|
||||
|
||||
Most of libs can be installed from [Homebrew][homebrew]. Only mpg123 needs to be installed from source (due to lack of universal compilation support). I think that some of libs can be installed from MacPorts or Fink too.
|
||||
|
||||
As OpenMW currently only supports i386 architecture on OS X, denendencies also should support it. Set some env vars in current terminal:
|
||||
|
||||
$ export CFLAGS="-arch i386"
|
||||
$ export CXXFLAGS="-arch i386"
|
||||
$ export LDFLAGS="-arch i386"
|
||||
|
||||
If you close your terminal, you should set env vars again before pcoceeding to next steps!
|
||||
|
||||
## Boost
|
||||
Download [boost][boost] and install it with the following command:
|
||||
|
||||
$ cd /path/to/boost/source
|
||||
$ ./bootstrap.sh --prefix=$OMW_LIB_PREFIX
|
||||
$ ./bjam --build-dir=build --layout=versioned \
|
||||
--toolset=darwin architecture=x86 address-model=32 \
|
||||
--link-shared,static --prefix=$OMW_LIB_PREFIX install
|
||||
|
||||
|
||||
Alternatively you can install boost with homebrew:
|
||||
|
||||
$ brew install boost --universal
|
||||
|
||||
I think MacPorts also should support universal build for boost.
|
||||
|
||||
## Ogre
|
||||
Download [Ogre][] SDK (tested with 1.7.3), unpack it somewhere and move
|
||||
`lib/Release/Ogre.framework` into `/Library/Frameworks`.
|
||||
|
||||
## OIS
|
||||
Download patched [OIS][] and use the XCode project provided. Be sure to set your build architecture to
|
||||
`i386`. Once it built, locate built OIS.framework with Xcode and move it to `/Library/Frameworks`.
|
||||
|
||||
## mpg123
|
||||
Download [MPG 123][mpg123] and build it:
|
||||
|
||||
$ cd /path/to/mpg123/source
|
||||
$ ./configure --prefix=$OMW_LIB_PREFIX --disable-debug \
|
||||
--disable-dependency-tracking \
|
||||
--with-optimization=4 \
|
||||
--with-audio=dummy \
|
||||
--with-default-audio=dummy \
|
||||
--with-cpu=sse_alone \
|
||||
$ make install
|
||||
|
||||
## libsndfile
|
||||
Download [libsndfile][] and build it:
|
||||
|
||||
$ cd /path/to/libsndfile/source
|
||||
$ ./configure --prefix=$OMW_LIB_PREFIX \
|
||||
--disable-dependency-tracking
|
||||
$ make install
|
||||
|
||||
or install with homebrew:
|
||||
|
||||
$ brew install libsndfile --universal
|
||||
|
||||
## Bullet
|
||||
Download [Bullet][] and build it:
|
||||
|
||||
$ cd /path/to/bullet/source
|
||||
$ mkdir build
|
||||
$ cd build
|
||||
$ cmake -DCMAKE_BUILD_TYPE=Release \
|
||||
-DCMAKE_INSTALL_PREFIX=$OMW_LIB_PREFIX \
|
||||
-DBUILD_EXTRAS=OFF \
|
||||
-DBUILD_DEMOS=OFF \
|
||||
-DCMAKE_OSX_ARCHITECTURES=i386 \
|
||||
-DCMAKE_INSTALL_NAME_DIR=$OMW_LIB_RPEFIX/lib \
|
||||
-G"Unix Makefiles" ../
|
||||
$ make install
|
||||
|
||||
or install with homebrew:
|
||||
|
||||
$ brew install bullet --HEAD --universal
|
||||
|
||||
I prefer head because 2.79 has some issue which causes OpenMW to lag. Also you can edit formula and install 2.77, which is stable and haven't mentioned issue.
|
||||
|
||||
## Qt
|
||||
Install [Qt][qt]. Qt SDK distributed by Nokia is not an option because it's 64 bit only, and OpenMW currently doesn't build for 64 bit on OS X. I'm installing it from Homebrew:
|
||||
|
||||
$ brew install qt --universal
|
||||
|
||||
## Run CMake
|
||||
Generate the Makefile for OpenMW as follows and build OpenMW:
|
||||
|
||||
$ mkdir /path/to/openmw/build/dir
|
||||
$ cd /path/to/open/build/dir
|
||||
$ cmake \
|
||||
-D CMAKE_OSX_ARCHITECTURES=i386 \
|
||||
-D OGRE_SDK=/path/to/ogre/sdk \
|
||||
-D BOOST_INCLUDEDIR=$OMW_LIB_PREFIX/include/boost-1_45 \
|
||||
-D BOOST_LIBRARYDIR=$OMW_LIB_PREFIX/lib \
|
||||
-D SNDFILE_INCLUDE_DIR=$OMW_LIB_PREFIX/include \
|
||||
-D SNDFILE_LIBRARY=$OMW_LIB_PREFIX/lib/libsndfile.a \
|
||||
-D MPG123_LIBRARY=$OMW_LIB_PREFIX/lib/libmpg123.a \
|
||||
-D MPG123_INCLUDE_DIR=$OMW_LIB_PREFIX/include \
|
||||
-D BULLET_DYNAMICS_LIBRARY=$OMW_LIB_PREFIX/lib/libBulletDynamics.a \
|
||||
-D BULLET_COLLISION_LIBRARY=$OMW_LIB_PREFIX/lib/libBulletCollision.a \
|
||||
-D BULLET_MATH_LIBRARY=$OMW_LIB_PREFIX/lib/libLinearMath.a \
|
||||
-D BULLET_SOFTBODY_LIBRARY=$OMW_LIB_PREFIX/lib/libBulletSoftBody.a \
|
||||
-D BULLET_INCLUDE_DIR=$OMW_LIB_PREFIX/include/bullet/ \
|
||||
-G "Unix Makefiles" /path/to/openmw/source/dir
|
||||
$ make
|
||||
|
||||
You can use `-G"Xcode"` if you prefer Xcode, or -G"Eclipse CDT4 - Unix Makefiles"
|
||||
if you prefer Eclipse. You also can specify `-D CMAKE_BUILD_TYPE=Debug` for debug
|
||||
build. As for CMake 2.8.7 and Xcode 4.3, Xcode generator is broken. Sadly Eclipse CDT also cannot import generated project at least on my machine.
|
||||
|
||||
If all libs installed via homebrew (excluding mpg123), then command would be even simplier:
|
||||
|
||||
$ cmake \
|
||||
-D CMAKE_OSX_ARCHITECTURES="i386" \
|
||||
-D OGRE_SDK=/path/to/ogre/sdk \
|
||||
-D MPG123_LIBRARY=$OMW_LIB_PREFIX/lib/libmpg123.a \
|
||||
-D MPG123_INCLUDE_DIR=$OMW_LIB_PREFIX/include \
|
||||
-G "Unix Makefiles" /path/to/openmw/source/dir
|
||||
$ make
|
||||
|
||||
Note for users with recent Xcode versions: you must explicitly specify what set of compilers do you use! If not, gcc will be used for C and Clang for C++. Just add this two -D's to command: `-D CMAKE_C_COMPILER=/usr/bin/clang` and `-D CMAKE_CXX_COMPILER=/usr/bin/clang`
|
||||
|
||||
Note for Xcode 4.3 users: you should specify full path to used SDK, because current CMake (2.8.7) couldn't find SDKs inside Xcode app bundle:
|
||||
|
||||
-D CMAKE_OSX_SYSROOT="/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.7.sdk"
|
||||
|
||||
# Run
|
||||
From your build directory run:
|
||||
|
||||
$ OpenMW.app/Contents/MacOS/openmw
|
||||
or:
|
||||
|
||||
$ open OpenMW.app
|
||||
Enjoy!
|
||||
|
||||
[homebrew]: https://github.com/mxcl/homebrew
|
||||
[boost]: http://www.boost.org
|
||||
[Ogre]: http://www.ogre3d.org
|
||||
[Bullet]: http://bulletphysics.org
|
||||
[OIS]: https://github.com/corristo/ois-fork
|
||||
[mpg123]: http://www.mpg123.de
|
||||
[libsndfile]: http://www.mega-nerd.com/libsndfile
|
||||
[official website]: http://openmw.com
|
||||
[Will Thimbleby's Ogre Framework]: http://www.thimbleby.net/ogre/
|
||||
[qt]: http://qt.nokia.com/
|
@ -1,88 +1,136 @@
|
||||
#ifndef DATAFILESPAGE_H
|
||||
#define DATAFILESPAGE_H
|
||||
|
||||
#include "ui_datafilespage.h"
|
||||
#include <QWidget>
|
||||
#include <QModelIndex>
|
||||
|
||||
#include "ui_datafilespage.h"
|
||||
|
||||
#include <QDir>
|
||||
#include <QFile>
|
||||
|
||||
class QSortFilterProxyModel;
|
||||
class QAbstractItemModel;
|
||||
class QAction;
|
||||
class QMenu;
|
||||
|
||||
class DataFilesModel;
|
||||
class TextInputDialog;
|
||||
class GameSettings;
|
||||
class LauncherSettings;
|
||||
class PluginsProxyModel;
|
||||
|
||||
namespace Files { struct ConfigurationManager; }
|
||||
namespace ContentSelectorView { class ContentSelector; }
|
||||
|
||||
class DataFilesPage : public QWidget, private Ui::DataFilesPage
|
||||
namespace Launcher
|
||||
{
|
||||
Q_OBJECT
|
||||
class TextInputDialog;
|
||||
class GameSettings;
|
||||
class LauncherSettings;
|
||||
class ProfilesComboBox;
|
||||
|
||||
class DataFilesPage : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
ContentSelectorView::ContentSelector *mSelector;
|
||||
Ui::DataFilesPage ui;
|
||||
|
||||
public:
|
||||
explicit DataFilesPage (Files::ConfigurationManager &cfg, GameSettings &gameSettings,
|
||||
LauncherSettings &launcherSettings, QWidget *parent = 0);
|
||||
|
||||
QAbstractItemModel* profilesModel() const;
|
||||
|
||||
int profilesIndex() const;
|
||||
|
||||
//void writeConfig(QString profile = QString());
|
||||
void saveSettings(const QString &profile = "");
|
||||
void loadSettings();
|
||||
|
||||
signals:
|
||||
void signalProfileChanged (int index);
|
||||
|
||||
public slots:
|
||||
void slotProfileChanged (int index);
|
||||
|
||||
private slots:
|
||||
|
||||
void slotProfileChangedByUser(const QString &previous, const QString ¤t);
|
||||
void slotProfileRenamed(const QString &previous, const QString ¤t);
|
||||
void slotProfileDeleted(const QString &item);
|
||||
|
||||
public:
|
||||
DataFilesPage(Files::ConfigurationManager &cfg, GameSettings &gameSettings, LauncherSettings &launcherSettings, QWidget *parent = 0);
|
||||
void on_newProfileAction_triggered();
|
||||
void on_deleteProfileAction_triggered();
|
||||
|
||||
QAbstractItemModel* profilesComboBoxModel();
|
||||
int profilesComboBoxIndex();
|
||||
private:
|
||||
|
||||
void writeConfig(QString profile = QString());
|
||||
void saveSettings();
|
||||
QMenu *mContextMenu;
|
||||
|
||||
signals:
|
||||
void profileChanged(int index);
|
||||
Files::ConfigurationManager &mCfgMgr;
|
||||
|
||||
public slots:
|
||||
void setCheckState(QModelIndex index);
|
||||
void setProfilesComboBoxIndex(int index);
|
||||
GameSettings &mGameSettings;
|
||||
LauncherSettings &mLauncherSettings;
|
||||
|
||||
void filterChanged(const QString filter);
|
||||
void showContextMenu(const QPoint &point);
|
||||
void profileChanged(const QString &previous, const QString ¤t);
|
||||
void profileRenamed(const QString &previous, const QString ¤t);
|
||||
void updateOkButton(const QString &text);
|
||||
void updateSplitter();
|
||||
void updateViews();
|
||||
QString mDataLocal;
|
||||
|
||||
// Action slots
|
||||
void on_newProfileAction_triggered();
|
||||
void on_deleteProfileAction_triggered();
|
||||
void on_checkAction_triggered();
|
||||
void on_uncheckAction_triggered();
|
||||
void setPluginsCheckstates(Qt::CheckState state);
|
||||
|
||||
private slots:
|
||||
void slotCurrentIndexChanged(int index);
|
||||
void buildView();
|
||||
void setupDataFiles();
|
||||
void setupConfig();
|
||||
void readConfig();
|
||||
void setProfile (int index, bool savePrevious);
|
||||
void setProfile (const QString &previous, const QString ¤t, bool savePrevious);
|
||||
void removeProfile (const QString &profile);
|
||||
bool showDeleteMessageBox (const QString &text);
|
||||
void addProfile (const QString &profile, bool setAsCurrent);
|
||||
void checkForDefaultProfile();
|
||||
|
||||
private:
|
||||
DataFilesModel *mDataFilesModel;
|
||||
class PathIterator
|
||||
{
|
||||
QStringList::ConstIterator mCitEnd;
|
||||
QStringList::ConstIterator mCitCurrent;
|
||||
QStringList::ConstIterator mCitBegin;
|
||||
QString mFile;
|
||||
QString mFilePath;
|
||||
|
||||
PluginsProxyModel *mPluginsProxyModel;
|
||||
QSortFilterProxyModel *mMastersProxyModel;
|
||||
public:
|
||||
PathIterator (const QStringList &list)
|
||||
{
|
||||
mCitBegin = list.constBegin();
|
||||
mCitCurrent = mCitBegin;
|
||||
mCitEnd = list.constEnd();
|
||||
}
|
||||
|
||||
QSortFilterProxyModel *mFilterProxyModel;
|
||||
QString findFirstPath (const QString &file)
|
||||
{
|
||||
mCitCurrent = mCitBegin;
|
||||
mFile = file;
|
||||
return path();
|
||||
}
|
||||
|
||||
QMenu *mContextMenu;
|
||||
QString findNextPath () { return path(); }
|
||||
|
||||
Files::ConfigurationManager &mCfgMgr;
|
||||
private:
|
||||
|
||||
GameSettings &mGameSettings;
|
||||
LauncherSettings &mLauncherSettings;
|
||||
QString path ()
|
||||
{
|
||||
bool success = false;
|
||||
QDir dir;
|
||||
QFileInfo file;
|
||||
|
||||
TextInputDialog *mNewProfileDialog;
|
||||
while (!success)
|
||||
{
|
||||
if (mCitCurrent == mCitEnd)
|
||||
break;
|
||||
|
||||
void setMastersCheckstates(Qt::CheckState state);
|
||||
void setPluginsCheckstates(Qt::CheckState state);
|
||||
dir.setPath (*(mCitCurrent++));
|
||||
file.setFile (dir.absoluteFilePath (mFile));
|
||||
|
||||
void createActions();
|
||||
void setupDataFiles();
|
||||
void setupConfig();
|
||||
void readConfig();
|
||||
success = file.exists();
|
||||
}
|
||||
|
||||
void loadSettings();
|
||||
if (success)
|
||||
return file.absoluteFilePath();
|
||||
|
||||
};
|
||||
return "";
|
||||
}
|
||||
|
||||
};
|
||||
};
|
||||
}
|
||||
#endif
|
||||
|
@ -1,6 +1,6 @@
|
||||
#include "textslotmsgbox.hpp"
|
||||
|
||||
void TextSlotMsgBox::setTextSlot(const QString& string)
|
||||
void Launcher::TextSlotMsgBox::setTextSlot(const QString& string)
|
||||
{
|
||||
setText(string);
|
||||
}
|
||||
|
@ -0,0 +1,47 @@
|
||||
#ifndef PROFILESCOMBOBOX_HPP
|
||||
#define PROFILESCOMBOBOX_HPP
|
||||
|
||||
#include "components/contentselector/view/combobox.hpp"
|
||||
#include "lineedit.hpp"
|
||||
|
||||
#include <QDebug>
|
||||
|
||||
class QString;
|
||||
|
||||
class ProfilesComboBox : public ContentSelectorView::ComboBox
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
class ComboBoxLineEdit : public LineEdit
|
||||
{
|
||||
public:
|
||||
explicit ComboBoxLineEdit (QWidget *parent = 0);
|
||||
};
|
||||
|
||||
public:
|
||||
|
||||
explicit ProfilesComboBox(QWidget *parent = 0);
|
||||
void setEditEnabled(bool editable);
|
||||
void setCurrentProfile(int index)
|
||||
{
|
||||
ComboBox::setCurrentIndex(index);
|
||||
mOldProfile = currentText();
|
||||
}
|
||||
|
||||
signals:
|
||||
void signalProfileTextChanged(const QString &item);
|
||||
void signalProfileChanged(const QString &previous, const QString ¤t);
|
||||
void signalProfileChanged(int index);
|
||||
void profileRenamed(const QString &oldName, const QString &newName);
|
||||
|
||||
private slots:
|
||||
|
||||
void slotEditingFinished();
|
||||
void slotIndexChangedByUser(int index);
|
||||
void slotTextChanged(const QString &text);
|
||||
|
||||
private:
|
||||
QString mOldProfile;
|
||||
};
|
||||
#endif // PROFILESCOMBOBOX_HPP
|
@ -0,0 +1,71 @@
|
||||
|
||||
#include "saving.hpp"
|
||||
|
||||
#include "../world/data.hpp"
|
||||
#include "../world/idcollection.hpp"
|
||||
|
||||
#include "state.hpp"
|
||||
#include "savingstages.hpp"
|
||||
#include "document.hpp"
|
||||
|
||||
CSMDoc::Saving::Saving (Document& document, const boost::filesystem::path& projectPath)
|
||||
: Operation (State_Saving, true, true), mDocument (document), mState (*this, projectPath)
|
||||
{
|
||||
// save project file
|
||||
appendStage (new OpenSaveStage (mDocument, mState, true));
|
||||
|
||||
appendStage (new WriteHeaderStage (mDocument, mState, true));
|
||||
|
||||
appendStage (new WriteFilterStage (mDocument, mState, CSMFilter::Filter::Scope_Project));
|
||||
|
||||
appendStage (new CloseSaveStage (mState));
|
||||
|
||||
// save content file
|
||||
appendStage (new OpenSaveStage (mDocument, mState, false));
|
||||
|
||||
appendStage (new WriteHeaderStage (mDocument, mState, false));
|
||||
|
||||
appendStage (new WriteCollectionStage<CSMWorld::IdCollection<ESM::Global> >
|
||||
(mDocument.getData().getGlobals(), mState));
|
||||
|
||||
appendStage (new WriteCollectionStage<CSMWorld::IdCollection<ESM::GameSetting> >
|
||||
(mDocument.getData().getGmsts(), mState));
|
||||
|
||||
appendStage (new WriteCollectionStage<CSMWorld::IdCollection<ESM::Skill> >
|
||||
(mDocument.getData().getSkills(), mState));
|
||||
|
||||
appendStage (new WriteCollectionStage<CSMWorld::IdCollection<ESM::Class> >
|
||||
(mDocument.getData().getClasses(), mState));
|
||||
|
||||
appendStage (new WriteCollectionStage<CSMWorld::IdCollection<ESM::Faction> >
|
||||
(mDocument.getData().getFactions(), mState));
|
||||
|
||||
appendStage (new WriteCollectionStage<CSMWorld::IdCollection<ESM::Race> >
|
||||
(mDocument.getData().getRaces(), mState));
|
||||
|
||||
appendStage (new WriteCollectionStage<CSMWorld::IdCollection<ESM::Sound> >
|
||||
(mDocument.getData().getSounds(), mState));
|
||||
|
||||
appendStage (new WriteCollectionStage<CSMWorld::IdCollection<ESM::Script> >
|
||||
(mDocument.getData().getScripts(), mState));
|
||||
|
||||
appendStage (new WriteCollectionStage<CSMWorld::IdCollection<ESM::Region> >
|
||||
(mDocument.getData().getRegions(), mState));
|
||||
|
||||
appendStage (new WriteCollectionStage<CSMWorld::IdCollection<ESM::BirthSign> >
|
||||
(mDocument.getData().getBirthsigns(), mState));
|
||||
|
||||
appendStage (new WriteCollectionStage<CSMWorld::IdCollection<ESM::Spell> >
|
||||
(mDocument.getData().getSpells(), mState));
|
||||
|
||||
appendStage (new WriteDialogueCollectionStage (mDocument, mState, false));
|
||||
|
||||
appendStage (new WriteDialogueCollectionStage (mDocument, mState, true));
|
||||
|
||||
appendStage (new WriteRefIdCollectionStage (mDocument, mState));
|
||||
|
||||
|
||||
appendStage (new CloseSaveStage (mState));
|
||||
|
||||
appendStage (new FinalSavingStage (mDocument, mState));
|
||||
}
|
@ -0,0 +1,27 @@
|
||||
#ifndef CSM_DOC_SAVING_H
|
||||
#define CSM_DOC_SAVING_H
|
||||
|
||||
#include <boost/filesystem/path.hpp>
|
||||
|
||||
#include "operation.hpp"
|
||||
#include "savingstate.hpp"
|
||||
|
||||
namespace CSMDoc
|
||||
{
|
||||
class Document;
|
||||
|
||||
class Saving : public Operation
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
Document& mDocument;
|
||||
SavingState mState;
|
||||
|
||||
public:
|
||||
|
||||
Saving (Document& document, const boost::filesystem::path& projectPath);
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
@ -0,0 +1,263 @@
|
||||
|
||||
#include "savingstages.hpp"
|
||||
|
||||
#include <fstream>
|
||||
|
||||
#include <boost/filesystem.hpp>
|
||||
|
||||
#include <QUndoStack>
|
||||
|
||||
#include <components/esm/loaddial.hpp>
|
||||
|
||||
#include "../world/infocollection.hpp"
|
||||
|
||||
#include "document.hpp"
|
||||
#include "savingstate.hpp"
|
||||
|
||||
CSMDoc::OpenSaveStage::OpenSaveStage (Document& document, SavingState& state, bool projectFile)
|
||||
: mDocument (document), mState (state), mProjectFile (projectFile)
|
||||
{}
|
||||
|
||||
int CSMDoc::OpenSaveStage::setup()
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
void CSMDoc::OpenSaveStage::perform (int stage, std::vector<std::string>& messages)
|
||||
{
|
||||
mState.start (mDocument, mProjectFile);
|
||||
|
||||
mState.getStream().open ((mProjectFile ? mState.getPath() : mState.getTmpPath()).string().c_str());
|
||||
|
||||
if (!mState.getStream().is_open())
|
||||
throw std::runtime_error ("failed to open stream for saving");
|
||||
}
|
||||
|
||||
|
||||
CSMDoc::WriteHeaderStage::WriteHeaderStage (Document& document, SavingState& state, bool simple)
|
||||
: mDocument (document), mState (state), mSimple (simple)
|
||||
{}
|
||||
|
||||
int CSMDoc::WriteHeaderStage::setup()
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
void CSMDoc::WriteHeaderStage::perform (int stage, std::vector<std::string>& messages)
|
||||
{
|
||||
mState.getWriter().setVersion();
|
||||
|
||||
mState.getWriter().clearMaster();
|
||||
|
||||
mState.getWriter().setFormat (0);
|
||||
|
||||
if (mSimple)
|
||||
{
|
||||
mState.getWriter().setAuthor ("");
|
||||
mState.getWriter().setDescription ("");
|
||||
mState.getWriter().setRecordCount (0);
|
||||
}
|
||||
else
|
||||
{
|
||||
mState.getWriter().setAuthor (mDocument.getData().getAuthor());
|
||||
mState.getWriter().setDescription (mDocument.getData().getDescription());
|
||||
mState.getWriter().setRecordCount (
|
||||
mDocument.getData().count (CSMWorld::RecordBase::State_Modified) +
|
||||
mDocument.getData().count (CSMWorld::RecordBase::State_ModifiedOnly) +
|
||||
mDocument.getData().count (CSMWorld::RecordBase::State_Deleted));
|
||||
|
||||
/// \todo refine dependency list (at least remove redundant dependencies)
|
||||
std::vector<boost::filesystem::path> dependencies = mDocument.getContentFiles();
|
||||
std::vector<boost::filesystem::path>::const_iterator end (--dependencies.end());
|
||||
|
||||
for (std::vector<boost::filesystem::path>::const_iterator iter (dependencies.begin());
|
||||
iter!=end; ++iter)
|
||||
{
|
||||
std::string name = iter->filename().string();
|
||||
uint64_t size = boost::filesystem::file_size (*iter);
|
||||
|
||||
mState.getWriter().addMaster (name, size);
|
||||
}
|
||||
}
|
||||
|
||||
mState.getWriter().save (mState.getStream());
|
||||
}
|
||||
|
||||
|
||||
CSMDoc::WriteDialogueCollectionStage::WriteDialogueCollectionStage (Document& document,
|
||||
SavingState& state, bool journal)
|
||||
: mDocument (document), mState (state),
|
||||
mTopics (journal ? document.getData().getJournals() : document.getData().getTopics()),
|
||||
mInfos (journal ? document.getData().getJournalInfos() : document.getData().getTopicInfos())
|
||||
{}
|
||||
|
||||
int CSMDoc::WriteDialogueCollectionStage::setup()
|
||||
{
|
||||
return mTopics.getSize();
|
||||
}
|
||||
|
||||
void CSMDoc::WriteDialogueCollectionStage::perform (int stage, std::vector<std::string>& messages)
|
||||
{
|
||||
const CSMWorld::Record<ESM::Dialogue>& topic = mTopics.getRecord (stage);
|
||||
|
||||
CSMWorld::RecordBase::State state = topic.mState;
|
||||
|
||||
if (state==CSMWorld::RecordBase::State_Deleted)
|
||||
{
|
||||
// if the topic is deleted, we do not need to bother with INFO records.
|
||||
|
||||
/// \todo wrote record with delete flag
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Test, if we need to save anything associated info records.
|
||||
bool infoModified = false;
|
||||
|
||||
CSMWorld::InfoCollection::Range range = mInfos.getTopicRange (topic.get().mId);
|
||||
|
||||
for (CSMWorld::InfoCollection::RecordConstIterator iter (range.first); iter!=range.second; ++iter)
|
||||
{
|
||||
CSMWorld::RecordBase::State state = iter->mState;
|
||||
|
||||
if (state==CSMWorld::RecordBase::State_Modified ||
|
||||
state==CSMWorld::RecordBase::State_ModifiedOnly ||
|
||||
state==CSMWorld::RecordBase::State_Deleted)
|
||||
{
|
||||
infoModified = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (state==CSMWorld::RecordBase::State_Modified ||
|
||||
state==CSMWorld::RecordBase::State_ModifiedOnly ||
|
||||
infoModified)
|
||||
{
|
||||
mState.getWriter().startRecord (topic.mModified.sRecordId);
|
||||
mState.getWriter().writeHNCString ("NAME", topic.mModified.mId);
|
||||
topic.mModified.save (mState.getWriter());
|
||||
mState.getWriter().endRecord (topic.mModified.sRecordId);
|
||||
|
||||
// write modified selected info records
|
||||
for (CSMWorld::InfoCollection::RecordConstIterator iter (range.first); iter!=range.second;
|
||||
++iter)
|
||||
{
|
||||
CSMWorld::RecordBase::State state = iter->mState;
|
||||
|
||||
if (state==CSMWorld::RecordBase::State_Deleted)
|
||||
{
|
||||
/// \todo wrote record with delete flag
|
||||
}
|
||||
else if (state==CSMWorld::RecordBase::State_Modified ||
|
||||
state==CSMWorld::RecordBase::State_ModifiedOnly)
|
||||
{
|
||||
ESM::DialInfo info = iter->get();
|
||||
info.mId = info.mId.substr (info.mId.find_last_of ('#')+1);
|
||||
|
||||
if (iter!=range.first)
|
||||
{
|
||||
CSMWorld::InfoCollection::RecordConstIterator prev = iter;
|
||||
--prev;
|
||||
|
||||
info.mPrev =
|
||||
prev->mModified.mId.substr (prev->mModified.mId.find_last_of ('#')+1);
|
||||
}
|
||||
|
||||
CSMWorld::InfoCollection::RecordConstIterator next = iter;
|
||||
++next;
|
||||
|
||||
if (next!=range.second)
|
||||
{
|
||||
info.mNext =
|
||||
next->mModified.mId.substr (next->mModified.mId.find_last_of ('#')+1);
|
||||
}
|
||||
|
||||
mState.getWriter().startRecord (info.sRecordId);
|
||||
mState.getWriter().writeHNCString ("INAM", info.mId);
|
||||
info.save (mState.getWriter());
|
||||
mState.getWriter().endRecord (info.sRecordId);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
CSMDoc::WriteRefIdCollectionStage::WriteRefIdCollectionStage (Document& document, SavingState& state)
|
||||
: mDocument (document), mState (state)
|
||||
{}
|
||||
|
||||
int CSMDoc::WriteRefIdCollectionStage::setup()
|
||||
{
|
||||
return mDocument.getData().getReferenceables().getSize();
|
||||
}
|
||||
|
||||
void CSMDoc::WriteRefIdCollectionStage::perform (int stage, std::vector<std::string>& messages)
|
||||
{
|
||||
mDocument.getData().getReferenceables().save (stage, mState.getWriter());
|
||||
}
|
||||
|
||||
|
||||
CSMDoc::WriteFilterStage::WriteFilterStage (Document& document, SavingState& state,
|
||||
CSMFilter::Filter::Scope scope)
|
||||
: WriteCollectionStage<CSMWorld::IdCollection<CSMFilter::Filter> > (document.getData().getFilters(),
|
||||
state),
|
||||
mDocument (document), mScope (scope)
|
||||
{}
|
||||
|
||||
void CSMDoc::WriteFilterStage::perform (int stage, std::vector<std::string>& messages)
|
||||
{
|
||||
const CSMWorld::Record<CSMFilter::Filter>& record =
|
||||
mDocument.getData().getFilters().getRecord (stage);
|
||||
|
||||
if (record.get().mScope==mScope)
|
||||
WriteCollectionStage<CSMWorld::IdCollection<CSMFilter::Filter> >::perform (stage, messages);
|
||||
}
|
||||
|
||||
|
||||
CSMDoc::CloseSaveStage::CloseSaveStage (SavingState& state)
|
||||
: mState (state)
|
||||
{}
|
||||
|
||||
int CSMDoc::CloseSaveStage::setup()
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
void CSMDoc::CloseSaveStage::perform (int stage, std::vector<std::string>& messages)
|
||||
{
|
||||
mState.getStream().close();
|
||||
|
||||
if (!mState.getStream())
|
||||
throw std::runtime_error ("saving failed");
|
||||
}
|
||||
|
||||
|
||||
CSMDoc::FinalSavingStage::FinalSavingStage (Document& document, SavingState& state)
|
||||
: mDocument (document), mState (state)
|
||||
{}
|
||||
|
||||
int CSMDoc::FinalSavingStage::setup()
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
void CSMDoc::FinalSavingStage::perform (int stage, std::vector<std::string>& messages)
|
||||
{
|
||||
if (mState.hasError())
|
||||
{
|
||||
mState.getWriter().close();
|
||||
mState.getStream().close();
|
||||
|
||||
if (boost::filesystem::exists (mState.getTmpPath()))
|
||||
boost::filesystem::remove (mState.getTmpPath());
|
||||
}
|
||||
else if (!mState.isProjectFile())
|
||||
{
|
||||
if (boost::filesystem::exists (mState.getPath()))
|
||||
boost::filesystem::remove (mState.getPath());
|
||||
|
||||
boost::filesystem::rename (mState.getTmpPath(), mState.getPath());
|
||||
|
||||
mDocument.getUndoStack().setClean();
|
||||
}
|
||||
}
|
@ -0,0 +1,201 @@
|
||||
#ifndef CSM_DOC_SAVINGSTAGES_H
|
||||
#define CSM_DOC_SAVINGSTAGES_H
|
||||
|
||||
#include "stage.hpp"
|
||||
|
||||
#include "../world/record.hpp"
|
||||
#include "../world/idcollection.hpp"
|
||||
|
||||
#include "../filter/filter.hpp"
|
||||
|
||||
#include "savingstate.hpp"
|
||||
|
||||
namespace ESM
|
||||
{
|
||||
struct Dialogue;
|
||||
}
|
||||
|
||||
namespace CSMWorld
|
||||
{
|
||||
class InfoCollection;
|
||||
}
|
||||
|
||||
namespace CSMDoc
|
||||
{
|
||||
class Document;
|
||||
class SavingState;
|
||||
|
||||
class OpenSaveStage : public Stage
|
||||
{
|
||||
Document& mDocument;
|
||||
SavingState& mState;
|
||||
bool mProjectFile;
|
||||
|
||||
public:
|
||||
|
||||
OpenSaveStage (Document& document, SavingState& state, bool projectFile);
|
||||
///< \param projectFile Saving the project file instead of the content file.
|
||||
|
||||
virtual int setup();
|
||||
///< \return number of steps
|
||||
|
||||
virtual void perform (int stage, std::vector<std::string>& messages);
|
||||
///< Messages resulting from this stage will be appended to \a messages.
|
||||
};
|
||||
|
||||
class WriteHeaderStage : public Stage
|
||||
{
|
||||
Document& mDocument;
|
||||
SavingState& mState;
|
||||
bool mSimple;
|
||||
|
||||
public:
|
||||
|
||||
WriteHeaderStage (Document& document, SavingState& state, bool simple);
|
||||
///< \param simple Simplified header (used for project files).
|
||||
|
||||
virtual int setup();
|
||||
///< \return number of steps
|
||||
|
||||
virtual void perform (int stage, std::vector<std::string>& messages);
|
||||
///< Messages resulting from this stage will be appended to \a messages.
|
||||
};
|
||||
|
||||
|
||||
template<class CollectionT>
|
||||
class WriteCollectionStage : public Stage
|
||||
{
|
||||
const CollectionT& mCollection;
|
||||
SavingState& mState;
|
||||
|
||||
public:
|
||||
|
||||
WriteCollectionStage (const CollectionT& collection, SavingState& state);
|
||||
|
||||
virtual int setup();
|
||||
///< \return number of steps
|
||||
|
||||
virtual void perform (int stage, std::vector<std::string>& messages);
|
||||
///< Messages resulting from this stage will be appended to \a messages.
|
||||
};
|
||||
|
||||
template<class CollectionT>
|
||||
WriteCollectionStage<CollectionT>::WriteCollectionStage (const CollectionT& collection,
|
||||
SavingState& state)
|
||||
: mCollection (collection), mState (state)
|
||||
{}
|
||||
|
||||
template<class CollectionT>
|
||||
int WriteCollectionStage<CollectionT>::setup()
|
||||
{
|
||||
return mCollection.getSize();
|
||||
}
|
||||
|
||||
template<class CollectionT>
|
||||
void WriteCollectionStage<CollectionT>::perform (int stage, std::vector<std::string>& messages)
|
||||
{
|
||||
CSMWorld::RecordBase::State state = mCollection.getRecord (stage).mState;
|
||||
|
||||
if (state==CSMWorld::RecordBase::State_Modified ||
|
||||
state==CSMWorld::RecordBase::State_ModifiedOnly)
|
||||
{
|
||||
std::string type;
|
||||
for (int i=0; i<4; ++i)
|
||||
/// \todo make endianess agnostic (change ESMWriter interface?)
|
||||
type += reinterpret_cast<const char *> (&mCollection.getRecord (stage).mModified.sRecordId)[i];
|
||||
|
||||
mState.getWriter().startRecord (mCollection.getRecord (stage).mModified.sRecordId);
|
||||
mState.getWriter().writeHNCString ("NAME", mCollection.getId (stage));
|
||||
mCollection.getRecord (stage).mModified.save (mState.getWriter());
|
||||
mState.getWriter().endRecord (mCollection.getRecord (stage).mModified.sRecordId);
|
||||
}
|
||||
else if (state==CSMWorld::RecordBase::State_Deleted)
|
||||
{
|
||||
/// \todo write record with delete flag
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class WriteDialogueCollectionStage : public Stage
|
||||
{
|
||||
Document& mDocument;
|
||||
SavingState& mState;
|
||||
const CSMWorld::IdCollection<ESM::Dialogue>& mTopics;
|
||||
CSMWorld::InfoCollection& mInfos;
|
||||
|
||||
public:
|
||||
|
||||
WriteDialogueCollectionStage (Document& document, SavingState& state, bool journal);
|
||||
|
||||
virtual int setup();
|
||||
///< \return number of steps
|
||||
|
||||
virtual void perform (int stage, std::vector<std::string>& messages);
|
||||
///< Messages resulting from this stage will be appended to \a messages.
|
||||
};
|
||||
|
||||
|
||||
class WriteRefIdCollectionStage : public Stage
|
||||
{
|
||||
Document& mDocument;
|
||||
SavingState& mState;
|
||||
|
||||
public:
|
||||
|
||||
WriteRefIdCollectionStage (Document& document, SavingState& state);
|
||||
|
||||
virtual int setup();
|
||||
///< \return number of steps
|
||||
|
||||
virtual void perform (int stage, std::vector<std::string>& messages);
|
||||
///< Messages resulting from this stage will be appended to \a messages.
|
||||
};
|
||||
|
||||
|
||||
class WriteFilterStage : public WriteCollectionStage<CSMWorld::IdCollection<CSMFilter::Filter> >
|
||||
{
|
||||
Document& mDocument;
|
||||
CSMFilter::Filter::Scope mScope;
|
||||
|
||||
public:
|
||||
|
||||
WriteFilterStage (Document& document, SavingState& state, CSMFilter::Filter::Scope scope);
|
||||
|
||||
virtual void perform (int stage, std::vector<std::string>& messages);
|
||||
///< Messages resulting from this stage will be appended to \a messages.
|
||||
};
|
||||
|
||||
|
||||
class CloseSaveStage : public Stage
|
||||
{
|
||||
SavingState& mState;
|
||||
|
||||
public:
|
||||
|
||||
CloseSaveStage (SavingState& state);
|
||||
|
||||
virtual int setup();
|
||||
///< \return number of steps
|
||||
|
||||
virtual void perform (int stage, std::vector<std::string>& messages);
|
||||
///< Messages resulting from this stage will be appended to \a messages.
|
||||
};
|
||||
|
||||
class FinalSavingStage : public Stage
|
||||
{
|
||||
Document& mDocument;
|
||||
SavingState& mState;
|
||||
|
||||
public:
|
||||
|
||||
FinalSavingStage (Document& document, SavingState& state);
|
||||
|
||||
virtual int setup();
|
||||
///< \return number of steps
|
||||
|
||||
virtual void perform (int stage, std::vector<std::string>& messages);
|
||||
///< Messages resulting from this stage will be appended to \a messages.
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
@ -0,0 +1,65 @@
|
||||
|
||||
#include "savingstate.hpp"
|
||||
|
||||
#include "operation.hpp"
|
||||
#include "document.hpp"
|
||||
|
||||
CSMDoc::SavingState::SavingState (Operation& operation, const boost::filesystem::path& projectPath)
|
||||
: mOperation (operation),
|
||||
/// \todo set encoding properly, once config implementation has been fixed.
|
||||
mEncoder (ToUTF8::calculateEncoding ("win1252")),
|
||||
mProjectPath (projectPath), mProjectFile (false)
|
||||
{
|
||||
mWriter.setEncoder (&mEncoder);
|
||||
}
|
||||
|
||||
bool CSMDoc::SavingState::hasError() const
|
||||
{
|
||||
return mOperation.hasError();
|
||||
}
|
||||
|
||||
void CSMDoc::SavingState::start (Document& document, bool project)
|
||||
{
|
||||
mProjectFile = project;
|
||||
|
||||
if (mStream.is_open())
|
||||
mStream.close();
|
||||
|
||||
mStream.clear();
|
||||
|
||||
if (project)
|
||||
mPath = mProjectPath;
|
||||
else
|
||||
mPath = document.getSavePath();
|
||||
|
||||
boost::filesystem::path file (mPath.filename().string() + ".tmp");
|
||||
|
||||
mTmpPath = mPath.parent_path();
|
||||
|
||||
mTmpPath /= file;
|
||||
}
|
||||
|
||||
const boost::filesystem::path& CSMDoc::SavingState::getPath() const
|
||||
{
|
||||
return mPath;
|
||||
}
|
||||
|
||||
const boost::filesystem::path& CSMDoc::SavingState::getTmpPath() const
|
||||
{
|
||||
return mTmpPath;
|
||||
}
|
||||
|
||||
std::ofstream& CSMDoc::SavingState::getStream()
|
||||
{
|
||||
return mStream;
|
||||
}
|
||||
|
||||
ESM::ESMWriter& CSMDoc::SavingState::getWriter()
|
||||
{
|
||||
return mWriter;
|
||||
}
|
||||
|
||||
bool CSMDoc::SavingState::isProjectFile() const
|
||||
{
|
||||
return mProjectFile;
|
||||
}
|
@ -0,0 +1,50 @@
|
||||
#ifndef CSM_DOC_SAVINGSTATE_H
|
||||
#define CSM_DOC_SAVINGSTATE_H
|
||||
|
||||
#include <fstream>
|
||||
|
||||
#include <boost/filesystem/path.hpp>
|
||||
|
||||
#include <components/esm/esmwriter.hpp>
|
||||
|
||||
namespace CSMDoc
|
||||
{
|
||||
class Operation;
|
||||
class Document;
|
||||
|
||||
class SavingState
|
||||
{
|
||||
Operation& mOperation;
|
||||
boost::filesystem::path mPath;
|
||||
boost::filesystem::path mTmpPath;
|
||||
ToUTF8::Utf8Encoder mEncoder;
|
||||
std::ofstream mStream;
|
||||
ESM::ESMWriter mWriter;
|
||||
boost::filesystem::path mProjectPath;
|
||||
bool mProjectFile;
|
||||
|
||||
public:
|
||||
|
||||
SavingState (Operation& operation, const boost::filesystem::path& projectPath);
|
||||
|
||||
bool hasError() const;
|
||||
|
||||
void start (Document& document, bool project);
|
||||
///< \param project Save project file instead of content file.
|
||||
|
||||
const boost::filesystem::path& getPath() const;
|
||||
|
||||
const boost::filesystem::path& getTmpPath() const;
|
||||
|
||||
std::ofstream& getStream();
|
||||
|
||||
ESM::ESMWriter& getWriter();
|
||||
|
||||
bool isProjectFile() const;
|
||||
///< Currently saving project file? (instead of content file)
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
|
||||
#endif
|
@ -0,0 +1,4 @@
|
||||
|
||||
#include "stage.hpp"
|
||||
|
||||
CSMDoc::Stage::~Stage() {}
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,78 @@
|
||||
#ifndef REFERENCEABLECHECKSTAGE_H
|
||||
#define REFERENCEABLECHECKSTAGE_H
|
||||
|
||||
#include "../world/universalid.hpp"
|
||||
#include "../doc/stage.hpp"
|
||||
#include "../world/data.hpp"
|
||||
#include "../world/refiddata.hpp"
|
||||
|
||||
namespace CSMTools
|
||||
{
|
||||
class ReferenceableCheckStage : public CSMDoc::Stage
|
||||
{
|
||||
public:
|
||||
ReferenceableCheckStage(const CSMWorld::RefIdData& referenceable,
|
||||
const CSMWorld::IdCollection<ESM::Race>& races,
|
||||
const CSMWorld::IdCollection<ESM::Class>& classes,
|
||||
const CSMWorld::IdCollection<ESM::Faction>& factions);
|
||||
|
||||
virtual void perform(int stage, std::vector< std::string >& messages);
|
||||
virtual int setup();
|
||||
|
||||
private:
|
||||
//CONCRETE CHECKS
|
||||
void bookCheck(int stage, const CSMWorld::RefIdDataContainer< ESM::Book >& records, std::vector< std::string >& messages);
|
||||
void activatorCheck(int stage, const CSMWorld::RefIdDataContainer< ESM::Activator >& records, std::vector< std::string >& messages);
|
||||
void potionCheck(int stage, const CSMWorld::RefIdDataContainer<ESM::Potion>& records, std::vector<std::string>& messages);
|
||||
void apparatusCheck(int stage, const CSMWorld::RefIdDataContainer<ESM::Apparatus>& records, std::vector<std::string>& messages);
|
||||
void armorCheck(int stage, const CSMWorld::RefIdDataContainer<ESM::Armor>& records, std::vector<std::string>& messages);
|
||||
void clothingCheck(int stage, const CSMWorld::RefIdDataContainer<ESM::Clothing>& records, std::vector<std::string>& messages);
|
||||
void containerCheck(int stage, const CSMWorld::RefIdDataContainer<ESM::Container>& records, std::vector<std::string>& messages);
|
||||
void creatureCheck(int stage, const CSMWorld::RefIdDataContainer<ESM::Creature>& records, std::vector<std::string>& messages);
|
||||
void doorCheck(int stage, const CSMWorld::RefIdDataContainer<ESM::Door>& records, std::vector<std::string>& messages);
|
||||
void ingredientCheck(int stage, const CSMWorld::RefIdDataContainer<ESM::Ingredient>& records, std::vector<std::string>& messages);
|
||||
void creaturesLevListCheck(int stage, const CSMWorld::RefIdDataContainer<ESM::CreatureLevList>& records, std::vector<std::string>& messages);
|
||||
void itemLevelledListCheck(int stage, const CSMWorld::RefIdDataContainer<ESM::ItemLevList>& records, std::vector<std::string>& messages);
|
||||
void lightCheck(int stage, const CSMWorld::RefIdDataContainer<ESM::Light>& records, std::vector<std::string>& messages);
|
||||
void lockpickCheck(int stage, const CSMWorld::RefIdDataContainer<ESM::Lockpick>& records, std::vector<std::string>& messages);
|
||||
void miscCheck(int stage, const CSMWorld::RefIdDataContainer<ESM::Miscellaneous>& records, std::vector<std::string>& messages);
|
||||
void npcCheck(int stage, const CSMWorld::RefIdDataContainer<ESM::NPC>& records, std::vector<std::string>& messages);
|
||||
void weaponCheck(int stage, const CSMWorld::RefIdDataContainer<ESM::Weapon>& records, std::vector<std::string>& messages);
|
||||
void probeCheck(int stage, const CSMWorld::RefIdDataContainer<ESM::Probe>& records, std::vector<std::string>& messages);
|
||||
void repairCheck(int stage, const CSMWorld::RefIdDataContainer<ESM::Repair>& records, std::vector<std::string>& messages);
|
||||
void staticCheck(int stage, const CSMWorld::RefIdDataContainer<ESM::Static>& records, std::vector<std::string>& messages);
|
||||
|
||||
//FINAL CHECK
|
||||
void finalCheck(std::vector<std::string>& messages);
|
||||
|
||||
//TEMPLATE CHECKS
|
||||
template<typename ITEM> void inventoryItemCheck(const ITEM& someItem,
|
||||
std::vector<std::string>& messages,
|
||||
const std::string& someID,
|
||||
bool enchantable); //for all enchantable items.
|
||||
|
||||
template<typename ITEM> void inventoryItemCheck(const ITEM& someItem,
|
||||
std::vector<std::string>& messages,
|
||||
const std::string& someID); //for non-enchantable items.
|
||||
|
||||
template<typename TOOL> void toolCheck(const TOOL& someTool,
|
||||
std::vector<std::string>& messages,
|
||||
const std::string& someID,
|
||||
bool canbebroken); //for tools with uses.
|
||||
|
||||
template<typename TOOL> void toolCheck(const TOOL& someTool,
|
||||
std::vector<std::string>& messages,
|
||||
const std::string& someID); //for tools without uses.
|
||||
|
||||
template<typename LIST> void listCheck(const LIST& someList,
|
||||
std::vector< std::string >& messages,
|
||||
const std::string& someID);
|
||||
|
||||
const CSMWorld::RefIdData& mReferencables;
|
||||
const CSMWorld::IdCollection<ESM::Race>& mRaces;
|
||||
const CSMWorld::IdCollection<ESM::Class>& mClasses;
|
||||
const CSMWorld::IdCollection<ESM::Faction>& mFactions;
|
||||
bool mPlayerPresent;
|
||||
};
|
||||
}
|
||||
#endif // REFERENCEABLECHECKSTAGE_H
|
@ -1,4 +0,0 @@
|
||||
|
||||
#include "stage.hpp"
|
||||
|
||||
CSMTools::Stage::~Stage() {}
|
@ -1,7 +0,0 @@
|
||||
|
||||
#include "verifier.hpp"
|
||||
|
||||
#include "../doc/state.hpp"
|
||||
|
||||
CSMTools::Verifier::Verifier() : Operation (CSMDoc::State_Verifying)
|
||||
{}
|
@ -1,17 +0,0 @@
|
||||
#ifndef CSM_TOOLS_VERIFIER_H
|
||||
#define CSM_TOOLS_VERIFIER_H
|
||||
|
||||
#include "operation.hpp"
|
||||
|
||||
namespace CSMTools
|
||||
{
|
||||
class Verifier : public Operation
|
||||
{
|
||||
public:
|
||||
|
||||
Verifier();
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
@ -1,6 +1,31 @@
|
||||
|
||||
#include "collectionbase.hpp"
|
||||
|
||||
#include <stdexcept>
|
||||
|
||||
#include "columnbase.hpp"
|
||||
|
||||
CSMWorld::CollectionBase::CollectionBase() {}
|
||||
|
||||
CSMWorld::CollectionBase::~CollectionBase() {}
|
||||
|
||||
int CSMWorld::CollectionBase::searchColumnIndex (Columns::ColumnId id) const
|
||||
{
|
||||
int columns = getColumns();
|
||||
|
||||
for (int i=0; i<columns; ++i)
|
||||
if (getColumn (i).mColumnId==id)
|
||||
return i;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
int CSMWorld::CollectionBase::findColumnIndex (Columns::ColumnId id) const
|
||||
{
|
||||
int index = searchColumnIndex (id);
|
||||
|
||||
if (index==-1)
|
||||
throw std::logic_error ("invalid column index");
|
||||
|
||||
return index;
|
||||
}
|
@ -0,0 +1,14 @@
|
||||
#ifndef CSM_WOLRD_INFO_H
|
||||
#define CSM_WOLRD_INFO_H
|
||||
|
||||
#include <components/esm/loadinfo.hpp>
|
||||
|
||||
namespace CSMWorld
|
||||
{
|
||||
struct Info : public ESM::DialInfo
|
||||
{
|
||||
std::string mTopicId;
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
@ -0,0 +1,184 @@
|
||||
|
||||
#include "infocollection.hpp"
|
||||
|
||||
#include <stdexcept>
|
||||
#include <iterator>
|
||||
|
||||
#include <components/esm/esmreader.hpp>
|
||||
#include <components/esm/loaddial.hpp>
|
||||
|
||||
#include <components/misc/stringops.hpp>
|
||||
|
||||
void CSMWorld::InfoCollection::load (const Info& record, bool base)
|
||||
{
|
||||
int index = searchId (record.mId);
|
||||
|
||||
if (index==-1)
|
||||
{
|
||||
// new record
|
||||
Record<Info> record2;
|
||||
record2.mState = base ? RecordBase::State_BaseOnly : RecordBase::State_ModifiedOnly;
|
||||
(base ? record2.mBase : record2.mModified) = record;
|
||||
|
||||
int index = -1;
|
||||
|
||||
std::string topic = Misc::StringUtils::lowerCase (record2.get().mTopicId);
|
||||
|
||||
if (!record2.get().mPrev.empty())
|
||||
{
|
||||
index = getIndex (record2.get().mPrev, topic);
|
||||
|
||||
if (index!=-1)
|
||||
++index;
|
||||
}
|
||||
|
||||
if (index==-1 && !record2.get().mNext.empty())
|
||||
{
|
||||
index = getIndex (record2.get().mNext, topic);
|
||||
}
|
||||
|
||||
if (index==-1)
|
||||
{
|
||||
Range range = getTopicRange (topic);
|
||||
|
||||
index = std::distance (getRecords().begin(), range.second);
|
||||
}
|
||||
|
||||
insertRecord (record2, index);
|
||||
}
|
||||
else
|
||||
{
|
||||
// old record
|
||||
Record<Info> record2 = getRecord (index);
|
||||
|
||||
if (base)
|
||||
record2.mBase = record;
|
||||
else
|
||||
record2.setModified (record);
|
||||
|
||||
setRecord (index, record2);
|
||||
}
|
||||
}
|
||||
|
||||
int CSMWorld::InfoCollection::getIndex (const std::string& id, const std::string& topic) const
|
||||
{
|
||||
std::string fullId = Misc::StringUtils::lowerCase (topic) + "#" + id;
|
||||
|
||||
std::pair<RecordConstIterator, RecordConstIterator> range = getTopicRange (topic);
|
||||
|
||||
for (; range.first!=range.second; ++range.first)
|
||||
if (Misc::StringUtils::ciEqual(range.first->get().mId, fullId))
|
||||
return std::distance (getRecords().begin(), range.first);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
int CSMWorld::InfoCollection::getAppendIndex (const std::string& id, UniversalId::Type type) const
|
||||
{
|
||||
std::string::size_type separator = id.find_last_of ('#');
|
||||
|
||||
if (separator==std::string::npos)
|
||||
throw std::runtime_error ("invalid info ID: " + id);
|
||||
|
||||
std::pair<RecordConstIterator, RecordConstIterator> range = getTopicRange (id.substr (0, separator));
|
||||
|
||||
if (range.first==range.second)
|
||||
return Collection<Info, IdAccessor<Info> >::getAppendIndex (id, type);
|
||||
|
||||
return std::distance (getRecords().begin(), range.second);
|
||||
}
|
||||
|
||||
bool CSMWorld::InfoCollection::reorderRows (int baseIndex, const std::vector<int>& newOrder)
|
||||
{
|
||||
// check if the range is valid
|
||||
int lastIndex = baseIndex + newOrder.size() -1;
|
||||
|
||||
if (lastIndex>=getSize())
|
||||
return false;
|
||||
|
||||
// Check that topics match
|
||||
if (getRecord (baseIndex).get().mTopicId!=getRecord (lastIndex).get().mTopicId)
|
||||
return false;
|
||||
|
||||
// reorder
|
||||
return reorderRowsImp (baseIndex, newOrder);
|
||||
}
|
||||
|
||||
void CSMWorld::InfoCollection::load (ESM::ESMReader& reader, bool base, const ESM::Dialogue& dialogue)
|
||||
{
|
||||
std::string id = Misc::StringUtils::lowerCase (dialogue.mId) + "#" +
|
||||
reader.getHNOString ("INAM");
|
||||
|
||||
if (reader.isNextSub ("DELE"))
|
||||
{
|
||||
int index = searchId (id);
|
||||
|
||||
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)
|
||||
{
|
||||
removeRows (index, 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
Record<Info> record = getRecord (index);
|
||||
record.mState = RecordBase::State_Deleted;
|
||||
setRecord (index, record);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Info record;
|
||||
record.mTopicId = dialogue.mId;
|
||||
record.mId = id;
|
||||
record.load (reader);
|
||||
|
||||
load (record, base);
|
||||
}
|
||||
}
|
||||
|
||||
CSMWorld::InfoCollection::Range CSMWorld::InfoCollection::getTopicRange (const std::string& topic)
|
||||
const
|
||||
{
|
||||
std::string topic2 = Misc::StringUtils::lowerCase (topic);
|
||||
|
||||
std::map<std::string, int>::const_iterator iter = getIdMap().lower_bound (topic2);
|
||||
|
||||
// Skip invalid records: The beginning of a topic string could be identical to another topic
|
||||
// string.
|
||||
for (; iter!=getIdMap().end(); ++iter)
|
||||
{
|
||||
std::string testTopicId =
|
||||
Misc::StringUtils::lowerCase (getRecord (iter->second).get().mTopicId);
|
||||
|
||||
if (testTopicId==topic2)
|
||||
break;
|
||||
|
||||
std::size_t size = topic2.size();
|
||||
|
||||
if (testTopicId.size()<size || testTopicId.substr (0, size)!=topic2)
|
||||
return Range (getRecords().end(), getRecords().end());
|
||||
}
|
||||
|
||||
if (iter==getIdMap().end())
|
||||
return Range (getRecords().end(), getRecords().end());
|
||||
|
||||
RecordConstIterator begin = getRecords().begin()+iter->second;
|
||||
|
||||
// Find end
|
||||
RecordConstIterator end = begin;
|
||||
|
||||
for (; end!=getRecords().end(); ++end)
|
||||
if (!Misc::StringUtils::ciEqual(end->get().mTopicId, topic2))
|
||||
break;
|
||||
|
||||
return Range (begin, end);
|
||||
}
|
@ -0,0 +1,50 @@
|
||||
#ifndef CSM_WOLRD_INFOCOLLECTION_H
|
||||
#define CSM_WOLRD_INFOCOLLECTION_H
|
||||
|
||||
#include "collection.hpp"
|
||||
#include "info.hpp"
|
||||
|
||||
namespace ESM
|
||||
{
|
||||
class Dialogue;
|
||||
}
|
||||
|
||||
namespace CSMWorld
|
||||
{
|
||||
class InfoCollection : public Collection<Info, IdAccessor<Info> >
|
||||
{
|
||||
public:
|
||||
|
||||
typedef std::vector<Record<Info> >::const_iterator RecordConstIterator;
|
||||
typedef std::pair<RecordConstIterator, RecordConstIterator> Range;
|
||||
|
||||
private:
|
||||
|
||||
void load (const Info& record, bool base);
|
||||
|
||||
int getIndex (const std::string& id, const std::string& topic) const;
|
||||
///< Return index for record \a id or -1 (if not present; deleted records are considered)
|
||||
///
|
||||
/// \param id info ID without topic prefix
|
||||
|
||||
public:
|
||||
|
||||
virtual int getAppendIndex (const std::string& id,
|
||||
UniversalId::Type type = UniversalId::Type_None) const;
|
||||
///< \param type Will be ignored, unless the collection supports multiple record types
|
||||
|
||||
virtual bool reorderRows (int baseIndex, const std::vector<int>& newOrder);
|
||||
///< Reorder the rows [baseIndex, baseIndex+newOrder.size()) according to the indices
|
||||
/// given in \a newOrder (baseIndex+newOrder[0] specifies the new index of row baseIndex).
|
||||
///
|
||||
/// \return Success?
|
||||
|
||||
void load (ESM::ESMReader& reader, bool base, const ESM::Dialogue& dialogue);
|
||||
|
||||
Range getTopicRange (const std::string& topic) const;
|
||||
///< Return iterators that point to the beginning and past the end of the range for
|
||||
/// the given topic.
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue