mirror of
				https://github.com/TES3MP/openmw-tes3mp.git
				synced 2025-11-03 23:56:47 +00:00 
			
		
		
		
	Merge remote-tracking branch 'zini/next' into animation2
This commit is contained in:
		
						commit
						34ddf69a31
					
				
					 83 changed files with 1953 additions and 716 deletions
				
			
		| 
						 | 
					@ -209,7 +209,10 @@ void loadCell(ESM::Cell &cell, ESM::ESMReader &esm, Arguments& info)
 | 
				
			||||||
    bool save = (info.mode == "clone");
 | 
					    bool save = (info.mode == "clone");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Skip back to the beginning of the reference list
 | 
					    // Skip back to the beginning of the reference list
 | 
				
			||||||
    cell.restore(esm);
 | 
					    // FIXME: Changes to the references backend required to support multiple plugins have
 | 
				
			||||||
 | 
					    //  almost certainly broken this following line. I'll leave it as is for now, so that
 | 
				
			||||||
 | 
					    //  the compiler does not complain.
 | 
				
			||||||
 | 
					    cell.restore(esm, 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Loop through all the references
 | 
					    // Loop through all the references
 | 
				
			||||||
    ESM::CellRef ref;
 | 
					    ESM::CellRef ref;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,17 +1,9 @@
 | 
				
			||||||
set(LAUNCHER
 | 
					set(LAUNCHER
 | 
				
			||||||
    datafilespage.cpp
 | 
					 | 
				
			||||||
    graphicspage.cpp
 | 
					    graphicspage.cpp
 | 
				
			||||||
    main.cpp
 | 
					    main.cpp
 | 
				
			||||||
    maindialog.cpp
 | 
					    maindialog.cpp
 | 
				
			||||||
    playpage.cpp
 | 
					    playpage.cpp
 | 
				
			||||||
 | 
					    datafilespage.cpp
 | 
				
			||||||
    model/datafilesmodel.cpp
 | 
					 | 
				
			||||||
    model/modelitem.cpp
 | 
					 | 
				
			||||||
    model/esm/esmfile.cpp
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    utils/filedialog.cpp
 | 
					 | 
				
			||||||
    utils/naturalsort.cpp
 | 
					 | 
				
			||||||
    utils/lineedit.cpp
 | 
					 | 
				
			||||||
    utils/profilescombobox.cpp
 | 
					    utils/profilescombobox.cpp
 | 
				
			||||||
    utils/textinputdialog.cpp
 | 
					    utils/textinputdialog.cpp
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -19,36 +11,20 @@ set(LAUNCHER
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
set(LAUNCHER_HEADER
 | 
					set(LAUNCHER_HEADER
 | 
				
			||||||
    datafilespage.hpp
 | 
					 | 
				
			||||||
    graphicspage.hpp
 | 
					    graphicspage.hpp
 | 
				
			||||||
    maindialog.hpp
 | 
					    maindialog.hpp
 | 
				
			||||||
    playpage.hpp
 | 
					    playpage.hpp
 | 
				
			||||||
 | 
					    datafilespage.hpp
 | 
				
			||||||
    model/datafilesmodel.hpp
 | 
					 | 
				
			||||||
    model/modelitem.hpp
 | 
					 | 
				
			||||||
    model/esm/esmfile.hpp
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    utils/lineedit.hpp
 | 
					 | 
				
			||||||
    utils/filedialog.hpp
 | 
					 | 
				
			||||||
    utils/naturalsort.hpp
 | 
					 | 
				
			||||||
    utils/profilescombobox.hpp
 | 
					    utils/profilescombobox.hpp
 | 
				
			||||||
    utils/textinputdialog.hpp
 | 
					    utils/textinputdialog.hpp
 | 
				
			||||||
 | 
					 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Headers that must be pre-processed
 | 
					# Headers that must be pre-processed
 | 
				
			||||||
set(LAUNCHER_HEADER_MOC
 | 
					set(LAUNCHER_HEADER_MOC
 | 
				
			||||||
    datafilespage.hpp
 | 
					 | 
				
			||||||
    graphicspage.hpp
 | 
					    graphicspage.hpp
 | 
				
			||||||
    maindialog.hpp
 | 
					    maindialog.hpp
 | 
				
			||||||
    playpage.hpp
 | 
					    playpage.hpp
 | 
				
			||||||
 | 
					    datafilespage.hpp
 | 
				
			||||||
    model/datafilesmodel.hpp
 | 
					 | 
				
			||||||
    model/modelitem.hpp
 | 
					 | 
				
			||||||
    model/esm/esmfile.hpp
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    utils/lineedit.hpp
 | 
					 | 
				
			||||||
    utils/filedialog.hpp
 | 
					 | 
				
			||||||
    utils/profilescombobox.hpp
 | 
					    utils/profilescombobox.hpp
 | 
				
			||||||
    utils/textinputdialog.hpp
 | 
					    utils/textinputdialog.hpp
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2,14 +2,17 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <components/esm/esmreader.hpp>
 | 
					#include <components/esm/esmreader.hpp>
 | 
				
			||||||
#include <components/files/configurationmanager.hpp>
 | 
					#include <components/files/configurationmanager.hpp>
 | 
				
			||||||
 | 
					#include <components/fileorderlist/datafileslist.hpp>
 | 
				
			||||||
 | 
					#include <components/fileorderlist/utils/lineedit.hpp>
 | 
				
			||||||
 | 
					#include <components/fileorderlist/utils/naturalsort.hpp>
 | 
				
			||||||
 | 
					#include <components/fileorderlist/utils/filedialog.hpp>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "model/datafilesmodel.hpp"
 | 
					////#include "model/datafilesmodel.hpp"
 | 
				
			||||||
#include "model/esm/esmfile.hpp"
 | 
					////#include "model/esm/esmfile.hpp"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "utils/profilescombobox.hpp"
 | 
					#include "utils/profilescombobox.hpp"
 | 
				
			||||||
#include "utils/filedialog.hpp"
 | 
					////#include "utils/filedialog.hpp"
 | 
				
			||||||
#include "utils/lineedit.hpp"
 | 
					////#include "utils/naturalsort.hpp"
 | 
				
			||||||
#include "utils/naturalsort.hpp"
 | 
					 | 
				
			||||||
#include "utils/textinputdialog.hpp"
 | 
					#include "utils/textinputdialog.hpp"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "datafilespage.hpp"
 | 
					#include "datafilespage.hpp"
 | 
				
			||||||
| 
						 | 
					@ -34,108 +37,11 @@ namespace boost
 | 
				
			||||||
using namespace ESM;
 | 
					using namespace ESM;
 | 
				
			||||||
using namespace std;
 | 
					using namespace std;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
//sort QModelIndexList ascending
 | 
					 | 
				
			||||||
bool rowGreaterThan(const QModelIndex &index1, const QModelIndex &index2)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    return index1.row() >= index2.row();
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
//sort QModelIndexList descending
 | 
					 | 
				
			||||||
bool rowSmallerThan(const QModelIndex &index1, const QModelIndex &index2)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    return index1.row() <= index2.row();
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
DataFilesPage::DataFilesPage(Files::ConfigurationManager &cfg, QWidget *parent)
 | 
					DataFilesPage::DataFilesPage(Files::ConfigurationManager &cfg, QWidget *parent)
 | 
				
			||||||
    : QWidget(parent)
 | 
					    : QWidget(parent)
 | 
				
			||||||
    , mCfgMgr(cfg)
 | 
					    , mCfgMgr(cfg)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    // Models
 | 
					    mDataFilesList = new DataFilesList(mCfgMgr, this);
 | 
				
			||||||
    mMastersModel = new DataFilesModel(this);
 | 
					 | 
				
			||||||
    mPluginsModel = new DataFilesModel(this);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    mPluginsProxyModel = new QSortFilterProxyModel();
 | 
					 | 
				
			||||||
    mPluginsProxyModel->setDynamicSortFilter(true);
 | 
					 | 
				
			||||||
    mPluginsProxyModel->setSourceModel(mPluginsModel);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    // Filter toolbar
 | 
					 | 
				
			||||||
    QLabel *filterLabel = new QLabel(tr("&Filter:"), this);
 | 
					 | 
				
			||||||
    LineEdit *filterLineEdit = new LineEdit(this);
 | 
					 | 
				
			||||||
    filterLabel->setBuddy(filterLineEdit);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    QToolBar *filterToolBar = new QToolBar(this);
 | 
					 | 
				
			||||||
    filterToolBar->setMovable(false);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    // Create a container widget and a layout to get the spacer to work
 | 
					 | 
				
			||||||
    QWidget *filterWidget = new QWidget(this);
 | 
					 | 
				
			||||||
    QHBoxLayout *filterLayout = new QHBoxLayout(filterWidget);
 | 
					 | 
				
			||||||
    QSpacerItem *hSpacer1 = new QSpacerItem(40, 20, QSizePolicy::Expanding, QSizePolicy::Minimum);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    filterLayout->addItem(hSpacer1);
 | 
					 | 
				
			||||||
    filterLayout->addWidget(filterLabel);
 | 
					 | 
				
			||||||
    filterLayout->addWidget(filterLineEdit);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    filterToolBar->addWidget(filterWidget);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    QCheckBox checkBox;
 | 
					 | 
				
			||||||
    unsigned int height = checkBox.sizeHint().height() + 4;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    mMastersTable = new QTableView(this);
 | 
					 | 
				
			||||||
    mMastersTable->setModel(mMastersModel);
 | 
					 | 
				
			||||||
    mMastersTable->setObjectName("MastersTable");
 | 
					 | 
				
			||||||
    mMastersTable->setSelectionBehavior(QAbstractItemView::SelectRows);
 | 
					 | 
				
			||||||
    mMastersTable->setSelectionMode(QAbstractItemView::SingleSelection);
 | 
					 | 
				
			||||||
    mMastersTable->setEditTriggers(QAbstractItemView::NoEditTriggers);
 | 
					 | 
				
			||||||
    mMastersTable->setAlternatingRowColors(true);
 | 
					 | 
				
			||||||
    mMastersTable->horizontalHeader()->setStretchLastSection(true);
 | 
					 | 
				
			||||||
    mMastersTable->horizontalHeader()->hide();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    // Set the row height to the size of the checkboxes
 | 
					 | 
				
			||||||
    mMastersTable->verticalHeader()->setDefaultSectionSize(height);
 | 
					 | 
				
			||||||
    mMastersTable->verticalHeader()->setResizeMode(QHeaderView::Fixed);
 | 
					 | 
				
			||||||
    mMastersTable->verticalHeader()->hide();
 | 
					 | 
				
			||||||
    mMastersTable->setColumnHidden(1, true);
 | 
					 | 
				
			||||||
    mMastersTable->setColumnHidden(2, true);
 | 
					 | 
				
			||||||
    mMastersTable->setColumnHidden(3, true);
 | 
					 | 
				
			||||||
    mMastersTable->setColumnHidden(4, true);
 | 
					 | 
				
			||||||
    mMastersTable->setColumnHidden(5, true);
 | 
					 | 
				
			||||||
    mMastersTable->setColumnHidden(6, true);
 | 
					 | 
				
			||||||
    mMastersTable->setColumnHidden(7, true);
 | 
					 | 
				
			||||||
    mMastersTable->setColumnHidden(8, true);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    mPluginsTable = new QTableView(this);
 | 
					 | 
				
			||||||
    mPluginsTable->setModel(mPluginsProxyModel);
 | 
					 | 
				
			||||||
    mPluginsTable->setObjectName("PluginsTable");
 | 
					 | 
				
			||||||
    mPluginsTable->setContextMenuPolicy(Qt::CustomContextMenu);
 | 
					 | 
				
			||||||
    mPluginsTable->setSelectionBehavior(QAbstractItemView::SelectRows);
 | 
					 | 
				
			||||||
    mPluginsTable->setSelectionMode(QAbstractItemView::SingleSelection);
 | 
					 | 
				
			||||||
    mPluginsTable->setEditTriggers(QAbstractItemView::NoEditTriggers);
 | 
					 | 
				
			||||||
    mPluginsTable->setAlternatingRowColors(true);
 | 
					 | 
				
			||||||
    mPluginsTable->setVerticalScrollMode(QAbstractItemView::ScrollPerItem);
 | 
					 | 
				
			||||||
    mPluginsTable->horizontalHeader()->setStretchLastSection(true);
 | 
					 | 
				
			||||||
    mPluginsTable->horizontalHeader()->hide();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    mPluginsTable->verticalHeader()->setDefaultSectionSize(height);
 | 
					 | 
				
			||||||
    mPluginsTable->verticalHeader()->setResizeMode(QHeaderView::Fixed);
 | 
					 | 
				
			||||||
    mPluginsTable->setColumnHidden(1, true);
 | 
					 | 
				
			||||||
    mPluginsTable->setColumnHidden(2, true);
 | 
					 | 
				
			||||||
    mPluginsTable->setColumnHidden(3, true);
 | 
					 | 
				
			||||||
    mPluginsTable->setColumnHidden(4, true);
 | 
					 | 
				
			||||||
    mPluginsTable->setColumnHidden(5, true);
 | 
					 | 
				
			||||||
    mPluginsTable->setColumnHidden(6, true);
 | 
					 | 
				
			||||||
    mPluginsTable->setColumnHidden(7, true);
 | 
					 | 
				
			||||||
    mPluginsTable->setColumnHidden(8, true);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    // Add both tables to a splitter
 | 
					 | 
				
			||||||
    QSplitter *splitter = new QSplitter(this);
 | 
					 | 
				
			||||||
    splitter->setOrientation(Qt::Horizontal);
 | 
					 | 
				
			||||||
    splitter->addWidget(mMastersTable);
 | 
					 | 
				
			||||||
    splitter->addWidget(mPluginsTable);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    // Adjust the default widget widths inside the splitter
 | 
					 | 
				
			||||||
    QList<int> sizeList;
 | 
					 | 
				
			||||||
    sizeList << 175 << 200;
 | 
					 | 
				
			||||||
    splitter->setSizes(sizeList);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Bottom part with profile options
 | 
					    // Bottom part with profile options
 | 
				
			||||||
    QLabel *profileLabel = new QLabel(tr("Current Profile: "), this);
 | 
					    QLabel *profileLabel = new QLabel(tr("Current Profile: "), this);
 | 
				
			||||||
| 
						 | 
					@ -155,24 +61,14 @@ DataFilesPage::DataFilesPage(Files::ConfigurationManager &cfg, QWidget *parent)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    QVBoxLayout *pageLayout = new QVBoxLayout(this);
 | 
					    QVBoxLayout *pageLayout = new QVBoxLayout(this);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    pageLayout->addWidget(filterToolBar);
 | 
					    pageLayout->addWidget(mDataFilesList);
 | 
				
			||||||
    pageLayout->addWidget(splitter);
 | 
					 | 
				
			||||||
    pageLayout->addWidget(mProfileToolBar);
 | 
					    pageLayout->addWidget(mProfileToolBar);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Create a dialog for the new profile name input
 | 
					    // Create a dialog for the new profile name input
 | 
				
			||||||
    mNewProfileDialog = new TextInputDialog(tr("New Profile"), tr("Profile name:"), this);
 | 
					    mNewProfileDialog = new TextInputDialog(tr("New Profile"), tr("Profile name:"), this);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    connect(mNewProfileDialog->lineEdit(), SIGNAL(textChanged(QString)), this, SLOT(updateOkButton(QString)));
 | 
					    connect(mNewProfileDialog->lineEdit(), SIGNAL(textChanged(QString)), this, SLOT(updateOkButton(QString)));
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
    connect(mPluginsTable, SIGNAL(doubleClicked(QModelIndex)), this, SLOT(setCheckState(QModelIndex)));
 | 
					 | 
				
			||||||
    connect(mMastersTable, SIGNAL(doubleClicked(QModelIndex)), this, SLOT(setCheckState(QModelIndex)));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    connect(mMastersModel, SIGNAL(checkedItemsChanged(QStringList,QStringList)), mPluginsModel, SLOT(slotcheckedItemsChanged(QStringList,QStringList)));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    connect(filterLineEdit, SIGNAL(textChanged(QString)), this, SLOT(filterChanged(QString)));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    connect(mPluginsTable, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(showContextMenu(QPoint)));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    connect(mProfilesComboBox, SIGNAL(profileRenamed(QString,QString)), this, SLOT(profileRenamed(QString,QString)));
 | 
					    connect(mProfilesComboBox, SIGNAL(profileRenamed(QString,QString)), this, SLOT(profileRenamed(QString,QString)));
 | 
				
			||||||
    connect(mProfilesComboBox, SIGNAL(profileChanged(QString,QString)), this, SLOT(profileChanged(QString,QString)));
 | 
					    connect(mProfilesComboBox, SIGNAL(profileChanged(QString,QString)), this, SLOT(profileChanged(QString,QString)));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -202,20 +98,6 @@ void DataFilesPage::createActions()
 | 
				
			||||||
    mProfileToolBar->addSeparator();
 | 
					    mProfileToolBar->addSeparator();
 | 
				
			||||||
    mProfileToolBar->addAction(mNewProfileAction);
 | 
					    mProfileToolBar->addAction(mNewProfileAction);
 | 
				
			||||||
    mProfileToolBar->addAction(mDeleteProfileAction);
 | 
					    mProfileToolBar->addAction(mDeleteProfileAction);
 | 
				
			||||||
 | 
					 | 
				
			||||||
    // Context menu actions
 | 
					 | 
				
			||||||
    mCheckAction = new QAction(tr("Check selected"), this);
 | 
					 | 
				
			||||||
    connect(mCheckAction, SIGNAL(triggered()), this, SLOT(check()));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    mUncheckAction = new QAction(tr("Uncheck selected"), this);
 | 
					 | 
				
			||||||
    connect(mUncheckAction, SIGNAL(triggered()), this, SLOT(uncheck()));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    // Context menu for the plugins table
 | 
					 | 
				
			||||||
    mContextMenu = new QMenu(this);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    mContextMenu->addAction(mCheckAction);
 | 
					 | 
				
			||||||
    mContextMenu->addAction(mUncheckAction);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void DataFilesPage::setupConfig()
 | 
					void DataFilesPage::setupConfig()
 | 
				
			||||||
| 
						 | 
					@ -267,12 +149,8 @@ void DataFilesPage::setupConfig()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void DataFilesPage::readConfig()
 | 
					void DataFilesPage::readConfig()
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    // Don't read the config if no masters are found
 | 
					 | 
				
			||||||
    if (mMastersModel->rowCount() < 1)
 | 
					 | 
				
			||||||
        return;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    QString profile = mProfilesComboBox->currentText();
 | 
					    QString profile = mProfilesComboBox->currentText();
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
    // Make sure we have no groups open
 | 
					    // Make sure we have no groups open
 | 
				
			||||||
    while (!mLauncherConfig->group().isEmpty()) {
 | 
					    while (!mLauncherConfig->group().isEmpty()) {
 | 
				
			||||||
        mLauncherConfig->endGroup();
 | 
					        mLauncherConfig->endGroup();
 | 
				
			||||||
| 
						 | 
					@ -290,54 +168,11 @@ void DataFilesPage::readConfig()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    foreach (const QString &key, childKeys) {
 | 
					    foreach (const QString &key, childKeys) {
 | 
				
			||||||
        const QString keyValue = mLauncherConfig->value(key).toString();
 | 
					        const QString keyValue = mLauncherConfig->value(key).toString();
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
        if (key.startsWith("Plugin")) {
 | 
					        mDataFilesList->setCheckState(keyValue, Qt::Checked);
 | 
				
			||||||
            //QStringList checked = mPluginsModel->checkedItems();
 | 
					 | 
				
			||||||
            EsmFile *file = mPluginsModel->findItem(keyValue);
 | 
					 | 
				
			||||||
            QModelIndex index = mPluginsModel->indexFromItem(file);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            mPluginsModel->setCheckState(index, Qt::Checked);
 | 
					 | 
				
			||||||
            // Move the row to the top of te view
 | 
					 | 
				
			||||||
            //mPluginsModel->moveRow(index.row(), checked.count());
 | 
					 | 
				
			||||||
            plugins << keyValue;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if (key.startsWith("Master")) {
 | 
					 | 
				
			||||||
            EsmFile *file = mMastersModel->findItem(keyValue);
 | 
					 | 
				
			||||||
            mMastersModel->setCheckState(mMastersModel->indexFromItem(file), Qt::Checked);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    qDebug() << plugins;
 | 
					    qDebug() << plugins;
 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
//    // Set the checked item positions
 | 
					 | 
				
			||||||
//    const QStringList checked = mPluginsModel->checkedItems();
 | 
					 | 
				
			||||||
//    for (int i = 0; i < plugins.size(); ++i) {
 | 
					 | 
				
			||||||
//        EsmFile *file = mPluginsModel->findItem(plugins.at(i));
 | 
					 | 
				
			||||||
//        QModelIndex index = mPluginsModel->indexFromItem(file);
 | 
					 | 
				
			||||||
//        mPluginsModel->moveRow(index.row(), i);
 | 
					 | 
				
			||||||
//        qDebug() << "Moving: " << plugins.at(i) << " from: " << index.row() << " to: " << i << " count: " << checked.count();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
//    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    // Iterate over the plugins to set their checkstate and position
 | 
					 | 
				
			||||||
//    for (int i = 0; i < plugins.size(); ++i) {
 | 
					 | 
				
			||||||
//        const QString plugin = plugins.at(i);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
//        const QList<QStandardItem *> pluginList = mPluginsModel->findItems(plugin);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
//        if (!pluginList.isEmpty())
 | 
					 | 
				
			||||||
//        {
 | 
					 | 
				
			||||||
//            foreach (const QStandardItem *currentPlugin, pluginList) {
 | 
					 | 
				
			||||||
//                mPluginsModel->setData(currentPlugin->index(), Qt::Checked, Qt::CheckStateRole);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
//                // Move the plugin to the position specified in the config file
 | 
					 | 
				
			||||||
//                mPluginsModel->insertRow(i, mPluginsModel->takeRow(currentPlugin->row()));
 | 
					 | 
				
			||||||
//            }
 | 
					 | 
				
			||||||
//        }
 | 
					 | 
				
			||||||
//    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
bool DataFilesPage::showDataFilesWarning()
 | 
					bool DataFilesPage::showDataFilesWarning()
 | 
				
			||||||
| 
						 | 
					@ -386,77 +221,51 @@ bool DataFilesPage::setupDataFiles()
 | 
				
			||||||
    // We use the Configuration Manager to retrieve the configuration values
 | 
					    // We use the Configuration Manager to retrieve the configuration values
 | 
				
			||||||
    boost::program_options::variables_map variables;
 | 
					    boost::program_options::variables_map variables;
 | 
				
			||||||
    boost::program_options::options_description desc;
 | 
					    boost::program_options::options_description desc;
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
    desc.add_options()
 | 
					    desc.add_options()
 | 
				
			||||||
        ("data", boost::program_options::value<Files::PathContainer>()->default_value(Files::PathContainer(), "data")->multitoken())
 | 
					    ("data", boost::program_options::value<Files::PathContainer>()->default_value(Files::PathContainer(), "data")->multitoken())
 | 
				
			||||||
        ("data-local", boost::program_options::value<std::string>()->default_value(""))
 | 
					    ("data-local", boost::program_options::value<std::string>()->default_value(""))
 | 
				
			||||||
        ("fs-strict", boost::program_options::value<bool>()->implicit_value(true)->default_value(false))
 | 
					    ("fs-strict", boost::program_options::value<bool>()->implicit_value(true)->default_value(false))
 | 
				
			||||||
        ("encoding", boost::program_options::value<std::string>()->default_value("win1252"));
 | 
					    ("encoding", boost::program_options::value<std::string>()->default_value("win1252"));
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
    boost::program_options::notify(variables);
 | 
					    boost::program_options::notify(variables);
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
    mCfgMgr.readConfiguration(variables, desc);
 | 
					    mCfgMgr.readConfiguration(variables, desc);
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
    if (variables["data"].empty()) {
 | 
					    if (variables["data"].empty()) {
 | 
				
			||||||
        if (!showDataFilesWarning())
 | 
					        if (!showDataFilesWarning())
 | 
				
			||||||
           return false;
 | 
					            return false;
 | 
				
			||||||
    } else {
 | 
					    } else {
 | 
				
			||||||
        mDataDirs = Files::PathContainer(variables["data"].as<Files::PathContainer>());
 | 
					        mDataDirs = Files::PathContainer(variables["data"].as<Files::PathContainer>());
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
     std::string local = variables["data-local"].as<std::string>();
 | 
					    std::string local = variables["data-local"].as<std::string>();
 | 
				
			||||||
     if (!local.empty()) {
 | 
					    if (!local.empty()) {
 | 
				
			||||||
         mDataLocal.push_back(Files::PathContainer::value_type(local));
 | 
					        mDataLocal.push_back(Files::PathContainer::value_type(local));
 | 
				
			||||||
     }
 | 
					    }
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
    mCfgMgr.processPaths(mDataDirs);
 | 
					    mCfgMgr.processPaths(mDataDirs);
 | 
				
			||||||
    mCfgMgr.processPaths(mDataLocal);
 | 
					    mCfgMgr.processPaths(mDataLocal);
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
    // Second chance to display the warning, the data= entries are invalid
 | 
					    // Second chance to display the warning, the data= entries are invalid
 | 
				
			||||||
    while (mDataDirs.empty()) {
 | 
					    while (mDataDirs.empty()) {
 | 
				
			||||||
        if (!showDataFilesWarning())
 | 
					        if (!showDataFilesWarning())
 | 
				
			||||||
            return false;
 | 
					            return false;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
    // Set the charset for reading the esm/esp files
 | 
					    // Set the charset for reading the esm/esp files
 | 
				
			||||||
    QString encoding = QString::fromStdString(variables["encoding"].as<std::string>());
 | 
					    QString encoding = QString::fromStdString(variables["encoding"].as<std::string>());
 | 
				
			||||||
    if (!encoding.isEmpty() && encoding != QLatin1String("win1252")) {
 | 
					    
 | 
				
			||||||
        mMastersModel->setEncoding(encoding);
 | 
					    Files::PathContainer paths;
 | 
				
			||||||
        mPluginsModel->setEncoding(encoding);
 | 
					    paths.insert(paths.end(), mDataDirs.begin(), mDataDirs.end());
 | 
				
			||||||
    }
 | 
					    paths.insert(paths.end(), mDataLocal.begin(), mDataLocal.end());
 | 
				
			||||||
 | 
					    mDataFilesList->setupDataFiles(paths, encoding);
 | 
				
			||||||
    // Add the paths to the respective models
 | 
					 | 
				
			||||||
    for (Files::PathContainer::iterator it = mDataDirs.begin(); it != mDataDirs.end(); ++it) {
 | 
					 | 
				
			||||||
        QString path = QString::fromStdString(it->string());
 | 
					 | 
				
			||||||
        path.remove(QChar('\"'));
 | 
					 | 
				
			||||||
        mMastersModel->addMasters(path);
 | 
					 | 
				
			||||||
        mPluginsModel->addPlugins(path);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    // Same for the data-local paths
 | 
					 | 
				
			||||||
    for (Files::PathContainer::iterator it = mDataLocal.begin(); it != mDataLocal.end(); ++it) {
 | 
					 | 
				
			||||||
        QString path = QString::fromStdString(it->string());
 | 
					 | 
				
			||||||
        path.remove(QChar('\"'));
 | 
					 | 
				
			||||||
        mMastersModel->addMasters(path);
 | 
					 | 
				
			||||||
        mPluginsModel->addPlugins(path);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    mMastersModel->sort(0);
 | 
					 | 
				
			||||||
    mPluginsModel->sort(0);
 | 
					 | 
				
			||||||
//    mMastersTable->sortByColumn(3, Qt::AscendingOrder);
 | 
					 | 
				
			||||||
//    mPluginsTable->sortByColumn(3, Qt::AscendingOrder);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    readConfig();
 | 
					    readConfig();
 | 
				
			||||||
    return true;
 | 
					    return true;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void DataFilesPage::writeConfig(QString profile)
 | 
					void DataFilesPage::writeConfig(QString profile)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    // Don't overwrite the config if no masters are found
 | 
					 | 
				
			||||||
    if (mMastersModel->rowCount() < 1)
 | 
					 | 
				
			||||||
        return;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    QString pathStr = QString::fromStdString(mCfgMgr.getUserPath().string());
 | 
					    QString pathStr = QString::fromStdString(mCfgMgr.getUserPath().string());
 | 
				
			||||||
    QDir userPath(pathStr);
 | 
					    QDir userPath(pathStr);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -579,24 +388,19 @@ void DataFilesPage::writeConfig(QString profile)
 | 
				
			||||||
    mLauncherConfig->remove(""); // Clear the subgroup
 | 
					    mLauncherConfig->remove(""); // Clear the subgroup
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Now write the masters to the configs
 | 
					    // Now write the masters to the configs
 | 
				
			||||||
    const QStringList masters = mMastersModel->checkedItems();
 | 
					    const QStringList checkedFiles = mDataFilesList->checkedFiles();
 | 
				
			||||||
 | 
					    for(int i=0; i < checkedFiles.size(); i++)
 | 
				
			||||||
    // We don't use foreach because we need i
 | 
					    {
 | 
				
			||||||
    for (int i = 0; i < masters.size(); ++i) {
 | 
					        if (checkedFiles.at(i).lastIndexOf("esm") != -1)
 | 
				
			||||||
        const QString currentMaster = masters.at(i);
 | 
					        {
 | 
				
			||||||
 | 
					            mLauncherConfig->setValue(QString("Master%0").arg(i), checkedFiles.at(i));
 | 
				
			||||||
        mLauncherConfig->setValue(QString("Master%0").arg(i), currentMaster);
 | 
					            gameConfig << "master=" << checkedFiles.at(i) << endl;
 | 
				
			||||||
        gameConfig << "master=" << currentMaster << endl;
 | 
					        }
 | 
				
			||||||
 | 
					        else
 | 
				
			||||||
    }
 | 
					        {
 | 
				
			||||||
 | 
					            mLauncherConfig->setValue(QString("Plugin%1").arg(i), checkedFiles.at(i));
 | 
				
			||||||
    // And finally write all checked plugins
 | 
					            gameConfig << "plugin=" << checkedFiles.at(i) << endl;
 | 
				
			||||||
    const QStringList plugins = mPluginsModel->checkedItems();
 | 
					        }
 | 
				
			||||||
 | 
					 | 
				
			||||||
    for (int i = 0; i < plugins.size(); ++i) {
 | 
					 | 
				
			||||||
        const QString currentPlugin = plugins.at(i);
 | 
					 | 
				
			||||||
        mLauncherConfig->setValue(QString("Plugin%1").arg(i), currentPlugin);
 | 
					 | 
				
			||||||
        gameConfig << "plugin=" << currentPlugin << endl;
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    file.close();
 | 
					    file.close();
 | 
				
			||||||
| 
						 | 
					@ -670,93 +474,6 @@ void DataFilesPage::deleteProfile()
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void DataFilesPage::check()
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    // Check the current selection
 | 
					 | 
				
			||||||
    if (!mPluginsTable->selectionModel()->hasSelection()) {
 | 
					 | 
				
			||||||
        return;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    QModelIndexList indexes = mPluginsTable->selectionModel()->selectedIndexes();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    //sort selection ascending because selectedIndexes returns an unsorted list
 | 
					 | 
				
			||||||
    //qSort(indexes.begin(), indexes.end(), rowSmallerThan);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    foreach (const QModelIndex &index, indexes) {
 | 
					 | 
				
			||||||
        if (!index.isValid())
 | 
					 | 
				
			||||||
            return;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        mPluginsModel->setCheckState(index, Qt::Checked);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void DataFilesPage::uncheck()
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    // uncheck the current selection
 | 
					 | 
				
			||||||
    if (!mPluginsTable->selectionModel()->hasSelection()) {
 | 
					 | 
				
			||||||
        return;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    QModelIndexList indexes = mPluginsTable->selectionModel()->selectedIndexes();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    //sort selection ascending because selectedIndexes returns an unsorted list
 | 
					 | 
				
			||||||
    //qSort(indexes.begin(), indexes.end(), rowSmallerThan);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    foreach (const QModelIndex &index, indexes) {
 | 
					 | 
				
			||||||
        if (!index.isValid())
 | 
					 | 
				
			||||||
            return;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        mPluginsModel->setCheckState(index, Qt::Unchecked);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void DataFilesPage::refresh()
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    mPluginsModel->sort(0);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    // Refresh the plugins table
 | 
					 | 
				
			||||||
    mPluginsTable->scrollToTop();
 | 
					 | 
				
			||||||
    writeConfig();
 | 
					 | 
				
			||||||
    readConfig();
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void DataFilesPage::setCheckState(QModelIndex index)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    if (!index.isValid())
 | 
					 | 
				
			||||||
        return;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    QObject *object = QObject::sender();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    // Not a signal-slot call
 | 
					 | 
				
			||||||
    if (!object)
 | 
					 | 
				
			||||||
        return;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if (object->objectName() == QLatin1String("PluginsTable")) {
 | 
					 | 
				
			||||||
        QModelIndex sourceIndex = mPluginsProxyModel->mapToSource(index);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        (mPluginsModel->checkState(sourceIndex) == Qt::Checked)
 | 
					 | 
				
			||||||
                ? mPluginsModel->setCheckState(sourceIndex, Qt::Unchecked)
 | 
					 | 
				
			||||||
                : mPluginsModel->setCheckState(sourceIndex, Qt::Checked);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if (object->objectName() == QLatin1String("MastersTable")) {
 | 
					 | 
				
			||||||
        (mMastersModel->checkState(index) == Qt::Checked)
 | 
					 | 
				
			||||||
                ? mMastersModel->setCheckState(index, Qt::Unchecked)
 | 
					 | 
				
			||||||
                : mMastersModel->setCheckState(index, Qt::Checked);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    return;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void DataFilesPage::filterChanged(const QString filter)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    QRegExp regExp(filter, Qt::CaseInsensitive, QRegExp::FixedString);
 | 
					 | 
				
			||||||
    mPluginsProxyModel->setFilterRegExp(regExp);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void DataFilesPage::profileChanged(const QString &previous, const QString ¤t)
 | 
					void DataFilesPage::profileChanged(const QString &previous, const QString ¤t)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    qDebug() << "Profile is changed from: " << previous << " to " << current;
 | 
					    qDebug() << "Profile is changed from: " << previous << " to " << current;
 | 
				
			||||||
| 
						 | 
					@ -780,8 +497,7 @@ void DataFilesPage::profileChanged(const QString &previous, const QString &curre
 | 
				
			||||||
        return;
 | 
					        return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    mMastersModel->uncheckAll();
 | 
					    mDataFilesList->uncheckAll();
 | 
				
			||||||
    mPluginsModel->uncheckAll();
 | 
					 | 
				
			||||||
    readConfig();
 | 
					    readConfig();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -810,35 +526,8 @@ void DataFilesPage::profileRenamed(const QString &previous, const QString &curre
 | 
				
			||||||
     // Remove the profile from the combobox
 | 
					     // Remove the profile from the combobox
 | 
				
			||||||
     mProfilesComboBox->removeItem(mProfilesComboBox->findText(previous));
 | 
					     mProfilesComboBox->removeItem(mProfilesComboBox->findText(previous));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
     mMastersModel->uncheckAll();
 | 
					     mDataFilesList->uncheckAll();
 | 
				
			||||||
     mPluginsModel->uncheckAll();
 | 
					     ////mMastersModel->uncheckAll();
 | 
				
			||||||
 | 
					     ////mPluginsModel->uncheckAll();
 | 
				
			||||||
     readConfig();
 | 
					     readConfig();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					 | 
				
			||||||
void DataFilesPage::showContextMenu(const QPoint &point)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    // Make sure there are plugins in the view
 | 
					 | 
				
			||||||
    if (!mPluginsTable->selectionModel()->hasSelection()) {
 | 
					 | 
				
			||||||
        return;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    QPoint globalPos = mPluginsTable->mapToGlobal(point);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    QModelIndexList indexes = mPluginsTable->selectionModel()->selectedIndexes();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    // Show the check/uncheck actions depending on the state of the selected items
 | 
					 | 
				
			||||||
    mUncheckAction->setEnabled(false);
 | 
					 | 
				
			||||||
    mCheckAction->setEnabled(false);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    foreach (const QModelIndex &index, indexes) {
 | 
					 | 
				
			||||||
        if (!index.isValid())
 | 
					 | 
				
			||||||
            return;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
         (mPluginsModel->checkState(index) == Qt::Checked)
 | 
					 | 
				
			||||||
             ? mUncheckAction->setEnabled(true)
 | 
					 | 
				
			||||||
             : mCheckAction->setEnabled(true);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    // Show menu
 | 
					 | 
				
			||||||
    mContextMenu->exec(globalPos);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -17,6 +17,7 @@ class ProfilesComboBox;
 | 
				
			||||||
class DataFilesModel;
 | 
					class DataFilesModel;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class TextInputDialog;
 | 
					class TextInputDialog;
 | 
				
			||||||
 | 
					class DataFilesList;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace Files { struct ConfigurationManager; }
 | 
					namespace Files { struct ConfigurationManager; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -34,10 +35,6 @@ public:
 | 
				
			||||||
    bool setupDataFiles();
 | 
					    bool setupDataFiles();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
public slots:
 | 
					public slots:
 | 
				
			||||||
    void setCheckState(QModelIndex index);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    void filterChanged(const QString filter);
 | 
					 | 
				
			||||||
    void showContextMenu(const QPoint &point);
 | 
					 | 
				
			||||||
    void profileChanged(const QString &previous, const QString ¤t);
 | 
					    void profileChanged(const QString &previous, const QString ¤t);
 | 
				
			||||||
    void profileRenamed(const QString &previous, const QString ¤t);
 | 
					    void profileRenamed(const QString &previous, const QString ¤t);
 | 
				
			||||||
    void updateOkButton(const QString &text);
 | 
					    void updateOkButton(const QString &text);
 | 
				
			||||||
| 
						 | 
					@ -49,21 +46,11 @@ public slots:
 | 
				
			||||||
//    void moveDown();
 | 
					//    void moveDown();
 | 
				
			||||||
//    void moveTop();
 | 
					//    void moveTop();
 | 
				
			||||||
//    void moveBottom();
 | 
					//    void moveBottom();
 | 
				
			||||||
    void check();
 | 
					 | 
				
			||||||
    void uncheck();
 | 
					 | 
				
			||||||
    void refresh();
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
private:
 | 
					private:
 | 
				
			||||||
    DataFilesModel *mMastersModel;
 | 
					    DataFilesList *mDataFilesList;
 | 
				
			||||||
    DataFilesModel *mPluginsModel;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    QSortFilterProxyModel *mPluginsProxyModel;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    QTableView *mMastersTable;
 | 
					 | 
				
			||||||
    QTableView *mPluginsTable;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    QToolBar *mProfileToolBar;
 | 
					    QToolBar *mProfileToolBar;
 | 
				
			||||||
    QMenu *mContextMenu;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    QAction *mNewProfileAction;
 | 
					    QAction *mNewProfileAction;
 | 
				
			||||||
    QAction *mDeleteProfileAction;
 | 
					    QAction *mDeleteProfileAction;
 | 
				
			||||||
| 
						 | 
					@ -72,8 +59,6 @@ private:
 | 
				
			||||||
//    QAction *mMoveDownAction;
 | 
					//    QAction *mMoveDownAction;
 | 
				
			||||||
//    QAction *mMoveTopAction;
 | 
					//    QAction *mMoveTopAction;
 | 
				
			||||||
//    QAction *mMoveBottomAction;
 | 
					//    QAction *mMoveBottomAction;
 | 
				
			||||||
    QAction *mCheckAction;
 | 
					 | 
				
			||||||
    QAction *mUncheckAction;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    Files::ConfigurationManager &mCfgMgr;
 | 
					    Files::ConfigurationManager &mCfgMgr;
 | 
				
			||||||
    Files::PathContainer mDataDirs;
 | 
					    Files::PathContainer mDataDirs;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -8,8 +8,7 @@
 | 
				
			||||||
#include <components/files/configurationmanager.hpp>
 | 
					#include <components/files/configurationmanager.hpp>
 | 
				
			||||||
#include <components/files/ogreplugin.hpp>
 | 
					#include <components/files/ogreplugin.hpp>
 | 
				
			||||||
#include <components/settings/settings.hpp>
 | 
					#include <components/settings/settings.hpp>
 | 
				
			||||||
 | 
					#include <components/fileorderlist/utils/naturalsort.hpp>
 | 
				
			||||||
#include "utils/naturalsort.hpp"
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "graphicspage.hpp"
 | 
					#include "graphicspage.hpp"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -5,7 +5,7 @@
 | 
				
			||||||
#include <QVBoxLayout>
 | 
					#include <QVBoxLayout>
 | 
				
			||||||
#include <QValidator>
 | 
					#include <QValidator>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "lineedit.hpp"
 | 
					#include <components/fileorderlist/utils/lineedit.hpp>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "textinputdialog.hpp"
 | 
					#include "textinputdialog.hpp"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -777,6 +777,39 @@ void MwIniImporter::insertMultistrmap(multistrmap &cfg, std::string key, std::st
 | 
				
			||||||
    cfg[key].push_back(value);
 | 
					    cfg[key].push_back(value);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void MwIniImporter::importArchives(multistrmap &cfg, multistrmap &ini) {
 | 
				
			||||||
 | 
					    std::vector<std::string> archives;
 | 
				
			||||||
 | 
					    std::string baseArchive("Archives:Archive ");
 | 
				
			||||||
 | 
					    std::string archive;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Search archives listed in ini file
 | 
				
			||||||
 | 
					    multistrmap::iterator it = ini.begin();
 | 
				
			||||||
 | 
					    for(int i=0; it != ini.end(); i++) {
 | 
				
			||||||
 | 
					        archive = baseArchive;
 | 
				
			||||||
 | 
					        archive.append(this->numberToString(i));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        it = ini.find(archive);
 | 
				
			||||||
 | 
					        if(it == ini.end()) {
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        for(std::vector<std::string>::iterator entry = it->second.begin(); entry!=it->second.end(); ++entry) {
 | 
				
			||||||
 | 
					            archives.push_back(*entry);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    cfg.erase("fallback-archive");
 | 
				
			||||||
 | 
					    cfg.insert( std::make_pair<std::string, std::vector<std::string> > ("fallback-archive", std::vector<std::string>()));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Add Morrowind.bsa by default, since Vanilla loads this archive even if it
 | 
				
			||||||
 | 
					    // does not appears in the ini file
 | 
				
			||||||
 | 
					    cfg["fallback-archive"].push_back("Morrowind.bsa");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for(std::vector<std::string>::iterator it=archives.begin(); it!=archives.end(); ++it) {
 | 
				
			||||||
 | 
					        cfg["fallback-archive"].push_back(*it);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void MwIniImporter::importGameFiles(multistrmap &cfg, multistrmap &ini) {
 | 
					void MwIniImporter::importGameFiles(multistrmap &cfg, multistrmap &ini) {
 | 
				
			||||||
    std::vector<std::string> esmFiles;
 | 
					    std::vector<std::string> esmFiles;
 | 
				
			||||||
    std::vector<std::string> espFiles;
 | 
					    std::vector<std::string> espFiles;
 | 
				
			||||||
| 
						 | 
					@ -794,7 +827,7 @@ void MwIniImporter::importGameFiles(multistrmap &cfg, multistrmap &ini) {
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        for(std::vector<std::string>::iterator entry = it->second.begin(); entry!=it->second.end(); ++entry) {
 | 
					        for(std::vector<std::string>::iterator entry = it->second.begin(); entry!=it->second.end(); ++entry) {
 | 
				
			||||||
            std::string filetype(entry->substr(entry->length()-4, 3));
 | 
					            std::string filetype(entry->substr(entry->length()-3));
 | 
				
			||||||
            Misc::StringUtils::toLower(filetype);
 | 
					            Misc::StringUtils::toLower(filetype);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            if(filetype.compare("esm") == 0) {
 | 
					            if(filetype.compare("esm") == 0) {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -23,6 +23,7 @@ class MwIniImporter {
 | 
				
			||||||
    void    merge(multistrmap &cfg, multistrmap &ini);
 | 
					    void    merge(multistrmap &cfg, multistrmap &ini);
 | 
				
			||||||
    void    mergeFallback(multistrmap &cfg, multistrmap &ini);
 | 
					    void    mergeFallback(multistrmap &cfg, multistrmap &ini);
 | 
				
			||||||
    void    importGameFiles(multistrmap &cfg, multistrmap &ini);
 | 
					    void    importGameFiles(multistrmap &cfg, multistrmap &ini);
 | 
				
			||||||
 | 
					    void    importArchives(multistrmap &cfg, multistrmap &ini);
 | 
				
			||||||
    void    writeToFile(boost::iostreams::stream<boost::iostreams::file_sink> &out, multistrmap &cfg);
 | 
					    void    writeToFile(boost::iostreams::stream<boost::iostreams::file_sink> &out, multistrmap &cfg);
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
  private:
 | 
					  private:
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -18,6 +18,7 @@ int main(int argc, char *argv[]) {
 | 
				
			||||||
        ("cfg,c", bpo::value<std::string>(), "openmw.cfg file")
 | 
					        ("cfg,c", bpo::value<std::string>(), "openmw.cfg file")
 | 
				
			||||||
        ("output,o", bpo::value<std::string>()->default_value(""), "openmw.cfg file")
 | 
					        ("output,o", bpo::value<std::string>()->default_value(""), "openmw.cfg file")
 | 
				
			||||||
        ("game-files,g", "import esm and esp files")
 | 
					        ("game-files,g", "import esm and esp files")
 | 
				
			||||||
 | 
					        ("no-archives,A", "disable bsa archives import")
 | 
				
			||||||
        ("encoding,e", bpo::value<std::string>()-> default_value("win1252"),
 | 
					        ("encoding,e", bpo::value<std::string>()-> default_value("win1252"),
 | 
				
			||||||
            "Character encoding used in OpenMW game messages:\n"
 | 
					            "Character encoding used in OpenMW game messages:\n"
 | 
				
			||||||
            "\n\twin1250 - Central and Eastern European such as Polish, Czech, Slovak, Hungarian, Slovene, Bosnian, Croatian, Serbian (Latin script), Romanian and Albanian languages\n"
 | 
					            "\n\twin1250 - Central and Eastern European such as Polish, Czech, Slovak, Hungarian, Slovene, Bosnian, Croatian, Serbian (Latin script), Romanian and Albanian languages\n"
 | 
				
			||||||
| 
						 | 
					@ -76,6 +77,10 @@ int main(int argc, char *argv[]) {
 | 
				
			||||||
        importer.importGameFiles(cfg, ini);
 | 
					        importer.importGameFiles(cfg, ini);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if(!vm.count("no-archives")) {
 | 
				
			||||||
 | 
					        importer.importArchives(cfg, ini);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    std::cout << "write to: " << outputFile << std::endl;
 | 
					    std::cout << "write to: " << outputFile << std::endl;
 | 
				
			||||||
    boost::iostreams::stream<boost::iostreams::file_sink> file(outputFile);
 | 
					    boost::iostreams::stream<boost::iostreams::file_sink> file(outputFile);
 | 
				
			||||||
    importer.writeToFile(file, cfg);
 | 
					    importer.writeToFile(file, cfg);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -21,6 +21,7 @@ opencs_units (model/world
 | 
				
			||||||
    idtable idtableproxymodel
 | 
					    idtable idtableproxymodel
 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
opencs_units_noqt (model/world
 | 
					opencs_units_noqt (model/world
 | 
				
			||||||
    universalid data record idcollection commands columnbase
 | 
					    universalid data record idcollection commands columnbase
 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
| 
						 | 
					@ -40,9 +41,10 @@ opencs_units_noqt (model/tools
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
opencs_units (view/doc
 | 
					opencs_units (view/doc
 | 
				
			||||||
    viewmanager view operations operation subview
 | 
					    viewmanager view operations operation subview startup opendialog
 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
opencs_units_noqt (view/doc
 | 
					opencs_units_noqt (view/doc
 | 
				
			||||||
    subviewfactory
 | 
					    subviewfactory
 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -11,39 +11,52 @@
 | 
				
			||||||
CS::Editor::Editor() : mViewManager (mDocumentManager), mNewDocumentIndex (0)
 | 
					CS::Editor::Editor() : mViewManager (mDocumentManager), mNewDocumentIndex (0)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    connect (&mViewManager, SIGNAL (newDocumentRequest ()), this, SLOT (createDocument ()));
 | 
					    connect (&mViewManager, SIGNAL (newDocumentRequest ()), this, SLOT (createDocument ()));
 | 
				
			||||||
 | 
					    connect (&mViewManager, SIGNAL (loadDocumentRequest ()), this, SLOT (loadDocument ()));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    connect (&mStartup, SIGNAL (createDocument()), this, SLOT (createDocument ()));
 | 
				
			||||||
 | 
					    connect (&mStartup, SIGNAL (loadDocument()), this, SLOT (loadDocument ()));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    connect (&mOpenDialog, SIGNAL(accepted()), this, SLOT(openFiles()));
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void CS::Editor::createDocument()
 | 
					void CS::Editor::createDocument()
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
					    mStartup.hide();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// \todo open the ESX picker instead
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    std::ostringstream stream;
 | 
					    std::ostringstream stream;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    stream << "NewDocument" << (++mNewDocumentIndex);
 | 
					    stream << "NewDocument" << (++mNewDocumentIndex);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    CSMDoc::Document *document = mDocumentManager.addDocument (stream.str());
 | 
					    std::vector<boost::filesystem::path> files;
 | 
				
			||||||
 | 
					    files.push_back (stream.str());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    static const char *sGlobals[] =
 | 
					    CSMDoc::Document *document = mDocumentManager.addDocument (files, true);
 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
            "Day", "DaysPassed", "GameHour", "Month", "PCRace", "PCVampire", "PCWerewolf", "PCYear", 0
 | 
					 | 
				
			||||||
    };
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    for (int i=0; sGlobals[i]; ++i)
 | 
					    mViewManager.addView (document);
 | 
				
			||||||
    {
 | 
					}
 | 
				
			||||||
        ESM::Global record;
 | 
					 | 
				
			||||||
        record.mId = sGlobals[i];
 | 
					 | 
				
			||||||
        record.mValue = i==0 ? 1 : 0;
 | 
					 | 
				
			||||||
        record.mType = ESM::VT_Float;
 | 
					 | 
				
			||||||
        document->getData().getGlobals().add (record);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    document->getData().merge(); /// \todo remove once proper ESX loading is implemented
 | 
					void CS::Editor::loadDocument()
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    mStartup.hide();
 | 
				
			||||||
 | 
					    mOpenDialog.show();
 | 
				
			||||||
 | 
					    mOpenDialog.raise();
 | 
				
			||||||
 | 
					    mOpenDialog.activateWindow();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void CS::Editor::openFiles()
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    std::vector<boost::filesystem::path> paths;
 | 
				
			||||||
 | 
					    mOpenDialog.getFileList(paths);
 | 
				
			||||||
 | 
					    CSMDoc::Document *document = mDocumentManager.addDocument(paths, false);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    mViewManager.addView (document);
 | 
					    mViewManager.addView (document);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int CS::Editor::run()
 | 
					int CS::Editor::run()
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    /// \todo Instead of creating an empty document, open a small welcome dialogue window with buttons for new/load/recent projects
 | 
					    mStartup.show();
 | 
				
			||||||
    createDocument();
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return QApplication::exec();
 | 
					    return QApplication::exec();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -4,7 +4,10 @@
 | 
				
			||||||
#include <QObject>
 | 
					#include <QObject>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "model/doc/documentmanager.hpp"
 | 
					#include "model/doc/documentmanager.hpp"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "view/doc/viewmanager.hpp"
 | 
					#include "view/doc/viewmanager.hpp"
 | 
				
			||||||
 | 
					#include "view/doc/startup.hpp"
 | 
				
			||||||
 | 
					#include "view/doc/opendialog.hpp"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace CS
 | 
					namespace CS
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
| 
						 | 
					@ -16,6 +19,8 @@ namespace CS
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            CSMDoc::DocumentManager mDocumentManager;
 | 
					            CSMDoc::DocumentManager mDocumentManager;
 | 
				
			||||||
            CSVDoc::ViewManager mViewManager;
 | 
					            CSVDoc::ViewManager mViewManager;
 | 
				
			||||||
 | 
					            CSVDoc::StartupDialogue mStartup;
 | 
				
			||||||
 | 
					            OpenDialog mOpenDialog;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            // not implemented
 | 
					            // not implemented
 | 
				
			||||||
            Editor (const Editor&);
 | 
					            Editor (const Editor&);
 | 
				
			||||||
| 
						 | 
					@ -28,9 +33,12 @@ namespace CS
 | 
				
			||||||
            int run();
 | 
					            int run();
 | 
				
			||||||
            ///< \return error status
 | 
					            ///< \return error status
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        public slots:
 | 
					        private slots:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            void createDocument();
 | 
					            void createDocument();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            void loadDocument();
 | 
				
			||||||
 | 
					            void openFiles();
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,10 +1,66 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "document.hpp"
 | 
					#include "document.hpp"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
CSMDoc::Document::Document (const std::string& name)
 | 
					#include <cassert>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void CSMDoc::Document::load (const std::vector<boost::filesystem::path>::const_iterator& begin,
 | 
				
			||||||
 | 
					    const std::vector<boost::filesystem::path>::const_iterator& end, bool lastAsModified)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    assert (begin!=end);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    std::vector<boost::filesystem::path>::const_iterator end2 (end);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (lastAsModified)
 | 
				
			||||||
 | 
					        --end2;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for (std::vector<boost::filesystem::path>::const_iterator iter (begin); iter!=end2; ++iter)
 | 
				
			||||||
 | 
					        getData().loadFile (*iter, true);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (lastAsModified)
 | 
				
			||||||
 | 
					        getData().loadFile (*end2, false);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void CSMDoc::Document::createBase()
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    static const char *sGlobals[] =
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        "Day", "DaysPassed", "GameHour", "Month", "PCRace", "PCVampire", "PCWerewolf", "PCYear", 0
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for (int i=0; sGlobals[i]; ++i)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        ESM::Global record;
 | 
				
			||||||
 | 
					        record.mId = sGlobals[i];
 | 
				
			||||||
 | 
					        record.mValue = i==0 ? 1 : 0;
 | 
				
			||||||
 | 
					        record.mType = ESM::VT_Float;
 | 
				
			||||||
 | 
					        getData().getGlobals().add (record);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					CSMDoc::Document::Document (const std::vector<boost::filesystem::path>& files, bool new_)
 | 
				
			||||||
: mTools (mData)
 | 
					: mTools (mData)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    mName = name; ///< \todo replace with ESX list
 | 
					    if (files.empty())
 | 
				
			||||||
 | 
					        throw std::runtime_error ("Empty content file sequence");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// \todo adjust last file name:
 | 
				
			||||||
 | 
					    /// \li make sure it is located in the data-local directory (adjust path if necessary)
 | 
				
			||||||
 | 
					    /// \li make sure the extension matches the new scheme (change it if necesarry)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    mName = files.back().filename().string();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (files.size()>1 || !new_)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        std::vector<boost::filesystem::path>::const_iterator end = files.end();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (new_)
 | 
				
			||||||
 | 
					            --end;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        load (files.begin(), end, !new_);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (new_ && files.size()==1)
 | 
				
			||||||
 | 
					        createBase();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    connect (&mUndoStack, SIGNAL (cleanChanged (bool)), this, SLOT (modificationStateChanged (bool)));
 | 
					    connect (&mUndoStack, SIGNAL (cleanChanged (bool)), this, SLOT (modificationStateChanged (bool)));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -86,10 +142,10 @@ void CSMDoc::Document::saving()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (mSaveCount>15)
 | 
					    if (mSaveCount>15)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
            mSaveCount = 0;
 | 
					        mSaveCount = 0;
 | 
				
			||||||
            mSaveTimer.stop();
 | 
					        mSaveTimer.stop();
 | 
				
			||||||
            mUndoStack.setClean();
 | 
					        mUndoStack.setClean();
 | 
				
			||||||
            emit stateChanged (getState(), this);
 | 
					        emit stateChanged (getState(), this);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -3,6 +3,8 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <string>
 | 
					#include <string>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <boost/filesystem/path.hpp>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <QUndoStack>
 | 
					#include <QUndoStack>
 | 
				
			||||||
#include <QObject>
 | 
					#include <QObject>
 | 
				
			||||||
#include <QTimer>
 | 
					#include <QTimer>
 | 
				
			||||||
| 
						 | 
					@ -38,10 +40,15 @@ namespace CSMDoc
 | 
				
			||||||
            Document (const Document&);
 | 
					            Document (const Document&);
 | 
				
			||||||
            Document& operator= (const Document&);
 | 
					            Document& operator= (const Document&);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            void load (const std::vector<boost::filesystem::path>::const_iterator& begin,
 | 
				
			||||||
 | 
					                const std::vector<boost::filesystem::path>::const_iterator& end, bool lastAsModified);
 | 
				
			||||||
 | 
					            ///< \param lastAsModified Store the last file in Modified instead of merging it into Base.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            void createBase();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        public:
 | 
					        public:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            Document (const std::string& name);
 | 
					            Document (const std::vector<boost::filesystem::path>& files, bool new_);
 | 
				
			||||||
            ///< \todo replace name with ESX list
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
            QUndoStack& getUndoStack();
 | 
					            QUndoStack& getUndoStack();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -14,9 +14,10 @@ CSMDoc::DocumentManager::~DocumentManager()
 | 
				
			||||||
        delete *iter;
 | 
					        delete *iter;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
CSMDoc::Document *CSMDoc::DocumentManager::addDocument (const std::string& name)
 | 
					CSMDoc::Document *CSMDoc::DocumentManager::addDocument (const std::vector<boost::filesystem::path>& files,
 | 
				
			||||||
 | 
					    bool new_)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    Document *document = new Document (name);
 | 
					    Document *document = new Document (files, new_);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    mDocuments.push_back (document);
 | 
					    mDocuments.push_back (document);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -4,6 +4,8 @@
 | 
				
			||||||
#include <vector>
 | 
					#include <vector>
 | 
				
			||||||
#include <string>
 | 
					#include <string>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <boost/filesystem/path.hpp>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace CSMDoc
 | 
					namespace CSMDoc
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    class Document;
 | 
					    class Document;
 | 
				
			||||||
| 
						 | 
					@ -21,8 +23,11 @@ namespace CSMDoc
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            ~DocumentManager();
 | 
					            ~DocumentManager();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            Document *addDocument (const std::string& name);
 | 
					            Document *addDocument (const std::vector<boost::filesystem::path>& files, bool new_);
 | 
				
			||||||
            ///< The ownership of the returned document is not transferred to the caller.
 | 
					            ///< The ownership of the returned document is not transferred to the caller.
 | 
				
			||||||
 | 
					            ///
 | 
				
			||||||
 | 
					            /// \param new_ Do not load the last content file in \a files and instead create in an
 | 
				
			||||||
 | 
					            /// appropriate way.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            bool removeDocument (Document *document);
 | 
					            bool removeDocument (Document *document);
 | 
				
			||||||
            ///< \return last document removed?
 | 
					            ///< \return last document removed?
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -28,7 +28,8 @@ namespace CSMWorld
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            Display_String,
 | 
					            Display_String,
 | 
				
			||||||
            Display_Integer,
 | 
					            Display_Integer,
 | 
				
			||||||
            Display_Float
 | 
					            Display_Float,
 | 
				
			||||||
 | 
					            Display_Var
 | 
				
			||||||
        };
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        std::string mTitle;
 | 
					        std::string mTitle;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -17,9 +17,9 @@ namespace CSMWorld
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        virtual void set (Record<ESXRecordT>& record, const QVariant& data)
 | 
					        virtual void set (Record<ESXRecordT>& record, const QVariant& data)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            ESXRecordT base = record.getBase();
 | 
					            ESXRecordT record2 = record.get();
 | 
				
			||||||
            base.mValue = data.toFloat();
 | 
					            record2.mValue = data.toFloat();
 | 
				
			||||||
            record.setModified (base);
 | 
					            record.setModified (record2);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        virtual bool isEditable() const
 | 
					        virtual bool isEditable() const
 | 
				
			||||||
| 
						 | 
					@ -91,6 +91,68 @@ namespace CSMWorld
 | 
				
			||||||
            return false;
 | 
					            return false;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    template<typename ESXRecordT>
 | 
				
			||||||
 | 
					    struct VarTypeColumn : public Column<ESXRecordT>
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        VarTypeColumn() : Column<ESXRecordT> ("Type", ColumnBase::Display_Integer) {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        virtual QVariant get (const Record<ESXRecordT>& record) const
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            return static_cast<int> (record.get().mType);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        virtual void set (Record<ESXRecordT>& record, const QVariant& data)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            ESXRecordT record2 = record.get();
 | 
				
			||||||
 | 
					            record2.mType = static_cast<ESM::VarType> (data.toInt());
 | 
				
			||||||
 | 
					            record.setModified (record2);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        virtual bool isEditable() const
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            return true;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    template<typename ESXRecordT>
 | 
				
			||||||
 | 
					    struct VarValueColumn : public Column<ESXRecordT>
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        VarValueColumn() : Column<ESXRecordT> ("Value", ColumnBase::Display_Var) {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        virtual QVariant get (const Record<ESXRecordT>& record) const
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            switch (record.get().mType)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                case ESM::VT_String: return record.get().mStr.c_str(); break;
 | 
				
			||||||
 | 
					                case ESM::VT_Int: return record.get().mI; break;
 | 
				
			||||||
 | 
					                case ESM::VT_Float: return record.get().mF; break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                default: return QVariant();
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        virtual void set (Record<ESXRecordT>& record, const QVariant& data)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            ESXRecordT record2 = record.get();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            switch (record2.mType)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                case ESM::VT_String: record2.mStr = data.toString().toUtf8().constData(); break;
 | 
				
			||||||
 | 
					                case ESM::VT_Int: record2.mI = data.toInt(); break;
 | 
				
			||||||
 | 
					                case ESM::VT_Float: record2.mF = data.toFloat(); break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                default: break;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            record.setModified (record2);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        virtual bool isEditable() const
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            return true;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
| 
						 | 
					@ -5,6 +5,7 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <QAbstractTableModel>
 | 
					#include <QAbstractTableModel>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <components/esm/esmreader.hpp>
 | 
				
			||||||
#include <components/esm/loadglob.hpp>
 | 
					#include <components/esm/loadglob.hpp>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "idtable.hpp"
 | 
					#include "idtable.hpp"
 | 
				
			||||||
| 
						 | 
					@ -27,7 +28,14 @@ CSMWorld::Data::Data()
 | 
				
			||||||
    mGlobals.addColumn (new FixedRecordTypeColumn<ESM::Global> (UniversalId::Type_Global));
 | 
					    mGlobals.addColumn (new FixedRecordTypeColumn<ESM::Global> (UniversalId::Type_Global));
 | 
				
			||||||
    mGlobals.addColumn (new FloatValueColumn<ESM::Global>);
 | 
					    mGlobals.addColumn (new FloatValueColumn<ESM::Global>);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    mGmsts.addColumn (new StringIdColumn<ESM::GameSetting>);
 | 
				
			||||||
 | 
					    mGmsts.addColumn (new RecordStateColumn<ESM::GameSetting>);
 | 
				
			||||||
 | 
					    mGmsts.addColumn (new FixedRecordTypeColumn<ESM::GameSetting> (UniversalId::Type_Gmst));
 | 
				
			||||||
 | 
					    mGmsts.addColumn (new VarTypeColumn<ESM::GameSetting>);
 | 
				
			||||||
 | 
					    mGmsts.addColumn (new VarValueColumn<ESM::GameSetting>);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    addModel (new IdTable (&mGlobals), UniversalId::Type_Globals, UniversalId::Type_Global);
 | 
					    addModel (new IdTable (&mGlobals), UniversalId::Type_Globals, UniversalId::Type_Global);
 | 
				
			||||||
 | 
					    addModel (new IdTable (&mGmsts), UniversalId::Type_Gmsts, UniversalId::Type_Gmst);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
CSMWorld::Data::~Data()
 | 
					CSMWorld::Data::~Data()
 | 
				
			||||||
| 
						 | 
					@ -59,4 +67,31 @@ QAbstractTableModel *CSMWorld::Data::getTableModel (const UniversalId& id)
 | 
				
			||||||
void CSMWorld::Data::merge()
 | 
					void CSMWorld::Data::merge()
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    mGlobals.merge();
 | 
					    mGlobals.merge();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void CSMWorld::Data::loadFile (const boost::filesystem::path& path, bool base)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    ESM::ESMReader reader;
 | 
				
			||||||
 | 
					    /// \todo set encoder
 | 
				
			||||||
 | 
					    reader.open (path.string());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Note: We do not need to send update signals here, because at this point the model is not connected
 | 
				
			||||||
 | 
					    // to any view.
 | 
				
			||||||
 | 
					    while (reader.hasMoreRecs())
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        ESM::NAME n = reader.getRecName();
 | 
				
			||||||
 | 
					        reader.getRecHeader();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        switch (n.val)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            case ESM::REC_GLOB: mGlobals.load (reader, base); break;
 | 
				
			||||||
 | 
					            case ESM::REC_GMST: mGmsts.load (reader, base); break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            default:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                /// \todo throw an exception instead, once all records are implemented
 | 
				
			||||||
 | 
					                reader.skipRecord();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -4,7 +4,10 @@
 | 
				
			||||||
#include <map>
 | 
					#include <map>
 | 
				
			||||||
#include <vector>
 | 
					#include <vector>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <boost/filesystem/path.hpp>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <components/esm/loadglob.hpp>
 | 
					#include <components/esm/loadglob.hpp>
 | 
				
			||||||
 | 
					#include <components/esm/loadgmst.hpp>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "idcollection.hpp"
 | 
					#include "idcollection.hpp"
 | 
				
			||||||
#include "universalid.hpp"
 | 
					#include "universalid.hpp"
 | 
				
			||||||
| 
						 | 
					@ -16,6 +19,7 @@ namespace CSMWorld
 | 
				
			||||||
    class Data
 | 
					    class Data
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
            IdCollection<ESM::Global> mGlobals;
 | 
					            IdCollection<ESM::Global> mGlobals;
 | 
				
			||||||
 | 
					            IdCollection<ESM::GameSetting> mGmsts;
 | 
				
			||||||
            std::vector<QAbstractTableModel *> mModels;
 | 
					            std::vector<QAbstractTableModel *> mModels;
 | 
				
			||||||
            std::map<UniversalId::Type, QAbstractTableModel *> mModelIndex;
 | 
					            std::map<UniversalId::Type, QAbstractTableModel *> mModelIndex;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -44,6 +48,9 @@ namespace CSMWorld
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            void merge();
 | 
					            void merge();
 | 
				
			||||||
            ///< Merge modified into base.
 | 
					            ///< Merge modified into base.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            void loadFile (const boost::filesystem::path& path, bool base);
 | 
				
			||||||
 | 
					            ///< Merging content of a file into base or modified.
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -3,4 +3,4 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
CSMWorld::IdCollectionBase::IdCollectionBase() {}
 | 
					CSMWorld::IdCollectionBase::IdCollectionBase() {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
CSMWorld::IdCollectionBase::~IdCollectionBase() {}
 | 
					CSMWorld::IdCollectionBase::~IdCollectionBase() {}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -11,9 +11,12 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <QVariant>
 | 
					#include <QVariant>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "columnbase.hpp"
 | 
					#include <components/esm/esmreader.hpp>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <components/misc/stringops.hpp>
 | 
					#include <components/misc/stringops.hpp>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "columnbase.hpp"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace CSMWorld
 | 
					namespace CSMWorld
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    class IdCollectionBase
 | 
					    class IdCollectionBase
 | 
				
			||||||
| 
						 | 
					@ -67,9 +70,11 @@ namespace CSMWorld
 | 
				
			||||||
            virtual std::string getId (const RecordBase& record) const = 0;
 | 
					            virtual std::string getId (const RecordBase& record) const = 0;
 | 
				
			||||||
            ///< Return ID for \a record.
 | 
					            ///< Return ID for \a record.
 | 
				
			||||||
            ///
 | 
					            ///
 | 
				
			||||||
            /// \attention Throw san exception, if the type of \a record does not match.
 | 
					            /// \attention Throws an exception, if the type of \a record does not match.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            virtual const RecordBase& getRecord (const std::string& id) const = 0;
 | 
					            virtual const RecordBase& getRecord (const std::string& id) const = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            virtual void load (ESM::ESMReader& reader, bool base) = 0;
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    ///< \brief Collection of ID-based records
 | 
					    ///< \brief Collection of ID-based records
 | 
				
			||||||
| 
						 | 
					@ -136,6 +141,8 @@ namespace CSMWorld
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            virtual const RecordBase& getRecord (const std::string& id) const;
 | 
					            virtual const RecordBase& getRecord (const std::string& id) const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            virtual void load (ESM::ESMReader& reader, bool base);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            void addColumn (Column<ESXRecordT> *column);
 | 
					            void addColumn (Column<ESXRecordT> *column);
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -309,6 +316,62 @@ namespace CSMWorld
 | 
				
			||||||
        return (record2.isModified() ? record2.mModified : record2.mBase).mId;
 | 
					        return (record2.isModified() ? record2.mModified : record2.mBase).mId;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    template<typename ESXRecordT>
 | 
				
			||||||
 | 
					    void IdCollection<ESXRecordT>::load (ESM::ESMReader& reader, bool base)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        std::string id = reader.getHNOString ("NAME");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        int index = searchId (id);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (reader.isNextSub ("DELE"))
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            reader.skipRecord();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if (index==-1)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                // deleting a record that does not exist
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                // ignore it for now
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                /// \todo report the problem to the user
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            else if (base)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                removeRows (index, 1);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            else
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                mRecords[index].mState = RecordBase::State_Deleted;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        else
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            ESXRecordT record;
 | 
				
			||||||
 | 
					            record.mId = id;
 | 
				
			||||||
 | 
					            record.load (reader);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if (index==-1)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                // new record
 | 
				
			||||||
 | 
					                Record<ESXRecordT> record2;
 | 
				
			||||||
 | 
					                record2.mState = base ? RecordBase::State_BaseOnly : RecordBase::State_ModifiedOnly;
 | 
				
			||||||
 | 
					                (base ? record2.mBase : record2.mModified) = record;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                appendRecord (record2);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            else
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                // old record
 | 
				
			||||||
 | 
					                Record<ESXRecordT>& record2 = mRecords[index];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                if (base)
 | 
				
			||||||
 | 
					                    record2.mBase = record;
 | 
				
			||||||
 | 
					                else
 | 
				
			||||||
 | 
					                    record2.setModified (record);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    template<typename ESXRecordT>
 | 
					    template<typename ESXRecordT>
 | 
				
			||||||
    const RecordBase& IdCollection<ESXRecordT>::getRecord (const std::string& id) const
 | 
					    const RecordBase& IdCollection<ESXRecordT>::getRecord (const std::string& id) const
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -18,6 +18,7 @@ namespace
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        { CSMWorld::UniversalId::Class_None, CSMWorld::UniversalId::Type_None, "empty" },
 | 
					        { CSMWorld::UniversalId::Class_None, CSMWorld::UniversalId::Type_None, "empty" },
 | 
				
			||||||
        { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Globals, "Global Variables" },
 | 
					        { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Globals, "Global Variables" },
 | 
				
			||||||
 | 
					        { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Gmsts, "Game Settings" },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        { CSMWorld::UniversalId::Class_None, CSMWorld::UniversalId::Type_None, 0 } // end marker
 | 
					        { CSMWorld::UniversalId::Class_None, CSMWorld::UniversalId::Type_None, 0 } // end marker
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
| 
						 | 
					@ -25,6 +26,7 @@ namespace
 | 
				
			||||||
    static const TypeData sIdArg[] =
 | 
					    static const TypeData sIdArg[] =
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Global, "Global Variable" },
 | 
					        { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Global, "Global Variable" },
 | 
				
			||||||
 | 
					        { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Gmst, "Game Setting" },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        { CSMWorld::UniversalId::Class_None, CSMWorld::UniversalId::Type_None, 0 } // end marker
 | 
					        { CSMWorld::UniversalId::Class_None, CSMWorld::UniversalId::Type_None, 0 } // end marker
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -33,12 +33,12 @@ namespace CSMWorld
 | 
				
			||||||
            enum Type
 | 
					            enum Type
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                Type_None,
 | 
					                Type_None,
 | 
				
			||||||
 | 
					 | 
				
			||||||
                Type_Globals,
 | 
					                Type_Globals,
 | 
				
			||||||
 | 
					 | 
				
			||||||
                Type_Global,
 | 
					                Type_Global,
 | 
				
			||||||
 | 
					                Type_VerificationResults,
 | 
				
			||||||
 | 
					                Type_Gmsts,
 | 
				
			||||||
 | 
					                Type_Gmst
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                Type_VerificationResults
 | 
					 | 
				
			||||||
            };
 | 
					            };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        private:
 | 
					        private:
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										62
									
								
								apps/opencs/view/doc/opendialog.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										62
									
								
								apps/opencs/view/doc/opendialog.cpp
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,62 @@
 | 
				
			||||||
 | 
					#include <QVBoxLayout>
 | 
				
			||||||
 | 
					#include <QDialogButtonBox>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <components/fileorderlist/datafileslist.hpp>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "opendialog.hpp"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					OpenDialog::OpenDialog(QWidget * parent) : QDialog(parent)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    QVBoxLayout *layout = new QVBoxLayout(this);
 | 
				
			||||||
 | 
					    mFileSelector = new DataFilesList(mCfgMgr, this);
 | 
				
			||||||
 | 
					    layout->addWidget(mFileSelector);
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    //FIXME - same as DataFilesPage::setupDataFiles
 | 
				
			||||||
 | 
					    // We use the Configuration Manager to retrieve the configuration values
 | 
				
			||||||
 | 
					    boost::program_options::variables_map variables;
 | 
				
			||||||
 | 
					    boost::program_options::options_description desc;
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    desc.add_options()
 | 
				
			||||||
 | 
					    ("data", boost::program_options::value<Files::PathContainer>()->default_value(Files::PathContainer(), "data")->multitoken())
 | 
				
			||||||
 | 
					    ("data-local", boost::program_options::value<std::string>()->default_value(""))
 | 
				
			||||||
 | 
					    ("fs-strict", boost::program_options::value<bool>()->implicit_value(true)->default_value(false))
 | 
				
			||||||
 | 
					    ("encoding", boost::program_options::value<std::string>()->default_value("win1252"));
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    boost::program_options::notify(variables);
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    mCfgMgr.readConfiguration(variables, desc);
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    Files::PathContainer mDataDirs, mDataLocal;
 | 
				
			||||||
 | 
					    if (!variables["data"].empty()) {
 | 
				
			||||||
 | 
					        mDataDirs = Files::PathContainer(variables["data"].as<Files::PathContainer>());
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    std::string local = variables["data-local"].as<std::string>();
 | 
				
			||||||
 | 
					    if (!local.empty()) {
 | 
				
			||||||
 | 
					        mDataLocal.push_back(Files::PathContainer::value_type(local));
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    mCfgMgr.processPaths(mDataDirs);
 | 
				
			||||||
 | 
					    mCfgMgr.processPaths(mDataLocal);
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    // Set the charset for reading the esm/esp files
 | 
				
			||||||
 | 
					    QString encoding = QString::fromStdString(variables["encoding"].as<std::string>());
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    Files::PathContainer dataDirs;
 | 
				
			||||||
 | 
					    dataDirs.insert(dataDirs.end(), mDataDirs.begin(), mDataDirs.end());
 | 
				
			||||||
 | 
					    dataDirs.insert(dataDirs.end(), mDataLocal.begin(), mDataLocal.end());
 | 
				
			||||||
 | 
					    mFileSelector->setupDataFiles(dataDirs, encoding);
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    buttonBox = new QDialogButtonBox(QDialogButtonBox::Open | QDialogButtonBox::Cancel, Qt::Horizontal, this);
 | 
				
			||||||
 | 
					    connect(buttonBox, SIGNAL(accepted()), this, SLOT(accept()));
 | 
				
			||||||
 | 
					    connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject()));
 | 
				
			||||||
 | 
					    layout->addWidget(buttonBox);
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    setLayout(layout);
 | 
				
			||||||
 | 
					    setWindowTitle(tr("Open"));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void OpenDialog::getFileList(std::vector<boost::filesystem::path>& paths)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    mFileSelector->selectedFiles(paths);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										17
									
								
								apps/opencs/view/doc/opendialog.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								apps/opencs/view/doc/opendialog.hpp
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,17 @@
 | 
				
			||||||
 | 
					#include <qdialog.h>
 | 
				
			||||||
 | 
					#include <components/files/configurationmanager.hpp>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class DataFilesList;
 | 
				
			||||||
 | 
					class QDialogButtonBox;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class OpenDialog : public QDialog {
 | 
				
			||||||
 | 
					    Q_OBJECT
 | 
				
			||||||
 | 
					public:
 | 
				
			||||||
 | 
					    OpenDialog(QWidget * parent = 0);
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    void getFileList(std::vector<boost::filesystem::path>& paths);
 | 
				
			||||||
 | 
					private:
 | 
				
			||||||
 | 
					    DataFilesList * mFileSelector;
 | 
				
			||||||
 | 
					    QDialogButtonBox * buttonBox;
 | 
				
			||||||
 | 
					    Files::ConfigurationManager mCfgMgr;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
							
								
								
									
										20
									
								
								apps/opencs/view/doc/startup.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								apps/opencs/view/doc/startup.cpp
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,20 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "startup.hpp"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <QPushButton>
 | 
				
			||||||
 | 
					#include <QHBoxLayout>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					CSVDoc::StartupDialogue::StartupDialogue()
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    QHBoxLayout *layout = new QHBoxLayout (this);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    QPushButton *createDocument = new QPushButton ("new", this);
 | 
				
			||||||
 | 
					    connect (createDocument, SIGNAL (clicked()), this, SIGNAL (createDocument()));
 | 
				
			||||||
 | 
					    layout->addWidget (createDocument);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    QPushButton *loadDocument = new QPushButton ("load", this);
 | 
				
			||||||
 | 
					    connect (loadDocument, SIGNAL (clicked()), this, SIGNAL (loadDocument()));
 | 
				
			||||||
 | 
					    layout->addWidget (loadDocument);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    setLayout (layout);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										24
									
								
								apps/opencs/view/doc/startup.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								apps/opencs/view/doc/startup.hpp
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,24 @@
 | 
				
			||||||
 | 
					#ifndef CSV_DOC_STARTUP_H
 | 
				
			||||||
 | 
					#define CSV_DOC_STARTUP_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <QWidget>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace CSVDoc
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    class StartupDialogue : public QWidget
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        Q_OBJECT
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            StartupDialogue();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        signals:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            void createDocument();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            void loadDocument();
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
| 
						 | 
					@ -32,6 +32,10 @@ void CSVDoc::View::setupFileMenu()
 | 
				
			||||||
    connect (new_, SIGNAL (triggered()), this, SIGNAL (newDocumentRequest()));
 | 
					    connect (new_, SIGNAL (triggered()), this, SIGNAL (newDocumentRequest()));
 | 
				
			||||||
    file->addAction (new_);
 | 
					    file->addAction (new_);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    QAction *open = new QAction (tr ("&Open"), this);
 | 
				
			||||||
 | 
					    connect (open, SIGNAL (triggered()), this, SIGNAL (loadDocumentRequest()));
 | 
				
			||||||
 | 
					    file->addAction (open);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    mSave = new QAction (tr ("&Save"), this);
 | 
					    mSave = new QAction (tr ("&Save"), this);
 | 
				
			||||||
    connect (mSave, SIGNAL (triggered()), this, SLOT (save()));
 | 
					    connect (mSave, SIGNAL (triggered()), this, SLOT (save()));
 | 
				
			||||||
    file->addAction (mSave);
 | 
					    file->addAction (mSave);
 | 
				
			||||||
| 
						 | 
					@ -67,6 +71,10 @@ void CSVDoc::View::setupWorldMenu()
 | 
				
			||||||
    connect (globals, SIGNAL (triggered()), this, SLOT (addGlobalsSubView()));
 | 
					    connect (globals, SIGNAL (triggered()), this, SLOT (addGlobalsSubView()));
 | 
				
			||||||
    world->addAction (globals);
 | 
					    world->addAction (globals);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    QAction *gmsts = new QAction (tr ("Game settings"), this);
 | 
				
			||||||
 | 
					    connect (gmsts, SIGNAL (triggered()), this, SLOT (addGmstsSubView()));
 | 
				
			||||||
 | 
					    world->addAction (gmsts);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    mVerify = new QAction (tr ("&Verify"), this);
 | 
					    mVerify = new QAction (tr ("&Verify"), this);
 | 
				
			||||||
    connect (mVerify, SIGNAL (triggered()), this, SLOT (verify()));
 | 
					    connect (mVerify, SIGNAL (triggered()), this, SLOT (verify()));
 | 
				
			||||||
    world->addAction (mVerify);
 | 
					    world->addAction (mVerify);
 | 
				
			||||||
| 
						 | 
					@ -213,4 +221,9 @@ void CSVDoc::View::verify()
 | 
				
			||||||
void CSVDoc::View::addGlobalsSubView()
 | 
					void CSVDoc::View::addGlobalsSubView()
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    addSubView (CSMWorld::UniversalId::Type_Globals);
 | 
					    addSubView (CSMWorld::UniversalId::Type_Globals);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void CSVDoc::View::addGmstsSubView()
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    addSubView (CSMWorld::UniversalId::Type_Gmsts);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -84,6 +84,8 @@ namespace CSVDoc
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            void newDocumentRequest();
 | 
					            void newDocumentRequest();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            void loadDocumentRequest();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        public slots:
 | 
					        public slots:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            void addSubView (const CSMWorld::UniversalId& id);
 | 
					            void addSubView (const CSMWorld::UniversalId& id);
 | 
				
			||||||
| 
						 | 
					@ -97,6 +99,8 @@ namespace CSVDoc
 | 
				
			||||||
            void verify();
 | 
					            void verify();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            void addGlobalsSubView();
 | 
					            void addGlobalsSubView();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            void addGmstsSubView();
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -57,6 +57,7 @@ CSVDoc::View *CSVDoc::ViewManager::addView (CSMDoc::Document *document)
 | 
				
			||||||
    view->show();
 | 
					    view->show();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    connect (view, SIGNAL (newDocumentRequest ()), this, SIGNAL (newDocumentRequest()));
 | 
					    connect (view, SIGNAL (newDocumentRequest ()), this, SIGNAL (newDocumentRequest()));
 | 
				
			||||||
 | 
					    connect (view, SIGNAL (loadDocumentRequest ()), this, SIGNAL (loadDocumentRequest()));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    updateIndices();
 | 
					    updateIndices();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -46,6 +46,8 @@ namespace CSVDoc
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            void newDocumentRequest();
 | 
					            void newDocumentRequest();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            void loadDocumentRequest();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        private slots:
 | 
					        private slots:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            void documentStateChanged (int state, CSMDoc::Document *document);
 | 
					            void documentStateChanged (int state, CSMDoc::Document *document);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -64,6 +64,8 @@ CSVWorld::DialogueSubView::DialogueSubView (const CSMWorld::UniversalId& id, CSM
 | 
				
			||||||
                        /// \todo configure widget properly (range, format?)
 | 
					                        /// \todo configure widget properly (range, format?)
 | 
				
			||||||
                        layout->addWidget (widget = new QDoubleSpinBox, i, 1);
 | 
					                        layout->addWidget (widget = new QDoubleSpinBox, i, 1);
 | 
				
			||||||
                        break;
 | 
					                        break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    default: break; // silence warnings for other times for now
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            else
 | 
					            else
 | 
				
			||||||
| 
						 | 
					@ -76,6 +78,8 @@ CSVWorld::DialogueSubView::DialogueSubView (const CSMWorld::UniversalId& id, CSM
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                        layout->addWidget (widget = new QLabel, i, 1);
 | 
					                        layout->addWidget (widget = new QLabel, i, 1);
 | 
				
			||||||
                        break;
 | 
					                        break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    default: break; // silence warnings for other times for now
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -11,6 +11,9 @@ void CSVWorld::addSubViewFactories (CSVDoc::SubViewFactoryManager& manager)
 | 
				
			||||||
    manager.add (CSMWorld::UniversalId::Type_Globals,
 | 
					    manager.add (CSMWorld::UniversalId::Type_Globals,
 | 
				
			||||||
        new CSVDoc::SubViewFactoryWithCreateFlag<TableSubView> (true));
 | 
					        new CSVDoc::SubViewFactoryWithCreateFlag<TableSubView> (true));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    manager.add (CSMWorld::UniversalId::Type_Gmsts,
 | 
				
			||||||
 | 
					        new CSVDoc::SubViewFactoryWithCreateFlag<TableSubView> (false));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    manager.add (CSMWorld::UniversalId::Type_Global,
 | 
					    manager.add (CSMWorld::UniversalId::Type_Global,
 | 
				
			||||||
        new CSVDoc::SubViewFactoryWithCreateFlag<DialogueSubView> (true));
 | 
					        new CSVDoc::SubViewFactoryWithCreateFlag<DialogueSubView> (true));
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -41,7 +41,7 @@ add_openmw_dir (mwscript
 | 
				
			||||||
    locals scriptmanagerimp compilercontext interpretercontext cellextensions miscextensions
 | 
					    locals scriptmanagerimp compilercontext interpretercontext cellextensions miscextensions
 | 
				
			||||||
    guiextensions soundextensions skyextensions statsextensions containerextensions
 | 
					    guiextensions soundextensions skyextensions statsextensions containerextensions
 | 
				
			||||||
    aiextensions controlextensions extensions globalscripts ref dialogueextensions
 | 
					    aiextensions controlextensions extensions globalscripts ref dialogueextensions
 | 
				
			||||||
    animationextensions transformationextensions consoleextensions userextensions
 | 
					    animationextensions transformationextensions consoleextensions userextensions locals
 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
add_openmw_dir (mwsound
 | 
					add_openmw_dir (mwsound
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -207,18 +207,31 @@ void OMW::Engine::setCell (const std::string& cellName)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Set master file (esm)
 | 
					// Set master file (esm)
 | 
				
			||||||
// - If the given name does not have an extension, ".esm" is added automatically
 | 
					// - If the given name does not have an extension, ".esm" is added automatically
 | 
				
			||||||
// - Currently OpenMW only supports one master at the same time.
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
void OMW::Engine::addMaster (const std::string& master)
 | 
					void OMW::Engine::addMaster (const std::string& master)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    assert (mMaster.empty());
 | 
					    mMaster.push_back(master);
 | 
				
			||||||
    mMaster = master;
 | 
					    std::string &str = mMaster.back();
 | 
				
			||||||
 | 
					 
 | 
				
			||||||
    // Append .esm if not already there
 | 
					    // Append .esm if not already there
 | 
				
			||||||
    std::string::size_type sep = mMaster.find_last_of (".");
 | 
					    std::string::size_type sep = str.find_last_of (".");
 | 
				
			||||||
    if (sep == std::string::npos)
 | 
					    if (sep == std::string::npos)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        mMaster += ".esm";
 | 
					        str += ".esm";
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Add plugin file (esp)
 | 
				
			||||||
 | 
					void OMW::Engine::addPlugin (const std::string& plugin)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    mPlugins.push_back(plugin);
 | 
				
			||||||
 | 
					    std::string &str = mPlugins.back();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Append .esp if not already there
 | 
				
			||||||
 | 
					    std::string::size_type sep = str.find_last_of (".");
 | 
				
			||||||
 | 
					    if (sep == std::string::npos)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        str += ".esp";
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -323,13 +336,13 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings)
 | 
				
			||||||
    MWGui::CursorReplace replacer;
 | 
					    MWGui::CursorReplace replacer;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Create the world
 | 
					    // Create the world
 | 
				
			||||||
    mEnvironment.setWorld (new MWWorld::World (*mOgre, mFileCollections, mMaster,
 | 
					    mEnvironment.setWorld( new MWWorld::World (*mOgre, mFileCollections, mMaster, mPlugins,
 | 
				
			||||||
        mResDir, mCfgMgr.getCachePath(), mNewGame, mEncoder, mFallbackMap,
 | 
					        mResDir, mCfgMgr.getCachePath(), mNewGame, mEncoder, mFallbackMap,
 | 
				
			||||||
        mActivationDistanceOverride));
 | 
					        mActivationDistanceOverride));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    //Load translation data
 | 
					    //Load translation data
 | 
				
			||||||
    mTranslationDataStorage.setEncoder(mEncoder);
 | 
					    mTranslationDataStorage.setEncoder(mEncoder);
 | 
				
			||||||
    mTranslationDataStorage.loadTranslationData(mFileCollections, mMaster);
 | 
					    mTranslationDataStorage.loadTranslationData(mFileCollections, mMaster[0]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Create window manager - this manages all the MW-specific GUI windows
 | 
					    // Create window manager - this manages all the MW-specific GUI windows
 | 
				
			||||||
    MWScript::registerExtensions (mExtensions);
 | 
					    MWScript::registerExtensions (mExtensions);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -67,7 +67,8 @@ namespace OMW
 | 
				
			||||||
            boost::filesystem::path mResDir;
 | 
					            boost::filesystem::path mResDir;
 | 
				
			||||||
            OEngine::Render::OgreRenderer *mOgre;
 | 
					            OEngine::Render::OgreRenderer *mOgre;
 | 
				
			||||||
            std::string mCellName;
 | 
					            std::string mCellName;
 | 
				
			||||||
            std::string mMaster;
 | 
					            std::vector<std::string> mMaster;
 | 
				
			||||||
 | 
					            std::vector<std::string> mPlugins;
 | 
				
			||||||
            int mFpsLevel;
 | 
					            int mFpsLevel;
 | 
				
			||||||
            bool mDebug;
 | 
					            bool mDebug;
 | 
				
			||||||
            bool mVerboseScripts;
 | 
					            bool mVerboseScripts;
 | 
				
			||||||
| 
						 | 
					@ -132,9 +133,12 @@ namespace OMW
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            /// Set master file (esm)
 | 
					            /// Set master file (esm)
 | 
				
			||||||
            /// - If the given name does not have an extension, ".esm" is added automatically
 | 
					            /// - If the given name does not have an extension, ".esm" is added automatically
 | 
				
			||||||
            /// - Currently OpenMW only supports one master at the same time.
 | 
					 | 
				
			||||||
            void addMaster(const std::string& master);
 | 
					            void addMaster(const std::string& master);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            /// Same as "addMaster", but for plugin files (esp)
 | 
				
			||||||
 | 
					            /// - If the given name does not have an extension, ".esp" is added automatically
 | 
				
			||||||
 | 
					            void addPlugin(const std::string& plugin);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            /// Enable fps counter
 | 
					            /// Enable fps counter
 | 
				
			||||||
            void showFPS(int level);
 | 
					            void showFPS(int level);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -211,18 +211,21 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat
 | 
				
			||||||
        master.push_back("Morrowind");
 | 
					        master.push_back("Morrowind");
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (master.size() > 1)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        std::cout
 | 
					 | 
				
			||||||
            << "Ignoring all but the first master file (multiple master files not yet supported)."
 | 
					 | 
				
			||||||
            << std::endl;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    engine.addMaster(master[0]);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    StringsVector plugin = variables["plugin"].as<StringsVector>();
 | 
					    StringsVector plugin = variables["plugin"].as<StringsVector>();
 | 
				
			||||||
    if (!plugin.empty())
 | 
					    // Removed check for 255 files, which would be the hard-coded limit in Morrowind.
 | 
				
			||||||
 | 
					    //  I'll keep the following variable in, maybe we can use it for something different.
 | 
				
			||||||
 | 
					    //  Say, a feedback like "loading file x/cnt".
 | 
				
			||||||
 | 
					    // Commenting this out for now to silence compiler warning.
 | 
				
			||||||
 | 
					    //int cnt = master.size() + plugin.size();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Prepare loading master/plugin files (i.e. send filenames to engine)
 | 
				
			||||||
 | 
					    for (std::vector<std::string>::size_type i = 0; i < master.size(); i++)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        std::cout << "Ignoring plugin files (plugins not yet supported)." << std::endl;
 | 
					        engine.addMaster(master[i]);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    for (std::vector<std::string>::size_type i = 0; i < plugin.size(); i++)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        engine.addPlugin(plugin[i]);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // startup-settings
 | 
					    // startup-settings
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -113,7 +113,7 @@ namespace MWBase
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            virtual const MWWorld::ESMStore& getStore() const = 0;
 | 
					            virtual const MWWorld::ESMStore& getStore() const = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            virtual ESM::ESMReader& getEsmReader() = 0;
 | 
					            virtual std::vector<ESM::ESMReader>& getEsmReader() = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            virtual MWWorld::LocalScripts& getLocalScripts() = 0;
 | 
					            virtual MWWorld::LocalScripts& getLocalScripts() = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -7,6 +7,8 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <boost/lexical_cast.hpp>
 | 
					#include <boost/lexical_cast.hpp>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <components/compiler/locals.hpp>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "../mwbase/world.hpp"
 | 
					#include "../mwbase/world.hpp"
 | 
				
			||||||
#include "../mwbase/environment.hpp"
 | 
					#include "../mwbase/environment.hpp"
 | 
				
			||||||
#include "../mwbase/soundmanager.hpp"
 | 
					#include "../mwbase/soundmanager.hpp"
 | 
				
			||||||
| 
						 | 
					@ -240,6 +242,12 @@ namespace MWGui
 | 
				
			||||||
            if (it != invStore.end() && *it == item)
 | 
					            if (it != invStore.end() && *it == item)
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                invStore.equip(slot, invStore.end());
 | 
					                invStore.equip(slot, invStore.end());
 | 
				
			||||||
 | 
					                std::string script = MWWorld::Class::get(*it).getScript(*it);
 | 
				
			||||||
 | 
					                
 | 
				
			||||||
 | 
					                // Unset OnPCEquip Variable on item's script, if it has a script with that variable declared
 | 
				
			||||||
 | 
					                if(script != "")
 | 
				
			||||||
 | 
					                    (*it).mRefData->getLocals().setVarByInt(script, "onpcequip", 0);
 | 
				
			||||||
 | 
					                
 | 
				
			||||||
                return;
 | 
					                return;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -144,7 +144,7 @@ namespace MWRender
 | 
				
			||||||
                std::map<uint16_t, int> indexes;
 | 
					                std::map<uint16_t, int> indexes;
 | 
				
			||||||
                initTerrainTextures(&terrainData, cellX, cellY,
 | 
					                initTerrainTextures(&terrainData, cellX, cellY,
 | 
				
			||||||
                                    x * numTextures, y * numTextures,
 | 
					                                    x * numTextures, y * numTextures,
 | 
				
			||||||
                                    numTextures, indexes);
 | 
					                                    numTextures, indexes, land->mPlugin);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                if (mTerrainGroup.getTerrain(terrainX, terrainY) == NULL)
 | 
					                if (mTerrainGroup.getTerrain(terrainX, terrainY) == NULL)
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
| 
						 | 
					@ -213,8 +213,13 @@ namespace MWRender
 | 
				
			||||||
    void TerrainManager::initTerrainTextures(Terrain::ImportData* terrainData,
 | 
					    void TerrainManager::initTerrainTextures(Terrain::ImportData* terrainData,
 | 
				
			||||||
                                             int cellX, int cellY,
 | 
					                                             int cellX, int cellY,
 | 
				
			||||||
                                             int fromX, int fromY, int size,
 | 
					                                             int fromX, int fromY, int size,
 | 
				
			||||||
                                             std::map<uint16_t, int>& indexes)
 | 
					                                             std::map<uint16_t, int>& indexes, size_t plugin)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
 | 
					        // FIXME: In a multiple esm configuration, we have multiple palettes. Since this code
 | 
				
			||||||
 | 
					        //  crosses cell boundaries, we no longer have a unique terrain palette. Instead, we need
 | 
				
			||||||
 | 
					        //  to adopt the following code for a dynamic palette. And this is evil - the current design
 | 
				
			||||||
 | 
					        //  does not work well for this task...
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        assert(terrainData != NULL && "Must have valid terrain data");
 | 
					        assert(terrainData != NULL && "Must have valid terrain data");
 | 
				
			||||||
        assert(fromX >= 0 && fromY >= 0 &&
 | 
					        assert(fromX >= 0 && fromY >= 0 &&
 | 
				
			||||||
               "Can't get a terrain texture on terrain outside the current cell");
 | 
					               "Can't get a terrain texture on terrain outside the current cell");
 | 
				
			||||||
| 
						 | 
					@ -227,12 +232,20 @@ namespace MWRender
 | 
				
			||||||
        //
 | 
					        //
 | 
				
			||||||
        //If we don't sort the ltex indexes, the splatting order may differ between
 | 
					        //If we don't sort the ltex indexes, the splatting order may differ between
 | 
				
			||||||
        //cells which may lead to inconsistent results when shading between cells
 | 
					        //cells which may lead to inconsistent results when shading between cells
 | 
				
			||||||
 | 
					        int num = MWBase::Environment::get().getWorld()->getStore().get<ESM::LandTexture>().getSize(plugin);
 | 
				
			||||||
        std::set<uint16_t> ltexIndexes;
 | 
					        std::set<uint16_t> ltexIndexes;
 | 
				
			||||||
        for ( int y = fromY - 1; y < fromY + size + 1; y++ )
 | 
					        for ( int y = fromY - 1; y < fromY + size + 1; y++ )
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            for ( int x = fromX - 1; x < fromX + size + 1; x++ )
 | 
					            for ( int x = fromX - 1; x < fromX + size + 1; x++ )
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                ltexIndexes.insert(getLtexIndexAt(cellX, cellY, x, y));
 | 
					                int idx = getLtexIndexAt(cellX, cellY, x, y);
 | 
				
			||||||
 | 
					                // This is a quick hack to prevent the program from trying to fetch textures
 | 
				
			||||||
 | 
					                //  from a neighboring cell, which might originate from a different plugin,
 | 
				
			||||||
 | 
					                //  and use a separate texture palette. Right now, we simply cast it to the
 | 
				
			||||||
 | 
					                //  default texture (i.e. 0).
 | 
				
			||||||
 | 
					                if (idx > num)
 | 
				
			||||||
 | 
					                  idx = 0;
 | 
				
			||||||
 | 
					                ltexIndexes.insert(idx);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -244,7 +257,7 @@ namespace MWRender
 | 
				
			||||||
              iter != ltexIndexes.end();
 | 
					              iter != ltexIndexes.end();
 | 
				
			||||||
              ++iter )
 | 
					              ++iter )
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            const uint16_t ltexIndex = *iter;
 | 
					            uint16_t ltexIndex = *iter;
 | 
				
			||||||
            //this is the base texture, so we can ignore this at present
 | 
					            //this is the base texture, so we can ignore this at present
 | 
				
			||||||
            if ( ltexIndex == baseTexture )
 | 
					            if ( ltexIndex == baseTexture )
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
| 
						 | 
					@ -260,8 +273,11 @@ namespace MWRender
 | 
				
			||||||
                const MWWorld::Store<ESM::LandTexture> <exStore =
 | 
					                const MWWorld::Store<ESM::LandTexture> <exStore =
 | 
				
			||||||
                    MWBase::Environment::get().getWorld()->getStore().get<ESM::LandTexture>();
 | 
					                    MWBase::Environment::get().getWorld()->getStore().get<ESM::LandTexture>();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                assert( (int)ltexStore.getSize() >= (int)ltexIndex - 1 &&
 | 
					                // NOTE: using the quick hack above, we should no longer end up with textures indices
 | 
				
			||||||
                       "LAND.VTEX must be within the bounds of the LTEX array");
 | 
					                //  that are out of bounds. However, I haven't updated the test to a multi-palette
 | 
				
			||||||
 | 
					                //  system yet. We probably need more work here, so we skip it for now.
 | 
				
			||||||
 | 
					                //assert( (int)ltexStore.getSize() >= (int)ltexIndex - 1 &&
 | 
				
			||||||
 | 
					                       //"LAND.VTEX must be within the bounds of the LTEX array");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                std::string texture;
 | 
					                std::string texture;
 | 
				
			||||||
                if ( ltexIndex == 0 )
 | 
					                if ( ltexIndex == 0 )
 | 
				
			||||||
| 
						 | 
					@ -270,7 +286,7 @@ namespace MWRender
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
                else
 | 
					                else
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
                    texture = ltexStore.search(ltexIndex-1)->mTexture;
 | 
					                    texture = ltexStore.search(ltexIndex-1, plugin)->mTexture;
 | 
				
			||||||
                    //TODO this is needed due to MWs messed up texture handling
 | 
					                    //TODO this is needed due to MWs messed up texture handling
 | 
				
			||||||
                    texture = texture.substr(0, texture.rfind(".")) + ".dds";
 | 
					                    texture = texture.substr(0, texture.rfind(".")) + ".dds";
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -75,7 +75,7 @@ namespace MWRender{
 | 
				
			||||||
        void initTerrainTextures(Ogre::Terrain::ImportData* terrainData,
 | 
					        void initTerrainTextures(Ogre::Terrain::ImportData* terrainData,
 | 
				
			||||||
                                 int cellX, int cellY,
 | 
					                                 int cellX, int cellY,
 | 
				
			||||||
                                 int fromX, int fromY, int size,
 | 
					                                 int fromX, int fromY, int size,
 | 
				
			||||||
                                 std::map<uint16_t, int>& indexes);
 | 
					                                 std::map<uint16_t, int>& indexes, size_t plugin);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        /**
 | 
					        /**
 | 
				
			||||||
         * Creates the blend (splatting maps) for the given terrain from the ltex data.
 | 
					         * Creates the blend (splatting maps) for the given terrain from the ltex data.
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -50,6 +50,14 @@ namespace MWScript
 | 
				
			||||||
                    MWWorld::ManualRef ref (MWBase::Environment::get().getWorld()->getStore(), item);
 | 
					                    MWWorld::ManualRef ref (MWBase::Environment::get().getWorld()->getStore(), item);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                    ref.getPtr().getRefData().setCount (count);
 | 
					                    ref.getPtr().getRefData().setCount (count);
 | 
				
			||||||
 | 
					                    
 | 
				
			||||||
 | 
					                    // Configure item's script variables
 | 
				
			||||||
 | 
					                    std::string script = MWWorld::Class::get(ref.getPtr()).getScript(ref.getPtr());
 | 
				
			||||||
 | 
					                    if (script != "")
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        const ESM::Script *esmscript = MWBase::Environment::get().getWorld()->getStore().get<ESM::Script>().find (script);
 | 
				
			||||||
 | 
					                        ref.getPtr().getRefData().setLocals(*esmscript);
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                    MWWorld::Class::get (ptr).getContainerStore (ptr).add (ref.getPtr());
 | 
					                    MWWorld::Class::get (ptr).getContainerStore (ptr).add (ref.getPtr());
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										41
									
								
								apps/openmw/mwscript/locals.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										41
									
								
								apps/openmw/mwscript/locals.cpp
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,41 @@
 | 
				
			||||||
 | 
					#include "locals.hpp"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "../mwbase/environment.hpp"
 | 
				
			||||||
 | 
					#include "../mwbase/scriptmanager.hpp"
 | 
				
			||||||
 | 
					#include <components/compiler/locals.hpp>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace MWScript
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    void Locals::configure (const ESM::Script& script)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        mShorts.clear();
 | 
				
			||||||
 | 
					        mShorts.resize (script.mData.mNumShorts, 0);
 | 
				
			||||||
 | 
					        mLongs.clear();
 | 
				
			||||||
 | 
					        mLongs.resize (script.mData.mNumLongs, 0);
 | 
				
			||||||
 | 
					        mFloats.clear();
 | 
				
			||||||
 | 
					        mFloats.resize (script.mData.mNumFloats, 0);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					    bool Locals::setVarByInt(const std::string& script, const std::string& var, int val)
 | 
				
			||||||
 | 
					    {    
 | 
				
			||||||
 | 
					        Compiler::Locals locals = MWBase::Environment::get().getScriptManager()->getLocals(script);
 | 
				
			||||||
 | 
					        int index = locals.getIndex(var);
 | 
				
			||||||
 | 
					        char type = locals.getType(var);
 | 
				
			||||||
 | 
					        if(index != -1)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            switch(type)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                case 's':
 | 
				
			||||||
 | 
					                    mShorts.at (index) = val; break;
 | 
				
			||||||
 | 
					                
 | 
				
			||||||
 | 
					                case 'l':
 | 
				
			||||||
 | 
					                    mLongs.at (index) = val; break;
 | 
				
			||||||
 | 
					                
 | 
				
			||||||
 | 
					                case 'f':
 | 
				
			||||||
 | 
					                    mFloats.at (index) = val; break;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            return true;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        return false;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -8,21 +8,16 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace MWScript
 | 
					namespace MWScript
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    struct Locals
 | 
					    class Locals
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        std::vector<Interpreter::Type_Short> mShorts;
 | 
					        public:
 | 
				
			||||||
        std::vector<Interpreter::Type_Integer> mLongs;
 | 
					            std::vector<Interpreter::Type_Short> mShorts;
 | 
				
			||||||
        std::vector<Interpreter::Type_Float> mFloats;
 | 
					            std::vector<Interpreter::Type_Integer> mLongs;
 | 
				
			||||||
 | 
					            std::vector<Interpreter::Type_Float> mFloats;
 | 
				
			||||||
 | 
					            
 | 
				
			||||||
 | 
					            void configure (const ESM::Script& script);
 | 
				
			||||||
 | 
					            bool setVarByInt(const std::string& script, const std::string& var, int val);
 | 
				
			||||||
        
 | 
					        
 | 
				
			||||||
        void configure (const ESM::Script& script)
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            mShorts.clear();
 | 
					 | 
				
			||||||
            mShorts.resize (script.mData.mNumShorts, 0);
 | 
					 | 
				
			||||||
            mLongs.clear();
 | 
					 | 
				
			||||||
            mLongs.resize (script.mData.mNumLongs, 0);
 | 
					 | 
				
			||||||
            mFloats.clear();
 | 
					 | 
				
			||||||
            mFloats.resize (script.mData.mNumFloats, 0);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -4,6 +4,8 @@
 | 
				
			||||||
#include "../mwbase/world.hpp"
 | 
					#include "../mwbase/world.hpp"
 | 
				
			||||||
#include "../mwbase/windowmanager.hpp"
 | 
					#include "../mwbase/windowmanager.hpp"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <components/compiler/locals.hpp>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "inventorystore.hpp"
 | 
					#include "inventorystore.hpp"
 | 
				
			||||||
#include "player.hpp"
 | 
					#include "player.hpp"
 | 
				
			||||||
#include "class.hpp"
 | 
					#include "class.hpp"
 | 
				
			||||||
| 
						 | 
					@ -35,6 +37,8 @@ namespace MWWorld
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        std::string npcRace = actor.get<ESM::NPC>()->mBase->mRace;
 | 
					        std::string npcRace = actor.get<ESM::NPC>()->mBase->mRace;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        bool equipped = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // equip the item in the first free slot
 | 
					        // equip the item in the first free slot
 | 
				
			||||||
        for (std::vector<int>::const_iterator slot=slots.first.begin();
 | 
					        for (std::vector<int>::const_iterator slot=slots.first.begin();
 | 
				
			||||||
            slot!=slots.first.end(); ++slot)
 | 
					            slot!=slots.first.end(); ++slot)
 | 
				
			||||||
| 
						 | 
					@ -91,6 +95,7 @@ namespace MWWorld
 | 
				
			||||||
            if (slot == --slots.first.end())
 | 
					            if (slot == --slots.first.end())
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                invStore.equip(*slot, it);
 | 
					                invStore.equip(*slot, it);
 | 
				
			||||||
 | 
					                equipped = true;
 | 
				
			||||||
                break;
 | 
					                break;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -98,8 +103,15 @@ namespace MWWorld
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                // slot is not occupied
 | 
					                // slot is not occupied
 | 
				
			||||||
                invStore.equip(*slot, it);
 | 
					                invStore.equip(*slot, it);
 | 
				
			||||||
 | 
					                equipped = true;
 | 
				
			||||||
                break;
 | 
					                break;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        std::string script = MWWorld::Class::get(*it).getScript(*it);
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        /* Set OnPCEquip Variable on item's script, if the player is equipping it, and it has a script with that variable declared */
 | 
				
			||||||
 | 
					        if(equipped && actor == MWBase::Environment::get().getWorld()->getPlayer().getPlayer() && script != "")
 | 
				
			||||||
 | 
					            (*it).mRefData->getLocals().setVarByInt(script, "onpcequip", 1);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -84,7 +84,7 @@ MWWorld::Ptr MWWorld::Cells::getPtrAndCache (const std::string& name, Ptr::CellS
 | 
				
			||||||
    return ptr;
 | 
					    return ptr;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
MWWorld::Cells::Cells (const MWWorld::ESMStore& store, ESM::ESMReader& reader)
 | 
					MWWorld::Cells::Cells (const MWWorld::ESMStore& store, std::vector<ESM::ESMReader>& reader)
 | 
				
			||||||
: mStore (store), mReader (reader),
 | 
					: mStore (store), mReader (reader),
 | 
				
			||||||
  mIdCache (20, std::pair<std::string, Ptr::CellStore *> ("", (Ptr::CellStore*)0)), /// \todo make cache size configurable
 | 
					  mIdCache (20, std::pair<std::string, Ptr::CellStore *> ("", (Ptr::CellStore*)0)), /// \todo make cache size configurable
 | 
				
			||||||
  mIdCacheIndex (0)
 | 
					  mIdCacheIndex (0)
 | 
				
			||||||
| 
						 | 
					@ -119,6 +119,7 @@ MWWorld::Ptr::CellStore *MWWorld::Cells::getExterior (int x, int y)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (result->second.mState!=Ptr::CellStore::State_Loaded)
 | 
					    if (result->second.mState!=Ptr::CellStore::State_Loaded)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
 | 
					        // Multiple plugin support for landscape data is much easier than for references. The last plugin wins.
 | 
				
			||||||
        result->second.load (mStore, mReader);
 | 
					        result->second.load (mStore, mReader);
 | 
				
			||||||
        fillContainers (result->second);
 | 
					        fillContainers (result->second);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2,6 +2,7 @@
 | 
				
			||||||
#define GAME_MWWORLD_CELLS_H
 | 
					#define GAME_MWWORLD_CELLS_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <map>
 | 
					#include <map>
 | 
				
			||||||
 | 
					#include <list>
 | 
				
			||||||
#include <string>
 | 
					#include <string>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "ptr.hpp"
 | 
					#include "ptr.hpp"
 | 
				
			||||||
| 
						 | 
					@ -19,7 +20,7 @@ namespace MWWorld
 | 
				
			||||||
    class Cells
 | 
					    class Cells
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
            const MWWorld::ESMStore& mStore;
 | 
					            const MWWorld::ESMStore& mStore;
 | 
				
			||||||
            ESM::ESMReader& mReader;
 | 
					            std::vector<ESM::ESMReader>& mReader;
 | 
				
			||||||
            std::map<std::string, CellStore> mInteriors;
 | 
					            std::map<std::string, CellStore> mInteriors;
 | 
				
			||||||
            std::map<std::pair<int, int>, CellStore> mExteriors;
 | 
					            std::map<std::pair<int, int>, CellStore> mExteriors;
 | 
				
			||||||
            std::vector<std::pair<std::string, CellStore *> > mIdCache;
 | 
					            std::vector<std::pair<std::string, CellStore *> > mIdCache;
 | 
				
			||||||
| 
						 | 
					@ -36,7 +37,7 @@ namespace MWWorld
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        public:
 | 
					        public:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            Cells (const MWWorld::ESMStore& store, ESM::ESMReader& reader);
 | 
					            Cells (const MWWorld::ESMStore& store, std::vector<ESM::ESMReader>& reader);
 | 
				
			||||||
            ///< \todo pass the dynamic part of the ESMStore isntead (once it is written) of the whole
 | 
					            ///< \todo pass the dynamic part of the ESMStore isntead (once it is written) of the whole
 | 
				
			||||||
            /// world
 | 
					            /// world
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -10,13 +10,48 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace MWWorld
 | 
					namespace MWWorld
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    template <typename X>
 | 
				
			||||||
 | 
					    void CellRefList<X>::load(ESM::CellRef &ref, const MWWorld::ESMStore &esmStore)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        // Get existing reference, in case we need to overwrite it.
 | 
				
			||||||
 | 
					        typename std::list<LiveRef>::iterator iter = std::find(mList.begin(), mList.end(), ref.mRefnum);
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        // Skip this when reference was deleted.
 | 
				
			||||||
 | 
					        // TODO: Support respawning references, in this case, we need to track it somehow.
 | 
				
			||||||
 | 
					        if (ref.mDeleted) {
 | 
				
			||||||
 | 
					            mList.erase(iter);
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        // for throwing exception on unhandled record type
 | 
				
			||||||
 | 
					        const MWWorld::Store<X> &store = esmStore.get<X>();
 | 
				
			||||||
 | 
					        const X *ptr = store.search(ref.mRefID);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        /// \note no longer redundant - changed to Store<X>::search(), don't throw
 | 
				
			||||||
 | 
					        ///  an exception on miss, try to continue (that's how MW does it, anyway)
 | 
				
			||||||
 | 
					        if (ptr == NULL) {
 | 
				
			||||||
 | 
					            std::cout << "Warning: could not resolve cell reference " << ref.mRefID << ", trying to continue anyway" << std::endl;
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					          if (iter != mList.end())
 | 
				
			||||||
 | 
					            *iter = LiveRef(ref, ptr);
 | 
				
			||||||
 | 
					          else
 | 
				
			||||||
 | 
					            mList.push_back(LiveRef(ref, ptr));
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    template<typename X> bool operator==(const LiveCellRef<X>& ref, int pRefnum)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return (ref.mRef.mRefnum == pRefnum);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    CellStore::CellStore (const ESM::Cell *cell)
 | 
					    CellStore::CellStore (const ESM::Cell *cell)
 | 
				
			||||||
      : mCell (cell), mState (State_Unloaded)
 | 
					      : mCell (cell), mState (State_Unloaded)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        mWaterLevel = cell->mWater;
 | 
					        mWaterLevel = cell->mWater;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    void CellStore::load (const MWWorld::ESMStore &store, ESM::ESMReader &esm)
 | 
					    void CellStore::load (const MWWorld::ESMStore &store, std::vector<ESM::ESMReader> &esm)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        if (mState!=State_Loaded)
 | 
					        if (mState!=State_Loaded)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
| 
						 | 
					@ -31,7 +66,7 @@ namespace MWWorld
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    void CellStore::preload (const MWWorld::ESMStore &store, ESM::ESMReader &esm)
 | 
					    void CellStore::preload (const MWWorld::ESMStore &store, std::vector<ESM::ESMReader> &esm)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        if (mState==State_Unloaded)
 | 
					        if (mState==State_Unloaded)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
| 
						 | 
					@ -41,57 +76,75 @@ namespace MWWorld
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    void CellStore::listRefs(const MWWorld::ESMStore &store, ESM::ESMReader &esm)
 | 
					    void CellStore::listRefs(const MWWorld::ESMStore &store, std::vector<ESM::ESMReader> &esm)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        assert (mCell);
 | 
					        assert (mCell);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (mCell->mContext.filename.empty())
 | 
					        if (mCell->mContextList.size() == 0)
 | 
				
			||||||
            return; // this is a dynamically generated cell -> skipping.
 | 
					            return; // this is a dynamically generated cell -> skipping.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // Reopen the ESM reader and seek to the right position.
 | 
					        // Load references from all plugins that do something with this cell.
 | 
				
			||||||
        mCell->restore (esm);
 | 
					        for (size_t i = 0; i < mCell->mContextList.size(); i++)
 | 
				
			||||||
 | 
					 | 
				
			||||||
        ESM::CellRef ref;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        // Get each reference in turn
 | 
					 | 
				
			||||||
        while (mCell->getNextRef (esm, ref))
 | 
					 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            std::string lowerCase = Misc::StringUtils::lowerCase (ref.mRefID);
 | 
					            // Reopen the ESM reader and seek to the right position.
 | 
				
			||||||
 | 
					            int index = mCell->mContextList.at(i).index;
 | 
				
			||||||
 | 
					            mCell->restore (esm[index], i);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            mIds.push_back (lowerCase);
 | 
					            ESM::CellRef ref;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            // Get each reference in turn
 | 
				
			||||||
 | 
					            while (mCell->getNextRef (esm[index], ref))
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                std::string lowerCase = Misc::StringUtils::lowerCase (ref.mRefID);
 | 
				
			||||||
 | 
					                if (ref.mDeleted) {
 | 
				
			||||||
 | 
					                    // Right now, don't do anything. Where is "listRefs" actually used, anyway?
 | 
				
			||||||
 | 
					                    //  Skipping for now...
 | 
				
			||||||
 | 
					                    continue;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                mIds.push_back (lowerCase);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        std::sort (mIds.begin(), mIds.end());
 | 
					        std::sort (mIds.begin(), mIds.end());
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    void CellStore::loadRefs(const MWWorld::ESMStore &store, ESM::ESMReader &esm)
 | 
					    void CellStore::loadRefs(const MWWorld::ESMStore &store, std::vector<ESM::ESMReader> &esm)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
      assert (mCell);
 | 
					      assert (mCell);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (mCell->mContext.filename.empty())
 | 
					        if (mCell->mContextList.size() == 0)
 | 
				
			||||||
            return; // this is a dynamically generated cell -> skipping.
 | 
					            return; // this is a dynamically generated cell -> skipping.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      // Reopen the ESM reader and seek to the right position.
 | 
					        // Load references from all plugins that do something with this cell.
 | 
				
			||||||
      mCell->restore(esm);
 | 
					        for (size_t i = 0; i < mCell->mContextList.size(); i++)
 | 
				
			||||||
 | 
					 | 
				
			||||||
      ESM::CellRef ref;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      // Get each reference in turn
 | 
					 | 
				
			||||||
      while(mCell->getNextRef(esm, ref))
 | 
					 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            std::string lowerCase = Misc::StringUtils::lowerCase(ref.mRefID);
 | 
					            // Reopen the ESM reader and seek to the right position.
 | 
				
			||||||
 | 
					            int index = mCell->mContextList.at(i).index;
 | 
				
			||||||
 | 
					            mCell->restore (esm[index], i);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            int rec = store.find(ref.mRefID);
 | 
					            ESM::CellRef ref;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            ref.mRefID = lowerCase;
 | 
					            // Get each reference in turn
 | 
				
			||||||
 | 
					            while(mCell->getNextRef(esm[index], ref))
 | 
				
			||||||
          /* We can optimize this further by storing the pointer to the
 | 
					 | 
				
			||||||
             record itself in store.all, so that we don't need to look it
 | 
					 | 
				
			||||||
             up again here. However, never optimize. There are infinite
 | 
					 | 
				
			||||||
             opportunities to do that later.
 | 
					 | 
				
			||||||
           */
 | 
					 | 
				
			||||||
          switch(rec)
 | 
					 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
 | 
					                // Don't load reference if it was moved to a different cell.
 | 
				
			||||||
 | 
					                std::string lowerCase = Misc::StringUtils::lowerCase(ref.mRefID);
 | 
				
			||||||
 | 
					                ESM::MovedCellRefTracker::const_iterator iter = std::find(mCell->mMovedRefs.begin(), mCell->mMovedRefs.end(), ref.mRefnum);
 | 
				
			||||||
 | 
					                if (iter != mCell->mMovedRefs.end()) {
 | 
				
			||||||
 | 
					                    continue;
 | 
				
			||||||
 | 
					                }                    
 | 
				
			||||||
 | 
					                int rec = store.find(ref.mRefID);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                ref.mRefID = lowerCase;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            /* We can optimize this further by storing the pointer to the
 | 
				
			||||||
 | 
					                record itself in store.all, so that we don't need to look it
 | 
				
			||||||
 | 
					                up again here. However, never optimize. There are infinite
 | 
				
			||||||
 | 
					                opportunities to do that later.
 | 
				
			||||||
 | 
					            */
 | 
				
			||||||
 | 
					            switch(rec)
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
            case ESM::REC_ACTI: mActivators.load(ref, store); break;
 | 
					            case ESM::REC_ACTI: mActivators.load(ref, store); break;
 | 
				
			||||||
            case ESM::REC_ALCH: mPotions.load(ref, store); break;
 | 
					            case ESM::REC_ALCH: mPotions.load(ref, store); break;
 | 
				
			||||||
            case ESM::REC_APPA: mAppas.load(ref, store); break;
 | 
					            case ESM::REC_APPA: mAppas.load(ref, store); break;
 | 
				
			||||||
| 
						 | 
					@ -113,10 +166,62 @@ namespace MWWorld
 | 
				
			||||||
            case ESM::REC_STAT: mStatics.load(ref, store); break;
 | 
					            case ESM::REC_STAT: mStatics.load(ref, store); break;
 | 
				
			||||||
            case ESM::REC_WEAP: mWeapons.load(ref, store); break;
 | 
					            case ESM::REC_WEAP: mWeapons.load(ref, store); break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            case 0: std::cout << "Cell reference " + ref.mRefID + " not found!\n"; break;
 | 
					                case 0: std::cout << "Cell reference " + ref.mRefID + " not found!\n"; break;
 | 
				
			||||||
            default:
 | 
					                default:
 | 
				
			||||||
              std::cout << "WARNING: Ignoring reference '" << ref.mRefID << "' of unhandled type\n";
 | 
					                std::cout << "WARNING: Ignoring reference '" << ref.mRefID << "' of unhandled type\n";
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Load moved references, from separately tracked list.
 | 
				
			||||||
 | 
					        for (ESM::CellRefTracker::const_iterator it = mCell->mLeasedRefs.begin(); it != mCell->mLeasedRefs.end(); it++)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            // Doesn't seem to work in one line... huh? Too sleepy to check...
 | 
				
			||||||
 | 
					            ESM::CellRef &ref = const_cast<ESM::CellRef&>(*it);
 | 
				
			||||||
 | 
					            //ESM::CellRef &ref = const_cast<ESM::CellRef&>(it->second);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            std::string lowerCase;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            std::transform (ref.mRefID.begin(), ref.mRefID.end(), std::back_inserter (lowerCase),
 | 
				
			||||||
 | 
					                (int(*)(int)) std::tolower);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            int rec = store.find(ref.mRefID);
 | 
				
			||||||
 | 
					            
 | 
				
			||||||
 | 
					            ref.mRefID = lowerCase;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            /* We can optimize this further by storing the pointer to the
 | 
				
			||||||
 | 
					                record itself in store.all, so that we don't need to look it
 | 
				
			||||||
 | 
					                up again here. However, never optimize. There are infinite
 | 
				
			||||||
 | 
					                opportunities to do that later.
 | 
				
			||||||
 | 
					            */
 | 
				
			||||||
 | 
					            switch(rec)
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					            case ESM::REC_ACTI: mActivators.load(ref, store); break;
 | 
				
			||||||
 | 
					            case ESM::REC_ALCH: mPotions.load(ref, store); break;
 | 
				
			||||||
 | 
					            case ESM::REC_APPA: mAppas.load(ref, store); break;
 | 
				
			||||||
 | 
					            case ESM::REC_ARMO: mArmors.load(ref, store); break;
 | 
				
			||||||
 | 
					            case ESM::REC_BOOK: mBooks.load(ref, store); break;
 | 
				
			||||||
 | 
					            case ESM::REC_CLOT: mClothes.load(ref, store); break;
 | 
				
			||||||
 | 
					            case ESM::REC_CONT: mContainers.load(ref, store); break;
 | 
				
			||||||
 | 
					            case ESM::REC_CREA: mCreatures.load(ref, store); break;
 | 
				
			||||||
 | 
					            case ESM::REC_DOOR: mDoors.load(ref, store); break;
 | 
				
			||||||
 | 
					            case ESM::REC_INGR: mIngreds.load(ref, store); break;
 | 
				
			||||||
 | 
					            case ESM::REC_LEVC: mCreatureLists.load(ref, store); break;
 | 
				
			||||||
 | 
					            case ESM::REC_LEVI: mItemLists.load(ref, store); break;
 | 
				
			||||||
 | 
					            case ESM::REC_LIGH: mLights.load(ref, store); break;
 | 
				
			||||||
 | 
					            case ESM::REC_LOCK: mLockpicks.load(ref, store); break;
 | 
				
			||||||
 | 
					            case ESM::REC_MISC: mMiscItems.load(ref, store); break;
 | 
				
			||||||
 | 
					            case ESM::REC_NPC_: mNpcs.load(ref, store); break;
 | 
				
			||||||
 | 
					            case ESM::REC_PROB: mProbes.load(ref, store); break;
 | 
				
			||||||
 | 
					            case ESM::REC_REPA: mRepairs.load(ref, store); break;
 | 
				
			||||||
 | 
					            case ESM::REC_STAT: mStatics.load(ref, store); break;
 | 
				
			||||||
 | 
					            case ESM::REC_WEAP: mWeapons.load(ref, store); break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                case 0: std::cout << "Cell reference " + ref.mRefID + " not found!\n"; break;
 | 
				
			||||||
 | 
					                default:
 | 
				
			||||||
 | 
					                std::cout << "WARNING: Ignoring reference '" << ref.mRefID << "' of unhandled type\n";
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -3,17 +3,18 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <components/esm/records.hpp>
 | 
					#include <components/esm/records.hpp>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <list>
 | 
					#include <deque>
 | 
				
			||||||
#include <algorithm>
 | 
					#include <algorithm>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "refdata.hpp"
 | 
					#include "refdata.hpp"
 | 
				
			||||||
#include "esmstore.hpp"
 | 
					#include "esmstore.hpp"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct C;
 | 
				
			||||||
namespace MWWorld
 | 
					namespace MWWorld
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    class Ptr;
 | 
					    class Ptr;
 | 
				
			||||||
    class ESMStore;
 | 
					    class ESMStore;
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
  /// A reference to one object (of any type) in a cell.
 | 
					  /// A reference to one object (of any type) in a cell.
 | 
				
			||||||
  ///
 | 
					  ///
 | 
				
			||||||
  /// Constructing this with a CellRef instance in the constructor means that
 | 
					  /// Constructing this with a CellRef instance in the constructor means that
 | 
				
			||||||
| 
						 | 
					@ -42,6 +43,8 @@ namespace MWWorld
 | 
				
			||||||
    /// runtime-data
 | 
					    /// runtime-data
 | 
				
			||||||
    RefData mData;
 | 
					    RefData mData;
 | 
				
			||||||
  };
 | 
					  };
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					  template<typename X> bool operator==(const LiveCellRef<X>& ref, int pRefnum);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  /// A list of cell references
 | 
					  /// A list of cell references
 | 
				
			||||||
  template <typename X>
 | 
					  template <typename X>
 | 
				
			||||||
| 
						 | 
					@ -51,21 +54,14 @@ namespace MWWorld
 | 
				
			||||||
    typedef std::list<LiveRef> List;
 | 
					    typedef std::list<LiveRef> List;
 | 
				
			||||||
    List mList;
 | 
					    List mList;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// Searches for reference of appropriate type in given ESMStore.
 | 
					    // Search for the given reference in the given reclist from
 | 
				
			||||||
    /// If reference exists, loads it into container, throws an exception
 | 
					    // ESMStore. Insert the reference into the list if a match is
 | 
				
			||||||
    /// on miss
 | 
					    // found. If not, throw an exception.
 | 
				
			||||||
    void load(ESM::CellRef &ref, const MWWorld::ESMStore &esmStore)
 | 
					    // Moved to cpp file, as we require a custom compare operator for it,
 | 
				
			||||||
    {
 | 
					    // and the build will fail with an ugly three-way cyclic header dependence
 | 
				
			||||||
        // for throwing exception on unhandled record type
 | 
					    // so we need to pass the instantiation of the method to the lnker, when
 | 
				
			||||||
        const MWWorld::Store<X> &store = esmStore.get<X>();
 | 
					    // all methods are known.
 | 
				
			||||||
        const X *ptr = store.find(ref.mRefID);
 | 
					    void load(ESM::CellRef &ref, const MWWorld::ESMStore &esmStore);
 | 
				
			||||||
 | 
					 | 
				
			||||||
        /// \note redundant because Store<X>::find() throws exception on miss
 | 
					 | 
				
			||||||
        if (ptr == NULL) {
 | 
					 | 
				
			||||||
            throw std::runtime_error("Error resolving cell reference " + ref.mRefID);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        mList.push_back(LiveRef(ref, ptr));
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    LiveRef *find (const std::string& name)
 | 
					    LiveRef *find (const std::string& name)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
| 
						 | 
					@ -124,9 +120,9 @@ namespace MWWorld
 | 
				
			||||||
    CellRefList<ESM::Static>            mStatics;
 | 
					    CellRefList<ESM::Static>            mStatics;
 | 
				
			||||||
    CellRefList<ESM::Weapon>            mWeapons;
 | 
					    CellRefList<ESM::Weapon>            mWeapons;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    void load (const MWWorld::ESMStore &store, ESM::ESMReader &esm);
 | 
					    void load (const MWWorld::ESMStore &store, std::vector<ESM::ESMReader> &esm);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    void preload (const MWWorld::ESMStore &store, ESM::ESMReader &esm);
 | 
					    void preload (const MWWorld::ESMStore &store, std::vector<ESM::ESMReader> &esm);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// Call functor (ref) for each reference. functor must return a bool. Returning
 | 
					    /// Call functor (ref) for each reference. functor must return a bool. Returning
 | 
				
			||||||
    /// false will abort the iteration.
 | 
					    /// false will abort the iteration.
 | 
				
			||||||
| 
						 | 
					@ -185,9 +181,9 @@ namespace MWWorld
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// Run through references and store IDs
 | 
					    /// Run through references and store IDs
 | 
				
			||||||
    void listRefs(const MWWorld::ESMStore &store, ESM::ESMReader &esm);
 | 
					    void listRefs(const MWWorld::ESMStore &store, std::vector<ESM::ESMReader> &esm);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    void loadRefs(const MWWorld::ESMStore &store, ESM::ESMReader &esm);
 | 
					    void loadRefs(const MWWorld::ESMStore &store, std::vector<ESM::ESMReader> &esm);
 | 
				
			||||||
  };
 | 
					  };
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -8,9 +8,11 @@
 | 
				
			||||||
#include <boost/algorithm/string.hpp>
 | 
					#include <boost/algorithm/string.hpp>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <components/esm/loadcont.hpp>
 | 
					#include <components/esm/loadcont.hpp>
 | 
				
			||||||
 | 
					#include <components/compiler/locals.hpp>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "../mwbase/environment.hpp"
 | 
					#include "../mwbase/environment.hpp"
 | 
				
			||||||
#include "../mwbase/world.hpp"
 | 
					#include "../mwbase/world.hpp"
 | 
				
			||||||
 | 
					#include "../mwbase/scriptmanager.hpp"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "manualref.hpp"
 | 
					#include "manualref.hpp"
 | 
				
			||||||
#include "refdata.hpp"
 | 
					#include "refdata.hpp"
 | 
				
			||||||
| 
						 | 
					@ -83,9 +85,14 @@ MWWorld::ContainerStoreIterator MWWorld::ContainerStore::add (const Ptr& ptr)
 | 
				
			||||||
        CellStore *cell;
 | 
					        CellStore *cell;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        Ptr player = MWBase::Environment::get().getWorld ()->getPlayer().getPlayer();
 | 
					        Ptr player = MWBase::Environment::get().getWorld ()->getPlayer().getPlayer();
 | 
				
			||||||
        // Items in players inventory have cell set to 0, so their scripts will never be removed
 | 
					        
 | 
				
			||||||
        if(&(MWWorld::Class::get (player).getContainerStore (player)) == this)
 | 
					        if(&(MWWorld::Class::get (player).getContainerStore (player)) == this)
 | 
				
			||||||
            cell = 0;
 | 
					        {
 | 
				
			||||||
 | 
					            cell = 0; // Items in player's inventory have cell set to 0, so their scripts will never be removed
 | 
				
			||||||
 | 
					           
 | 
				
			||||||
 | 
					            // Set OnPCAdd special variable, if it is declared 
 | 
				
			||||||
 | 
					            item.mRefData->getLocals().setVarByInt(script, "onpcadd", 1);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
        else
 | 
					        else
 | 
				
			||||||
            cell = player.getCell();
 | 
					            cell = player.getCell();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -3,6 +3,8 @@
 | 
				
			||||||
#include <set>
 | 
					#include <set>
 | 
				
			||||||
#include <iostream>
 | 
					#include <iostream>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <boost/filesystem/v3/operations.hpp>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace MWWorld
 | 
					namespace MWWorld
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -25,6 +27,33 @@ void ESMStore::load(ESM::ESMReader &esm)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    ESM::Dialogue *dialogue = 0;
 | 
					    ESM::Dialogue *dialogue = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // 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();
 | 
				
			||||||
 | 
					    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]);
 | 
				
			||||||
 | 
					        std::string fname = mast.name;
 | 
				
			||||||
 | 
					        for (int i = 0; i < esm.getIndex(); i++) {
 | 
				
			||||||
 | 
					            const std::string &candidate = allPlugins->at(i).getContext().filename;
 | 
				
			||||||
 | 
					            std::string fnamecandidate = boost::filesystem::path(candidate).filename().string();
 | 
				
			||||||
 | 
					            if (fname == fnamecandidate) {
 | 
				
			||||||
 | 
					                index = i;
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        if (index == (int)~0) {
 | 
				
			||||||
 | 
					            // Tried to load a parent file that has not been loaded yet. This is bad,
 | 
				
			||||||
 | 
					            //  the launcher should have taken care of this.
 | 
				
			||||||
 | 
					            std::string fstring = "File " + fname + " asks for parent file " + masters[j].name
 | 
				
			||||||
 | 
					                + ", but it has not been loaded yet. Please check your load order.";
 | 
				
			||||||
 | 
					            esm.fail(fstring);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        mast.index = index;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Loop through all records
 | 
					    // Loop through all records
 | 
				
			||||||
    while(esm.hasMoreRecs())
 | 
					    while(esm.hasMoreRecs())
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
| 
						 | 
					@ -55,12 +84,21 @@ void ESMStore::load(ESM::ESMReader &esm)
 | 
				
			||||||
        } else {
 | 
					        } else {
 | 
				
			||||||
            // Load it
 | 
					            // Load it
 | 
				
			||||||
            std::string id = esm.getHNOString("NAME");
 | 
					            std::string id = esm.getHNOString("NAME");
 | 
				
			||||||
 | 
					            // ... unless it got deleted! This means that the following record
 | 
				
			||||||
 | 
					            //  has been deleted, and trying to load it using standard assumptions
 | 
				
			||||||
 | 
					            //  on the structure will (probably) fail.
 | 
				
			||||||
 | 
					            if (esm.isNextSub("DELE")) {
 | 
				
			||||||
 | 
					              esm.skipRecord();
 | 
				
			||||||
 | 
					              it->second->eraseStatic(id);
 | 
				
			||||||
 | 
					              continue;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
            it->second->load(esm, id);
 | 
					            it->second->load(esm, id);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            if (n.val==ESM::REC_DIAL) {
 | 
					            if (n.val==ESM::REC_DIAL) {
 | 
				
			||||||
                // dirty hack, but it is better than non-const search()
 | 
					                // dirty hack, but it is better than non-const search()
 | 
				
			||||||
                // or friends
 | 
					                // or friends
 | 
				
			||||||
                dialogue = &mDialogs.mStatic.back();
 | 
					                //dialogue = &mDialogs.mStatic.back();
 | 
				
			||||||
 | 
					                dialogue = const_cast<ESM::Dialogue*>(mDialogs.find(id));
 | 
				
			||||||
                assert (dialogue->mId == id);
 | 
					                assert (dialogue->mId == id);
 | 
				
			||||||
            } else {
 | 
					            } else {
 | 
				
			||||||
                dialogue = 0;
 | 
					                dialogue = 0;
 | 
				
			||||||
| 
						 | 
					@ -84,7 +122,6 @@ void ESMStore::load(ESM::ESMReader &esm)
 | 
				
			||||||
    cout << *it << " ";
 | 
					    cout << *it << " ";
 | 
				
			||||||
  cout << endl;
 | 
					  cout << endl;
 | 
				
			||||||
  */
 | 
					  */
 | 
				
			||||||
    setUp();
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void ESMStore::setUp()
 | 
					void ESMStore::setUp()
 | 
				
			||||||
| 
						 | 
					@ -100,12 +137,11 @@ void ESMStore::setUp()
 | 
				
			||||||
    ESM::NPC item;
 | 
					    ESM::NPC item;
 | 
				
			||||||
    item.mId = "player";
 | 
					    item.mId = "player";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    std::vector<ESM::NPC>::iterator pIt =
 | 
					    const ESM::NPC *pIt = mNpcs.find("player");
 | 
				
			||||||
        std::lower_bound(mNpcs.mStatic.begin(), mNpcs.mStatic.end(), item, RecordCmp());
 | 
					    assert(pIt != NULL);
 | 
				
			||||||
    assert(pIt != mNpcs.mStatic.end() && pIt->mId == "player");
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    mNpcs.insert(*pIt);
 | 
					    mNpcs.insert(*pIt);
 | 
				
			||||||
    mNpcs.mStatic.erase(pIt);
 | 
					    mNpcs.eraseStatic(pIt->mId);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
} // end namespace
 | 
					} // end namespace
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -94,6 +94,9 @@ namespace MWWorld
 | 
				
			||||||
        ESMStore()
 | 
					        ESMStore()
 | 
				
			||||||
          : mDynamicCount(0)
 | 
					          : mDynamicCount(0)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
 | 
					            // Cell store needs access to this for tracking moved references
 | 
				
			||||||
 | 
					            mCells.mEsmStore = this;
 | 
				
			||||||
 | 
					            
 | 
				
			||||||
            mStores[ESM::REC_ACTI] = &mActivators;
 | 
					            mStores[ESM::REC_ACTI] = &mActivators;
 | 
				
			||||||
            mStores[ESM::REC_ALCH] = &mPotions;
 | 
					            mStores[ESM::REC_ALCH] = &mPotions;
 | 
				
			||||||
            mStores[ESM::REC_APPA] = &mAppas;
 | 
					            mStores[ESM::REC_APPA] = &mAppas;
 | 
				
			||||||
| 
						 | 
					@ -168,7 +171,8 @@ namespace MWWorld
 | 
				
			||||||
            return ptr;
 | 
					            return ptr;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private:
 | 
					        // This method must be called once, after loading all master/plugin files. This can only be done
 | 
				
			||||||
 | 
					        //  from the outside, so it must be public.
 | 
				
			||||||
        void setUp();
 | 
					        void setUp();
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										65
									
								
								apps/openmw/mwworld/store.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										65
									
								
								apps/openmw/mwworld/store.cpp
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,65 @@
 | 
				
			||||||
 | 
					#include "store.hpp"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace MWWorld {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void Store<ESM::Cell>::load(ESM::ESMReader &esm, const std::string &id)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    // Don't automatically assume that a new cell must be spawned. Multiple plugins write to the same cell,
 | 
				
			||||||
 | 
					    //  and we merge all this data into one Cell object. However, we can't simply search for the cell id,
 | 
				
			||||||
 | 
					    //  as many exterior cells do not have a name. Instead, we need to search by (x,y) coordinates - and they
 | 
				
			||||||
 | 
					    //  are not available until both cells have been loaded! So first, proceed as usual.
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    // All cells have a name record, even nameless exterior cells.
 | 
				
			||||||
 | 
					    std::string idLower = Misc::StringUtils::lowerCase(id);
 | 
				
			||||||
 | 
					    ESM::Cell *cell = new ESM::Cell;
 | 
				
			||||||
 | 
					    cell->mName = id;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // The cell itself takes care of some of the hairy details
 | 
				
			||||||
 | 
					    cell->load(esm, *mEsmStore);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if(cell->mData.mFlags & ESM::Cell::Interior)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        // Store interior cell by name, try to merge with existing parent data.
 | 
				
			||||||
 | 
					        ESM::Cell *oldcell = const_cast<ESM::Cell*>(search(idLower));
 | 
				
			||||||
 | 
					        if (oldcell) {
 | 
				
			||||||
 | 
					            // push the new references on the list of references to manage
 | 
				
			||||||
 | 
					            oldcell->mContextList.push_back(cell->mContextList.at(0));
 | 
				
			||||||
 | 
					            // copy list into new cell
 | 
				
			||||||
 | 
					            cell->mContextList = oldcell->mContextList;
 | 
				
			||||||
 | 
					            // have new cell replace old cell
 | 
				
			||||||
 | 
					            *oldcell = *cell;
 | 
				
			||||||
 | 
					        } else
 | 
				
			||||||
 | 
					            mInt[idLower] = *cell;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    else
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        // Store exterior cells by grid position, try to merge with existing parent data.
 | 
				
			||||||
 | 
					        ESM::Cell *oldcell = const_cast<ESM::Cell*>(search(cell->getGridX(), cell->getGridY()));
 | 
				
			||||||
 | 
					        if (oldcell) {
 | 
				
			||||||
 | 
					            // push the new references on the list of references to manage
 | 
				
			||||||
 | 
					            oldcell->mContextList.push_back(cell->mContextList.at(0));
 | 
				
			||||||
 | 
					            // copy list into new cell
 | 
				
			||||||
 | 
					            cell->mContextList = oldcell->mContextList;
 | 
				
			||||||
 | 
					            // merge lists of leased references, use newer data in case of conflict
 | 
				
			||||||
 | 
					            for (ESM::MovedCellRefTracker::const_iterator it = cell->mMovedRefs.begin(); it != cell->mMovedRefs.end(); it++) {
 | 
				
			||||||
 | 
					                // remove reference from current leased ref tracker and add it to new cell
 | 
				
			||||||
 | 
					                ESM::MovedCellRefTracker::iterator itold = std::find(oldcell->mMovedRefs.begin(), oldcell->mMovedRefs.end(), it->mRefnum);
 | 
				
			||||||
 | 
					                if (itold != oldcell->mMovedRefs.end()) {
 | 
				
			||||||
 | 
					                    ESM::MovedCellRef target0 = *itold;
 | 
				
			||||||
 | 
					                    ESM::Cell *wipecell = const_cast<ESM::Cell*>(search(target0.mTarget[0], target0.mTarget[1]));
 | 
				
			||||||
 | 
					                    ESM::CellRefTracker::iterator it_lease = std::find(wipecell->mLeasedRefs.begin(), wipecell->mLeasedRefs.end(), it->mRefnum);
 | 
				
			||||||
 | 
					                    wipecell->mLeasedRefs.erase(it_lease);
 | 
				
			||||||
 | 
					                    *itold = *it;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            cell->mMovedRefs = oldcell->mMovedRefs;
 | 
				
			||||||
 | 
					            // have new cell replace old cell
 | 
				
			||||||
 | 
					            *oldcell = *cell;
 | 
				
			||||||
 | 
					        } else
 | 
				
			||||||
 | 
					            mExt[std::make_pair(cell->mData.mX, cell->mData.mY)] = *cell;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    delete cell;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -19,6 +19,8 @@ namespace MWWorld
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        virtual int getSize() const = 0;
 | 
					        virtual int getSize() const = 0;
 | 
				
			||||||
        virtual void load(ESM::ESMReader &esm, const std::string &id) = 0;
 | 
					        virtual void load(ESM::ESMReader &esm, const std::string &id) = 0;
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        virtual bool eraseStatic(const std::string &id) {return false;}
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    template <class T>
 | 
					    template <class T>
 | 
				
			||||||
| 
						 | 
					@ -85,7 +87,7 @@ namespace MWWorld
 | 
				
			||||||
    template <class T>
 | 
					    template <class T>
 | 
				
			||||||
    class Store : public StoreBase
 | 
					    class Store : public StoreBase
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        std::vector<T>      mStatic;
 | 
					        std::map<std::string, T>      mStatic;
 | 
				
			||||||
        std::vector<T *>    mShared;
 | 
					        std::vector<T *>    mShared;
 | 
				
			||||||
        std::map<std::string, T> mDynamic;
 | 
					        std::map<std::string, T> mDynamic;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -107,11 +109,10 @@ namespace MWWorld
 | 
				
			||||||
            T item;
 | 
					            T item;
 | 
				
			||||||
            item.mId = Misc::StringUtils::lowerCase(id);
 | 
					            item.mId = Misc::StringUtils::lowerCase(id);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            typename std::vector<T>::const_iterator it =
 | 
					            typename std::map<std::string, T>::const_iterator it = mStatic.find(item.mId);
 | 
				
			||||||
                std::lower_bound(mStatic.begin(), mStatic.end(), item, RecordCmp());
 | 
					            
 | 
				
			||||||
 | 
					            if (it != mStatic.end() && Misc::StringUtils::ciEqual(it->second.mId, id)) {
 | 
				
			||||||
            if (it != mStatic.end() && Misc::StringUtils::ciEqual(it->mId, id)) {
 | 
					                return &(it->second);
 | 
				
			||||||
                return &(*it);
 | 
					 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            typename Dynamic::const_iterator dit = mDynamic.find(item.mId);
 | 
					            typename Dynamic::const_iterator dit = mDynamic.find(item.mId);
 | 
				
			||||||
| 
						 | 
					@ -133,18 +134,19 @@ namespace MWWorld
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        void load(ESM::ESMReader &esm, const std::string &id) {
 | 
					        void load(ESM::ESMReader &esm, const std::string &id) {
 | 
				
			||||||
            mStatic.push_back(T());
 | 
					            std::string idLower = Misc::StringUtils::lowerCase(id);
 | 
				
			||||||
            mStatic.back().mId = Misc::StringUtils::lowerCase(id);
 | 
					            mStatic[idLower] = T();
 | 
				
			||||||
            mStatic.back().load(esm);
 | 
					            mStatic[idLower].mId = idLower;
 | 
				
			||||||
 | 
					            mStatic[idLower].load(esm);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        void setUp() {
 | 
					        void setUp() {
 | 
				
			||||||
            std::sort(mStatic.begin(), mStatic.end(), RecordCmp());
 | 
					            //std::sort(mStatic.begin(), mStatic.end(), RecordCmp());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            mShared.reserve(mStatic.size());
 | 
					            mShared.reserve(mStatic.size());
 | 
				
			||||||
            typename std::vector<T>::iterator it = mStatic.begin();
 | 
					            typename std::map<std::string, T>::iterator it = mStatic.begin();
 | 
				
			||||||
            for (; it != mStatic.end(); ++it) {
 | 
					            for (; it != mStatic.end(); ++it) {
 | 
				
			||||||
                mShared.push_back(&(*it));
 | 
					                mShared.push_back(&(it->second));
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -181,6 +183,19 @@ namespace MWWorld
 | 
				
			||||||
            return ptr;
 | 
					            return ptr;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        bool eraseStatic(const std::string &id) {
 | 
				
			||||||
 | 
					            T item;
 | 
				
			||||||
 | 
					            item.mId = Misc::StringUtils::lowerCase(id);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            typename std::map<std::string, T>::iterator it = mStatic.find(item.mId);
 | 
				
			||||||
 | 
					            
 | 
				
			||||||
 | 
					            if (it != mStatic.end() && Misc::StringUtils::ciEqual(it->second.mId, id)) {
 | 
				
			||||||
 | 
					                mStatic.erase(it);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            return true;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
        bool erase(const std::string &id) {
 | 
					        bool erase(const std::string &id) {
 | 
				
			||||||
            std::string key = Misc::StringUtils::lowerCase(id);
 | 
					            std::string key = Misc::StringUtils::lowerCase(id);
 | 
				
			||||||
            typename Dynamic::iterator it = mDynamic.find(key);
 | 
					            typename Dynamic::iterator it = mDynamic.find(key);
 | 
				
			||||||
| 
						 | 
					@ -204,39 +219,48 @@ namespace MWWorld
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    template <>
 | 
					    template <>
 | 
				
			||||||
    inline void Store<ESM::Dialogue>::load(ESM::ESMReader &esm, const std::string &id) {
 | 
					    inline void Store<ESM::Dialogue>::load(ESM::ESMReader &esm, const std::string &id) {
 | 
				
			||||||
        mStatic.push_back(ESM::Dialogue());
 | 
					        std::string idLower = Misc::StringUtils::lowerCase(id);
 | 
				
			||||||
        mStatic.back().mId = id;
 | 
					        mStatic[idLower] = ESM::Dialogue();
 | 
				
			||||||
        mStatic.back().load(esm);
 | 
					        mStatic[idLower].mId = id; // don't smash case here, as this line is printed... I think
 | 
				
			||||||
 | 
					        mStatic[idLower].load(esm);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    template <>
 | 
					    template <>
 | 
				
			||||||
    inline void Store<ESM::Script>::load(ESM::ESMReader &esm, const std::string &id) {
 | 
					    inline void Store<ESM::Script>::load(ESM::ESMReader &esm, const std::string &id) {
 | 
				
			||||||
        mStatic.push_back(ESM::Script());
 | 
					        ESM::Script scpt;
 | 
				
			||||||
        mStatic.back().load(esm);
 | 
					        scpt.load(esm);
 | 
				
			||||||
        Misc::StringUtils::toLower(mStatic.back().mId);
 | 
					        Misc::StringUtils::toLower(scpt.mId);
 | 
				
			||||||
 | 
					        mStatic[scpt.mId] = scpt;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    template <>
 | 
					    template <>
 | 
				
			||||||
    class Store<ESM::LandTexture> : public StoreBase
 | 
					    class Store<ESM::LandTexture> : public StoreBase
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        std::vector<ESM::LandTexture> mStatic;
 | 
					        // For multiple ESM/ESP files we need one list per file.
 | 
				
			||||||
 | 
					        typedef std::vector<ESM::LandTexture> LandTextureList;
 | 
				
			||||||
 | 
					        std::vector<LandTextureList> mStatic;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public:
 | 
					    public:
 | 
				
			||||||
        Store<ESM::LandTexture>() {
 | 
					        Store<ESM::LandTexture>() {
 | 
				
			||||||
            mStatic.reserve(128);
 | 
					            mStatic.push_back(LandTextureList());
 | 
				
			||||||
 | 
					            LandTextureList <exl = mStatic[0];
 | 
				
			||||||
 | 
					            // More than enough to hold Morrowind.esm. Extra lists for plugins will we
 | 
				
			||||||
 | 
					            //  added on-the-fly in a different method.
 | 
				
			||||||
 | 
					            ltexl.reserve(128);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        typedef std::vector<ESM::LandTexture>::const_iterator iterator;
 | 
					        typedef std::vector<ESM::LandTexture>::const_iterator iterator;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        const ESM::LandTexture *search(size_t index) const {
 | 
					        const ESM::LandTexture *search(size_t index, size_t plugin) const {
 | 
				
			||||||
            if (index < mStatic.size()) {
 | 
					            assert(plugin < mStatic.size());
 | 
				
			||||||
                return &mStatic.at(index);
 | 
					            const LandTextureList <exl = mStatic[plugin];
 | 
				
			||||||
            }
 | 
					
 | 
				
			||||||
            return 0;
 | 
					            assert(index < ltexl.size());
 | 
				
			||||||
 | 
					            return <exl.at(index);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        const ESM::LandTexture *find(size_t index) const {
 | 
					        const ESM::LandTexture *find(size_t index, size_t plugin) const {
 | 
				
			||||||
            const ESM::LandTexture *ptr = search(index);
 | 
					            const ESM::LandTexture *ptr = search(index, plugin);
 | 
				
			||||||
            if (ptr == 0) {
 | 
					            if (ptr == 0) {
 | 
				
			||||||
                std::ostringstream msg;
 | 
					                std::ostringstream msg;
 | 
				
			||||||
                msg << "Land texture with index " << index << " not found";
 | 
					                msg << "Land texture with index " << index << " not found";
 | 
				
			||||||
| 
						 | 
					@ -249,23 +273,40 @@ namespace MWWorld
 | 
				
			||||||
            return mStatic.size();
 | 
					            return mStatic.size();
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        void load(ESM::ESMReader &esm, const std::string &id) {
 | 
					        int getSize(size_t plugin) const {
 | 
				
			||||||
            ESM::LandTexture ltex;
 | 
					            assert(plugin < mStatic.size());
 | 
				
			||||||
            ltex.load(esm);
 | 
					            return mStatic[plugin].size();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            if (ltex.mIndex >= (int) mStatic.size()) {
 | 
					        void load(ESM::ESMReader &esm, const std::string &id, size_t plugin) {
 | 
				
			||||||
                mStatic.resize(ltex.mIndex + 1);
 | 
					            ESM::LandTexture lt;
 | 
				
			||||||
 | 
					            lt.load(esm);
 | 
				
			||||||
 | 
					            lt.mId = id;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            // Make sure we have room for the structure
 | 
				
			||||||
 | 
					            if (plugin >= mStatic.size()) {
 | 
				
			||||||
 | 
					                mStatic.resize(plugin+1);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            mStatic[ltex.mIndex] = ltex;
 | 
					            LandTextureList <exl = mStatic[plugin];
 | 
				
			||||||
            mStatic[ltex.mIndex].mId = id;
 | 
					            if(lt.mIndex + 1 > (int)ltexl.size())
 | 
				
			||||||
 | 
					                ltexl.resize(lt.mIndex+1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            // Store it
 | 
				
			||||||
 | 
					            ltexl[lt.mIndex] = lt;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        iterator begin() const {
 | 
					        void load(ESM::ESMReader &esm, const std::string &id) {
 | 
				
			||||||
            return mStatic.begin();
 | 
					            load(esm, id, esm.getIndex());
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        iterator end() const {
 | 
					        iterator begin(size_t plugin) const {
 | 
				
			||||||
            return mStatic.end();
 | 
					            assert(plugin < mStatic.size());
 | 
				
			||||||
 | 
					            return mStatic[plugin].begin();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        iterator end(size_t plugin) const {
 | 
				
			||||||
 | 
					            assert(plugin < mStatic.size());
 | 
				
			||||||
 | 
					            return mStatic[plugin].end();
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -357,19 +398,18 @@ namespace MWWorld
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        };
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        std::vector<ESM::Cell>      mInt;
 | 
					        typedef std::map<std::string, ESM::Cell>            DynamicInt;
 | 
				
			||||||
        std::vector<ESM::Cell>      mExt;
 | 
					        typedef std::map<std::pair<int, int>, ESM::Cell>    DynamicExt;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        DynamicInt      mInt;
 | 
				
			||||||
 | 
					        DynamicExt      mExt;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        std::vector<ESM::Cell *>    mSharedInt;
 | 
					        std::vector<ESM::Cell *>    mSharedInt;
 | 
				
			||||||
        std::vector<ESM::Cell *>    mSharedExt;
 | 
					        std::vector<ESM::Cell *>    mSharedExt;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        typedef std::map<std::string, ESM::Cell>            DynamicInt;
 | 
					 | 
				
			||||||
        typedef std::map<std::pair<int, int>, ESM::Cell>    DynamicExt;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        DynamicInt mDynamicInt;
 | 
					        DynamicInt mDynamicInt;
 | 
				
			||||||
        DynamicExt mDynamicExt;
 | 
					        DynamicExt mDynamicExt;
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					 | 
				
			||||||
        const ESM::Cell *search(const ESM::Cell &cell) const {
 | 
					        const ESM::Cell *search(const ESM::Cell &cell) const {
 | 
				
			||||||
            if (cell.isExterior()) {
 | 
					            if (cell.isExterior()) {
 | 
				
			||||||
                return search(cell.getGridX(), cell.getGridY());
 | 
					                return search(cell.getGridX(), cell.getGridY());
 | 
				
			||||||
| 
						 | 
					@ -378,6 +418,8 @@ namespace MWWorld
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public:
 | 
					    public:
 | 
				
			||||||
 | 
					        ESMStore *mEsmStore;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        typedef SharedIterator<ESM::Cell> iterator;
 | 
					        typedef SharedIterator<ESM::Cell> iterator;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        Store<ESM::Cell>()
 | 
					        Store<ESM::Cell>()
 | 
				
			||||||
| 
						 | 
					@ -387,11 +429,10 @@ namespace MWWorld
 | 
				
			||||||
            ESM::Cell cell;
 | 
					            ESM::Cell cell;
 | 
				
			||||||
            cell.mName = Misc::StringUtils::lowerCase(id);
 | 
					            cell.mName = Misc::StringUtils::lowerCase(id);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            std::vector<ESM::Cell>::const_iterator it =
 | 
					            std::map<std::string, ESM::Cell>::const_iterator it = mInt.find(cell.mName);
 | 
				
			||||||
                std::lower_bound(mInt.begin(), mInt.end(), cell, RecordCmp());
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
            if (it != mInt.end() && Misc::StringUtils::ciEqual(it->mName, id)) {
 | 
					            if (it != mInt.end() && Misc::StringUtils::ciEqual(it->second.mName, id)) {
 | 
				
			||||||
                return &(*it);
 | 
					                return &(it->second);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            DynamicInt::const_iterator dit = mDynamicInt.find(cell.mName);
 | 
					            DynamicInt::const_iterator dit = mDynamicInt.find(cell.mName);
 | 
				
			||||||
| 
						 | 
					@ -406,14 +447,12 @@ namespace MWWorld
 | 
				
			||||||
            ESM::Cell cell;
 | 
					            ESM::Cell cell;
 | 
				
			||||||
            cell.mData.mX = x, cell.mData.mY = y;
 | 
					            cell.mData.mX = x, cell.mData.mY = y;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            std::vector<ESM::Cell>::const_iterator it =
 | 
					            std::pair<int, int> key(x, y);
 | 
				
			||||||
                std::lower_bound(mExt.begin(), mExt.end(), cell, ExtCmp());
 | 
					            std::map<std::pair<int, int>, ESM::Cell>::const_iterator it = mExt.find(key);
 | 
				
			||||||
 | 
					            if (it != mExt.end()) {
 | 
				
			||||||
            if (it != mExt.end() && it->mData.mX == x && it->mData.mY == y) {
 | 
					                return &(it->second);
 | 
				
			||||||
                return &(*it);
 | 
					 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            std::pair<int, int> key(x, y);
 | 
					 | 
				
			||||||
            DynamicExt::const_iterator dit = mDynamicExt.find(key);
 | 
					            DynamicExt::const_iterator dit = mDynamicExt.find(key);
 | 
				
			||||||
            if (dit != mDynamicExt.end()) {
 | 
					            if (dit != mDynamicExt.end()) {
 | 
				
			||||||
                return &dit->second;
 | 
					                return &dit->second;
 | 
				
			||||||
| 
						 | 
					@ -422,6 +461,30 @@ namespace MWWorld
 | 
				
			||||||
            return 0;
 | 
					            return 0;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        const ESM::Cell *searchOrCreate(int x, int y) {
 | 
				
			||||||
 | 
					            ESM::Cell cell;
 | 
				
			||||||
 | 
					            cell.mData.mX = x, cell.mData.mY = y;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            std::pair<int, int> key(x, y);
 | 
				
			||||||
 | 
					            std::map<std::pair<int, int>, ESM::Cell>::const_iterator it = mExt.find(key);
 | 
				
			||||||
 | 
					            if (it != mExt.end()) {
 | 
				
			||||||
 | 
					                return &(it->second);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            DynamicExt::const_iterator dit = mDynamicExt.find(key);
 | 
				
			||||||
 | 
					            if (dit != mDynamicExt.end()) {
 | 
				
			||||||
 | 
					                return &dit->second;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            ESM::Cell *newCell = new ESM::Cell;
 | 
				
			||||||
 | 
					            newCell->mData.mX = x;
 | 
				
			||||||
 | 
					            newCell->mData.mY = y;
 | 
				
			||||||
 | 
					            mExt[std::make_pair(x, y)] = *newCell;
 | 
				
			||||||
 | 
					            delete newCell;
 | 
				
			||||||
 | 
					            
 | 
				
			||||||
 | 
					            return &mExt[std::make_pair(x, y)];
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        const ESM::Cell *find(const std::string &id) const {
 | 
					        const ESM::Cell *find(const std::string &id) const {
 | 
				
			||||||
            const ESM::Cell *ptr = search(id);
 | 
					            const ESM::Cell *ptr = search(id);
 | 
				
			||||||
            if (ptr == 0) {
 | 
					            if (ptr == 0) {
 | 
				
			||||||
| 
						 | 
					@ -443,33 +506,29 @@ namespace MWWorld
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        void setUp() {
 | 
					        void setUp() {
 | 
				
			||||||
            typedef std::vector<ESM::Cell>::iterator Iterator;
 | 
					            //typedef std::vector<ESM::Cell>::iterator Iterator;
 | 
				
			||||||
 | 
					            typedef std::map<std::pair<int, int>, ESM::Cell>::iterator ExtIterator;
 | 
				
			||||||
 | 
					            typedef std::map<std::string, ESM::Cell>::iterator IntIterator;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            std::sort(mInt.begin(), mInt.end(), RecordCmp());
 | 
					            //std::sort(mInt.begin(), mInt.end(), RecordCmp());
 | 
				
			||||||
            mSharedInt.reserve(mInt.size());
 | 
					            mSharedInt.reserve(mInt.size());
 | 
				
			||||||
            for (Iterator it = mInt.begin(); it != mInt.end(); ++it) {
 | 
					            for (IntIterator it = mInt.begin(); it != mInt.end(); ++it) {
 | 
				
			||||||
                mSharedInt.push_back(&(*it));
 | 
					                mSharedInt.push_back(&(it->second));
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            std::sort(mExt.begin(), mExt.end(), ExtCmp());
 | 
					            //std::sort(mExt.begin(), mExt.end(), ExtCmp());
 | 
				
			||||||
            mSharedExt.reserve(mExt.size());
 | 
					            mSharedExt.reserve(mExt.size());
 | 
				
			||||||
            for (Iterator it = mExt.begin(); it != mExt.end(); ++it) {
 | 
					            for (ExtIterator it = mExt.begin(); it != mExt.end(); ++it) {
 | 
				
			||||||
                mSharedExt.push_back(&(*it));
 | 
					                mSharedExt.push_back(&(it->second));
 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        void load(ESM::ESMReader &esm, const std::string &id) {
 | 
					 | 
				
			||||||
            ESM::Cell cell;
 | 
					 | 
				
			||||||
            cell.mName = id;
 | 
					 | 
				
			||||||
            cell.load(esm);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            if (cell.isExterior()) {
 | 
					 | 
				
			||||||
                mExt.push_back(cell);
 | 
					 | 
				
			||||||
            } else {
 | 
					 | 
				
			||||||
                mInt.push_back(cell);
 | 
					 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // HACK: Method implementation had to be moved to a separate cpp file, as we would otherwise get
 | 
				
			||||||
 | 
					        //  errors related to the compare operator used in std::find for ESM::MovedCellRefTracker::find.
 | 
				
			||||||
 | 
					        //  There some nasty three-way cyclic header dependency involved, which I could only fix by moving
 | 
				
			||||||
 | 
					        //  this method.
 | 
				
			||||||
 | 
					        void load(ESM::ESMReader &esm, const std::string &id);
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
        iterator intBegin() const {
 | 
					        iterator intBegin() const {
 | 
				
			||||||
            return iterator(mSharedInt.begin());
 | 
					            return iterator(mSharedInt.begin());
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -4,11 +4,13 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <components/bsa/bsa_archive.hpp>
 | 
					#include <components/bsa/bsa_archive.hpp>
 | 
				
			||||||
#include <components/files/collections.hpp>
 | 
					#include <components/files/collections.hpp>
 | 
				
			||||||
 | 
					#include <components/compiler/locals.hpp>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "../mwbase/environment.hpp"
 | 
					#include "../mwbase/environment.hpp"
 | 
				
			||||||
#include "../mwbase/soundmanager.hpp"
 | 
					#include "../mwbase/soundmanager.hpp"
 | 
				
			||||||
#include "../mwbase/mechanicsmanager.hpp"
 | 
					#include "../mwbase/mechanicsmanager.hpp"
 | 
				
			||||||
#include "../mwbase/windowmanager.hpp"
 | 
					#include "../mwbase/windowmanager.hpp"
 | 
				
			||||||
 | 
					#include "../mwbase/scriptmanager.hpp"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "../mwrender/sky.hpp"
 | 
					#include "../mwrender/sky.hpp"
 | 
				
			||||||
#include "../mwrender/player.hpp"
 | 
					#include "../mwrender/player.hpp"
 | 
				
			||||||
| 
						 | 
					@ -56,7 +58,7 @@ namespace
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        for (iterator iter (refList.mList.begin()); iter!=refList.mList.end(); ++iter)
 | 
					        for (iterator iter (refList.mList.begin()); iter!=refList.mList.end(); ++iter)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            if(iter->mData.getCount() > 0 && iter->mData.getBaseNode()){
 | 
					            if (iter->mData.getCount() > 0 && iter->mData.getBaseNode()){
 | 
				
			||||||
            if (iter->mData.getHandle()==handle)
 | 
					            if (iter->mData.getHandle()==handle)
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                return &*iter;
 | 
					                return &*iter;
 | 
				
			||||||
| 
						 | 
					@ -172,7 +174,8 @@ namespace MWWorld
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    World::World (OEngine::Render::OgreRenderer& renderer,
 | 
					    World::World (OEngine::Render::OgreRenderer& renderer,
 | 
				
			||||||
        const Files::Collections& fileCollections,
 | 
					        const Files::Collections& fileCollections,
 | 
				
			||||||
        const std::string& master, const boost::filesystem::path& resDir, const boost::filesystem::path& cacheDir, bool newGame,
 | 
					        const std::vector<std::string>& master, const std::vector<std::string>& plugins,
 | 
				
			||||||
 | 
						const boost::filesystem::path& resDir, const boost::filesystem::path& cacheDir, bool newGame,
 | 
				
			||||||
        ToUTF8::Utf8Encoder* encoder, std::map<std::string,std::string> fallbackMap, int mActivationDistanceOverride)
 | 
					        ToUTF8::Utf8Encoder* encoder, std::map<std::string,std::string> fallbackMap, int mActivationDistanceOverride)
 | 
				
			||||||
    : mPlayer (0), mLocalScripts (mStore), mGlobalVariables (0),
 | 
					    : mPlayer (0), mLocalScripts (mStore), mGlobalVariables (0),
 | 
				
			||||||
      mSky (true), mCells (mStore, mEsm),
 | 
					      mSky (true), mCells (mStore, mEsm),
 | 
				
			||||||
| 
						 | 
					@ -185,14 +188,42 @@ namespace MWWorld
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        mWeatherManager = new MWWorld::WeatherManager(mRendering);
 | 
					        mWeatherManager = new MWWorld::WeatherManager(mRendering);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        boost::filesystem::path masterPath (fileCollections.getCollection (".esm").getPath (master));
 | 
					        int idx = 0;
 | 
				
			||||||
 | 
					        // NOTE: We might need to reserve one more for the running game / save.
 | 
				
			||||||
 | 
					        mEsm.resize(master.size() + plugins.size());
 | 
				
			||||||
 | 
					        for (std::vector<std::string>::size_type i = 0; i < master.size(); i++, idx++)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            boost::filesystem::path masterPath (fileCollections.getCollection (".esm").getPath (master[i]));
 | 
				
			||||||
 | 
					            
 | 
				
			||||||
 | 
					            std::cout << "Loading ESM " << masterPath.string() << "\n";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        std::cout << "Loading ESM " << masterPath.string() << "\n";
 | 
					            // This parses the ESM file
 | 
				
			||||||
 | 
					            ESM::ESMReader lEsm;
 | 
				
			||||||
 | 
					            lEsm.setEncoder(encoder);
 | 
				
			||||||
 | 
					            lEsm.setIndex(idx);
 | 
				
			||||||
 | 
					            lEsm.setGlobalReaderList(&mEsm);
 | 
				
			||||||
 | 
					            lEsm.open (masterPath.string());
 | 
				
			||||||
 | 
					            mEsm[idx] = lEsm;
 | 
				
			||||||
 | 
					            mStore.load (mEsm[idx]);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					 
 | 
				
			||||||
 | 
					        for (std::vector<std::string>::size_type i = 0; i < plugins.size(); i++, idx++)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            boost::filesystem::path pluginPath (fileCollections.getCollection (".esp").getPath (plugins[i]));
 | 
				
			||||||
 | 
					            
 | 
				
			||||||
 | 
					            std::cout << "Loading ESP " << pluginPath.string() << "\n";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // This parses the ESM file and loads a sample cell
 | 
					            // This parses the ESP file
 | 
				
			||||||
        mEsm.setEncoder(encoder);
 | 
					            ESM::ESMReader lEsm;
 | 
				
			||||||
        mEsm.open (masterPath.string());
 | 
					            lEsm.setEncoder(encoder);
 | 
				
			||||||
        mStore.load (mEsm);
 | 
					            lEsm.setIndex(idx);
 | 
				
			||||||
 | 
					            lEsm.setGlobalReaderList(&mEsm);
 | 
				
			||||||
 | 
					            lEsm.open (pluginPath.string());
 | 
				
			||||||
 | 
					            mEsm[idx] = lEsm;
 | 
				
			||||||
 | 
					            mStore.load (mEsm[idx]);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        mStore.setUp();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        mPlayer = new MWWorld::Player (mStore.get<ESM::NPC>().find ("player"), *this);
 | 
					        mPlayer = new MWWorld::Player (mStore.get<ESM::NPC>().find ("player"), *this);
 | 
				
			||||||
        mRendering->attachCameraTo(mPlayer->getPlayer());
 | 
					        mRendering->attachCameraTo(mPlayer->getPlayer());
 | 
				
			||||||
| 
						 | 
					@ -271,7 +302,7 @@ namespace MWWorld
 | 
				
			||||||
        return mStore;
 | 
					        return mStore;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    ESM::ESMReader& World::getEsmReader()
 | 
					    std::vector<ESM::ESMReader>& World::getEsmReader()
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        return mEsm;
 | 
					        return mEsm;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
| 
						 | 
					@ -701,6 +732,8 @@ namespace MWWorld
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (*currCell != newCell)
 | 
					        if (*currCell != newCell)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
 | 
					        removeContainerScripts(ptr);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            if (isPlayer)
 | 
					            if (isPlayer)
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                if (!newCell.isExterior())
 | 
					                if (!newCell.isExterior())
 | 
				
			||||||
| 
						 | 
					@ -1192,8 +1225,8 @@ namespace MWWorld
 | 
				
			||||||
        std::vector<World::DoorMarker> result;
 | 
					        std::vector<World::DoorMarker> result;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        MWWorld::CellRefList<ESM::Door>& doors = cell->mDoors;
 | 
					        MWWorld::CellRefList<ESM::Door>& doors = cell->mDoors;
 | 
				
			||||||
        std::list< MWWorld::LiveCellRef<ESM::Door> >& refList = doors.mList;
 | 
					        CellRefList<ESM::Door>::List& refList = doors.mList;
 | 
				
			||||||
        for (std::list< MWWorld::LiveCellRef<ESM::Door> >::iterator it = refList.begin(); it != refList.end(); ++it)
 | 
					        for (CellRefList<ESM::Door>::List::iterator it = refList.begin(); it != refList.end(); ++it)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            MWWorld::LiveCellRef<ESM::Door>& ref = *it;
 | 
					            MWWorld::LiveCellRef<ESM::Door>& ref = *it;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1233,6 +1266,15 @@ namespace MWWorld
 | 
				
			||||||
        mRendering->toggleWater();
 | 
					        mRendering->toggleWater();
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    void World::PCDropped (const Ptr& item)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        std::string script = MWWorld::Class::get(item).getScript(item);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Set OnPCDrop Variable on item's script, if it has a script with that variable declared
 | 
				
			||||||
 | 
					        if(script != "")
 | 
				
			||||||
 | 
					            item.mRefData->getLocals().setVarByInt(script, "onpcdrop", 1);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    bool World::placeObject (const Ptr& object, float cursorX, float cursorY)
 | 
					    bool World::placeObject (const Ptr& object, float cursorX, float cursorY)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        std::pair<bool, Ogre::Vector3> result = mPhysics->castRay(cursorX, cursorY);
 | 
					        std::pair<bool, Ogre::Vector3> result = mPhysics->castRay(cursorX, cursorY);
 | 
				
			||||||
| 
						 | 
					@ -1255,7 +1297,8 @@ namespace MWWorld
 | 
				
			||||||
        pos.pos[1] = -result.second[2];
 | 
					        pos.pos[1] = -result.second[2];
 | 
				
			||||||
        pos.pos[2] = result.second[1];
 | 
					        pos.pos[2] = result.second[1];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        copyObjectToCell(object, *cell, pos);
 | 
					        Ptr dropped = copyObjectToCell(object, *cell, pos);
 | 
				
			||||||
 | 
					        PCDropped(dropped);
 | 
				
			||||||
        object.getRefData().setCount(0);
 | 
					        object.getRefData().setCount(0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return true;
 | 
					        return true;
 | 
				
			||||||
| 
						 | 
					@ -1272,8 +1315,8 @@ namespace MWWorld
 | 
				
			||||||
        return true;
 | 
					        return true;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    void
 | 
					
 | 
				
			||||||
    World::copyObjectToCell(const Ptr &object, CellStore &cell, const ESM::Position &pos)
 | 
					    Ptr World::copyObjectToCell(const Ptr &object, CellStore &cell, const ESM::Position &pos)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        /// \todo add searching correct cell for position specified
 | 
					        /// \todo add searching correct cell for position specified
 | 
				
			||||||
        MWWorld::Ptr dropped =
 | 
					        MWWorld::Ptr dropped =
 | 
				
			||||||
| 
						 | 
					@ -1297,6 +1340,8 @@ namespace MWWorld
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            addContainerScripts(dropped, &cell);
 | 
					            addContainerScripts(dropped, &cell);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return dropped;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    void World::dropObjectOnGround (const Ptr& actor, const Ptr& object)
 | 
					    void World::dropObjectOnGround (const Ptr& actor, const Ptr& object)
 | 
				
			||||||
| 
						 | 
					@ -1317,7 +1362,9 @@ namespace MWWorld
 | 
				
			||||||
            mPhysics->castRay(orig, dir, len);
 | 
					            mPhysics->castRay(orig, dir, len);
 | 
				
			||||||
        pos.pos[2] = hit.second.z;
 | 
					        pos.pos[2] = hit.second.z;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        copyObjectToCell(object, *cell, pos);
 | 
					        Ptr dropped = copyObjectToCell(object, *cell, pos);
 | 
				
			||||||
 | 
					        if(actor == mPlayer->getPlayer()) // Only call if dropped by player
 | 
				
			||||||
 | 
					            PCDropped(dropped);
 | 
				
			||||||
        object.getRefData().setCount(0);
 | 
					        object.getRefData().setCount(0);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -55,7 +55,7 @@ namespace MWWorld
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            MWWorld::Scene *mWorldScene;
 | 
					            MWWorld::Scene *mWorldScene;
 | 
				
			||||||
            MWWorld::Player *mPlayer;
 | 
					            MWWorld::Player *mPlayer;
 | 
				
			||||||
            ESM::ESMReader mEsm;
 | 
					            std::vector<ESM::ESMReader> mEsm;
 | 
				
			||||||
            MWWorld::ESMStore mStore;
 | 
					            MWWorld::ESMStore mStore;
 | 
				
			||||||
            LocalScripts mLocalScripts;
 | 
					            LocalScripts mLocalScripts;
 | 
				
			||||||
            MWWorld::Globals *mGlobalVariables;
 | 
					            MWWorld::Globals *mGlobalVariables;
 | 
				
			||||||
| 
						 | 
					@ -92,8 +92,8 @@ namespace MWWorld
 | 
				
			||||||
            bool moveObjectImp (const Ptr& ptr, float x, float y, float z);
 | 
					            bool moveObjectImp (const Ptr& ptr, float x, float y, float z);
 | 
				
			||||||
            ///< @return true if the active cell (cell player is in) changed
 | 
					            ///< @return true if the active cell (cell player is in) changed
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            virtual void
 | 
					            
 | 
				
			||||||
            copyObjectToCell(const Ptr &ptr, CellStore &cell, const ESM::Position &pos);
 | 
					            Ptr copyObjectToCell(const Ptr &ptr, CellStore &cell, const ESM::Position &pos);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            void updateWindowManager ();
 | 
					            void updateWindowManager ();
 | 
				
			||||||
            void performUpdateSceneQueries ();
 | 
					            void performUpdateSceneQueries ();
 | 
				
			||||||
| 
						 | 
					@ -108,12 +108,14 @@ namespace MWWorld
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            void removeContainerScripts(const Ptr& reference);
 | 
					            void removeContainerScripts(const Ptr& reference);
 | 
				
			||||||
            void addContainerScripts(const Ptr& reference, Ptr::CellStore* cell);
 | 
					            void addContainerScripts(const Ptr& reference, Ptr::CellStore* cell);
 | 
				
			||||||
 | 
					            void PCDropped (const Ptr& item);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        public:
 | 
					        public:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            World (OEngine::Render::OgreRenderer& renderer,
 | 
					            World (OEngine::Render::OgreRenderer& renderer,
 | 
				
			||||||
                const Files::Collections& fileCollections,
 | 
					                const Files::Collections& fileCollections,
 | 
				
			||||||
                const std::string& master, const boost::filesystem::path& resDir, const boost::filesystem::path& cacheDir, bool newGame,
 | 
					                const std::vector<std::string>& master, const std::vector<std::string>& plugins,
 | 
				
			||||||
 | 
					        	const boost::filesystem::path& resDir, const boost::filesystem::path& cacheDir, bool newGame,
 | 
				
			||||||
                ToUTF8::Utf8Encoder* encoder, std::map<std::string,std::string> fallbackMap, int mActivationDistanceOverride);
 | 
					                ToUTF8::Utf8Encoder* encoder, std::map<std::string,std::string> fallbackMap, int mActivationDistanceOverride);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            virtual ~World();
 | 
					            virtual ~World();
 | 
				
			||||||
| 
						 | 
					@ -143,7 +145,7 @@ namespace MWWorld
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            virtual const MWWorld::ESMStore& getStore() const;
 | 
					            virtual const MWWorld::ESMStore& getStore() const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            virtual ESM::ESMReader& getEsmReader();
 | 
					            virtual std::vector<ESM::ESMReader>& getEsmReader();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            virtual LocalScripts& getLocalScripts();
 | 
					            virtual LocalScripts& getLocalScripts();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -23,6 +23,22 @@ endforeach (u)
 | 
				
			||||||
source_group ("components\\${dir}" FILES ${files})
 | 
					source_group ("components\\${dir}" FILES ${files})
 | 
				
			||||||
endmacro (add_component_dir)
 | 
					endmacro (add_component_dir)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					macro (add_component_qt_dir dir)
 | 
				
			||||||
 | 
					set (files)
 | 
				
			||||||
 | 
					foreach (u ${ARGN})
 | 
				
			||||||
 | 
					file (GLOB ALL ${CMAKE_CURRENT_SOURCE_DIR} "${dir}/${u}.[ch]pp")
 | 
				
			||||||
 | 
					foreach (f ${ALL})
 | 
				
			||||||
 | 
					list (APPEND files "${f}")
 | 
				
			||||||
 | 
					list (APPEND COMPONENT_FILES "${f}")
 | 
				
			||||||
 | 
					endforeach (f)
 | 
				
			||||||
 | 
					file (GLOB MOC_H ${CMAKE_CURRENT_SOURCE_DIR} "${dir}/${u}.hpp")
 | 
				
			||||||
 | 
					foreach (fi ${MOC_H})
 | 
				
			||||||
 | 
					list (APPEND COMPONENT_MOC_FILES "${fi}")
 | 
				
			||||||
 | 
					endforeach (fi)
 | 
				
			||||||
 | 
					endforeach (u)
 | 
				
			||||||
 | 
					source_group ("components\\${dir}" FILES ${files})
 | 
				
			||||||
 | 
					endmacro (add_component_qt_dir)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
macro (copy_all_files source_dir destination_dir files)
 | 
					macro (copy_all_files source_dir destination_dir files)
 | 
				
			||||||
foreach (f ${files})
 | 
					foreach (f ${files})
 | 
				
			||||||
get_filename_component(filename ${f} NAME)
 | 
					get_filename_component(filename ${f} NAME)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -66,9 +66,21 @@ add_component_dir (translation
 | 
				
			||||||
    translation
 | 
					    translation
 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					find_package(Qt4 COMPONENTS QtCore QtGui)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					if(QT_QTGUI_LIBRARY AND QT_QTCORE_LIBRARY)
 | 
				
			||||||
 | 
					   add_component_qt_dir (fileorderlist
 | 
				
			||||||
 | 
					       datafileslist model/modelitem model/datafilesmodel model/esm/esmfile
 | 
				
			||||||
 | 
					       utils/filedialog utils/lineedit utils/naturalsort
 | 
				
			||||||
 | 
					       )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					   include(${QT_USE_FILE})
 | 
				
			||||||
 | 
					   QT4_WRAP_CPP(MOC_SRCS ${COMPONENT_MOC_FILES})
 | 
				
			||||||
 | 
					endif(QT_QTGUI_LIBRARY AND QT_QTCORE_LIBRARY)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
include_directories(${BULLET_INCLUDE_DIRS})
 | 
					include_directories(${BULLET_INCLUDE_DIRS})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
add_library(components STATIC ${COMPONENT_FILES})
 | 
					add_library(components STATIC ${COMPONENT_FILES} ${MOC_SRCS})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
target_link_libraries(components ${Boost_LIBRARIES} ${OGRE_LIBRARIES})
 | 
					target_link_libraries(components ${Boost_LIBRARIES} ${OGRE_LIBRARIES})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -89,6 +89,7 @@ struct MasterData
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  std::string name;
 | 
					  std::string name;
 | 
				
			||||||
  uint64_t size;
 | 
					  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
 | 
					// Data that is only present in save game files
 | 
				
			||||||
| 
						 | 
					@ -113,6 +114,10 @@ struct ESM_Context
 | 
				
			||||||
  size_t leftFile;
 | 
					  size_t leftFile;
 | 
				
			||||||
  NAME recName, subName;
 | 
					  NAME recName, subName;
 | 
				
			||||||
  HEDRstruct header;
 | 
					  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.
 | 
				
			||||||
 | 
					  int index;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // True if subName has been read but not used.
 | 
					  // True if subName has been read but not used.
 | 
				
			||||||
  bool subCached;
 | 
					  bool subCached;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -78,6 +78,17 @@ public:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  void openRaw(const std::string &file);
 | 
					  void openRaw(const std::string &file);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // This is a quick hack for multiple esm/esp files. Each plugin introduces its own
 | 
				
			||||||
 | 
					  //  terrain palette, but ESMReader does not pass a reference to the correct plugin
 | 
				
			||||||
 | 
					  //  to the individual load() methods. This hack allows to pass this reference
 | 
				
			||||||
 | 
					  //  indirectly to the load() method.
 | 
				
			||||||
 | 
					  int mIdx;
 | 
				
			||||||
 | 
					  void setIndex(const int index) {mIdx = index; mCtx.index = index;}
 | 
				
			||||||
 | 
					  const int getIndex() {return mIdx;}
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					  void setGlobalReaderList(std::vector<ESMReader> *list) {mGlobalReaderList = list;}
 | 
				
			||||||
 | 
					  std::vector<ESMReader> *getGlobalReaderList() {return mGlobalReaderList;}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  /*************************************************************************
 | 
					  /*************************************************************************
 | 
				
			||||||
   *
 | 
					   *
 | 
				
			||||||
   *  Medium-level reading shortcuts
 | 
					   *  Medium-level reading shortcuts
 | 
				
			||||||
| 
						 | 
					@ -110,6 +121,14 @@ public:
 | 
				
			||||||
      getHT(x);
 | 
					      getHT(x);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  template <typename X>
 | 
				
			||||||
 | 
					  void getHNOT(X &x, const char* name, int size)
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					      assert(sizeof(X) == size);
 | 
				
			||||||
 | 
					      if(isNextSub(name))
 | 
				
			||||||
 | 
					          getHT(x);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  int64_t getHNLong(const char *name);
 | 
					  int64_t getHNLong(const char *name);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // Get data of a given type/size, including subrecord header
 | 
					  // Get data of a given type/size, including subrecord header
 | 
				
			||||||
| 
						 | 
					@ -251,6 +270,7 @@ private:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  SaveData mSaveData;
 | 
					  SaveData mSaveData;
 | 
				
			||||||
  MasterList mMasters;
 | 
					  MasterList mMasters;
 | 
				
			||||||
 | 
					  std::vector<ESMReader> *mGlobalReaderList;
 | 
				
			||||||
  ToUTF8::Utf8Encoder* mEncoder;
 | 
					  ToUTF8::Utf8Encoder* mEncoder;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2,13 +2,29 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <string>
 | 
					#include <string>
 | 
				
			||||||
#include <sstream>
 | 
					#include <sstream>
 | 
				
			||||||
 | 
					#include <list>
 | 
				
			||||||
 | 
					#include <boost/concept_check.hpp>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "esmreader.hpp"
 | 
					#include "esmreader.hpp"
 | 
				
			||||||
#include "esmwriter.hpp"
 | 
					#include "esmwriter.hpp"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <apps/openmw/mwworld/store.hpp>
 | 
				
			||||||
 | 
					#include <apps/openmw/mwworld/cellstore.hpp>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace ESM
 | 
					namespace ESM
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// Some overloaded copare operators.
 | 
				
			||||||
 | 
					bool operator==(const MovedCellRef& ref, int pRefnum)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  return (ref.mRefnum == pRefnum);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool operator==(const CellRef& ref, int pRefnum)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  return (ref.mRefnum == pRefnum);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void CellRef::save(ESMWriter &esm)
 | 
					void CellRef::save(ESMWriter &esm)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    esm.writeHNT("FRMR", mRefnum);
 | 
					    esm.writeHNT("FRMR", mRefnum);
 | 
				
			||||||
| 
						 | 
					@ -63,10 +79,11 @@ void CellRef::save(ESMWriter &esm)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void Cell::load(ESMReader &esm)
 | 
					void Cell::load(ESMReader &esm, MWWorld::ESMStore &store)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    // Ignore this for now, it might mean we should delete the entire
 | 
					    // Ignore this for now, it might mean we should delete the entire
 | 
				
			||||||
    // cell?
 | 
					    // cell?
 | 
				
			||||||
 | 
					    // TODO: treat the special case "another plugin moved this ref, but we want to delete it"!
 | 
				
			||||||
    if (esm.isNextSub("DELE")) {
 | 
					    if (esm.isNextSub("DELE")) {
 | 
				
			||||||
        esm.skipHSub();
 | 
					        esm.skipHSub();
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
| 
						 | 
					@ -109,9 +126,37 @@ void Cell::load(ESMReader &esm)
 | 
				
			||||||
    if (esm.isNextSub("NAM0")) {
 | 
					    if (esm.isNextSub("NAM0")) {
 | 
				
			||||||
        esm.getHT(mNAM0);
 | 
					        esm.getHT(mNAM0);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    // preload moved references
 | 
				
			||||||
 | 
					    while (esm.isNextSub("MVRF")) {
 | 
				
			||||||
 | 
					        CellRef ref;
 | 
				
			||||||
 | 
					        MovedCellRef cMRef;
 | 
				
			||||||
 | 
					        getNextMVRF(esm, cMRef);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        MWWorld::Store<ESM::Cell> &cStore = const_cast<MWWorld::Store<ESM::Cell>&>(store.get<ESM::Cell>());
 | 
				
			||||||
 | 
					        ESM::Cell *cellAlt = const_cast<ESM::Cell*>(cStore.searchOrCreate(cMRef.mTarget[0], cMRef.mTarget[1]));
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        // Get regular moved reference data. Adapted from CellStore::loadRefs. Maybe we can optimize the following
 | 
				
			||||||
 | 
					        //  implementation when the oher implementation works as well.
 | 
				
			||||||
 | 
					        getNextRef(esm, ref);
 | 
				
			||||||
 | 
					        std::string lowerCase;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        std::transform (ref.mRefID.begin(), ref.mRefID.end(), std::back_inserter (lowerCase),
 | 
				
			||||||
 | 
					            (int(*)(int)) std::tolower);
 | 
				
			||||||
 | 
					                
 | 
				
			||||||
 | 
					        // Add data required to make reference appear in the correct cell.
 | 
				
			||||||
 | 
					        // We should not need to test for duplicates, as this part of the code is pre-cell merge.
 | 
				
			||||||
 | 
					        mMovedRefs.push_back(cMRef);
 | 
				
			||||||
 | 
					        // But there may be duplicates here!
 | 
				
			||||||
 | 
					        ESM::CellRefTracker::iterator iter = std::find(cellAlt->mLeasedRefs.begin(), cellAlt->mLeasedRefs.end(), ref.mRefnum);
 | 
				
			||||||
 | 
					        if (iter == cellAlt->mLeasedRefs.end())
 | 
				
			||||||
 | 
					          cellAlt->mLeasedRefs.push_back(ref);
 | 
				
			||||||
 | 
					        else
 | 
				
			||||||
 | 
					          *iter = ref;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Save position of the cell references and move on
 | 
					    // Save position of the cell references and move on
 | 
				
			||||||
    mContext = esm.getContext();
 | 
					    mContextList.push_back(esm.getContext());
 | 
				
			||||||
    esm.skipRecord();
 | 
					    esm.skipRecord();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -146,9 +191,9 @@ void Cell::save(ESMWriter &esm)
 | 
				
			||||||
        esm.writeHNT("NAM0", mNAM0);
 | 
					        esm.writeHNT("NAM0", mNAM0);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void Cell::restore(ESMReader &esm) const
 | 
					void Cell::restore(ESMReader &esm, int iCtx) const
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    esm.restoreContext(mContext);
 | 
					    esm.restoreContext(mContextList[iCtx]);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
std::string Cell::getDescription() const
 | 
					std::string Cell::getDescription() const
 | 
				
			||||||
| 
						 | 
					@ -167,17 +212,61 @@ std::string Cell::getDescription() const
 | 
				
			||||||
 | 
					
 | 
				
			||||||
bool Cell::getNextRef(ESMReader &esm, CellRef &ref)
 | 
					bool Cell::getNextRef(ESMReader &esm, CellRef &ref)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
					    // TODO: Try and document reference numbering, I don't think this has been done anywhere else.
 | 
				
			||||||
    if (!esm.hasMoreSubs())
 | 
					    if (!esm.hasMoreSubs())
 | 
				
			||||||
        return false;
 | 
					        return false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // NOTE: We should not need this check. It is a safety check until we have checked
 | 
				
			||||||
 | 
					    // more plugins, and how they treat these moved references.
 | 
				
			||||||
 | 
					    if (esm.isNextSub("MVRF")) {
 | 
				
			||||||
 | 
					        esm.skipRecord(); // skip MVRF
 | 
				
			||||||
 | 
					        esm.skipRecord(); // skip CNDT
 | 
				
			||||||
 | 
					        // That should be it, I haven't seen any other fields yet.
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    esm.getHNT(ref.mRefnum, "FRMR");
 | 
					    esm.getHNT(ref.mRefnum, "FRMR");
 | 
				
			||||||
    ref.mRefID = esm.getHNString("NAME");
 | 
					    ref.mRefID = esm.getHNString("NAME");
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    // Identify references belonging to a parent file and adapt the ID accordingly.
 | 
				
			||||||
 | 
					    int local = (ref.mRefnum & 0xff000000) >> 24;
 | 
				
			||||||
 | 
					    size_t global = esm.getIndex() + 1;
 | 
				
			||||||
 | 
					    if (local)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        // 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();
 | 
				
			||||||
 | 
					        global = masters[local-1].index + 1;
 | 
				
			||||||
 | 
					        ref.mRefnum |= global << 24; // insert global plugin ID
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    else
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        // This is an addition by the present plugin. Set the corresponding plugin index.
 | 
				
			||||||
 | 
					        ref.mRefnum |= global << 24; // insert global plugin ID
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // getHNOT will not change the existing value if the subrecord is
 | 
					    // getHNOT will not change the existing value if the subrecord is
 | 
				
			||||||
    // missing
 | 
					    // missing
 | 
				
			||||||
    ref.mScale = 1.0;
 | 
					    ref.mScale = 1.0;
 | 
				
			||||||
    esm.getHNOT(ref.mScale, "XSCL");
 | 
					    esm.getHNOT(ref.mScale, "XSCL");
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    // TODO: support loading references from saves, there are tons of keys not recognized yet.
 | 
				
			||||||
 | 
					    // The following is just an incomplete list.
 | 
				
			||||||
 | 
					    if (esm.isNextSub("ACTN"))
 | 
				
			||||||
 | 
					        esm.skipHSub();
 | 
				
			||||||
 | 
					    if (esm.isNextSub("STPR"))
 | 
				
			||||||
 | 
					        esm.skipHSub();
 | 
				
			||||||
 | 
					    if (esm.isNextSub("ACDT"))
 | 
				
			||||||
 | 
					        esm.skipHSub();
 | 
				
			||||||
 | 
					    if (esm.isNextSub("ACSC"))
 | 
				
			||||||
 | 
					        esm.skipHSub();
 | 
				
			||||||
 | 
					    if (esm.isNextSub("ACSL"))
 | 
				
			||||||
 | 
					        esm.skipHSub();
 | 
				
			||||||
 | 
					    if (esm.isNextSub("CHRD"))
 | 
				
			||||||
 | 
					        esm.skipHSub();
 | 
				
			||||||
 | 
					    else if (esm.isNextSub("CRED")) // ???
 | 
				
			||||||
 | 
					        esm.skipHSub();
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
    ref.mOwner = esm.getHNOString("ANAM");
 | 
					    ref.mOwner = esm.getHNOString("ANAM");
 | 
				
			||||||
    ref.mGlob = esm.getHNOString("BNAM");
 | 
					    ref.mGlob = esm.getHNOString("BNAM");
 | 
				
			||||||
    ref.mSoul = esm.getHNOString("XSOL");
 | 
					    ref.mSoul = esm.getHNOString("XSOL");
 | 
				
			||||||
| 
						 | 
					@ -215,17 +304,43 @@ bool Cell::getNextRef(ESMReader &esm, CellRef &ref)
 | 
				
			||||||
    esm.getHNOT(ref.mUnam, "UNAM");
 | 
					    esm.getHNOT(ref.mUnam, "UNAM");
 | 
				
			||||||
    esm.getHNOT(ref.mFltv, "FLTV");
 | 
					    esm.getHNOT(ref.mFltv, "FLTV");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    esm.getHNT(ref.mPos, "DATA", 24);
 | 
					    esm.getHNOT(ref.mPos, "DATA", 24);
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
    // Number of references in the cell? Maximum once in each cell,
 | 
					    // Number of references in the cell? Maximum once in each cell,
 | 
				
			||||||
    // but not always at the beginning, and not always right. In other
 | 
					    // but not always at the beginning, and not always right. In other
 | 
				
			||||||
    // words, completely useless.
 | 
					    // words, completely useless.
 | 
				
			||||||
 | 
					    // Update: Well, maybe not completely useless. This might actually be
 | 
				
			||||||
 | 
					    //  number_of_references + number_of_references_moved_here_Across_boundaries,
 | 
				
			||||||
 | 
					    //  and could be helpful for collecting these weird moved references.
 | 
				
			||||||
    ref.mNam0 = 0;
 | 
					    ref.mNam0 = 0;
 | 
				
			||||||
    if (esm.isNextSub("NAM0"))
 | 
					    if (esm.isNextSub("NAM0"))
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        esm.getHT(ref.mNam0);
 | 
					        esm.getHT(ref.mNam0);
 | 
				
			||||||
        //esm.getHNOT(NAM0, "NAM0");
 | 
					        //esm.getHNOT(NAM0, "NAM0");
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    if (esm.isNextSub("DELE")) {
 | 
				
			||||||
 | 
					        esm.skipHSub();
 | 
				
			||||||
 | 
					        ref.mDeleted = 2; // Deleted, will not respawn.
 | 
				
			||||||
 | 
					        // TODO: find out when references do respawn.
 | 
				
			||||||
 | 
					    } else
 | 
				
			||||||
 | 
					        ref.mDeleted = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return true;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool Cell::getNextMVRF(ESMReader &esm, MovedCellRef &mref)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    esm.getHT(mref.mRefnum);
 | 
				
			||||||
 | 
					    esm.getHNOT(mref.mTarget, "CNDT");
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    // Identify references belonging to a parent file and adapt the ID accordingly.
 | 
				
			||||||
 | 
					    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();
 | 
				
			||||||
 | 
					    global = masters[local-1].index + 1;
 | 
				
			||||||
 | 
					    mref.mRefnum |= global << 24; // insert global plugin ID
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return true;
 | 
					    return true;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2,9 +2,18 @@
 | 
				
			||||||
#define OPENMW_ESM_CELL_H
 | 
					#define OPENMW_ESM_CELL_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <string>
 | 
					#include <string>
 | 
				
			||||||
 | 
					#include <vector>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "esmcommon.hpp"
 | 
					#include "esmcommon.hpp"
 | 
				
			||||||
#include "defs.hpp"
 | 
					#include "defs.hpp"
 | 
				
			||||||
 | 
					#include "apps/openmw/mwbase/world.hpp"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					namespace MWWorld {
 | 
				
			||||||
 | 
					  class ESMStore;
 | 
				
			||||||
 | 
					  class CellStore;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace ESM
 | 
					namespace ESM
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
| 
						 | 
					@ -69,6 +78,9 @@ public:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // No idea - occurs ONCE in Morrowind.esm, for an activator
 | 
					  // No idea - occurs ONCE in Morrowind.esm, for an activator
 | 
				
			||||||
  char mUnam;
 | 
					  char mUnam;
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					  // Track deleted references. 0 - not deleted, 1 - deleted, but respawns, 2 - deleted and does not respawn.
 | 
				
			||||||
 | 
					  int mDeleted;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // Occurs in Tribunal.esm, eg. in the cell "Mournhold, Plaza
 | 
					  // Occurs in Tribunal.esm, eg. in the cell "Mournhold, Plaza
 | 
				
			||||||
  // Brindisi Dorom", where it has the value 100. Also only for
 | 
					  // Brindisi Dorom", where it has the value 100. Also only for
 | 
				
			||||||
| 
						 | 
					@ -82,6 +94,31 @@ public:
 | 
				
			||||||
  void save(ESMWriter &esm);
 | 
					  void save(ESMWriter &esm);
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Moved cell reference tracking object. This mainly stores the target cell
 | 
				
			||||||
 | 
					        of the reference, so we can easily know where it has been moved when another
 | 
				
			||||||
 | 
					        plugin tries to move it independently.
 | 
				
			||||||
 | 
					    Unfortunately, we need to implement this here.
 | 
				
			||||||
 | 
					    */
 | 
				
			||||||
 | 
					class MovedCellRef
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					public:
 | 
				
			||||||
 | 
					    int mRefnum;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Target cell (if exterior)
 | 
				
			||||||
 | 
					    int mTarget[2];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // TODO: Support moving references between exterior and interior cells!
 | 
				
			||||||
 | 
					    //  This may happen in saves, when an NPC follows the player. Tribunal
 | 
				
			||||||
 | 
					    //  introduces a henchman (which no one uses), so we may need this as well.
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// Overloaded copare operator used to search inside a list of cell refs.
 | 
				
			||||||
 | 
					bool operator==(const MovedCellRef& ref, int pRefnum);
 | 
				
			||||||
 | 
					bool operator==(const CellRef& ref, int pRefnum);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					typedef std::list<MovedCellRef> MovedCellRefTracker;
 | 
				
			||||||
 | 
					typedef std::list<CellRef> CellRefTracker;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Cells hold data about objects, creatures, statics (rocks, walls,
 | 
					/* Cells hold data about objects, creatures, statics (rocks, walls,
 | 
				
			||||||
   buildings) and landscape (for exterior cells). Cells frequently
 | 
					   buildings) and landscape (for exterior cells). Cells frequently
 | 
				
			||||||
   also has other associated LAND and PGRD records. Combined, all this
 | 
					   also has other associated LAND and PGRD records. Combined, all this
 | 
				
			||||||
| 
						 | 
					@ -120,15 +157,24 @@ struct Cell
 | 
				
			||||||
  // Optional region name for exterior and quasi-exterior cells.
 | 
					  // Optional region name for exterior and quasi-exterior cells.
 | 
				
			||||||
  std::string mRegion;
 | 
					  std::string mRegion;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  ESM_Context mContext; // File position
 | 
					  std::vector<ESM_Context> mContextList; // File position; multiple positions for multiple plugin support
 | 
				
			||||||
  DATAstruct mData;
 | 
					  DATAstruct mData;
 | 
				
			||||||
  AMBIstruct mAmbi;
 | 
					  AMBIstruct mAmbi;
 | 
				
			||||||
  float mWater; // Water level
 | 
					  float mWater; // Water level
 | 
				
			||||||
  bool mWaterInt;
 | 
					  bool mWaterInt;
 | 
				
			||||||
  int mMapColor;
 | 
					  int mMapColor;
 | 
				
			||||||
  int mNAM0;
 | 
					  int mNAM0;
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
  void load(ESMReader &esm);
 | 
					  // References "leased" from another cell (i.e. a different cell
 | 
				
			||||||
 | 
					  //  introduced this ref, and it has been moved here by a plugin)
 | 
				
			||||||
 | 
					  CellRefTracker mLeasedRefs;
 | 
				
			||||||
 | 
					  MovedCellRefTracker mMovedRefs;
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					  void load(ESMReader &esm, MWWorld::ESMStore &store);
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					  // This method is left in for compatibility with esmtool. Parsing moved references currently requires
 | 
				
			||||||
 | 
					  //  passing ESMStore, bit it does not know about this parameter, so we do it this way.
 | 
				
			||||||
 | 
					  void load(ESMReader &esm) {};
 | 
				
			||||||
  void save(ESMWriter &esm);
 | 
					  void save(ESMWriter &esm);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  bool isExterior() const
 | 
					  bool isExterior() const
 | 
				
			||||||
| 
						 | 
					@ -151,7 +197,7 @@ struct Cell
 | 
				
			||||||
  // somewhere other than the file system, you need to pre-open the
 | 
					  // somewhere other than the file system, you need to pre-open the
 | 
				
			||||||
  // ESMReader, and the filename must match the stored filename
 | 
					  // ESMReader, and the filename must match the stored filename
 | 
				
			||||||
  // exactly.
 | 
					  // exactly.
 | 
				
			||||||
  void restore(ESMReader &esm) const;
 | 
					  void restore(ESMReader &esm, int iCtx) const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  std::string getDescription() const;
 | 
					  std::string getDescription() const;
 | 
				
			||||||
  ///< Return a short string describing the cell (mostly used for debugging/logging purpose)
 | 
					  ///< Return a short string describing the cell (mostly used for debugging/logging purpose)
 | 
				
			||||||
| 
						 | 
					@ -163,6 +209,11 @@ struct Cell
 | 
				
			||||||
     reuse one memory location without blanking it between calls.
 | 
					     reuse one memory location without blanking it between calls.
 | 
				
			||||||
  */
 | 
					  */
 | 
				
			||||||
  static bool getNextRef(ESMReader &esm, CellRef &ref);
 | 
					  static bool getNextRef(ESMReader &esm, CellRef &ref);
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					  /* This fetches an MVRF record, which is used to track moved references.
 | 
				
			||||||
 | 
					   * Since they are comparably rare, we use a separate method for this.
 | 
				
			||||||
 | 
					   */
 | 
				
			||||||
 | 
					  static bool getNextMVRF(ESMReader &esm, MovedCellRef &mref);
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -76,8 +76,29 @@ std::string GameSetting::getString() const
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    if (mType==VT_String)
 | 
					    if (mType==VT_String)
 | 
				
			||||||
        return mStr;
 | 
					        return mStr;
 | 
				
			||||||
        
 | 
					
 | 
				
			||||||
    throw std::runtime_error ("GMST " + mId + " is not a string");
 | 
					    throw std::runtime_error ("GMST " + mId + " is not a string");
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    void GameSetting::blank()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        mStr.clear();
 | 
				
			||||||
 | 
					        mI = 0;
 | 
				
			||||||
 | 
					        mF = 0;
 | 
				
			||||||
 | 
					        mType = VT_Float;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    bool operator== (const GameSetting& left, const GameSetting& right)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        if (left.mType!=right.mType)
 | 
				
			||||||
 | 
					            return false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        switch (left.mType)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            case VT_Float: return left.mF==right.mF;
 | 
				
			||||||
 | 
					            case VT_Int: return left.mI==right.mI;
 | 
				
			||||||
 | 
					            case VT_String: return left.mStr==right.mStr;
 | 
				
			||||||
 | 
					            default: return false;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -26,17 +26,22 @@ struct GameSetting
 | 
				
			||||||
    VarType mType;
 | 
					    VarType mType;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    void load(ESMReader &esm);
 | 
					    void load(ESMReader &esm);
 | 
				
			||||||
    
 | 
					
 | 
				
			||||||
    int getInt() const;
 | 
					    int getInt() const;
 | 
				
			||||||
    ///< Throws an exception if GMST is not of type int or float.
 | 
					    ///< Throws an exception if GMST is not of type int or float.
 | 
				
			||||||
    
 | 
					
 | 
				
			||||||
    float getFloat() const;
 | 
					    float getFloat() const;
 | 
				
			||||||
    ///< Throws an exception if GMST is not of type int or float.
 | 
					    ///< Throws an exception if GMST is not of type int or float.
 | 
				
			||||||
    
 | 
					
 | 
				
			||||||
    std::string getString() const;
 | 
					    std::string getString() const;
 | 
				
			||||||
    ///< Throwns an exception if GMST is not of type string.
 | 
					    ///< Throwns an exception if GMST is not of type string.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    void save(ESMWriter &esm);
 | 
					    void save(ESMWriter &esm);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    void blank();
 | 
				
			||||||
 | 
					    ///< Set record to default state (does not touch the ID).
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    bool operator== (const GameSetting& left, const GameSetting& right);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -81,6 +81,7 @@ Land::~Land()
 | 
				
			||||||
void Land::load(ESMReader &esm)
 | 
					void Land::load(ESMReader &esm)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    mEsm = &esm;
 | 
					    mEsm = &esm;
 | 
				
			||||||
 | 
					    mPlugin = mEsm->getIndex();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Get the grid location
 | 
					    // Get the grid location
 | 
				
			||||||
    esm.getSubNameIs("INTV");
 | 
					    esm.getSubNameIs("INTV");
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -23,6 +23,7 @@ struct Land
 | 
				
			||||||
    int mFlags; // Only first four bits seem to be used, don't know what
 | 
					    int mFlags; // Only first four bits seem to be used, don't know what
 | 
				
			||||||
    // they mean.
 | 
					    // they mean.
 | 
				
			||||||
    int mX, mY; // Map coordinates.
 | 
					    int mX, mY; // Map coordinates.
 | 
				
			||||||
 | 
					    int mPlugin; // Plugin index, used to reference the correct material palette.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // File context. This allows the ESM reader to be 'reset' to this
 | 
					    // File context. This allows the ESM reader to be 'reset' to this
 | 
				
			||||||
    // location later when we are ready to load the full data set.
 | 
					    // location later when we are ready to load the full data set.
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										351
									
								
								components/fileorderlist/datafileslist.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										351
									
								
								components/fileorderlist/datafileslist.cpp
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,351 @@
 | 
				
			||||||
 | 
					#include <QtGui>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <components/esm/esmreader.hpp>
 | 
				
			||||||
 | 
					#include <components/files/configurationmanager.hpp>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "model/datafilesmodel.hpp"
 | 
				
			||||||
 | 
					#include "model/esm/esmfile.hpp"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "utils/filedialog.hpp"
 | 
				
			||||||
 | 
					#include "utils/lineedit.hpp"
 | 
				
			||||||
 | 
					#include "utils/naturalsort.hpp"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "datafileslist.hpp"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <boost/version.hpp>
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Workaround for problems with whitespaces in paths in older versions of Boost library
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					#if (BOOST_VERSION <= 104600)
 | 
				
			||||||
 | 
					namespace boost
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    template<>
 | 
				
			||||||
 | 
					    inline boost::filesystem::path lexical_cast<boost::filesystem::path, std::string>(const std::string& arg)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return boost::filesystem::path(arg);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					} /* namespace boost */
 | 
				
			||||||
 | 
					#endif /* (BOOST_VERSION <= 104600) */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					using namespace ESM;
 | 
				
			||||||
 | 
					using namespace std;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//sort QModelIndexList ascending
 | 
				
			||||||
 | 
					bool rowGreaterThan(const QModelIndex &index1, const QModelIndex &index2)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    return index1.row() >= index2.row();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//sort QModelIndexList descending
 | 
				
			||||||
 | 
					bool rowSmallerThan(const QModelIndex &index1, const QModelIndex &index2)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    return index1.row() <= index2.row();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					DataFilesList::DataFilesList(Files::ConfigurationManager &cfg, QWidget *parent)
 | 
				
			||||||
 | 
					    : QWidget(parent)
 | 
				
			||||||
 | 
					    , mCfgMgr(cfg)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    // Models
 | 
				
			||||||
 | 
					    mMastersModel = new DataFilesModel(this);
 | 
				
			||||||
 | 
					    mPluginsModel = new DataFilesModel(this);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    mPluginsProxyModel = new QSortFilterProxyModel();
 | 
				
			||||||
 | 
					    mPluginsProxyModel->setDynamicSortFilter(true);
 | 
				
			||||||
 | 
					    mPluginsProxyModel->setSourceModel(mPluginsModel);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Filter toolbar
 | 
				
			||||||
 | 
					    QLabel *filterLabel = new QLabel(tr("&Filter:"), this);
 | 
				
			||||||
 | 
					    LineEdit *filterLineEdit = new LineEdit(this);
 | 
				
			||||||
 | 
					    filterLabel->setBuddy(filterLineEdit);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    QToolBar *filterToolBar = new QToolBar(this);
 | 
				
			||||||
 | 
					    filterToolBar->setMovable(false);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Create a container widget and a layout to get the spacer to work
 | 
				
			||||||
 | 
					    QWidget *filterWidget = new QWidget(this);
 | 
				
			||||||
 | 
					    QHBoxLayout *filterLayout = new QHBoxLayout(filterWidget);
 | 
				
			||||||
 | 
					    QSpacerItem *hSpacer1 = new QSpacerItem(40, 20, QSizePolicy::Expanding, QSizePolicy::Minimum);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    filterLayout->addItem(hSpacer1);
 | 
				
			||||||
 | 
					    filterLayout->addWidget(filterLabel);
 | 
				
			||||||
 | 
					    filterLayout->addWidget(filterLineEdit);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    filterToolBar->addWidget(filterWidget);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    QCheckBox checkBox;
 | 
				
			||||||
 | 
					    unsigned int height = checkBox.sizeHint().height() + 4;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    mMastersTable = new QTableView(this);
 | 
				
			||||||
 | 
					    mMastersTable->setModel(mMastersModel);
 | 
				
			||||||
 | 
					    mMastersTable->setObjectName("MastersTable");
 | 
				
			||||||
 | 
					    mMastersTable->setSelectionBehavior(QAbstractItemView::SelectRows);
 | 
				
			||||||
 | 
					    mMastersTable->setSelectionMode(QAbstractItemView::SingleSelection);
 | 
				
			||||||
 | 
					    mMastersTable->setEditTriggers(QAbstractItemView::NoEditTriggers);
 | 
				
			||||||
 | 
					    mMastersTable->setAlternatingRowColors(true);
 | 
				
			||||||
 | 
					    mMastersTable->horizontalHeader()->setStretchLastSection(true);
 | 
				
			||||||
 | 
					    mMastersTable->horizontalHeader()->hide();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Set the row height to the size of the checkboxes
 | 
				
			||||||
 | 
					    mMastersTable->verticalHeader()->setDefaultSectionSize(height);
 | 
				
			||||||
 | 
					    mMastersTable->verticalHeader()->setResizeMode(QHeaderView::Fixed);
 | 
				
			||||||
 | 
					    mMastersTable->verticalHeader()->hide();
 | 
				
			||||||
 | 
					    mMastersTable->setColumnHidden(1, true);
 | 
				
			||||||
 | 
					    mMastersTable->setColumnHidden(2, true);
 | 
				
			||||||
 | 
					    mMastersTable->setColumnHidden(3, true);
 | 
				
			||||||
 | 
					    mMastersTable->setColumnHidden(4, true);
 | 
				
			||||||
 | 
					    mMastersTable->setColumnHidden(5, true);
 | 
				
			||||||
 | 
					    mMastersTable->setColumnHidden(6, true);
 | 
				
			||||||
 | 
					    mMastersTable->setColumnHidden(7, true);
 | 
				
			||||||
 | 
					    mMastersTable->setColumnHidden(8, true);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    mPluginsTable = new QTableView(this);
 | 
				
			||||||
 | 
					    mPluginsTable->setModel(mPluginsProxyModel);
 | 
				
			||||||
 | 
					    mPluginsTable->setObjectName("PluginsTable");
 | 
				
			||||||
 | 
					    mPluginsTable->setContextMenuPolicy(Qt::CustomContextMenu);
 | 
				
			||||||
 | 
					    mPluginsTable->setSelectionBehavior(QAbstractItemView::SelectRows);
 | 
				
			||||||
 | 
					    mPluginsTable->setSelectionMode(QAbstractItemView::SingleSelection);
 | 
				
			||||||
 | 
					    mPluginsTable->setEditTriggers(QAbstractItemView::NoEditTriggers);
 | 
				
			||||||
 | 
					    mPluginsTable->setAlternatingRowColors(true);
 | 
				
			||||||
 | 
					    mPluginsTable->setVerticalScrollMode(QAbstractItemView::ScrollPerItem);
 | 
				
			||||||
 | 
					    mPluginsTable->horizontalHeader()->setStretchLastSection(true);
 | 
				
			||||||
 | 
					    mPluginsTable->horizontalHeader()->hide();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    mPluginsTable->verticalHeader()->setDefaultSectionSize(height);
 | 
				
			||||||
 | 
					    mPluginsTable->verticalHeader()->setResizeMode(QHeaderView::Fixed);
 | 
				
			||||||
 | 
					    mPluginsTable->setColumnHidden(1, true);
 | 
				
			||||||
 | 
					    mPluginsTable->setColumnHidden(2, true);
 | 
				
			||||||
 | 
					    mPluginsTable->setColumnHidden(3, true);
 | 
				
			||||||
 | 
					    mPluginsTable->setColumnHidden(4, true);
 | 
				
			||||||
 | 
					    mPluginsTable->setColumnHidden(5, true);
 | 
				
			||||||
 | 
					    mPluginsTable->setColumnHidden(6, true);
 | 
				
			||||||
 | 
					    mPluginsTable->setColumnHidden(7, true);
 | 
				
			||||||
 | 
					    mPluginsTable->setColumnHidden(8, true);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Add both tables to a splitter
 | 
				
			||||||
 | 
					    QSplitter *splitter = new QSplitter(this);
 | 
				
			||||||
 | 
					    splitter->setOrientation(Qt::Horizontal);
 | 
				
			||||||
 | 
					    splitter->addWidget(mMastersTable);
 | 
				
			||||||
 | 
					    splitter->addWidget(mPluginsTable);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Adjust the default widget widths inside the splitter
 | 
				
			||||||
 | 
					    QList<int> sizeList;
 | 
				
			||||||
 | 
					    sizeList << 175 << 200;
 | 
				
			||||||
 | 
					    splitter->setSizes(sizeList);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    QVBoxLayout *pageLayout = new QVBoxLayout(this);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pageLayout->addWidget(filterToolBar);
 | 
				
			||||||
 | 
					    pageLayout->addWidget(splitter);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    connect(mPluginsTable, SIGNAL(doubleClicked(QModelIndex)), this, SLOT(setCheckState(QModelIndex)));
 | 
				
			||||||
 | 
					    connect(mMastersTable, SIGNAL(doubleClicked(QModelIndex)), this, SLOT(setCheckState(QModelIndex)));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    connect(mMastersModel, SIGNAL(checkedItemsChanged(QStringList,QStringList)), mPluginsModel, SLOT(slotcheckedItemsChanged(QStringList,QStringList)));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    connect(filterLineEdit, SIGNAL(textChanged(QString)), this, SLOT(filterChanged(QString)));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    connect(mPluginsTable, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(showContextMenu(QPoint)));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    createActions();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void DataFilesList::createActions()
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    // Refresh the plugins
 | 
				
			||||||
 | 
					    QAction *refreshAction = new QAction(tr("Refresh"), this);
 | 
				
			||||||
 | 
					    refreshAction->setShortcut(QKeySequence(tr("F5")));
 | 
				
			||||||
 | 
					    connect(refreshAction, SIGNAL(triggered()), this, SLOT(refresh()));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Context menu actions
 | 
				
			||||||
 | 
					    mCheckAction = new QAction(tr("Check selected"), this);
 | 
				
			||||||
 | 
					    connect(mCheckAction, SIGNAL(triggered()), this, SLOT(check()));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    mUncheckAction = new QAction(tr("Uncheck selected"), this);
 | 
				
			||||||
 | 
					    connect(mUncheckAction, SIGNAL(triggered()), this, SLOT(uncheck()));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Context menu for the plugins table
 | 
				
			||||||
 | 
					    mContextMenu = new QMenu(this);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    mContextMenu->addAction(mCheckAction);
 | 
				
			||||||
 | 
					    mContextMenu->addAction(mUncheckAction);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool DataFilesList::setupDataFiles(Files::PathContainer dataDirs, const QString encoding)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    // Set the charset for reading the esm/esp files
 | 
				
			||||||
 | 
					    if (!encoding.isEmpty() && encoding != QLatin1String("win1252")) {
 | 
				
			||||||
 | 
					        mMastersModel->setEncoding(encoding);
 | 
				
			||||||
 | 
					        mPluginsModel->setEncoding(encoding);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Add the paths to the respective models
 | 
				
			||||||
 | 
					    for (Files::PathContainer::iterator it = dataDirs.begin(); it != dataDirs.end(); ++it) {
 | 
				
			||||||
 | 
					        QString path = QString::fromStdString(it->string());
 | 
				
			||||||
 | 
					        path.remove(QChar('\"'));
 | 
				
			||||||
 | 
					        mMastersModel->addMasters(path);
 | 
				
			||||||
 | 
					        mPluginsModel->addPlugins(path);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    mMastersModel->sort(0);
 | 
				
			||||||
 | 
					    mPluginsModel->sort(0);
 | 
				
			||||||
 | 
					//    mMastersTable->sortByColumn(3, Qt::AscendingOrder);
 | 
				
			||||||
 | 
					//    mPluginsTable->sortByColumn(3, Qt::AscendingOrder);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return true;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void DataFilesList::selectedFiles(std::vector<boost::filesystem::path>& paths)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    QStringList masterPaths = mMastersModel->checkedItemsPaths();
 | 
				
			||||||
 | 
					    foreach (const QString &path, masterPaths)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        paths.push_back(path.toStdString());
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    QStringList pluginPaths = mPluginsModel->checkedItemsPaths();
 | 
				
			||||||
 | 
					    foreach (const QString &path, pluginPaths)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        paths.push_back(path.toStdString());
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void DataFilesList::check()
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    // Check the current selection
 | 
				
			||||||
 | 
					    if (!mPluginsTable->selectionModel()->hasSelection()) {
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    QModelIndexList indexes = mPluginsTable->selectionModel()->selectedIndexes();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    //sort selection ascending because selectedIndexes returns an unsorted list
 | 
				
			||||||
 | 
					    //qSort(indexes.begin(), indexes.end(), rowSmallerThan);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    foreach (const QModelIndex &index, indexes) {
 | 
				
			||||||
 | 
					        if (!index.isValid())
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        mPluginsModel->setCheckState(index, Qt::Checked);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void DataFilesList::uncheck()
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    // uncheck the current selection
 | 
				
			||||||
 | 
					    if (!mPluginsTable->selectionModel()->hasSelection()) {
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    QModelIndexList indexes = mPluginsTable->selectionModel()->selectedIndexes();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    //sort selection ascending because selectedIndexes returns an unsorted list
 | 
				
			||||||
 | 
					    //qSort(indexes.begin(), indexes.end(), rowSmallerThan);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    foreach (const QModelIndex &index, indexes) {
 | 
				
			||||||
 | 
					        if (!index.isValid())
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        mPluginsModel->setCheckState(index, Qt::Unchecked);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void DataFilesList::refresh()
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    mPluginsModel->sort(0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Refresh the plugins table
 | 
				
			||||||
 | 
					    mPluginsTable->scrollToTop();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void DataFilesList::setCheckState(QModelIndex index)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    if (!index.isValid())
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    QObject *object = QObject::sender();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Not a signal-slot call
 | 
				
			||||||
 | 
					    if (!object)
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (object->objectName() == QLatin1String("PluginsTable")) {
 | 
				
			||||||
 | 
					        QModelIndex sourceIndex = mPluginsProxyModel->mapToSource(index);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        (mPluginsModel->checkState(sourceIndex) == Qt::Checked)
 | 
				
			||||||
 | 
					                ? mPluginsModel->setCheckState(sourceIndex, Qt::Unchecked)
 | 
				
			||||||
 | 
					                : mPluginsModel->setCheckState(sourceIndex, Qt::Checked);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (object->objectName() == QLatin1String("MastersTable")) {
 | 
				
			||||||
 | 
					        (mMastersModel->checkState(index) == Qt::Checked)
 | 
				
			||||||
 | 
					                ? mMastersModel->setCheckState(index, Qt::Unchecked)
 | 
				
			||||||
 | 
					                : mMastersModel->setCheckState(index, Qt::Checked);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void DataFilesList::uncheckAll()
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    mMastersModel->uncheckAll();
 | 
				
			||||||
 | 
					    mPluginsModel->uncheckAll();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void DataFilesList::filterChanged(const QString filter)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    QRegExp regExp(filter, Qt::CaseInsensitive, QRegExp::FixedString);
 | 
				
			||||||
 | 
					    mPluginsProxyModel->setFilterRegExp(regExp);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void DataFilesList::showContextMenu(const QPoint &point)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    // Make sure there are plugins in the view
 | 
				
			||||||
 | 
					    if (!mPluginsTable->selectionModel()->hasSelection()) {
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    QPoint globalPos = mPluginsTable->mapToGlobal(point);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    QModelIndexList indexes = mPluginsTable->selectionModel()->selectedIndexes();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Show the check/uncheck actions depending on the state of the selected items
 | 
				
			||||||
 | 
					    mUncheckAction->setEnabled(false);
 | 
				
			||||||
 | 
					    mCheckAction->setEnabled(false);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    foreach (const QModelIndex &index, indexes) {
 | 
				
			||||||
 | 
					        if (!index.isValid())
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					         (mPluginsModel->checkState(index) == Qt::Checked)
 | 
				
			||||||
 | 
					             ? mUncheckAction->setEnabled(true)
 | 
				
			||||||
 | 
					             : mCheckAction->setEnabled(true);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Show menu
 | 
				
			||||||
 | 
					    mContextMenu->exec(globalPos);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void DataFilesList::setCheckState(const QString& element, Qt::CheckState state)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    EsmFile *file = mPluginsModel->findItem(element);
 | 
				
			||||||
 | 
					    if (file)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        mPluginsModel->setCheckState(mPluginsModel->indexFromItem(file), Qt::Checked);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    else
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        file = mMastersModel->findItem(element);
 | 
				
			||||||
 | 
					        mMastersModel->setCheckState(mMastersModel->indexFromItem(file), Qt::Checked);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					QStringList DataFilesList::checkedFiles()
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    return mMastersModel->checkedItems() + mPluginsModel->checkedItems();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										77
									
								
								components/fileorderlist/datafileslist.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										77
									
								
								components/fileorderlist/datafileslist.hpp
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,77 @@
 | 
				
			||||||
 | 
					#ifndef DATAFILESLIST_H
 | 
				
			||||||
 | 
					#define DATAFILESLIST_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <QWidget>
 | 
				
			||||||
 | 
					#include <QModelIndex>
 | 
				
			||||||
 | 
					#include <components/files/collections.hpp>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class QTableView;
 | 
				
			||||||
 | 
					class QSortFilterProxyModel;
 | 
				
			||||||
 | 
					class QSettings;
 | 
				
			||||||
 | 
					class QAction;
 | 
				
			||||||
 | 
					class QToolBar;
 | 
				
			||||||
 | 
					class QMenu;
 | 
				
			||||||
 | 
					class ProfilesComboBox;
 | 
				
			||||||
 | 
					class DataFilesModel;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class TextInputDialog;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace Files { struct ConfigurationManager; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class DataFilesList : public QWidget
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    Q_OBJECT
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public:
 | 
				
			||||||
 | 
					    DataFilesList(Files::ConfigurationManager& cfg, QWidget *parent = 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    bool setupDataFiles(Files::PathContainer dataDirs, const QString encoding);
 | 
				
			||||||
 | 
					    void selectedFiles(std::vector<boost::filesystem::path>& paths);
 | 
				
			||||||
 | 
					    void uncheckAll();
 | 
				
			||||||
 | 
					    QStringList checkedFiles();
 | 
				
			||||||
 | 
					    void setCheckState(const QString& element, Qt::CheckState);
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public slots:
 | 
				
			||||||
 | 
					    void setCheckState(QModelIndex index);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    void filterChanged(const QString filter);
 | 
				
			||||||
 | 
					    void showContextMenu(const QPoint &point);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Action slots
 | 
				
			||||||
 | 
					//    void moveUp();
 | 
				
			||||||
 | 
					//    void moveDown();
 | 
				
			||||||
 | 
					//    void moveTop();
 | 
				
			||||||
 | 
					//    void moveBottom();
 | 
				
			||||||
 | 
					    void check();
 | 
				
			||||||
 | 
					    void uncheck();
 | 
				
			||||||
 | 
					    void refresh();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					private:
 | 
				
			||||||
 | 
					    DataFilesModel *mMastersModel;
 | 
				
			||||||
 | 
					    DataFilesModel *mPluginsModel;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    QSortFilterProxyModel *mPluginsProxyModel;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    QTableView *mMastersTable;
 | 
				
			||||||
 | 
					    QTableView *mPluginsTable;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    QMenu *mContextMenu;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//    QAction *mMoveUpAction;
 | 
				
			||||||
 | 
					//    QAction *mMoveDownAction;
 | 
				
			||||||
 | 
					//    QAction *mMoveTopAction;
 | 
				
			||||||
 | 
					//    QAction *mMoveBottomAction;
 | 
				
			||||||
 | 
					    QAction *mCheckAction;
 | 
				
			||||||
 | 
					    QAction *mUncheckAction;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    Files::ConfigurationManager &mCfgMgr;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//    const QStringList checkedPlugins();
 | 
				
			||||||
 | 
					//    const QStringList selectedMasters();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    void createActions();
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
| 
						 | 
					@ -292,6 +292,7 @@ void DataFilesModel::addMasters(const QString &path)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                EsmFile *file = new EsmFile(master);
 | 
					                EsmFile *file = new EsmFile(master);
 | 
				
			||||||
                file->setDates(info.lastModified(), info.lastRead());
 | 
					                file->setDates(info.lastModified(), info.lastRead());
 | 
				
			||||||
 | 
					                file->setPath(info.absoluteFilePath());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                // Add the master to the table
 | 
					                // Add the master to the table
 | 
				
			||||||
                if (findItem(master) == 0)
 | 
					                if (findItem(master) == 0)
 | 
				
			||||||
| 
						 | 
					@ -427,6 +428,25 @@ QStringList DataFilesModel::checkedItems()
 | 
				
			||||||
    return list;
 | 
					    return list;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					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);
 | 
				
			||||||
 | 
					        ++i;
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        if (mCheckStates[file->fileName()] == Qt::Checked && mAvailableFiles.contains(file->fileName()))
 | 
				
			||||||
 | 
					            list << file->path();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    return list;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void DataFilesModel::uncheckAll()
 | 
					void DataFilesModel::uncheckAll()
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    emit layoutAboutToBeChanged();
 | 
					    emit layoutAboutToBeChanged();
 | 
				
			||||||
| 
						 | 
					@ -43,6 +43,7 @@ public:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    QStringList checkedItems();
 | 
					    QStringList checkedItems();
 | 
				
			||||||
    QStringList uncheckedItems();
 | 
					    QStringList uncheckedItems();
 | 
				
			||||||
 | 
					    QStringList checkedItemsPaths();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    Qt::CheckState checkState(const QModelIndex &index);
 | 
					    Qt::CheckState checkState(const QModelIndex &index);
 | 
				
			||||||
    void setCheckState(const QModelIndex &index, Qt::CheckState state);
 | 
					    void setCheckState(const QModelIndex &index, Qt::CheckState state);
 | 
				
			||||||
							
								
								
									
										99
									
								
								extern/shiny/Main/Factory.cpp
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										99
									
								
								extern/shiny/Main/Factory.cpp
									
									
									
									
										vendored
									
									
								
							| 
						 | 
					@ -50,7 +50,7 @@ namespace sh
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		assert(mCurrentLanguage != Language_None);
 | 
							assert(mCurrentLanguage != Language_None);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		bool anyShaderDirty = false;
 | 
							bool removeBinaryCache = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (boost::filesystem::exists (mPlatform->getCacheFolder () + "/lastModified.txt"))
 | 
							if (boost::filesystem::exists (mPlatform->getCacheFolder () + "/lastModified.txt"))
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
| 
						 | 
					@ -182,57 +182,33 @@ namespace sh
 | 
				
			||||||
					}
 | 
										}
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
				std::string sourceFile = mPlatform->getBasePath() + "/" + it->second->findChild("source")->getValue();
 | 
									std::string sourceAbsolute = mPlatform->getBasePath() + "/" + it->second->findChild("source")->getValue();
 | 
				
			||||||
 | 
									std::string sourceRelative = it->second->findChild("source")->getValue();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
				ShaderSet newSet (it->second->findChild("type")->getValue(), cg_profile, hlsl_profile,
 | 
									ShaderSet newSet (it->second->findChild("type")->getValue(), cg_profile, hlsl_profile,
 | 
				
			||||||
								  sourceFile,
 | 
													  sourceAbsolute,
 | 
				
			||||||
								  mPlatform->getBasePath(),
 | 
													  mPlatform->getBasePath(),
 | 
				
			||||||
								  it->first,
 | 
													  it->first,
 | 
				
			||||||
								  &mGlobalSettings);
 | 
													  &mGlobalSettings);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
				int lastModified = boost::filesystem::last_write_time (boost::filesystem::path(sourceFile));
 | 
									int lastModified = boost::filesystem::last_write_time (boost::filesystem::path(sourceAbsolute));
 | 
				
			||||||
				mShadersLastModifiedNew[sourceFile] = lastModified;
 | 
									mShadersLastModifiedNew[sourceRelative] = lastModified;
 | 
				
			||||||
				if (mShadersLastModified.find(sourceFile) != mShadersLastModified.end()
 | 
									if (mShadersLastModified.find(sourceRelative) != mShadersLastModified.end())
 | 
				
			||||||
						&& mShadersLastModified[sourceFile] != lastModified)
 | 
					 | 
				
			||||||
				{
 | 
									{
 | 
				
			||||||
					// delete any outdated shaders based on this shader set.
 | 
										if (mShadersLastModified[sourceRelative] != lastModified)
 | 
				
			||||||
					if ( boost::filesystem::exists(mPlatform->getCacheFolder())
 | 
					 | 
				
			||||||
						 && boost::filesystem::is_directory(mPlatform->getCacheFolder()))
 | 
					 | 
				
			||||||
					{
 | 
										{
 | 
				
			||||||
						boost::filesystem::directory_iterator end_iter;
 | 
											// delete any outdated shaders based on this shader set
 | 
				
			||||||
						for( boost::filesystem::directory_iterator dir_iter(mPlatform->getCacheFolder()) ; dir_iter != end_iter ; ++dir_iter)
 | 
											removeCache (it->first);
 | 
				
			||||||
						{
 | 
											// remove the whole binary cache (removing only the individual shaders does not seem to be possible at this point with OGRE)
 | 
				
			||||||
							if (boost::filesystem::is_regular_file(dir_iter->status()) )
 | 
											removeBinaryCache = true;
 | 
				
			||||||
							{
 | 
					 | 
				
			||||||
								boost::filesystem::path file = dir_iter->path();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
								std::string pathname = file.filename().string();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
								// get first part of filename, e.g. main_fragment_546457654 -> main_fragment
 | 
					 | 
				
			||||||
								// there is probably a better method for this...
 | 
					 | 
				
			||||||
								std::vector<std::string> tokens;
 | 
					 | 
				
			||||||
								boost::split(tokens, pathname, boost::is_any_of("_"));
 | 
					 | 
				
			||||||
								tokens.erase(--tokens.end());
 | 
					 | 
				
			||||||
								std::string shaderName;
 | 
					 | 
				
			||||||
								for (std::vector<std::string>::const_iterator vector_iter = tokens.begin(); vector_iter != tokens.end();)
 | 
					 | 
				
			||||||
								{
 | 
					 | 
				
			||||||
									shaderName += *(vector_iter++);
 | 
					 | 
				
			||||||
									if (vector_iter != tokens.end())
 | 
					 | 
				
			||||||
										shaderName += "_";
 | 
					 | 
				
			||||||
								}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
								if (shaderName == it->first)
 | 
					 | 
				
			||||||
								{
 | 
					 | 
				
			||||||
									boost::filesystem::remove(file);
 | 
					 | 
				
			||||||
									std::cout << "Removing outdated file: " << file << std::endl;
 | 
					 | 
				
			||||||
								}
 | 
					 | 
				
			||||||
							}
 | 
					 | 
				
			||||||
						}
 | 
					 | 
				
			||||||
					}
 | 
										}
 | 
				
			||||||
 | 
					 | 
				
			||||||
					anyShaderDirty = true;
 | 
					 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
 | 
									else
 | 
				
			||||||
 | 
									{
 | 
				
			||||||
 | 
										// if we get here, this is either the first run or a new shader file was added
 | 
				
			||||||
 | 
										// in both cases we can safely delete
 | 
				
			||||||
 | 
										removeCache (it->first);
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
				mShaderSets.insert(std::make_pair(it->first, newSet));
 | 
									mShaderSets.insert(std::make_pair(it->first, newSet));
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
| 
						 | 
					@ -326,7 +302,7 @@ namespace sh
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (mPlatform->supportsShaderSerialization () && mReadMicrocodeCache && !anyShaderDirty)
 | 
							if (mPlatform->supportsShaderSerialization () && mReadMicrocodeCache && !removeBinaryCache)
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			std::string file = mPlatform->getCacheFolder () + "/shShaderCache.txt";
 | 
								std::string file = mPlatform->getCacheFolder () + "/shShaderCache.txt";
 | 
				
			||||||
			if (boost::filesystem::exists(file))
 | 
								if (boost::filesystem::exists(file))
 | 
				
			||||||
| 
						 | 
					@ -613,4 +589,41 @@ namespace sh
 | 
				
			||||||
		assert(m);
 | 
							assert(m);
 | 
				
			||||||
		m->createForConfiguration (configuration, 0);
 | 
							m->createForConfiguration (configuration, 0);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						void Factory::removeCache(const std::string& pattern)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							if ( boost::filesystem::exists(mPlatform->getCacheFolder())
 | 
				
			||||||
 | 
								 && boost::filesystem::is_directory(mPlatform->getCacheFolder()))
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								boost::filesystem::directory_iterator end_iter;
 | 
				
			||||||
 | 
								for( boost::filesystem::directory_iterator dir_iter(mPlatform->getCacheFolder()) ; dir_iter != end_iter ; ++dir_iter)
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									if (boost::filesystem::is_regular_file(dir_iter->status()) )
 | 
				
			||||||
 | 
									{
 | 
				
			||||||
 | 
										boost::filesystem::path file = dir_iter->path();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										std::string pathname = file.filename().string();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										// get first part of filename, e.g. main_fragment_546457654 -> main_fragment
 | 
				
			||||||
 | 
										// there is probably a better method for this...
 | 
				
			||||||
 | 
										std::vector<std::string> tokens;
 | 
				
			||||||
 | 
										boost::split(tokens, pathname, boost::is_any_of("_"));
 | 
				
			||||||
 | 
										tokens.erase(--tokens.end());
 | 
				
			||||||
 | 
										std::string shaderName;
 | 
				
			||||||
 | 
										for (std::vector<std::string>::const_iterator vector_iter = tokens.begin(); vector_iter != tokens.end();)
 | 
				
			||||||
 | 
										{
 | 
				
			||||||
 | 
											shaderName += *(vector_iter++);
 | 
				
			||||||
 | 
											if (vector_iter != tokens.end())
 | 
				
			||||||
 | 
												shaderName += "_";
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										if (shaderName == pattern)
 | 
				
			||||||
 | 
										{
 | 
				
			||||||
 | 
											boost::filesystem::remove(file);
 | 
				
			||||||
 | 
											std::cout << "Removing outdated shader: " << file << std::endl;
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										2
									
								
								extern/shiny/Main/Factory.hpp
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								extern/shiny/Main/Factory.hpp
									
									
									
									
										vendored
									
									
								
							| 
						 | 
					@ -202,6 +202,8 @@ namespace sh
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		MaterialInstance* findInstance (const std::string& name);
 | 
							MaterialInstance* findInstance (const std::string& name);
 | 
				
			||||||
		MaterialInstance* searchInstance (const std::string& name);
 | 
							MaterialInstance* searchInstance (const std::string& name);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							void removeCache (const std::string& pattern);
 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue