mirror of
https://gitlab.com/pholy/OSCAR-code.git
synced 2025-04-04 18:20:42 +00:00
386 lines
11 KiB
C++
386 lines
11 KiB
C++
/* SleepLib Preferences Implementation
|
|
*
|
|
* Copyright (c) 2019-2024 The OSCAR Team
|
|
* Copyright (c) 2011-2018 Mark Watkins
|
|
*
|
|
* This file is subject to the terms and conditions of the GNU General Public
|
|
* License. See the file COPYING in the main directory of the source code
|
|
* for more details. */
|
|
|
|
#include <QString>
|
|
#include <QDomDocument>
|
|
#include <QDomElement>
|
|
#include <QDomNode>
|
|
#include <QVariant>
|
|
#include <QDateTime>
|
|
#include <QDir>
|
|
#include <QDesktopServices>
|
|
#include <QDebug>
|
|
#include <QSettings>
|
|
#include <QMessageBox>
|
|
#include <QTranslator>
|
|
|
|
#ifdef Q_OS_WIN
|
|
#include "windows.h"
|
|
#include "lmcons.h"
|
|
#endif
|
|
|
|
#include "common.h"
|
|
#include "preferences.h"
|
|
|
|
const QString &getUserName()
|
|
{
|
|
static QString userName;
|
|
userName = getenv("USER");
|
|
|
|
if (userName.isEmpty()) {
|
|
userName = QObject::tr("Windows User");
|
|
|
|
#if defined (Q_OS_WIN)
|
|
#if defined(UNICODE)
|
|
|
|
if (QSysInfo::WindowsVersion >= QSysInfo::WV_NT) {
|
|
TCHAR winUserName[UNLEN + 1]; // UNLEN is defined in LMCONS.H
|
|
DWORD winUserNameSize = sizeof(winUserName);
|
|
GetUserNameW(winUserName, &winUserNameSize);
|
|
userName = QString::fromStdWString(winUserName);
|
|
} else
|
|
#endif
|
|
{
|
|
char winUserName[UNLEN + 1]; // UNLEN is defined in LMCONS.H
|
|
DWORD winUserNameSize = sizeof(winUserName);
|
|
GetUserNameA(winUserName, &winUserNameSize);
|
|
userName = QString::fromLocal8Bit(winUserName);
|
|
}
|
|
|
|
#endif
|
|
}
|
|
|
|
return userName;
|
|
}
|
|
|
|
|
|
QString GetAppData()
|
|
{
|
|
QSettings settings;
|
|
|
|
QString HomeAppData = settings.value("Settings/AppData").toString();
|
|
|
|
if (HomeAppData.isEmpty()) {
|
|
HomeAppData = QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation)+"/"+getModifiedAppData();
|
|
}
|
|
|
|
return HomeAppData;
|
|
}
|
|
|
|
|
|
Preferences::Preferences()
|
|
{
|
|
p_name = "Preferences";
|
|
p_path = GetAppData();
|
|
}
|
|
|
|
Preferences::Preferences(QString name, QString filename)
|
|
{
|
|
if (name.endsWith(STR_ext_XML)) {
|
|
p_name = name.section(".", 0, 0);
|
|
} else {
|
|
p_name = name;
|
|
}
|
|
|
|
if (filename.isEmpty()) {
|
|
p_filename = GetAppData() + "/" + p_name + STR_ext_XML;
|
|
} else {
|
|
if (!filename.contains("/")) {
|
|
p_filename = GetAppData() + "/";
|
|
} else { p_filename = ""; }
|
|
|
|
p_filename += filename;
|
|
|
|
if (!p_filename.endsWith(STR_ext_XML)) { p_filename += STR_ext_XML; }
|
|
}
|
|
}
|
|
|
|
Preferences::~Preferences()
|
|
{
|
|
//Save(); // Don't..Save calls a virtual function.
|
|
}
|
|
|
|
/*int Preferences::GetCode(QString s)
|
|
{
|
|
int prefcode=0;
|
|
for (QHash<int,QString>::iterator i=p_codes.begin(); i!=p_codes.end(); i++) {
|
|
if (i.value()==s) return i.key();
|
|
prefcode++;
|
|
}
|
|
p_codes[prefcode]=s;
|
|
return prefcode;
|
|
}*/
|
|
|
|
const QString Preferences::Get(QString name)
|
|
{
|
|
QString temp;
|
|
QChar obr = QChar('{');
|
|
QChar cbr = QChar('}');
|
|
QString t, a, ref; // How I miss Regular Expressions here..
|
|
|
|
if (p_preferences.find(name) != p_preferences.end()) {
|
|
temp = "";
|
|
t = p_preferences[name].toString();
|
|
|
|
if (p_preferences[name].type() != QVariant::String) {
|
|
return t;
|
|
}
|
|
} else {
|
|
t = name; // parse the string..
|
|
}
|
|
|
|
while (t.contains(obr)) {
|
|
temp += t.section(obr, 0, 0);
|
|
a = t.section(obr, 1);
|
|
|
|
if (a.startsWith("{")) {
|
|
temp += obr;
|
|
t = a.section(obr, 1);
|
|
continue;
|
|
}
|
|
|
|
ref = a.section(cbr, 0, 0);
|
|
|
|
if (ref.toLower() == "home") {
|
|
temp += GetAppData();
|
|
} else if (ref.toLower() == "user") {
|
|
temp += getUserName();
|
|
} else if (ref.toLower() == "sep") { // redundant in QT
|
|
temp += "/";
|
|
} else {
|
|
temp += Get(ref);
|
|
}
|
|
|
|
t = a.section(cbr, 1);
|
|
}
|
|
|
|
temp += t;
|
|
temp.replace("}}", "}"); // Make things look a bit better when escaping braces.
|
|
|
|
return temp;
|
|
}
|
|
|
|
|
|
bool Preferences::Open(QString filename)
|
|
{
|
|
if (!filename.isEmpty()) {
|
|
p_filename = filename;
|
|
}
|
|
|
|
QDomDocument doc(p_name);
|
|
QFile file(p_filename);
|
|
qDebug() << "Opening " << p_filename.toLocal8Bit().data();
|
|
|
|
if (!file.open(QIODevice::ReadOnly)) {
|
|
// qWarning() << "Could not open" << p_filename.toLocal8Bit().data() << " Error: " << file.error();
|
|
qWarning() << "Could not open preferences file for reading, error code" << file.error() << file.errorString();
|
|
return false;
|
|
}
|
|
|
|
QString errorMsg;
|
|
int errorLine;
|
|
int errorColumn;
|
|
if (!doc.setContent(&file,false, &errorMsg, &errorLine, &errorColumn)) {
|
|
qWarning() << "Invalid XML Content in" << p_filename.toLocal8Bit().data();
|
|
qWarning() << "Error:" << errorMsg << "in line" << errorLine << ":" << errorColumn;
|
|
return false;
|
|
}
|
|
|
|
file.close();
|
|
|
|
|
|
QDomElement root = doc.documentElement();
|
|
|
|
if (root.tagName() != STR_AppName) {
|
|
if (root.tagName() == "SleepyHead" ) {
|
|
QString msg = QObject::tr("Using ") + p_filename + QObject::tr(", found SleepyHead -\n") +
|
|
QObject::tr( "You must run the OSCAR Migration Tool");
|
|
QMessageBox::warning(nullptr, STR_MessageBox_Error, msg, QMessageBox::Ok);
|
|
exit(1);
|
|
}
|
|
return false;
|
|
}
|
|
|
|
root = root.firstChildElement();
|
|
|
|
if (root.tagName() != p_name) {
|
|
return false;
|
|
}
|
|
|
|
bool ok;
|
|
p_preferences.clear();
|
|
QDomNode n = root.firstChild();
|
|
|
|
while (!n.isNull()) {
|
|
QDomElement e = n.toElement();
|
|
|
|
if (!e.isNull()) {
|
|
QString name = e.tagName();
|
|
QString type = e.attribute("type").toLower();
|
|
QString value = e.text();
|
|
|
|
if (type == "double") {
|
|
double d;
|
|
d = value.toDouble(&ok);
|
|
|
|
if (ok) {
|
|
p_preferences[name] = d;
|
|
} else {
|
|
qDebug() << "XML Error:" << name << "=" << value << "??";
|
|
}
|
|
} else if (type == "qlonglong") {
|
|
qint64 d;
|
|
d = value.toLongLong(&ok);
|
|
|
|
if (ok) {
|
|
p_preferences[name] = d;
|
|
} else {
|
|
qDebug() << "XML Error:" << name << "=" << value << "??";
|
|
}
|
|
} else if (type == "int") {
|
|
int d;
|
|
d = value.toInt(&ok);
|
|
|
|
if (ok) {
|
|
p_preferences[name] = d;
|
|
} else {
|
|
qDebug() << "XML Error:" << name << "=" << value << "??";
|
|
}
|
|
} else if (type == "bool") {
|
|
QString v = value.toLower();
|
|
|
|
if ((v == "true") || (v == "on") || (v == "yes")) {
|
|
p_preferences[name] = true;
|
|
} else if ((v == "false") || (v == "off") || (v == "no")) {
|
|
p_preferences[name] = false;
|
|
} else {
|
|
int d;
|
|
d = value.toInt(&ok);
|
|
|
|
if (ok) {
|
|
p_preferences[name] = d != 0;
|
|
} else {
|
|
qDebug() << "XML Error:" << name << "=" << value << "??";
|
|
}
|
|
}
|
|
} else if (type == "qdatetime") {
|
|
QDateTime d;
|
|
d = QDateTime::fromString(value, "yyyy-MM-dd HH:mm:ss");
|
|
|
|
if (d.isValid()) {
|
|
p_preferences[name] = d;
|
|
} else {
|
|
qWarning() << "XML Error: Invalid DateTime record" << name << value;
|
|
}
|
|
|
|
} else if (type == "qtime") {
|
|
QTime d;
|
|
d = QTime::fromString(value, "hh:mm:ss");
|
|
|
|
if (d.isValid()) {
|
|
p_preferences[name] = d;
|
|
} else {
|
|
qWarning() << "XML Error: Invalid Time record" << name << value;
|
|
}
|
|
|
|
} else {
|
|
p_preferences[name] = value;
|
|
}
|
|
|
|
}
|
|
|
|
n = n.nextSibling();
|
|
}
|
|
|
|
root = root.nextSiblingElement();
|
|
|
|
//////////////////////////////////////////////////////////////////////////////////////
|
|
// This is a dirty hack to clean up a legacy issue
|
|
// The old Profile system used to have devices in Profile.xml
|
|
// We need to clean up this mistake up here, because C++ polymorphism won't otherwise
|
|
// let us open properly in constructor
|
|
//////////////////////////////////////////////////////////////////////////////////////
|
|
if ((p_name == "Profile") && (root.tagName().toLower() == "machines")) {
|
|
|
|
// Save this sucker
|
|
QDomDocument doc("Machines");
|
|
|
|
doc.appendChild(root);
|
|
|
|
QFile file(p_path+"/machines.xml");
|
|
|
|
// Don't do anything if machines.xml already exists.. the user ran the old version!
|
|
if (!file.exists()) {
|
|
if (!file.open(QFile::WriteOnly)) {
|
|
qWarning() << "Could not open" << filename << "for writing, error code" << file.error() << file.errorString();
|
|
} else {
|
|
file.write(doc.toByteArray());
|
|
file.close();
|
|
}
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool Preferences::Save(QString filename)
|
|
{
|
|
if (!filename.isEmpty()) {
|
|
p_filename = filename;
|
|
}
|
|
|
|
QDomDocument doc(p_name);
|
|
|
|
QDomProcessingInstruction pi = doc.createProcessingInstruction("xml", "version=\"1.0\" encoding=\"UTF-8\"");
|
|
doc.appendChild(pi);
|
|
|
|
QDomElement droot = doc.createElement(STR_AppName);
|
|
doc.appendChild(droot);
|
|
|
|
QDomElement root = doc.createElement(p_name);
|
|
droot.appendChild(root);
|
|
|
|
for (QHash<QString, QVariant>::iterator i = p_preferences.begin(); i != p_preferences.end(); i++) {
|
|
QVariant::Type type = i.value().type();
|
|
|
|
if (type == QVariant::Invalid) { continue; }
|
|
|
|
QDomElement cn = doc.createElement(i.key());
|
|
cn.setAttribute("type", i.value().typeName());
|
|
|
|
if (type == QVariant::DateTime) {
|
|
cn.appendChild(doc.createTextNode(i.value().toDateTime().toString("yyyy-MM-dd HH:mm:ss")));
|
|
} else if (type == QVariant::Time) {
|
|
cn.appendChild(doc.createTextNode(i.value().toTime().toString("hh:mm:ss")));
|
|
} else {
|
|
cn.appendChild(doc.createTextNode(i.value().toString()));
|
|
}
|
|
|
|
root.appendChild(cn);
|
|
}
|
|
|
|
QFile file(p_filename);
|
|
|
|
if (!file.open(QIODevice::WriteOnly)) {
|
|
qWarning() << "Could not open" << p_filename << "for writing, error code" << file.error() << file.errorString();
|
|
return false;
|
|
}
|
|
|
|
QTextStream ts(&file);
|
|
ts.setCodec("UTF-8");
|
|
ts.setGenerateByteOrderMark(true);
|
|
ts << doc.toString();
|
|
file.close();
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
AppWideSetting *AppSetting = nullptr;
|
|
|