mirror of
https://gitlab.com/OpenMW/openmw.git
synced 2025-02-13 21:40:11 +00:00
Merge branch 'next' of git://github.com/zinnschlag/openmw into next
This commit is contained in:
commit
e4717d7c92
@ -23,8 +23,7 @@ struct ESMData
|
||||
std::string author;
|
||||
std::string description;
|
||||
int version;
|
||||
int type;
|
||||
ESM::ESMReader::MasterList masters;
|
||||
std::vector<ESM::Header::MasterData> masters;
|
||||
|
||||
std::deque<EsmTool::RecordBase *> mRecords;
|
||||
std::map<ESM::Cell *, std::deque<ESM::CellRef> > mCellRefs;
|
||||
@ -284,16 +283,13 @@ int load(Arguments& info)
|
||||
info.data.author = esm.getAuthor();
|
||||
info.data.description = esm.getDesc();
|
||||
info.data.masters = esm.getMasters();
|
||||
info.data.version = esm.getVer();
|
||||
info.data.type = esm.getType();
|
||||
|
||||
if (!quiet)
|
||||
{
|
||||
std::cout << "Author: " << esm.getAuthor() << std::endl
|
||||
<< "Description: " << esm.getDesc() << std::endl
|
||||
<< "File format version: " << esm.getFVer() << std::endl
|
||||
<< "Special flag: " << esm.getSpecial() << std::endl;
|
||||
ESM::ESMReader::MasterList m = esm.getMasters();
|
||||
<< "File format version: " << esm.getFVer() << std::endl;
|
||||
std::vector<ESM::Header::MasterData> m = esm.getMasters();
|
||||
if (!m.empty())
|
||||
{
|
||||
std::cout << "Masters:" << std::endl;
|
||||
@ -430,9 +426,9 @@ int clone(Arguments& info)
|
||||
esm.setAuthor(info.data.author);
|
||||
esm.setDescription(info.data.description);
|
||||
esm.setVersion(info.data.version);
|
||||
esm.setType(info.data.type);
|
||||
esm.setRecordCount (recordCount);
|
||||
|
||||
for (ESM::ESMReader::MasterList::iterator it = info.data.masters.begin(); it != info.data.masters.end(); ++it)
|
||||
for (std::vector<ESM::Header::MasterData>::iterator it = info.data.masters.begin(); it != info.data.masters.end(); ++it)
|
||||
esm.addMaster(it->name, it->size);
|
||||
|
||||
std::fstream save(info.outname.c_str(), std::fstream::out | std::fstream::binary);
|
||||
|
@ -1,4 +1,3 @@
|
||||
|
||||
set (OPENCS_SRC main.cpp)
|
||||
|
||||
opencs_units (. editor)
|
||||
|
@ -113,5 +113,7 @@ int CS::Editor::run()
|
||||
{
|
||||
mStartup.show();
|
||||
|
||||
QApplication::setQuitOnLastWindowClosed (true);
|
||||
|
||||
return QApplication::exec();
|
||||
}
|
||||
|
@ -2,7 +2,7 @@
|
||||
#include "document.hpp"
|
||||
|
||||
#include <cassert>
|
||||
|
||||
#include <QDebug>
|
||||
void CSMDoc::Document::load (const std::vector<boost::filesystem::path>::const_iterator& begin,
|
||||
const std::vector<boost::filesystem::path>::const_iterator& end, bool lastAsModified)
|
||||
{
|
||||
@ -237,6 +237,9 @@ CSMDoc::Document::Document (const std::vector<boost::filesystem::path>& files, b
|
||||
connect (&mSaveTimer, SIGNAL(timeout()), this, SLOT (saving()));
|
||||
}
|
||||
|
||||
CSMDoc::Document::~Document()
|
||||
{}
|
||||
|
||||
QUndoStack& CSMDoc::Document::getUndoStack()
|
||||
{
|
||||
return mUndoStack;
|
||||
@ -290,11 +293,13 @@ void CSMDoc::Document::abortOperation (int type)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void CSMDoc::Document::modificationStateChanged (bool clean)
|
||||
{
|
||||
emit stateChanged (getState(), this);
|
||||
}
|
||||
|
||||
|
||||
void CSMDoc::Document::operationDone (int type)
|
||||
{
|
||||
emit stateChanged (getState(), this);
|
||||
@ -308,9 +313,12 @@ void CSMDoc::Document::saving()
|
||||
|
||||
if (mSaveCount>15)
|
||||
{
|
||||
//clear the stack before resetting the save state
|
||||
//to avoid emitting incorrect states
|
||||
mUndoStack.setClean();
|
||||
|
||||
mSaveCount = 0;
|
||||
mSaveTimer.stop();
|
||||
mUndoStack.setClean();
|
||||
emit stateChanged (getState(), this);
|
||||
}
|
||||
}
|
||||
|
@ -63,6 +63,7 @@ namespace CSMDoc
|
||||
public:
|
||||
|
||||
Document (const std::vector<boost::filesystem::path>& files, bool new_);
|
||||
~Document();
|
||||
|
||||
QUndoStack& getUndoStack();
|
||||
|
||||
@ -105,4 +106,4 @@ namespace CSMDoc
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
@ -56,7 +56,7 @@ void CSVDoc::Operations::quitOperation (int type)
|
||||
|
||||
mLayout->removeItem ((*iter)->getLayout());
|
||||
|
||||
delete *iter;
|
||||
(*iter)->deleteLater();
|
||||
mOperations.erase (iter);
|
||||
|
||||
if (oldCount > 1)
|
||||
|
@ -7,6 +7,7 @@
|
||||
#include <QMenuBar>
|
||||
#include <QMdiArea>
|
||||
#include <QDockWidget>
|
||||
#include <QtGui/QApplication>
|
||||
|
||||
#include "../../model/doc/document.hpp"
|
||||
|
||||
@ -39,6 +40,16 @@ void CSVDoc::View::setupFileMenu()
|
||||
mSave = new QAction (tr ("&Save"), this);
|
||||
connect (mSave, SIGNAL (triggered()), this, SLOT (save()));
|
||||
file->addAction (mSave);
|
||||
|
||||
QAction *close = new QAction (tr ("&Close"), this);
|
||||
connect (close, SIGNAL (triggered()), this, SLOT (close()));
|
||||
file->addAction(close);
|
||||
|
||||
QAction *exit = new QAction (tr ("&Exit"), this);
|
||||
connect (exit, SIGNAL (triggered()), this, SLOT (exit()));
|
||||
connect (this, SIGNAL(exitApplicationRequest(CSVDoc::View *)), &mViewManager, SLOT(exitApplication(CSVDoc::View *)));
|
||||
|
||||
file->addAction(exit);
|
||||
}
|
||||
|
||||
void CSVDoc::View::setupEditMenu()
|
||||
@ -117,15 +128,15 @@ void CSVDoc::View::updateActions()
|
||||
mVerify->setEnabled (!(mDocument->getState() & CSMDoc::State_Verifying));
|
||||
}
|
||||
|
||||
CSVDoc::View::View (ViewManager& viewManager, CSMDoc::Document *document, int totalViews, QMainWindow *viewParent)
|
||||
: mViewManager (viewManager), mDocument (document), mViewIndex (totalViews-1), mViewTotal (totalViews), QMainWindow (viewParent)
|
||||
CSVDoc::View::View (ViewManager& viewManager, CSMDoc::Document *document, int totalViews)
|
||||
: mViewManager (viewManager), mDocument (document), mViewIndex (totalViews-1),
|
||||
mViewTotal (totalViews)
|
||||
{
|
||||
setDockOptions (QMainWindow::AllowNestedDocks);
|
||||
|
||||
resize (300, 300); /// \todo get default size from settings and set reasonable minimal size
|
||||
|
||||
mSubViewWindow = new QMainWindow();
|
||||
setCentralWidget (mSubViewWindow);
|
||||
mSubViewWindow.setDockOptions (QMainWindow::AllowNestedDocks);
|
||||
|
||||
setCentralWidget (&mSubViewWindow);
|
||||
|
||||
mOperations = new Operations;
|
||||
addDockWidget (Qt::BottomDockWidgetArea, mOperations);
|
||||
@ -200,7 +211,7 @@ void CSVDoc::View::addSubView (const CSMWorld::UniversalId& id)
|
||||
/// \todo add an user setting to reuse sub views (on a per document basis or on a per top level view basis)
|
||||
|
||||
SubView *view = mSubViewFactory.makeSubView (id, *mDocument);
|
||||
mSubViewWindow->addDockWidget (Qt::TopDockWidgetArea, view);
|
||||
mSubViewWindow.addDockWidget (Qt::TopDockWidgetArea, view);
|
||||
|
||||
connect (view, SIGNAL (focusId (const CSMWorld::UniversalId&)), this,
|
||||
SLOT (addSubView (const CSMWorld::UniversalId&)));
|
||||
@ -239,7 +250,12 @@ void CSVDoc::View::abortOperation (int type)
|
||||
updateActions();
|
||||
}
|
||||
|
||||
QDockWidget *CSVDoc::View::getOperations() const
|
||||
CSVDoc::Operations *CSVDoc::View::getOperations() const
|
||||
{
|
||||
return mOperations;
|
||||
}
|
||||
|
||||
void CSVDoc::View::exit()
|
||||
{
|
||||
emit exitApplicationRequest (this);
|
||||
}
|
||||
|
@ -41,7 +41,8 @@ namespace CSVDoc
|
||||
std::vector<QAction *> mEditingActions;
|
||||
Operations *mOperations;
|
||||
SubViewFactoryManager mSubViewFactory;
|
||||
QMainWindow* mSubViewWindow;
|
||||
QMainWindow mSubViewWindow;
|
||||
|
||||
|
||||
// not implemented
|
||||
View (const View&);
|
||||
@ -65,9 +66,12 @@ namespace CSVDoc
|
||||
|
||||
void updateActions();
|
||||
|
||||
void exitApplication();
|
||||
|
||||
public:
|
||||
|
||||
View (ViewManager& viewManager, CSMDoc::Document *document, int totalViews, QMainWindow *viewParent);
|
||||
View (ViewManager& viewManager, CSMDoc::Document *document, int totalViews);
|
||||
|
||||
///< The ownership of \a document is not transferred to *this.
|
||||
|
||||
virtual ~View();
|
||||
@ -82,7 +86,7 @@ namespace CSVDoc
|
||||
|
||||
void updateProgress (int current, int max, int type, int threads);
|
||||
|
||||
QDockWidget *getOperations() const;
|
||||
Operations *getOperations() const;
|
||||
|
||||
signals:
|
||||
|
||||
@ -90,23 +94,28 @@ namespace CSVDoc
|
||||
|
||||
void loadDocumentRequest();
|
||||
|
||||
void exitApplicationRequest (CSVDoc::View *view);
|
||||
|
||||
public slots:
|
||||
|
||||
void addSubView (const CSMWorld::UniversalId& id);
|
||||
|
||||
void abortOperation (int type);
|
||||
|
||||
private slots:
|
||||
|
||||
void newView();
|
||||
|
||||
void save();
|
||||
|
||||
void exit();
|
||||
|
||||
void verify();
|
||||
|
||||
void addGlobalsSubView();
|
||||
|
||||
void addGmstsSubView();
|
||||
|
||||
void abortOperation (int type);
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -12,6 +12,11 @@
|
||||
|
||||
#include "view.hpp"
|
||||
|
||||
#include <QMessageBox>
|
||||
#include <QPushButton>
|
||||
#include <QtGui/QApplication>
|
||||
#include <QDebug>
|
||||
|
||||
void CSVDoc::ViewManager::updateIndices()
|
||||
{
|
||||
std::map<CSMDoc::Document *, std::pair<int, int> > documents;
|
||||
@ -31,7 +36,7 @@ void CSVDoc::ViewManager::updateIndices()
|
||||
}
|
||||
|
||||
CSVDoc::ViewManager::ViewManager (CSMDoc::DocumentManager& documentManager)
|
||||
: mDocumentManager (documentManager)
|
||||
: mDocumentManager (documentManager), mExitOnSaveStateChange(false), mUserWarned(false)
|
||||
{
|
||||
mDelegateFactories = new CSVWorld::CommandDelegateFactoryCollection;
|
||||
|
||||
@ -40,7 +45,6 @@ CSVDoc::ViewManager::ViewManager (CSMDoc::DocumentManager& documentManager)
|
||||
|
||||
mDelegateFactories->add (CSMWorld::ColumnBase::Display_GlobalVarType,
|
||||
new CSVWorld::VarTypeDelegateFactory (ESM::VT_Short, ESM::VT_Long, ESM::VT_Float));
|
||||
|
||||
}
|
||||
|
||||
CSVDoc::ViewManager::~ViewManager()
|
||||
@ -63,9 +67,8 @@ CSVDoc::View *CSVDoc::ViewManager::addView (CSMDoc::Document *document)
|
||||
this, SLOT (progress (int, int, int, int, CSMDoc::Document *)));
|
||||
}
|
||||
|
||||
QMainWindow *mainWindow = new QMainWindow;
|
||||
View *view = new View (*this, document, countViews (document)+1);
|
||||
|
||||
View *view = new View (*this, document, countViews (document)+1, mainWindow);
|
||||
|
||||
mViews.push_back (view);
|
||||
|
||||
@ -94,23 +97,143 @@ bool CSVDoc::ViewManager::closeRequest (View *view)
|
||||
{
|
||||
std::vector<View *>::iterator iter = std::find (mViews.begin(), mViews.end(), view);
|
||||
|
||||
bool continueWithClose = true;
|
||||
|
||||
if (iter!=mViews.end())
|
||||
{
|
||||
bool last = countViews (view->getDocument())<=1;
|
||||
|
||||
/// \todo check if save is in progress -> warn user about possible data loss
|
||||
/// \todo check if document has not been saved -> return false and start close dialogue
|
||||
|
||||
mViews.erase (iter);
|
||||
view->deleteLater();
|
||||
|
||||
if (last)
|
||||
mDocumentManager.removeDocument (view->getDocument());
|
||||
continueWithClose = notifySaveOnClose (view);
|
||||
else
|
||||
{
|
||||
(*iter)->deleteLater();
|
||||
mViews.erase (iter);
|
||||
|
||||
updateIndices();
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
return continueWithClose;
|
||||
}
|
||||
|
||||
bool CSVDoc::ViewManager::notifySaveOnClose (CSVDoc::View *view)
|
||||
{
|
||||
bool result = true;
|
||||
CSMDoc::Document *document = view->getDocument();
|
||||
|
||||
//notify user of saving in progress
|
||||
if ( (document->getState() & CSMDoc::State_Saving) )
|
||||
result = showSaveInProgressMessageBox (view);
|
||||
|
||||
//notify user of unsaved changes and process response
|
||||
else if ( document->getState() & CSMDoc::State_Modified)
|
||||
result = showModifiedDocumentMessageBox (view);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool CSVDoc::ViewManager::showModifiedDocumentMessageBox (CSVDoc::View *view)
|
||||
{
|
||||
QMessageBox messageBox;
|
||||
CSMDoc::Document *document = view->getDocument();
|
||||
|
||||
messageBox.setText ("The document has been modified.");
|
||||
messageBox.setInformativeText ("Do you want to save your changes?");
|
||||
messageBox.setStandardButtons (QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel);
|
||||
messageBox.setDefaultButton (QMessageBox::Save);
|
||||
|
||||
bool retVal = true;
|
||||
|
||||
connect (this, SIGNAL (closeMessageBox()), &messageBox, SLOT (close()));
|
||||
|
||||
connect (document, SIGNAL (stateChanged (int, CSMDoc::Document *)), this, SLOT (onExitWarningHandler(int, CSMDoc::Document *)));
|
||||
|
||||
mUserWarned = true;
|
||||
int response = messageBox.exec();
|
||||
mUserWarned = false;
|
||||
|
||||
switch (response)
|
||||
{
|
||||
case QMessageBox::Save:
|
||||
|
||||
document->save();
|
||||
mExitOnSaveStateChange = true;
|
||||
retVal = false;
|
||||
break;
|
||||
|
||||
case QMessageBox::Discard:
|
||||
|
||||
disconnect (document, SIGNAL (stateChanged (int, CSMDoc::Document *)), this, SLOT (onExitWarningHandler(int, CSMDoc::Document *)));
|
||||
break;
|
||||
|
||||
case QMessageBox::Cancel:
|
||||
|
||||
//disconnect to prevent unintended view closures
|
||||
disconnect (document, SIGNAL (stateChanged (int, CSMDoc::Document *)), this, SLOT (onExitWarningHandler(int, CSMDoc::Document *)));
|
||||
retVal = false;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
||||
bool CSVDoc::ViewManager::showSaveInProgressMessageBox (CSVDoc::View *view)
|
||||
{
|
||||
QMessageBox messageBox;
|
||||
CSMDoc::Document *document = view->getDocument();
|
||||
|
||||
messageBox.setText ("The document is currently being saved.");
|
||||
messageBox.setInformativeText("Do you want to close now and abort saving, or wait until saving has completed?");
|
||||
|
||||
QPushButton* waitButton = messageBox.addButton (tr("Wait"), QMessageBox::YesRole);
|
||||
QPushButton* closeButton = messageBox.addButton (tr("Close Now"), QMessageBox::RejectRole);
|
||||
QPushButton* cancelButton = messageBox.addButton (tr("Cancel"), QMessageBox::NoRole);
|
||||
|
||||
messageBox.setDefaultButton (waitButton);
|
||||
|
||||
bool retVal = true;
|
||||
|
||||
//Connections shut down message box if operation ends before user makes a decision.
|
||||
connect (document, SIGNAL (stateChanged (int, CSMDoc::Document *)), this, SLOT (onExitWarningHandler(int, CSMDoc::Document *)));
|
||||
connect (this, SIGNAL (closeMessageBox()), &messageBox, SLOT (close()));
|
||||
|
||||
//set / clear the user warned flag to indicate whether or not the message box is currently active.
|
||||
mUserWarned = true;
|
||||
messageBox.exec();
|
||||
mUserWarned = false;
|
||||
|
||||
//if closed by the warning handler, defaults to the RejectRole button (closeButton)
|
||||
if (messageBox.clickedButton() == waitButton)
|
||||
{
|
||||
//save the View iterator for shutdown after the save operation ends
|
||||
mExitOnSaveStateChange = true;
|
||||
retVal = false;
|
||||
}
|
||||
|
||||
else if (messageBox.clickedButton() == closeButton)
|
||||
{
|
||||
//disconnect to avoid segmentation fault
|
||||
disconnect (document, SIGNAL (stateChanged (int, CSMDoc::Document *)), this, SLOT (onExitWarningHandler(int, CSMDoc::Document *)));
|
||||
|
||||
view->abortOperation(CSMDoc::State_Saving);
|
||||
mExitOnSaveStateChange = true;
|
||||
}
|
||||
|
||||
else if (messageBox.clickedButton() == cancelButton)
|
||||
{
|
||||
//abort shutdown, allow save to complete
|
||||
//disconnection to prevent unintended view closures
|
||||
mExitOnSaveStateChange = false;
|
||||
disconnect (document, SIGNAL (stateChanged (int, CSMDoc::Document *)), this, SLOT (onExitWarningHandler(int, CSMDoc::Document *)));
|
||||
retVal = false;
|
||||
}
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
||||
void CSVDoc::ViewManager::documentStateChanged (int state, CSMDoc::Document *document)
|
||||
@ -126,3 +249,25 @@ void CSVDoc::ViewManager::progress (int current, int max, int type, int threads,
|
||||
if ((*iter)->getDocument()==document)
|
||||
(*iter)->updateProgress (current, max, type, threads);
|
||||
}
|
||||
|
||||
void CSVDoc::ViewManager::onExitWarningHandler (int state, CSMDoc::Document *document)
|
||||
{
|
||||
if ( !(state & CSMDoc::State_Saving) )
|
||||
{
|
||||
//if the user is being warned (message box is active), shut down the message box,
|
||||
//as there is no save operation currently running
|
||||
if ( mUserWarned )
|
||||
emit closeMessageBox();
|
||||
|
||||
//otherwise, the user has closed the message box before the save operation ended.
|
||||
//exit the application
|
||||
else if (mExitOnSaveStateChange)
|
||||
QApplication::instance()->exit();
|
||||
}
|
||||
}
|
||||
|
||||
void CSVDoc::ViewManager::exitApplication (CSVDoc::View *view)
|
||||
{
|
||||
if (notifySaveOnClose (view))
|
||||
QApplication::instance()->exit();
|
||||
}
|
||||
|
@ -27,12 +27,17 @@ namespace CSVDoc
|
||||
CSMDoc::DocumentManager& mDocumentManager;
|
||||
std::vector<View *> mViews;
|
||||
CSVWorld::CommandDelegateFactoryCollection *mDelegateFactories;
|
||||
bool mExitOnSaveStateChange;
|
||||
bool mUserWarned;
|
||||
|
||||
// not implemented
|
||||
ViewManager (const ViewManager&);
|
||||
ViewManager& operator= (const ViewManager&);
|
||||
|
||||
void updateIndices();
|
||||
bool notifySaveOnClose (View *view = 0);
|
||||
bool showModifiedDocumentMessageBox (View *view);
|
||||
bool showSaveInProgressMessageBox (View *view);
|
||||
|
||||
public:
|
||||
|
||||
@ -54,13 +59,21 @@ namespace CSVDoc
|
||||
|
||||
void loadDocumentRequest();
|
||||
|
||||
void closeMessageBox();
|
||||
|
||||
public slots:
|
||||
|
||||
void exitApplication (CSVDoc::View *view);
|
||||
|
||||
private slots:
|
||||
|
||||
void documentStateChanged (int state, CSMDoc::Document *document);
|
||||
|
||||
void progress (int current, int max, int type, int threads, CSMDoc::Document *document);
|
||||
|
||||
void onExitWarningHandler(int state, CSMDoc::Document* document);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
@ -27,14 +27,15 @@ void ESMStore::load(ESM::ESMReader &esm)
|
||||
|
||||
ESM::Dialogue *dialogue = 0;
|
||||
|
||||
/// \todo Move this to somewhere else. ESMReader?
|
||||
// Cache parent esX files by tracking their indices in the global list of
|
||||
// all files/readers used by the engine. This will greaty accelerate
|
||||
// refnumber mangling, as required for handling moved references.
|
||||
int index = ~0;
|
||||
const ESM::ESMReader::MasterList &masters = esm.getMasters();
|
||||
const std::vector<ESM::Header::MasterData> &masters = esm.getMasters();
|
||||
std::vector<ESM::ESMReader> *allPlugins = esm.getGlobalReaderList();
|
||||
for (size_t j = 0; j < masters.size(); j++) {
|
||||
ESM::MasterData &mast = const_cast<ESM::MasterData&>(masters[j]);
|
||||
ESM::Header::MasterData &mast = const_cast<ESM::Header::MasterData&>(masters[j]);
|
||||
std::string fname = mast.name;
|
||||
for (int i = 0; i < esm.getIndex(); i++) {
|
||||
const std::string &candidate = allPlugins->at(i).getContext().filename;
|
||||
|
@ -39,7 +39,7 @@ add_component_dir (esm
|
||||
loadclas loadclot loadcont loadcrea loadcrec loaddial loaddoor loadench loadfact loadglob loadgmst
|
||||
loadinfo loadingr loadland loadlevlist loadligh loadlocks loadltex loadmgef loadmisc loadnpcc
|
||||
loadnpc loadpgrd loadrace loadregn loadscpt loadskil loadsndg loadsoun loadspel loadsscr loadstat
|
||||
loadweap records aipackage effectlist spelllist variant variantimp
|
||||
loadweap records aipackage effectlist spelllist variant variantimp loadtes3
|
||||
)
|
||||
|
||||
add_component_dir (misc
|
||||
|
@ -2,6 +2,7 @@
|
||||
#define OPENMW_ESM_COMMON_H
|
||||
|
||||
#include <string>
|
||||
#include <cstring>
|
||||
|
||||
#include <libs/platform/stdint.h>
|
||||
#include <libs/platform/string.h>
|
||||
@ -14,24 +15,6 @@ enum Version
|
||||
VER_13 = 0x3fa66666
|
||||
};
|
||||
|
||||
enum FileType
|
||||
{
|
||||
FT_ESP = 0, // Plugin
|
||||
FT_ESM = 1, // Master
|
||||
FT_ESS = 32 // Savegame
|
||||
};
|
||||
|
||||
// Used to mark special files. The original ESM files are given
|
||||
// special treatment in a few places, most noticably in loading and
|
||||
// filtering out "dirtly" GMST entries correctly.
|
||||
enum SpecialFile
|
||||
{
|
||||
SF_Other,
|
||||
SF_Morrowind,
|
||||
SF_Tribunal,
|
||||
SF_Bloodmoon
|
||||
};
|
||||
|
||||
/* A structure used for holding fixed-length strings. In the case of
|
||||
LEN=4, it can be more efficient to match the string as a 32 bit
|
||||
number, therefore the struct is implemented as a union with an int.
|
||||
@ -41,7 +24,7 @@ union NAME_T
|
||||
{
|
||||
char name[LEN];
|
||||
int32_t val;
|
||||
|
||||
|
||||
bool operator==(const char *str) const
|
||||
{
|
||||
for(int i=0; i<LEN; i++)
|
||||
@ -61,6 +44,8 @@ union NAME_T
|
||||
bool operator!=(int v) const { return v != val; }
|
||||
|
||||
std::string toString() const { return std::string(name, strnlen(name, LEN)); }
|
||||
|
||||
void assign (const std::string& value) { std::strncpy (name, value.c_str(), LEN); }
|
||||
};
|
||||
|
||||
typedef NAME_T<4> NAME;
|
||||
@ -70,28 +55,6 @@ typedef NAME_T<256> NAME256;
|
||||
|
||||
#pragma pack(push)
|
||||
#pragma pack(1)
|
||||
/// File header data for all ES files
|
||||
struct HEDRstruct
|
||||
{
|
||||
/* File format version. This is actually a float, the supported
|
||||
versions are 1.2 and 1.3. These correspond to:
|
||||
1.2 = 0x3f99999a and 1.3 = 0x3fa66666
|
||||
*/
|
||||
int version;
|
||||
int type; // 0=esp, 1=esm, 32=ess
|
||||
NAME32 author; // Author's name
|
||||
NAME256 desc; // File description
|
||||
int records; // Number of records? Not used.
|
||||
};
|
||||
|
||||
// Defines another files (esm or esp) that this file depends upon.
|
||||
struct MasterData
|
||||
{
|
||||
std::string name;
|
||||
uint64_t size;
|
||||
int index; // Position of the parent file in the global list of loaded files
|
||||
};
|
||||
|
||||
// Data that is only present in save game files
|
||||
struct SaveData
|
||||
{
|
||||
@ -113,7 +76,6 @@ struct ESM_Context
|
||||
uint32_t leftRec, leftSub;
|
||||
size_t leftFile;
|
||||
NAME recName, subName;
|
||||
HEDRstruct header;
|
||||
// When working with multiple esX files, we will generate lists of all files that
|
||||
// actually contribute to a specific cell. Therefore, we need to store the index
|
||||
// of the file belonging to this contest. See CellStore::(list/load)refs for details.
|
||||
|
@ -15,11 +15,16 @@ ESM_Context ESMReader::getContext()
|
||||
return mCtx;
|
||||
}
|
||||
|
||||
ESMReader::ESMReader(void):
|
||||
ESMReader::ESMReader():
|
||||
mBuffer(50*1024)
|
||||
{
|
||||
}
|
||||
|
||||
int ESMReader::getFormat() const
|
||||
{
|
||||
return mHeader.mFormat;
|
||||
}
|
||||
|
||||
void ESMReader::restoreContext(const ESM_Context &rc)
|
||||
{
|
||||
// Reopen the file if necessary
|
||||
@ -51,18 +56,6 @@ void ESMReader::openRaw(Ogre::DataStreamPtr _esm, const std::string &name)
|
||||
mEsm = _esm;
|
||||
mCtx.filename = name;
|
||||
mCtx.leftFile = mEsm->size();
|
||||
|
||||
// Flag certain files for special treatment, based on the file
|
||||
// name.
|
||||
const char *cstr = mCtx.filename.c_str();
|
||||
if (iends(cstr, "Morrowind.esm"))
|
||||
mSpf = SF_Morrowind;
|
||||
else if (iends(cstr, "Tribunal.esm"))
|
||||
mSpf = SF_Tribunal;
|
||||
else if (iends(cstr, "Bloodmoon.esm"))
|
||||
mSpf = SF_Bloodmoon;
|
||||
else
|
||||
mSpf = SF_Other;
|
||||
}
|
||||
|
||||
void ESMReader::open(Ogre::DataStreamPtr _esm, const std::string &name)
|
||||
@ -74,42 +67,7 @@ void ESMReader::open(Ogre::DataStreamPtr _esm, const std::string &name)
|
||||
|
||||
getRecHeader();
|
||||
|
||||
// Get the header
|
||||
getHNT(mCtx.header, "HEDR", 300);
|
||||
|
||||
// Some mods abuse the header.version field for the version of the mod instead of the version of the file format, so we can only ignore it.
|
||||
|
||||
while (isNextSub("MAST"))
|
||||
{
|
||||
MasterData m;
|
||||
m.name = getHString();
|
||||
m.size = getHNLong("DATA");
|
||||
mMasters.push_back(m);
|
||||
}
|
||||
|
||||
if (mCtx.header.type == FT_ESS)
|
||||
{
|
||||
// Savegame-related data
|
||||
|
||||
// Player position etc
|
||||
getHNT(mSaveData, "GMDT", 124);
|
||||
|
||||
/* Image properties, five ints. Is always:
|
||||
Red-mask: 0xff0000
|
||||
Blue-mask: 0x00ff00
|
||||
Green-mask: 0x0000ff
|
||||
Alpha-mask: 0x000000
|
||||
Bpp: 32
|
||||
*/
|
||||
getSubNameIs("SCRD");
|
||||
skipHSubSize(20);
|
||||
|
||||
/* Savegame screenshot:
|
||||
128x128 pixels * 4 bytes per pixel
|
||||
*/
|
||||
getSubNameIs("SCRS");
|
||||
skipHSubSize(65536);
|
||||
}
|
||||
mHeader.load (*this);
|
||||
}
|
||||
|
||||
void ESMReader::open(const std::string &file)
|
||||
|
@ -12,7 +12,9 @@
|
||||
#include <components/misc/stringops.hpp>
|
||||
|
||||
#include <components/to_utf8/to_utf8.hpp>
|
||||
|
||||
#include "esmcommon.hpp"
|
||||
#include "loadtes3.hpp"
|
||||
|
||||
namespace ESM {
|
||||
|
||||
@ -20,15 +22,7 @@ class ESMReader
|
||||
{
|
||||
public:
|
||||
|
||||
ESMReader(void);
|
||||
|
||||
/*************************************************************************
|
||||
*
|
||||
* Public type definitions
|
||||
*
|
||||
*************************************************************************/
|
||||
|
||||
typedef std::vector<MasterData> MasterList;
|
||||
ESMReader();
|
||||
|
||||
/*************************************************************************
|
||||
*
|
||||
@ -36,14 +30,12 @@ public:
|
||||
*
|
||||
*************************************************************************/
|
||||
|
||||
int getVer() const { return mCtx.header.version; }
|
||||
float getFVer() const { if(mCtx.header.version == VER_12) return 1.2; else return 1.3; }
|
||||
int getSpecial() const { return mSpf; }
|
||||
int getType() const { return mCtx.header.type; }
|
||||
const std::string getAuthor() const { return mCtx.header.author.toString(); }
|
||||
const std::string getDesc() const { return mCtx.header.desc.toString(); }
|
||||
const SaveData &getSaveData() const { return mSaveData; }
|
||||
const MasterList &getMasters() const { return mMasters; }
|
||||
int getVer() const { return mHeader.mData.version; }
|
||||
float getFVer() const { if(mHeader.mData.version == VER_12) return 1.2; else return 1.3; }
|
||||
const std::string getAuthor() const { return mHeader.mData.author.toString(); }
|
||||
const std::string getDesc() const { return mHeader.mData.desc.toString(); }
|
||||
const std::vector<Header::MasterData> &getMasters() const { return mHeader.mMaster; }
|
||||
int getFormat() const;
|
||||
const NAME &retSubName() const { return mCtx.subName; }
|
||||
uint32_t getSubSize() const { return mCtx.leftSub; }
|
||||
|
||||
@ -263,13 +255,12 @@ private:
|
||||
ESM_Context mCtx;
|
||||
|
||||
// Special file signifier (see SpecialFile enum above)
|
||||
int mSpf;
|
||||
|
||||
// Buffer for ESM strings
|
||||
std::vector<char> mBuffer;
|
||||
|
||||
SaveData mSaveData;
|
||||
MasterList mMasters;
|
||||
Header mHeader;
|
||||
|
||||
std::vector<ESMReader> *mGlobalReaderList;
|
||||
ToUTF8::Utf8Encoder* mEncoder;
|
||||
};
|
||||
|
@ -1,6 +1,8 @@
|
||||
#include "esmwriter.hpp"
|
||||
|
||||
#include <cassert>
|
||||
#include <fstream>
|
||||
#include <cstring>
|
||||
#include <iostream>
|
||||
|
||||
bool count = true;
|
||||
|
||||
@ -9,40 +11,40 @@ namespace ESM
|
||||
|
||||
int ESMWriter::getVersion()
|
||||
{
|
||||
return m_header.version;
|
||||
return mHeader.mData.version;
|
||||
}
|
||||
|
||||
void ESMWriter::setVersion(int ver)
|
||||
{
|
||||
m_header.version = ver;
|
||||
}
|
||||
|
||||
int ESMWriter::getType()
|
||||
{
|
||||
return m_header.type;
|
||||
}
|
||||
|
||||
void ESMWriter::setType(int type)
|
||||
{
|
||||
m_header.type = type;
|
||||
mHeader.mData.version = ver;
|
||||
}
|
||||
|
||||
void ESMWriter::setAuthor(const std::string& auth)
|
||||
{
|
||||
strncpy((char*)&m_header.author, auth.c_str(), 32);
|
||||
mHeader.mData.author.assign (auth);
|
||||
}
|
||||
|
||||
void ESMWriter::setDescription(const std::string& desc)
|
||||
{
|
||||
strncpy((char*)&m_header.desc, desc.c_str(), 256);
|
||||
mHeader.mData.desc.assign (desc);
|
||||
}
|
||||
|
||||
void ESMWriter::setRecordCount (int count)
|
||||
{
|
||||
mHeader.mData.records = count;
|
||||
}
|
||||
|
||||
void ESMWriter::setFormat (int format)
|
||||
{
|
||||
mHeader.mFormat = format;
|
||||
}
|
||||
|
||||
void ESMWriter::addMaster(const std::string& name, uint64_t size)
|
||||
{
|
||||
MasterData d;
|
||||
Header::MasterData d;
|
||||
d.name = name;
|
||||
d.size = size;
|
||||
m_masters.push_back(d);
|
||||
mHeader.mMaster.push_back(d);
|
||||
}
|
||||
|
||||
void ESMWriter::save(const std::string& file)
|
||||
@ -58,25 +60,13 @@ void ESMWriter::save(std::ostream& file)
|
||||
|
||||
startRecord("TES3", 0);
|
||||
|
||||
m_header.records = 0;
|
||||
writeHNT("HEDR", m_header, 300);
|
||||
m_headerPos = m_stream->tellp() - (std::streampos)4;
|
||||
|
||||
for (std::list<MasterData>::iterator it = m_masters.begin(); it != m_masters.end(); ++it)
|
||||
{
|
||||
writeHNCString("MAST", it->name);
|
||||
writeHNT("DATA", it->size);
|
||||
}
|
||||
mHeader.save (*this);
|
||||
|
||||
endRecord("TES3");
|
||||
}
|
||||
|
||||
void ESMWriter::close()
|
||||
{
|
||||
std::cout << "Writing amount of saved records (" << m_recordCount - 1 << ")" << std::endl;
|
||||
m_stream->seekp(m_headerPos);
|
||||
writeT<int>(m_recordCount-1);
|
||||
m_stream->seekp(0, std::ios::end);
|
||||
m_stream->flush();
|
||||
|
||||
if (!m_records.empty())
|
||||
@ -86,7 +76,7 @@ void ESMWriter::close()
|
||||
void ESMWriter::startRecord(const std::string& name, uint32_t flags)
|
||||
{
|
||||
m_recordCount++;
|
||||
|
||||
|
||||
writeName(name);
|
||||
RecordData rec;
|
||||
rec.name = name;
|
||||
@ -109,7 +99,7 @@ void ESMWriter::startSubRecord(const std::string& name)
|
||||
rec.size = 0;
|
||||
writeT<int>(0); // Size goes here
|
||||
m_records.push_back(rec);
|
||||
|
||||
|
||||
assert(m_records.back().size == 0);
|
||||
}
|
||||
|
||||
@ -118,7 +108,7 @@ void ESMWriter::endRecord(const std::string& name)
|
||||
RecordData rec = m_records.back();
|
||||
assert(rec.name == name);
|
||||
m_records.pop_back();
|
||||
|
||||
|
||||
m_stream->seekp(rec.position);
|
||||
|
||||
count = false;
|
||||
|
@ -1,12 +1,13 @@
|
||||
#ifndef OPENMW_ESM_WRITER_H
|
||||
#define OPENMW_ESM_WRITER_H
|
||||
|
||||
#include <iostream>
|
||||
#include <iosfwd>
|
||||
#include <list>
|
||||
#include <assert.h>
|
||||
|
||||
#include <components/to_utf8/to_utf8.hpp>
|
||||
|
||||
#include "esmcommon.hpp"
|
||||
#include <components/to_utf8/to_utf8.hpp>
|
||||
#include "loadtes3.hpp"
|
||||
|
||||
namespace ESM {
|
||||
|
||||
@ -22,11 +23,11 @@ class ESMWriter
|
||||
public:
|
||||
int getVersion();
|
||||
void setVersion(int ver);
|
||||
int getType();
|
||||
void setType(int type);
|
||||
void setEncoder(ToUTF8::Utf8Encoder *encoding); // Write strings as UTF-8?
|
||||
void setAuthor(const std::string& author);
|
||||
void setDescription(const std::string& desc);
|
||||
void setRecordCount (int count);
|
||||
void setFormat (int format);
|
||||
|
||||
void addMaster(const std::string& name, uint64_t size);
|
||||
|
||||
@ -80,7 +81,7 @@ public:
|
||||
{
|
||||
write((char*)&data, size);
|
||||
}
|
||||
|
||||
|
||||
void startRecord(const std::string& name, uint32_t flags);
|
||||
void startSubRecord(const std::string& name);
|
||||
void endRecord(const std::string& name);
|
||||
@ -90,14 +91,13 @@ public:
|
||||
void write(const char* data, size_t size);
|
||||
|
||||
private:
|
||||
std::list<MasterData> m_masters;
|
||||
std::list<RecordData> m_records;
|
||||
std::ostream* m_stream;
|
||||
std::streampos m_headerPos;
|
||||
ToUTF8::Utf8Encoder* m_encoder;
|
||||
int m_recordCount;
|
||||
|
||||
HEDRstruct m_header;
|
||||
Header mHeader;
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -245,7 +245,7 @@ bool Cell::getNextRef(ESMReader &esm, CellRef &ref)
|
||||
// If the most significant 8 bits are used, then this reference already exists.
|
||||
// In this case, do not spawn a new reference, but overwrite the old one.
|
||||
ref.mRefnum &= 0x00ffffff; // delete old plugin ID
|
||||
const ESM::ESMReader::MasterList &masters = esm.getMasters();
|
||||
const std::vector<Header::MasterData> &masters = esm.getMasters();
|
||||
global = masters[local-1].index + 1;
|
||||
ref.mRefnum |= global << 24; // insert global plugin ID
|
||||
}
|
||||
@ -348,7 +348,7 @@ bool Cell::getNextMVRF(ESMReader &esm, MovedCellRef &mref)
|
||||
int local = (mref.mRefnum & 0xff000000) >> 24;
|
||||
size_t global = esm.getIndex() + 1;
|
||||
mref.mRefnum &= 0x00ffffff; // delete old plugin ID
|
||||
const ESM::ESMReader::MasterList &masters = esm.getMasters();
|
||||
const std::vector<Header::MasterData> &masters = esm.getMasters();
|
||||
global = masters[local-1].index + 1;
|
||||
mref.mRefnum |= global << 24; // insert global plugin ID
|
||||
|
||||
|
53
components/esm/loadtes3.cpp
Normal file
53
components/esm/loadtes3.cpp
Normal file
@ -0,0 +1,53 @@
|
||||
|
||||
#include "loadtes3.hpp"
|
||||
|
||||
#include "esmcommon.hpp"
|
||||
#include "esmreader.hpp"
|
||||
#include "esmwriter.hpp"
|
||||
|
||||
void ESM::Header::blank()
|
||||
{
|
||||
mData.version = ESM::VER_13;
|
||||
mData.type = 0;
|
||||
mData.author.assign ("");
|
||||
mData.desc.assign ("");
|
||||
mData.records = 0;
|
||||
mFormat = CurrentFormat;
|
||||
}
|
||||
|
||||
void ESM::Header::load (ESMReader &esm)
|
||||
{
|
||||
esm.getHNT (mData, "HEDR", 300);
|
||||
|
||||
if (esm.isNextSub ("FORM"))
|
||||
{
|
||||
esm.getHT (mFormat);
|
||||
if (mFormat<0)
|
||||
esm.fail ("invalid format code");
|
||||
}
|
||||
else
|
||||
mFormat = 0;
|
||||
|
||||
while (esm.isNextSub ("MAST"))
|
||||
{
|
||||
MasterData m;
|
||||
m.name = esm.getHString();
|
||||
m.size = esm.getHNLong ("DATA");
|
||||
mMaster.push_back (m);
|
||||
}
|
||||
}
|
||||
|
||||
void ESM::Header::save (ESMWriter &esm)
|
||||
{
|
||||
esm.writeHNT ("HEDR", mData, 300);
|
||||
|
||||
if (mFormat>0)
|
||||
esm.writeHNT ("FORM", mFormat);
|
||||
|
||||
for (std::vector<Header::MasterData>::iterator iter = mMaster.begin();
|
||||
iter != mMaster.end(); ++iter)
|
||||
{
|
||||
esm.writeHNCString ("MAST", iter->name);
|
||||
esm.writeHNT ("DATA", iter->size);
|
||||
}
|
||||
}
|
55
components/esm/loadtes3.hpp
Normal file
55
components/esm/loadtes3.hpp
Normal file
@ -0,0 +1,55 @@
|
||||
#ifndef COMPONENT_ESM_TES3_H
|
||||
#define COMPONENT_ESM_TES3_H
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "esmcommon.hpp"
|
||||
|
||||
namespace ESM
|
||||
{
|
||||
class ESMReader;
|
||||
class ESMWriter;
|
||||
|
||||
#pragma pack(push)
|
||||
#pragma pack(1)
|
||||
|
||||
/// \brief File header record
|
||||
struct Header
|
||||
{
|
||||
static const int CurrentFormat = 0; // most recent known format
|
||||
|
||||
struct Data
|
||||
{
|
||||
/* File format version. This is actually a float, the supported
|
||||
versions are 1.2 and 1.3. These correspond to:
|
||||
1.2 = 0x3f99999a and 1.3 = 0x3fa66666
|
||||
*/
|
||||
int version;
|
||||
int type; // 0=esp, 1=esm, 32=ess (unused)
|
||||
NAME32 author; // Author's name
|
||||
NAME256 desc; // File description
|
||||
int records; // Number of records? Not used.
|
||||
};
|
||||
|
||||
// Defines another files (esm or esp) that this file depends upon.
|
||||
struct MasterData
|
||||
{
|
||||
std::string name;
|
||||
uint64_t size;
|
||||
int index; // Position of the parent file in the global list of loaded files
|
||||
};
|
||||
|
||||
Data mData;
|
||||
int mFormat;
|
||||
std::vector<MasterData> mMaster;
|
||||
|
||||
void blank();
|
||||
|
||||
void load (ESMReader &esm);
|
||||
void save (ESMWriter &esm);
|
||||
};
|
||||
#pragma pack(pop)
|
||||
|
||||
}
|
||||
|
||||
#endif
|
@ -1,6 +1,6 @@
|
||||
#include <QDebug>
|
||||
#include <QFileInfo>
|
||||
#include <QDir>
|
||||
#include <QDebug>
|
||||
|
||||
#include <stdexcept>
|
||||
|
||||
@ -157,7 +157,7 @@ Qt::ItemFlags DataFilesModel::flags(const QModelIndex &index) const
|
||||
if (!file)
|
||||
return Qt::NoItemFlags;
|
||||
|
||||
if (canBeChecked(file)) {
|
||||
if (canBeChecked(file)) {
|
||||
if (index.column() == 0) {
|
||||
return Qt::ItemIsUserCheckable | Qt::ItemIsEnabled | Qt::ItemIsSelectable;
|
||||
} else {
|
||||
@ -226,7 +226,7 @@ bool lessThanEsmFile(const EsmFile *e1, const EsmFile *e2)
|
||||
return true;
|
||||
if (!e1->fileName().endsWith(".esm") && e2->fileName().endsWith(".esm"))
|
||||
return false;
|
||||
|
||||
|
||||
return e1->fileName().toLower() < e2->fileName().toLower();
|
||||
}
|
||||
|
||||
@ -281,7 +281,7 @@ void DataFilesModel::addFiles(const QString &path)
|
||||
fileReader.setEncoder(&encoder);
|
||||
fileReader.open(dir.absoluteFilePath(path).toStdString());
|
||||
|
||||
ESM::ESMReader::MasterList mlist = fileReader.getMasters();
|
||||
std::vector<ESM::Header::MasterData> mlist = fileReader.getMasters();
|
||||
QStringList masters;
|
||||
|
||||
for (unsigned int i = 0; i < mlist.size(); ++i) {
|
||||
@ -369,10 +369,10 @@ QStringList DataFilesModel::checkedItems()
|
||||
QStringList DataFilesModel::checkedItemsPaths()
|
||||
{
|
||||
QStringList list;
|
||||
|
||||
|
||||
QList<EsmFile *>::ConstIterator it;
|
||||
QList<EsmFile *>::ConstIterator itEnd = mFiles.constEnd();
|
||||
|
||||
|
||||
int i = 0;
|
||||
for (it = mFiles.constBegin(); it != itEnd; ++it) {
|
||||
EsmFile *file = item(i);
|
||||
@ -381,7 +381,7 @@ QStringList DataFilesModel::checkedItemsPaths()
|
||||
if (mCheckStates[file->fileName()] == Qt::Checked && canBeChecked(file))
|
||||
list << file->path();
|
||||
}
|
||||
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user