mirror of
https://gitlab.com/OpenMW/openmw.git
synced 2025-01-26 18:35:20 +00:00
Merge branch 'gmst' into next
This commit is contained in:
commit
2d937cd9e2
@ -1,17 +1,9 @@
|
||||
set(LAUNCHER
|
||||
datafilespage.cpp
|
||||
graphicspage.cpp
|
||||
main.cpp
|
||||
maindialog.cpp
|
||||
playpage.cpp
|
||||
|
||||
model/datafilesmodel.cpp
|
||||
model/modelitem.cpp
|
||||
model/esm/esmfile.cpp
|
||||
|
||||
utils/filedialog.cpp
|
||||
utils/naturalsort.cpp
|
||||
utils/lineedit.cpp
|
||||
datafilespage.cpp
|
||||
utils/profilescombobox.cpp
|
||||
utils/textinputdialog.cpp
|
||||
|
||||
@ -19,36 +11,20 @@ set(LAUNCHER
|
||||
)
|
||||
|
||||
set(LAUNCHER_HEADER
|
||||
datafilespage.hpp
|
||||
graphicspage.hpp
|
||||
maindialog.hpp
|
||||
playpage.hpp
|
||||
|
||||
model/datafilesmodel.hpp
|
||||
model/modelitem.hpp
|
||||
model/esm/esmfile.hpp
|
||||
|
||||
utils/lineedit.hpp
|
||||
utils/filedialog.hpp
|
||||
utils/naturalsort.hpp
|
||||
datafilespage.hpp
|
||||
utils/profilescombobox.hpp
|
||||
utils/textinputdialog.hpp
|
||||
|
||||
)
|
||||
|
||||
# Headers that must be pre-processed
|
||||
set(LAUNCHER_HEADER_MOC
|
||||
datafilespage.hpp
|
||||
graphicspage.hpp
|
||||
maindialog.hpp
|
||||
playpage.hpp
|
||||
|
||||
model/datafilesmodel.hpp
|
||||
model/modelitem.hpp
|
||||
model/esm/esmfile.hpp
|
||||
|
||||
utils/lineedit.hpp
|
||||
utils/filedialog.hpp
|
||||
datafilespage.hpp
|
||||
utils/profilescombobox.hpp
|
||||
utils/textinputdialog.hpp
|
||||
)
|
||||
|
@ -2,14 +2,17 @@
|
||||
|
||||
#include <components/esm/esmreader.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/esm/esmfile.hpp"
|
||||
////#include "model/datafilesmodel.hpp"
|
||||
////#include "model/esm/esmfile.hpp"
|
||||
|
||||
#include "utils/profilescombobox.hpp"
|
||||
#include "utils/filedialog.hpp"
|
||||
#include "utils/lineedit.hpp"
|
||||
#include "utils/naturalsort.hpp"
|
||||
////#include "utils/filedialog.hpp"
|
||||
////#include "utils/naturalsort.hpp"
|
||||
#include "utils/textinputdialog.hpp"
|
||||
|
||||
#include "datafilespage.hpp"
|
||||
@ -34,108 +37,11 @@ namespace boost
|
||||
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();
|
||||
}
|
||||
|
||||
DataFilesPage::DataFilesPage(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);
|
||||
mDataFilesList = new DataFilesList(mCfgMgr, this);
|
||||
|
||||
// Bottom part with profile options
|
||||
QLabel *profileLabel = new QLabel(tr("Current Profile: "), this);
|
||||
@ -155,24 +61,14 @@ DataFilesPage::DataFilesPage(Files::ConfigurationManager &cfg, QWidget *parent)
|
||||
|
||||
QVBoxLayout *pageLayout = new QVBoxLayout(this);
|
||||
|
||||
pageLayout->addWidget(filterToolBar);
|
||||
pageLayout->addWidget(splitter);
|
||||
pageLayout->addWidget(mDataFilesList);
|
||||
pageLayout->addWidget(mProfileToolBar);
|
||||
|
||||
// Create a dialog for the new profile name input
|
||||
mNewProfileDialog = new TextInputDialog(tr("New Profile"), tr("Profile name:"), this);
|
||||
|
||||
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(profileChanged(QString,QString)), this, SLOT(profileChanged(QString,QString)));
|
||||
|
||||
@ -202,20 +98,6 @@ void DataFilesPage::createActions()
|
||||
mProfileToolBar->addSeparator();
|
||||
mProfileToolBar->addAction(mNewProfileAction);
|
||||
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()
|
||||
@ -267,12 +149,8 @@ void DataFilesPage::setupConfig()
|
||||
|
||||
void DataFilesPage::readConfig()
|
||||
{
|
||||
// Don't read the config if no masters are found
|
||||
if (mMastersModel->rowCount() < 1)
|
||||
return;
|
||||
|
||||
QString profile = mProfilesComboBox->currentText();
|
||||
|
||||
|
||||
// Make sure we have no groups open
|
||||
while (!mLauncherConfig->group().isEmpty()) {
|
||||
mLauncherConfig->endGroup();
|
||||
@ -290,54 +168,11 @@ void DataFilesPage::readConfig()
|
||||
|
||||
foreach (const QString &key, childKeys) {
|
||||
const QString keyValue = mLauncherConfig->value(key).toString();
|
||||
|
||||
if (key.startsWith("Plugin")) {
|
||||
//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);
|
||||
}
|
||||
|
||||
mDataFilesList->setCheckState(keyValue, Qt::Checked);
|
||||
}
|
||||
|
||||
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()
|
||||
@ -386,77 +221,51 @@ bool 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"));
|
||||
|
||||
("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);
|
||||
|
||||
|
||||
if (variables["data"].empty()) {
|
||||
if (!showDataFilesWarning())
|
||||
return false;
|
||||
return false;
|
||||
} else {
|
||||
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));
|
||||
}
|
||||
|
||||
|
||||
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);
|
||||
|
||||
|
||||
// Second chance to display the warning, the data= entries are invalid
|
||||
while (mDataDirs.empty()) {
|
||||
if (!showDataFilesWarning())
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
// Set the charset for reading the esm/esp files
|
||||
QString encoding = QString::fromStdString(variables["encoding"].as<std::string>());
|
||||
if (!encoding.isEmpty() && encoding != QLatin1String("win1252")) {
|
||||
mMastersModel->setEncoding(encoding);
|
||||
mPluginsModel->setEncoding(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);
|
||||
|
||||
|
||||
|
||||
Files::PathContainer paths;
|
||||
paths.insert(paths.end(), mDataDirs.begin(), mDataDirs.end());
|
||||
paths.insert(paths.end(), mDataLocal.begin(), mDataLocal.end());
|
||||
mDataFilesList->setupDataFiles(paths, encoding);
|
||||
readConfig();
|
||||
return true;
|
||||
}
|
||||
|
||||
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());
|
||||
QDir userPath(pathStr);
|
||||
|
||||
@ -579,24 +388,19 @@ void DataFilesPage::writeConfig(QString profile)
|
||||
mLauncherConfig->remove(""); // Clear the subgroup
|
||||
|
||||
// Now write the masters to the configs
|
||||
const QStringList masters = mMastersModel->checkedItems();
|
||||
|
||||
// We don't use foreach because we need i
|
||||
for (int i = 0; i < masters.size(); ++i) {
|
||||
const QString currentMaster = masters.at(i);
|
||||
|
||||
mLauncherConfig->setValue(QString("Master%0").arg(i), currentMaster);
|
||||
gameConfig << "master=" << currentMaster << endl;
|
||||
|
||||
}
|
||||
|
||||
// And finally write all checked plugins
|
||||
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;
|
||||
const QStringList checkedFiles = mDataFilesList->checkedFiles();
|
||||
for(int i=0; i < checkedFiles.size(); i++)
|
||||
{
|
||||
if (checkedFiles.at(i).lastIndexOf("esm") != -1)
|
||||
{
|
||||
mLauncherConfig->setValue(QString("Master%0").arg(i), checkedFiles.at(i));
|
||||
gameConfig << "master=" << checkedFiles.at(i) << endl;
|
||||
}
|
||||
else
|
||||
{
|
||||
mLauncherConfig->setValue(QString("Plugin%1").arg(i), checkedFiles.at(i));
|
||||
gameConfig << "plugin=" << checkedFiles.at(i) << endl;
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
qDebug() << "Profile is changed from: " << previous << " to " << current;
|
||||
@ -780,8 +497,7 @@ void DataFilesPage::profileChanged(const QString &previous, const QString &curre
|
||||
return;
|
||||
}
|
||||
|
||||
mMastersModel->uncheckAll();
|
||||
mPluginsModel->uncheckAll();
|
||||
mDataFilesList->uncheckAll();
|
||||
readConfig();
|
||||
}
|
||||
|
||||
@ -810,35 +526,8 @@ void DataFilesPage::profileRenamed(const QString &previous, const QString &curre
|
||||
// Remove the profile from the combobox
|
||||
mProfilesComboBox->removeItem(mProfilesComboBox->findText(previous));
|
||||
|
||||
mMastersModel->uncheckAll();
|
||||
mPluginsModel->uncheckAll();
|
||||
mDataFilesList->uncheckAll();
|
||||
////mMastersModel->uncheckAll();
|
||||
////mPluginsModel->uncheckAll();
|
||||
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 TextInputDialog;
|
||||
class DataFilesList;
|
||||
|
||||
namespace Files { struct ConfigurationManager; }
|
||||
|
||||
@ -34,10 +35,6 @@ public:
|
||||
bool setupDataFiles();
|
||||
|
||||
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 profileRenamed(const QString &previous, const QString ¤t);
|
||||
void updateOkButton(const QString &text);
|
||||
@ -49,21 +46,11 @@ public slots:
|
||||
// void moveDown();
|
||||
// void moveTop();
|
||||
// void moveBottom();
|
||||
void check();
|
||||
void uncheck();
|
||||
void refresh();
|
||||
|
||||
private:
|
||||
DataFilesModel *mMastersModel;
|
||||
DataFilesModel *mPluginsModel;
|
||||
|
||||
QSortFilterProxyModel *mPluginsProxyModel;
|
||||
|
||||
QTableView *mMastersTable;
|
||||
QTableView *mPluginsTable;
|
||||
DataFilesList *mDataFilesList;
|
||||
|
||||
QToolBar *mProfileToolBar;
|
||||
QMenu *mContextMenu;
|
||||
|
||||
QAction *mNewProfileAction;
|
||||
QAction *mDeleteProfileAction;
|
||||
@ -72,8 +59,6 @@ private:
|
||||
// QAction *mMoveDownAction;
|
||||
// QAction *mMoveTopAction;
|
||||
// QAction *mMoveBottomAction;
|
||||
QAction *mCheckAction;
|
||||
QAction *mUncheckAction;
|
||||
|
||||
Files::ConfigurationManager &mCfgMgr;
|
||||
Files::PathContainer mDataDirs;
|
||||
|
@ -8,8 +8,7 @@
|
||||
#include <components/files/configurationmanager.hpp>
|
||||
#include <components/files/ogreplugin.hpp>
|
||||
#include <components/settings/settings.hpp>
|
||||
|
||||
#include "utils/naturalsort.hpp"
|
||||
#include <components/fileorderlist/utils/naturalsort.hpp>
|
||||
|
||||
#include "graphicspage.hpp"
|
||||
|
||||
|
@ -5,7 +5,7 @@
|
||||
#include <QVBoxLayout>
|
||||
#include <QValidator>
|
||||
|
||||
#include "lineedit.hpp"
|
||||
#include <components/fileorderlist/utils/lineedit.hpp>
|
||||
|
||||
#include "textinputdialog.hpp"
|
||||
|
||||
|
@ -21,6 +21,7 @@ opencs_units (model/world
|
||||
idtable idtableproxymodel
|
||||
)
|
||||
|
||||
|
||||
opencs_units_noqt (model/world
|
||||
universalid data record idcollection commands columnbase
|
||||
)
|
||||
@ -40,9 +41,10 @@ opencs_units_noqt (model/tools
|
||||
|
||||
|
||||
opencs_units (view/doc
|
||||
viewmanager view operations operation subview
|
||||
viewmanager view operations operation subview startup opendialog
|
||||
)
|
||||
|
||||
|
||||
opencs_units_noqt (view/doc
|
||||
subviewfactory
|
||||
)
|
||||
|
@ -11,39 +11,52 @@
|
||||
CS::Editor::Editor() : mViewManager (mDocumentManager), mNewDocumentIndex (0)
|
||||
{
|
||||
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()
|
||||
{
|
||||
mStartup.hide();
|
||||
|
||||
/// \todo open the ESX picker instead
|
||||
|
||||
std::ostringstream stream;
|
||||
|
||||
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[] =
|
||||
{
|
||||
"Day", "DaysPassed", "GameHour", "Month", "PCRace", "PCVampire", "PCWerewolf", "PCYear", 0
|
||||
};
|
||||
CSMDoc::Document *document = mDocumentManager.addDocument (files, true);
|
||||
|
||||
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;
|
||||
document->getData().getGlobals().add (record);
|
||||
}
|
||||
mViewManager.addView (document);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
int CS::Editor::run()
|
||||
{
|
||||
/// \todo Instead of creating an empty document, open a small welcome dialogue window with buttons for new/load/recent projects
|
||||
createDocument();
|
||||
mStartup.show();
|
||||
|
||||
return QApplication::exec();
|
||||
}
|
@ -4,7 +4,10 @@
|
||||
#include <QObject>
|
||||
|
||||
#include "model/doc/documentmanager.hpp"
|
||||
|
||||
#include "view/doc/viewmanager.hpp"
|
||||
#include "view/doc/startup.hpp"
|
||||
#include "view/doc/opendialog.hpp"
|
||||
|
||||
namespace CS
|
||||
{
|
||||
@ -16,6 +19,8 @@ namespace CS
|
||||
|
||||
CSMDoc::DocumentManager mDocumentManager;
|
||||
CSVDoc::ViewManager mViewManager;
|
||||
CSVDoc::StartupDialogue mStartup;
|
||||
OpenDialog mOpenDialog;
|
||||
|
||||
// not implemented
|
||||
Editor (const Editor&);
|
||||
@ -28,9 +33,12 @@ namespace CS
|
||||
int run();
|
||||
///< \return error status
|
||||
|
||||
public slots:
|
||||
private slots:
|
||||
|
||||
void createDocument();
|
||||
|
||||
void loadDocument();
|
||||
void openFiles();
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -1,10 +1,66 @@
|
||||
|
||||
#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)
|
||||
{
|
||||
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)));
|
||||
|
||||
@ -86,10 +142,10 @@ void CSMDoc::Document::saving()
|
||||
|
||||
if (mSaveCount>15)
|
||||
{
|
||||
mSaveCount = 0;
|
||||
mSaveTimer.stop();
|
||||
mUndoStack.setClean();
|
||||
emit stateChanged (getState(), this);
|
||||
mSaveCount = 0;
|
||||
mSaveTimer.stop();
|
||||
mUndoStack.setClean();
|
||||
emit stateChanged (getState(), this);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3,6 +3,8 @@
|
||||
|
||||
#include <string>
|
||||
|
||||
#include <boost/filesystem/path.hpp>
|
||||
|
||||
#include <QUndoStack>
|
||||
#include <QObject>
|
||||
#include <QTimer>
|
||||
@ -38,10 +40,15 @@ namespace CSMDoc
|
||||
Document (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:
|
||||
|
||||
Document (const std::string& name);
|
||||
///< \todo replace name with ESX list
|
||||
Document (const std::vector<boost::filesystem::path>& files, bool new_);
|
||||
|
||||
QUndoStack& getUndoStack();
|
||||
|
||||
|
@ -14,9 +14,10 @@ CSMDoc::DocumentManager::~DocumentManager()
|
||||
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);
|
||||
|
||||
|
@ -4,6 +4,8 @@
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
#include <boost/filesystem/path.hpp>
|
||||
|
||||
namespace CSMDoc
|
||||
{
|
||||
class Document;
|
||||
@ -21,8 +23,11 @@ namespace CSMDoc
|
||||
|
||||
~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.
|
||||
///
|
||||
/// \param new_ Do not load the last content file in \a files and instead create in an
|
||||
/// appropriate way.
|
||||
|
||||
bool removeDocument (Document *document);
|
||||
///< \return last document removed?
|
||||
|
@ -28,7 +28,8 @@ namespace CSMWorld
|
||||
{
|
||||
Display_String,
|
||||
Display_Integer,
|
||||
Display_Float
|
||||
Display_Float,
|
||||
Display_Var
|
||||
};
|
||||
|
||||
std::string mTitle;
|
||||
|
@ -17,9 +17,9 @@ namespace CSMWorld
|
||||
|
||||
virtual void set (Record<ESXRecordT>& record, const QVariant& data)
|
||||
{
|
||||
ESXRecordT base = record.getBase();
|
||||
base.mValue = data.toFloat();
|
||||
record.setModified (base);
|
||||
ESXRecordT record2 = record.get();
|
||||
record2.mValue = data.toFloat();
|
||||
record.setModified (record2);
|
||||
}
|
||||
|
||||
virtual bool isEditable() const
|
||||
@ -91,6 +91,68 @@ namespace CSMWorld
|
||||
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
|
@ -5,6 +5,7 @@
|
||||
|
||||
#include <QAbstractTableModel>
|
||||
|
||||
#include <components/esm/esmreader.hpp>
|
||||
#include <components/esm/loadglob.hpp>
|
||||
|
||||
#include "idtable.hpp"
|
||||
@ -27,7 +28,14 @@ CSMWorld::Data::Data()
|
||||
mGlobals.addColumn (new FixedRecordTypeColumn<ESM::Global> (UniversalId::Type_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 (&mGmsts), UniversalId::Type_Gmsts, UniversalId::Type_Gmst);
|
||||
}
|
||||
|
||||
CSMWorld::Data::~Data()
|
||||
@ -59,4 +67,31 @@ QAbstractTableModel *CSMWorld::Data::getTableModel (const UniversalId& id)
|
||||
void CSMWorld::Data::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 <vector>
|
||||
|
||||
#include <boost/filesystem/path.hpp>
|
||||
|
||||
#include <components/esm/loadglob.hpp>
|
||||
#include <components/esm/loadgmst.hpp>
|
||||
|
||||
#include "idcollection.hpp"
|
||||
#include "universalid.hpp"
|
||||
@ -16,6 +19,7 @@ namespace CSMWorld
|
||||
class Data
|
||||
{
|
||||
IdCollection<ESM::Global> mGlobals;
|
||||
IdCollection<ESM::GameSetting> mGmsts;
|
||||
std::vector<QAbstractTableModel *> mModels;
|
||||
std::map<UniversalId::Type, QAbstractTableModel *> mModelIndex;
|
||||
|
||||
@ -44,6 +48,9 @@ namespace CSMWorld
|
||||
|
||||
void merge();
|
||||
///< 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() {}
|
||||
|
@ -11,9 +11,12 @@
|
||||
|
||||
#include <QVariant>
|
||||
|
||||
#include "columnbase.hpp"
|
||||
#include <components/esm/esmreader.hpp>
|
||||
|
||||
#include <components/misc/stringops.hpp>
|
||||
|
||||
#include "columnbase.hpp"
|
||||
|
||||
namespace CSMWorld
|
||||
{
|
||||
class IdCollectionBase
|
||||
@ -67,9 +70,11 @@ namespace CSMWorld
|
||||
virtual std::string getId (const RecordBase& record) const = 0;
|
||||
///< 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 void load (ESM::ESMReader& reader, bool base) = 0;
|
||||
};
|
||||
|
||||
///< \brief Collection of ID-based records
|
||||
@ -136,6 +141,8 @@ namespace CSMWorld
|
||||
|
||||
virtual const RecordBase& getRecord (const std::string& id) const;
|
||||
|
||||
virtual void load (ESM::ESMReader& reader, bool base);
|
||||
|
||||
void addColumn (Column<ESXRecordT> *column);
|
||||
};
|
||||
|
||||
@ -309,6 +316,62 @@ namespace CSMWorld
|
||||
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>
|
||||
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_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
|
||||
};
|
||||
@ -25,6 +26,7 @@ namespace
|
||||
static const TypeData sIdArg[] =
|
||||
{
|
||||
{ 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
|
||||
};
|
||||
|
@ -33,12 +33,12 @@ namespace CSMWorld
|
||||
enum Type
|
||||
{
|
||||
Type_None,
|
||||
|
||||
Type_Globals,
|
||||
|
||||
Type_Global,
|
||||
Type_VerificationResults,
|
||||
Type_Gmsts,
|
||||
Type_Gmst
|
||||
|
||||
Type_VerificationResults
|
||||
};
|
||||
|
||||
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()));
|
||||
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);
|
||||
connect (mSave, SIGNAL (triggered()), this, SLOT (save()));
|
||||
file->addAction (mSave);
|
||||
@ -67,6 +71,10 @@ void CSVDoc::View::setupWorldMenu()
|
||||
connect (globals, SIGNAL (triggered()), this, SLOT (addGlobalsSubView()));
|
||||
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);
|
||||
connect (mVerify, SIGNAL (triggered()), this, SLOT (verify()));
|
||||
world->addAction (mVerify);
|
||||
@ -213,4 +221,9 @@ void CSVDoc::View::verify()
|
||||
void CSVDoc::View::addGlobalsSubView()
|
||||
{
|
||||
addSubView (CSMWorld::UniversalId::Type_Globals);
|
||||
}
|
||||
|
||||
void CSVDoc::View::addGmstsSubView()
|
||||
{
|
||||
addSubView (CSMWorld::UniversalId::Type_Gmsts);
|
||||
}
|
@ -84,6 +84,8 @@ namespace CSVDoc
|
||||
|
||||
void newDocumentRequest();
|
||||
|
||||
void loadDocumentRequest();
|
||||
|
||||
public slots:
|
||||
|
||||
void addSubView (const CSMWorld::UniversalId& id);
|
||||
@ -97,6 +99,8 @@ namespace CSVDoc
|
||||
void verify();
|
||||
|
||||
void addGlobalsSubView();
|
||||
|
||||
void addGmstsSubView();
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -57,6 +57,7 @@ CSVDoc::View *CSVDoc::ViewManager::addView (CSMDoc::Document *document)
|
||||
view->show();
|
||||
|
||||
connect (view, SIGNAL (newDocumentRequest ()), this, SIGNAL (newDocumentRequest()));
|
||||
connect (view, SIGNAL (loadDocumentRequest ()), this, SIGNAL (loadDocumentRequest()));
|
||||
|
||||
updateIndices();
|
||||
|
||||
|
@ -46,6 +46,8 @@ namespace CSVDoc
|
||||
|
||||
void newDocumentRequest();
|
||||
|
||||
void loadDocumentRequest();
|
||||
|
||||
private slots:
|
||||
|
||||
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?)
|
||||
layout->addWidget (widget = new QDoubleSpinBox, i, 1);
|
||||
break;
|
||||
|
||||
default: break; // silence warnings for other times for now
|
||||
}
|
||||
}
|
||||
else
|
||||
@ -76,6 +78,8 @@ CSVWorld::DialogueSubView::DialogueSubView (const CSMWorld::UniversalId& id, CSM
|
||||
|
||||
layout->addWidget (widget = new QLabel, i, 1);
|
||||
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,
|
||||
new CSVDoc::SubViewFactoryWithCreateFlag<TableSubView> (true));
|
||||
|
||||
manager.add (CSMWorld::UniversalId::Type_Gmsts,
|
||||
new CSVDoc::SubViewFactoryWithCreateFlag<TableSubView> (false));
|
||||
|
||||
manager.add (CSMWorld::UniversalId::Type_Global,
|
||||
new CSVDoc::SubViewFactoryWithCreateFlag<DialogueSubView> (true));
|
||||
}
|
@ -23,6 +23,22 @@ endforeach (u)
|
||||
source_group ("components\\${dir}" FILES ${files})
|
||||
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)
|
||||
foreach (f ${files})
|
||||
get_filename_component(filename ${f} NAME)
|
||||
|
@ -66,9 +66,21 @@ add_component_dir (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})
|
||||
|
||||
add_library(components STATIC ${COMPONENT_FILES})
|
||||
add_library(components STATIC ${COMPONENT_FILES} ${MOC_SRCS})
|
||||
|
||||
target_link_libraries(components ${Boost_LIBRARIES} ${OGRE_LIBRARIES})
|
||||
|
||||
|
@ -76,8 +76,29 @@ std::string GameSetting::getString() const
|
||||
{
|
||||
if (mType==VT_String)
|
||||
return mStr;
|
||||
|
||||
|
||||
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;
|
||||
|
||||
void load(ESMReader &esm);
|
||||
|
||||
|
||||
int getInt() const;
|
||||
///< Throws an exception if GMST is not of type int or float.
|
||||
|
||||
|
||||
float getFloat() const;
|
||||
///< Throws an exception if GMST is not of type int or float.
|
||||
|
||||
|
||||
std::string getString() const;
|
||||
///< Throwns an exception if GMST is not of type string.
|
||||
|
||||
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
|
||||
|
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);
|
||||
file->setDates(info.lastModified(), info.lastRead());
|
||||
file->setPath(info.absoluteFilePath());
|
||||
|
||||
// Add the master to the table
|
||||
if (findItem(master) == 0)
|
||||
@ -427,6 +428,25 @@ QStringList DataFilesModel::checkedItems()
|
||||
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()
|
||||
{
|
||||
emit layoutAboutToBeChanged();
|
@ -43,6 +43,7 @@ public:
|
||||
|
||||
QStringList checkedItems();
|
||||
QStringList uncheckedItems();
|
||||
QStringList checkedItemsPaths();
|
||||
|
||||
Qt::CheckState checkState(const QModelIndex &index);
|
||||
void setCheckState(const QModelIndex &index, Qt::CheckState state);
|
Loading…
x
Reference in New Issue
Block a user