|
|
|
@ -1,8 +1,6 @@
|
|
|
|
|
#include <QtGui>
|
|
|
|
|
|
|
|
|
|
#include <components/esm/esm_reader.hpp>
|
|
|
|
|
#include <components/files/collections.hpp>
|
|
|
|
|
#include <components/files/multidircollection.hpp>
|
|
|
|
|
#include <components/files/configurationmanager.hpp>
|
|
|
|
|
|
|
|
|
|
#include "datafilespage.hpp"
|
|
|
|
@ -120,11 +118,12 @@ DataFilesPage::DataFilesPage(Files::ConfigurationManager &cfg, QWidget *parent)
|
|
|
|
|
connect(mPluginsTable, SIGNAL(doubleClicked(QModelIndex)), this, SLOT(setCheckState(QModelIndex)));
|
|
|
|
|
connect(mPluginsTable, SIGNAL(customContextMenuRequested(const QPoint&)), this, SLOT(showContextMenu(const QPoint&)));
|
|
|
|
|
|
|
|
|
|
connect(mProfilesComboBox, SIGNAL(textChanged(const QString&, const QString&)), this, SLOT(profileChanged(const QString&, const QString&)));
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
createActions();
|
|
|
|
|
setupConfig();
|
|
|
|
|
setupDataFiles();
|
|
|
|
|
createActions();
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void DataFilesPage::setupConfig()
|
|
|
|
@ -138,8 +137,7 @@ void DataFilesPage::setupConfig()
|
|
|
|
|
|
|
|
|
|
// Open our config file
|
|
|
|
|
mLauncherConfig = new QSettings(config, QSettings::IniFormat);
|
|
|
|
|
mLauncherConfig->sync();
|
|
|
|
|
|
|
|
|
|
file.close();
|
|
|
|
|
|
|
|
|
|
// Make sure we have no groups open
|
|
|
|
|
while (!mLauncherConfig->group().isEmpty()) {
|
|
|
|
@ -162,13 +160,14 @@ void DataFilesPage::setupConfig()
|
|
|
|
|
// No current profile selected
|
|
|
|
|
currentProfile = "Default";
|
|
|
|
|
}
|
|
|
|
|
mProfilesComboBox->setCurrentIndex(mProfilesComboBox->findText(currentProfile));
|
|
|
|
|
|
|
|
|
|
mLauncherConfig->endGroup();
|
|
|
|
|
const int currentIndex = mProfilesComboBox->findText(currentProfile);
|
|
|
|
|
if (currentIndex != -1) {
|
|
|
|
|
// Profile is found
|
|
|
|
|
mProfilesComboBox->setCurrentIndex(currentIndex);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Now we connect the combobox to do something if the profile changes
|
|
|
|
|
// This prevents strange behaviour while reading and appending the profiles
|
|
|
|
|
connect(mProfilesComboBox, SIGNAL(textChanged(const QString&, const QString&)), this, SLOT(profileChanged(const QString&, const QString&)));
|
|
|
|
|
mLauncherConfig->endGroup();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@ -188,19 +187,51 @@ void DataFilesPage::setupDataFiles()
|
|
|
|
|
|
|
|
|
|
// Put the paths in a boost::filesystem vector to use with Files::Collections
|
|
|
|
|
Files::PathContainer dataDirs(variables["data"].as<Files::PathContainer>());
|
|
|
|
|
mDataDirs = dataDirs;
|
|
|
|
|
|
|
|
|
|
std::string local(variables["data-local"].as<std::string>());
|
|
|
|
|
if (!local.empty())
|
|
|
|
|
{
|
|
|
|
|
std::string local = variables["data-local"].as<std::string>();
|
|
|
|
|
if (!local.empty()) {
|
|
|
|
|
mDataLocal.push_back(Files::PathContainer::value_type(local));
|
|
|
|
|
dataDirs.push_back(Files::PathContainer::value_type(local));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (dataDirs.empty())
|
|
|
|
|
{
|
|
|
|
|
dataDirs.push_back(mCfgMgr.getLocalPath());
|
|
|
|
|
mCfgMgr.processPaths(dataDirs);
|
|
|
|
|
|
|
|
|
|
while (dataDirs.empty()) {
|
|
|
|
|
// No valid data files directory found
|
|
|
|
|
|
|
|
|
|
QMessageBox msgBox;
|
|
|
|
|
msgBox.setWindowTitle("Error detecting Morrowind installation");
|
|
|
|
|
msgBox.setIcon(QMessageBox::Critical);
|
|
|
|
|
msgBox.setStandardButtons(QMessageBox::Cancel);
|
|
|
|
|
msgBox.setText(tr("<br><b>Could not find the Data Files location</b><br><br> \
|
|
|
|
|
The directory containing the Data Files was not found.<br><br> \
|
|
|
|
|
Press \"Browse...\" to specify the location manually.<br>"));
|
|
|
|
|
|
|
|
|
|
QAbstractButton *dirSelectButton =
|
|
|
|
|
msgBox.addButton(tr("B&rowse..."), QMessageBox::ActionRole);
|
|
|
|
|
|
|
|
|
|
msgBox.exec();
|
|
|
|
|
|
|
|
|
|
if (msgBox.clickedButton() == dirSelectButton) {
|
|
|
|
|
|
|
|
|
|
QString dataDir = QFileDialog::getExistingDirectory(
|
|
|
|
|
this, tr("Select Data Files Directory"),
|
|
|
|
|
"/home",
|
|
|
|
|
QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks);
|
|
|
|
|
|
|
|
|
|
dataDirs.push_back(Files::PathContainer::value_type(dataDir.toStdString()));
|
|
|
|
|
mDataDirs.push_back(Files::PathContainer::value_type(dataDir.toStdString()));
|
|
|
|
|
} else {
|
|
|
|
|
// Cancel
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
mCfgMgr.processPaths(dataDirs);
|
|
|
|
|
// Check if cancel was clicked because we can't exit from while loop
|
|
|
|
|
if (dataDirs.empty()) {
|
|
|
|
|
QApplication::exit(1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Create a file collection for the dataDirs
|
|
|
|
|
Files::Collections fileCollections(dataDirs, !variables["fs-strict"].as<bool>());
|
|
|
|
@ -209,15 +240,13 @@ void DataFilesPage::setupDataFiles()
|
|
|
|
|
const Files::MultiDirCollection &esm = fileCollections.getCollection(".esm");
|
|
|
|
|
unsigned int i = 0; // Row number
|
|
|
|
|
|
|
|
|
|
for (Files::MultiDirCollection::TIter iter(esm.begin()); iter!=esm.end(); ++iter)
|
|
|
|
|
{
|
|
|
|
|
for (Files::MultiDirCollection::TIter iter(esm.begin()); iter!=esm.end(); ++iter) {
|
|
|
|
|
QString currentMaster = QString::fromStdString(
|
|
|
|
|
boost::filesystem::path (iter->second.filename()).string());
|
|
|
|
|
|
|
|
|
|
const QList<QTableWidgetItem*> itemList = mMastersWidget->findItems(currentMaster, Qt::MatchExactly);
|
|
|
|
|
|
|
|
|
|
if (itemList.isEmpty()) // Master is not yet in the widget
|
|
|
|
|
{
|
|
|
|
|
if (itemList.isEmpty()) { // Master is not yet in the widget
|
|
|
|
|
mMastersWidget->insertRow(i);
|
|
|
|
|
QTableWidgetItem *item = new QTableWidgetItem(currentMaster);
|
|
|
|
|
mMastersWidget->setItem(i, 0, item);
|
|
|
|
@ -228,8 +257,7 @@ void DataFilesPage::setupDataFiles()
|
|
|
|
|
// Now on to the plugins
|
|
|
|
|
const Files::MultiDirCollection &esp = fileCollections.getCollection(".esp");
|
|
|
|
|
|
|
|
|
|
for (Files::MultiDirCollection::TIter iter(esp.begin()); iter!=esp.end(); ++iter)
|
|
|
|
|
{
|
|
|
|
|
for (Files::MultiDirCollection::TIter iter(esp.begin()); iter!=esp.end(); ++iter) {
|
|
|
|
|
ESMReader fileReader;
|
|
|
|
|
QStringList availableMasters; // Will contain all found masters
|
|
|
|
|
|
|
|
|
@ -245,8 +273,7 @@ void DataFilesPage::setupDataFiles()
|
|
|
|
|
|
|
|
|
|
const QList<QTableWidgetItem*> itemList = mMastersWidget->findItems(currentMaster, Qt::MatchExactly);
|
|
|
|
|
|
|
|
|
|
if (itemList.isEmpty()) // Master is not yet in the widget
|
|
|
|
|
{
|
|
|
|
|
if (itemList.isEmpty()) { // Master is not yet in the widget
|
|
|
|
|
mMastersWidget->insertRow(i);
|
|
|
|
|
|
|
|
|
|
QTableWidgetItem *item = new QTableWidgetItem(currentMaster);
|
|
|
|
@ -435,18 +462,18 @@ void DataFilesPage::deleteProfile()
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QMessageBox deleteMessageBox(this);
|
|
|
|
|
deleteMessageBox.setWindowTitle(tr("Delete Profile"));
|
|
|
|
|
deleteMessageBox.setText(tr("Are you sure you want to delete <b>%0</b>?").arg(profile));
|
|
|
|
|
deleteMessageBox.setIcon(QMessageBox::Warning);
|
|
|
|
|
QAbstractButton *deleteButton =
|
|
|
|
|
deleteMessageBox.addButton(tr("Delete"), QMessageBox::ActionRole);
|
|
|
|
|
QMessageBox msgBox(this);
|
|
|
|
|
msgBox.setWindowTitle(tr("Delete Profile"));
|
|
|
|
|
msgBox.setIcon(QMessageBox::Warning);
|
|
|
|
|
msgBox.setStandardButtons(QMessageBox::Cancel);
|
|
|
|
|
msgBox.setText(tr("Are you sure you want to delete <b>%0</b>?").arg(profile));
|
|
|
|
|
|
|
|
|
|
deleteMessageBox.addButton(QMessageBox::Cancel);
|
|
|
|
|
QAbstractButton *deleteButton =
|
|
|
|
|
msgBox.addButton(tr("Delete"), QMessageBox::ActionRole);
|
|
|
|
|
|
|
|
|
|
deleteMessageBox.exec();
|
|
|
|
|
msgBox.exec();
|
|
|
|
|
|
|
|
|
|
if (deleteMessageBox.clickedButton() == deleteButton) {
|
|
|
|
|
if (msgBox.clickedButton() == deleteButton) {
|
|
|
|
|
// Make sure we have no groups open
|
|
|
|
|
while (!mLauncherConfig->group().isEmpty()) {
|
|
|
|
|
mLauncherConfig->endGroup();
|
|
|
|
@ -503,7 +530,6 @@ void DataFilesPage::moveUp()
|
|
|
|
|
void DataFilesPage::moveDown()
|
|
|
|
|
{
|
|
|
|
|
// Shift the selected plugins down one row
|
|
|
|
|
|
|
|
|
|
if (!mPluginsTable->selectionModel()->hasSelection()) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
@ -919,9 +945,18 @@ void DataFilesPage::filterChanged(const QString filter)
|
|
|
|
|
|
|
|
|
|
void DataFilesPage::profileChanged(const QString &previous, const QString ¤t)
|
|
|
|
|
{
|
|
|
|
|
// Prevent the deletion of the default profile
|
|
|
|
|
if (current == "Default") {
|
|
|
|
|
mDeleteProfileAction->setEnabled(false);
|
|
|
|
|
} else {
|
|
|
|
|
mDeleteProfileAction->setEnabled(true);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!previous.isEmpty()) {
|
|
|
|
|
writeConfig(previous);
|
|
|
|
|
mLauncherConfig->sync();
|
|
|
|
|
} else {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
uncheckPlugins();
|
|
|
|
@ -989,22 +1024,12 @@ void DataFilesPage::readConfig()
|
|
|
|
|
|
|
|
|
|
void DataFilesPage::writeConfig(QString profile)
|
|
|
|
|
{
|
|
|
|
|
// Don't overwrite the config if no plugins are found
|
|
|
|
|
if (mPluginsModel->rowCount() < 1) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (profile.isEmpty()) {
|
|
|
|
|
profile = mProfilesComboBox->currentText();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (profile.isEmpty()) {
|
|
|
|
|
// Don't overwrite the config if no masters are found
|
|
|
|
|
if (mMastersWidget->rowCount() < 1) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Prepare the OpenMW config
|
|
|
|
|
|
|
|
|
|
// Open the config as a QFile
|
|
|
|
|
// Open the OpenMW config as a QFile
|
|
|
|
|
QFile file(QString::fromStdString((mCfgMgr.getUserPath()/"openmw.cfg").string()));
|
|
|
|
|
|
|
|
|
|
if (!file.open(QIODevice::ReadWrite | QIODevice::Text)) {
|
|
|
|
@ -1023,10 +1048,14 @@ void DataFilesPage::writeConfig(QString profile)
|
|
|
|
|
QTextStream in(&file);
|
|
|
|
|
QByteArray buffer;
|
|
|
|
|
|
|
|
|
|
// Remove all previous master/plugin entries from config
|
|
|
|
|
// Remove all previous entries from config
|
|
|
|
|
while (!in.atEnd()) {
|
|
|
|
|
QString line = in.readLine();
|
|
|
|
|
if (!line.contains("master") && !line.contains("plugin")) {
|
|
|
|
|
if (!line.startsWith("master") &&
|
|
|
|
|
!line.startsWith("plugin") &&
|
|
|
|
|
!line.startsWith("data") &&
|
|
|
|
|
!line.startsWith("data-local"))
|
|
|
|
|
{
|
|
|
|
|
buffer += line += "\n";
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
@ -1046,9 +1075,52 @@ void DataFilesPage::writeConfig(QString profile)
|
|
|
|
|
QApplication::exit(1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!buffer.isEmpty()) {
|
|
|
|
|
file.write(buffer);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QTextStream gameConfig(&file);
|
|
|
|
|
|
|
|
|
|
// First write the list of data dirs
|
|
|
|
|
mCfgMgr.processPaths(mDataDirs);
|
|
|
|
|
mCfgMgr.processPaths(mDataLocal);
|
|
|
|
|
|
|
|
|
|
QString path;
|
|
|
|
|
|
|
|
|
|
// data= directories
|
|
|
|
|
for (Files::PathContainer::iterator it = mDataDirs.begin(); it != mDataDirs.end(); ++it) {
|
|
|
|
|
path = QString::fromStdString(it->string());
|
|
|
|
|
path.remove(QChar('\"'));
|
|
|
|
|
|
|
|
|
|
// Make sure the string is quoted when it contains spaces
|
|
|
|
|
if (path.contains(" ")) {
|
|
|
|
|
gameConfig << "data=\"" << path << "\"" << endl;
|
|
|
|
|
} else {
|
|
|
|
|
gameConfig << "data=" << path << endl;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// data-local directory
|
|
|
|
|
if (!mDataLocal.empty()) {
|
|
|
|
|
path = QString::fromStdString(mDataLocal.front().string());
|
|
|
|
|
path.remove(QChar('\"'));
|
|
|
|
|
|
|
|
|
|
if (path.contains(" ")) {
|
|
|
|
|
gameConfig << "data-local=\"" << path << "\"" << endl;
|
|
|
|
|
} else {
|
|
|
|
|
gameConfig << "data-local=" << path << endl;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (profile.isEmpty()) {
|
|
|
|
|
profile = mProfilesComboBox->currentText();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (profile.isEmpty()) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Make sure we have no groups open
|
|
|
|
|
while (!mLauncherConfig->group().isEmpty()) {
|
|
|
|
|
mLauncherConfig->endGroup();
|
|
|
|
@ -1061,7 +1133,7 @@ void DataFilesPage::writeConfig(QString profile)
|
|
|
|
|
mLauncherConfig->beginGroup(profile);
|
|
|
|
|
mLauncherConfig->remove(""); // Clear the subgroup
|
|
|
|
|
|
|
|
|
|
// First write the masters to the configs
|
|
|
|
|
// Now write the masters to the configs
|
|
|
|
|
const QStringList masters = selectedMasters();
|
|
|
|
|
|
|
|
|
|
// We don't use foreach because we need i
|
|
|
|
@ -1073,11 +1145,10 @@ void DataFilesPage::writeConfig(QString profile)
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Now write all checked plugins
|
|
|
|
|
// And finally write all checked plugins
|
|
|
|
|
const QStringList plugins = checkedPlugins();
|
|
|
|
|
|
|
|
|
|
for (int i = 0; i < plugins.size(); ++i)
|
|
|
|
|
{
|
|
|
|
|
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;
|
|
|
|
@ -1086,5 +1157,6 @@ void DataFilesPage::writeConfig(QString profile)
|
|
|
|
|
file.close();
|
|
|
|
|
mLauncherConfig->endGroup();
|
|
|
|
|
mLauncherConfig->endGroup();
|
|
|
|
|
mLauncherConfig->sync();
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|