commit
58add97676
@ -1,24 +1,55 @@
|
|||||||
build
|
## make
|
||||||
*~
|
|
||||||
Doxygen
|
|
||||||
prebuilt
|
|
||||||
apps/openmw/config.hpp
|
|
||||||
Docs/mainpage.hpp
|
|
||||||
CMakeFiles
|
CMakeFiles
|
||||||
*/CMakeFiles
|
*/CMakeFiles
|
||||||
CMakeCache.txt
|
CMakeCache.txt
|
||||||
moc_*.cxx
|
|
||||||
cmake_install.cmake
|
cmake_install.cmake
|
||||||
*.[ao]
|
|
||||||
Makefile
|
Makefile
|
||||||
makefile
|
makefile
|
||||||
data
|
build
|
||||||
|
prebuilt
|
||||||
|
|
||||||
|
## doxygen
|
||||||
|
Doxygen
|
||||||
|
|
||||||
|
## ides/editors
|
||||||
|
*~
|
||||||
*.kdev4
|
*.kdev4
|
||||||
CMakeLists.txt.user
|
|
||||||
*.swp
|
*.swp
|
||||||
*.swo
|
*.swo
|
||||||
*.kate-swp
|
*.kate-swp
|
||||||
.cproject
|
.cproject
|
||||||
.project
|
.project
|
||||||
.settings/
|
.settings
|
||||||
.directory
|
.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
|
#ifndef DATAFILESPAGE_H
|
||||||
#define DATAFILESPAGE_H
|
#define DATAFILESPAGE_H
|
||||||
|
|
||||||
|
#include "ui_datafilespage.h"
|
||||||
#include <QWidget>
|
#include <QWidget>
|
||||||
#include <QModelIndex>
|
|
||||||
|
|
||||||
#include "ui_datafilespage.h"
|
|
||||||
|
#include <QDir>
|
||||||
|
#include <QFile>
|
||||||
|
|
||||||
class QSortFilterProxyModel;
|
class QSortFilterProxyModel;
|
||||||
class QAbstractItemModel;
|
class QAbstractItemModel;
|
||||||
class QAction;
|
|
||||||
class QMenu;
|
class QMenu;
|
||||||
|
|
||||||
class DataFilesModel;
|
|
||||||
class TextInputDialog;
|
|
||||||
class GameSettings;
|
|
||||||
class LauncherSettings;
|
|
||||||
class PluginsProxyModel;
|
|
||||||
|
|
||||||
namespace Files { struct ConfigurationManager; }
|
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:
|
void on_newProfileAction_triggered();
|
||||||
DataFilesPage(Files::ConfigurationManager &cfg, GameSettings &gameSettings, LauncherSettings &launcherSettings, QWidget *parent = 0);
|
void on_deleteProfileAction_triggered();
|
||||||
|
|
||||||
QAbstractItemModel* profilesComboBoxModel();
|
private:
|
||||||
int profilesComboBoxIndex();
|
|
||||||
|
|
||||||
void writeConfig(QString profile = QString());
|
QMenu *mContextMenu;
|
||||||
void saveSettings();
|
|
||||||
|
|
||||||
signals:
|
Files::ConfigurationManager &mCfgMgr;
|
||||||
void profileChanged(int index);
|
|
||||||
|
|
||||||
public slots:
|
GameSettings &mGameSettings;
|
||||||
void setCheckState(QModelIndex index);
|
LauncherSettings &mLauncherSettings;
|
||||||
void setProfilesComboBoxIndex(int index);
|
|
||||||
|
|
||||||
void filterChanged(const QString filter);
|
QString mDataLocal;
|
||||||
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();
|
|
||||||
|
|
||||||
// Action slots
|
void setPluginsCheckstates(Qt::CheckState state);
|
||||||
void on_newProfileAction_triggered();
|
|
||||||
void on_deleteProfileAction_triggered();
|
|
||||||
void on_checkAction_triggered();
|
|
||||||
void on_uncheckAction_triggered();
|
|
||||||
|
|
||||||
private slots:
|
void buildView();
|
||||||
void slotCurrentIndexChanged(int index);
|
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:
|
class PathIterator
|
||||||
DataFilesModel *mDataFilesModel;
|
{
|
||||||
|
QStringList::ConstIterator mCitEnd;
|
||||||
|
QStringList::ConstIterator mCitCurrent;
|
||||||
|
QStringList::ConstIterator mCitBegin;
|
||||||
|
QString mFile;
|
||||||
|
QString mFilePath;
|
||||||
|
|
||||||
PluginsProxyModel *mPluginsProxyModel;
|
public:
|
||||||
QSortFilterProxyModel *mMastersProxyModel;
|
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;
|
QString path ()
|
||||||
LauncherSettings &mLauncherSettings;
|
{
|
||||||
|
bool success = false;
|
||||||
|
QDir dir;
|
||||||
|
QFileInfo file;
|
||||||
|
|
||||||
TextInputDialog *mNewProfileDialog;
|
while (!success)
|
||||||
|
{
|
||||||
|
if (mCitCurrent == mCitEnd)
|
||||||
|
break;
|
||||||
|
|
||||||
void setMastersCheckstates(Qt::CheckState state);
|
dir.setPath (*(mCitCurrent++));
|
||||||
void setPluginsCheckstates(Qt::CheckState state);
|
file.setFile (dir.absoluteFilePath (mFile));
|
||||||
|
|
||||||
void createActions();
|
success = file.exists();
|
||||||
void setupDataFiles();
|
}
|
||||||
void setupConfig();
|
|
||||||
void readConfig();
|
|
||||||
|
|
||||||
void loadSettings();
|
if (success)
|
||||||
|
return file.absoluteFilePath();
|
||||||
|
|
||||||
};
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
#include "textslotmsgbox.hpp"
|
#include "textslotmsgbox.hpp"
|
||||||
|
|
||||||
void TextSlotMsgBox::setTextSlot(const QString& string)
|
void Launcher::TextSlotMsgBox::setTextSlot(const QString& string)
|
||||||
{
|
{
|
||||||
setText(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 "collectionbase.hpp"
|
||||||
|
|
||||||
|
#include <stdexcept>
|
||||||
|
|
||||||
|
#include "columnbase.hpp"
|
||||||
|
|
||||||
CSMWorld::CollectionBase::CollectionBase() {}
|
CSMWorld::CollectionBase::CollectionBase() {}
|
||||||
|
|
||||||
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