Allow comments (lines starting with # character) and blank lines in openmw.cfg. Should resolve Feature #2535.

- controlled via a checkbox in launcher settings
pull/607/head
cc9cii 10 years ago
parent 5c37079f0c
commit 15fe5d88e2

@ -490,7 +490,16 @@ bool Launcher::MainDialog::writeSettings()
// Game settings
QFile file(userPath + QString("openmw.cfg"));
if (!file.open(QIODevice::ReadWrite | QIODevice::Text | QIODevice::Truncate)) {
QIODevice::OpenMode mode(0);
bool keepComments = mLauncherSettings.value(QString("Settings/keep-comments"), QString("true"))
== QLatin1String("true");
if (keepComments)
mode = QIODevice::ReadWrite | QIODevice::Text;
else
mode = QIODevice::ReadWrite | QIODevice::Text | QIODevice::Truncate;
if (!file.open(mode)) {
// File cannot be opened or created
QMessageBox msgBox;
msgBox.setWindowTitle(tr("Error writing OpenMW configuration file"));
@ -504,9 +513,15 @@ bool Launcher::MainDialog::writeSettings()
}
QTextStream stream(&file);
stream.setCodec(QTextCodec::codecForName("UTF-8"));
mGameSettings.writeFile(stream);
if (keepComments)
mGameSettings.writeFileWithComments(file);
else
{
stream.setCodec(QTextCodec::codecForName("UTF-8"));
mGameSettings.writeFile(stream);
}
file.close();
// Graphics settings

@ -260,6 +260,10 @@ void Launcher::SettingsPage::saveSettings()
} else {
mGameSettings.setValue(QLatin1String("encoding"), QLatin1String("win1252"));
}
QString keepComments(saveCommentsCheckBox->isChecked() ? "true" : "false");
mLauncherSettings.setValue(QLatin1String("Settings/keep-comments"), keepComments);
}
bool Launcher::SettingsPage::loadSettings()
@ -271,5 +275,9 @@ bool Launcher::SettingsPage::loadSettings()
if (index != -1)
languageComboBox->setCurrentIndex(index);
QString keepComments(mLauncherSettings.value(QLatin1String("Settings/keep-comments")));
saveCommentsCheckBox->setChecked(keepComments == "true");
return true;
}

@ -1,6 +1,7 @@
#include "gamesettings.hpp"
#include "launchersettings.hpp"
#include <QTextCodec>
#include <QTextStream>
#include <QDir>
#include <QString>
@ -173,6 +174,133 @@ bool Config::GameSettings::writeFile(QTextStream &stream)
return true;
}
// Policy:
//
// - Always ignore a line beginning with '#' or empty lines
//
// - If a line in file exists with matching key and first part of value (before ',',
// '\n', etc) also matches, then replace the line with that of mUserSettings.
// - else remove line (maybe replace the line with '#' in front instead?)
//
// - If there is no corresponding line in file, add at the end
//
bool Config::GameSettings::writeFileWithComments(QFile &file)
{
QTextStream stream(&file);
stream.setCodec(QTextCodec::codecForName("UTF-8"));
// slurp
std::vector<QString> fileCopy;
QString line = stream.readLine();
while (!line.isNull())
{
fileCopy.push_back(line);
line = stream.readLine();
}
stream.seek(0);
// empty file, no comments to keep
if (fileCopy.empty())
return writeFile(stream);
// Temp copy of settings to save, but with the keys appended with the first part of the value
//
// ATTENTION!
//
// A hack to avoid looping through each line, makes use of the fact that fallbacks values
// are comma separated.
QMap<QString, QString> userSettingsCopy;
QRegExp settingRegex("^([^=]+)\\s*=\\s*([^,]+)(.*)$");
QString settingLine;
QMap<QString, QString>::const_iterator settingsIter = mUserSettings.begin();
for (; settingsIter != mUserSettings.end(); ++settingsIter)
{
settingLine = settingsIter.key()+"="+settingsIter.value();
if (settingRegex.indexIn(settingLine) != -1)
{
userSettingsCopy[settingRegex.cap(1)+"="+settingRegex.cap(2)] =
(settingRegex.captureCount() < 3) ? "" : settingRegex.cap(3);
}
}
QString keyVal;
for (std::vector<QString>::iterator iter = fileCopy.begin(); iter != fileCopy.end(); ++iter)
{
// skip empty or comment lines
if ((*iter).isEmpty() || (*iter).startsWith("#"))
continue;
// look for a key in the line
if (settingRegex.indexIn(*iter) == -1 || settingRegex.captureCount() < 2)
{
// no key or first part of value found in line, replace with a null string which
// will be remved later
*iter = QString();
continue;
}
// look for a matching key in user settings
keyVal = settingRegex.cap(1)+"="+settingRegex.cap(2);
QMap<QString, QString>::iterator it = userSettingsCopy.find(keyVal);
if (it == userSettingsCopy.end())
{
// no such key+valStart, replace with a null string which will be remved later
*iter = QString();
}
else
{
*iter = QString(it.key()+it.value());
userSettingsCopy.erase(it);
}
}
// write the new config file
QString key;
QString value;
for (std::vector<QString>::iterator iter = fileCopy.begin(); iter != fileCopy.end(); ++iter)
{
if ((*iter).isNull())
continue;
if ((*iter).isEmpty() || (*iter).startsWith("#"))
stream << *iter << "\n";
if (settingRegex.indexIn(*iter) == -1 || settingRegex.captureCount() < 2)
continue;
// Quote paths with spaces
key = settingRegex.cap(1);
value = settingRegex.cap(2)+settingRegex.cap(3);
if (key == QLatin1String("data")
|| key == QLatin1String("data-local")
|| key == QLatin1String("resources"))
{
if (value.contains(QChar(' ')))
{
value.remove(QChar('\"')); // Remove quotes
stream << key << "=\"" << value << "\"\n";
continue;
}
}
stream << key << "=" << value << "\n";
}
if (!userSettingsCopy.empty())
{
stream << "# new entries" << "\n";
QMap<QString, QString>::const_iterator it = userSettingsCopy.begin();
for (; it != userSettingsCopy.end(); ++it)
{
stream << it.key() << it.value() << "\n";
}
}
file.resize(file.pos());
return true;
}
bool Config::GameSettings::hasMaster()
{
bool result = false;

@ -4,6 +4,7 @@
#include <QTextStream>
#include <QStringList>
#include <QString>
#include <QFile>
#include <QMap>
#include <boost/filesystem/path.hpp>
@ -66,6 +67,7 @@ namespace Config
bool readUserFile(QTextStream &stream);
bool writeFile(QTextStream &stream);
bool writeFileWithComments(QFile &file);
void setContentList(const QStringList& fileNames);
QStringList getContentList() const;

@ -40,6 +40,16 @@
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QCheckBox" name="saveCommentsCheckBox">
<property name="text">
<string>Keep comments in openmw.cfg</string>
</property>
<property name="checked">
<bool>false</bool>
</property>
</widget>
</item>
</layout>
</widget>
</item>

Loading…
Cancel
Save