diff --git a/assignment-client/src/AssignmentClient.cpp b/assignment-client/src/AssignmentClient.cpp index 800f00b352..cb1f9edc88 100644 --- a/assignment-client/src/AssignmentClient.cpp +++ b/assignment-client/src/AssignmentClient.cpp @@ -12,7 +12,6 @@ #include #include -#include #include #include #include @@ -50,8 +49,6 @@ AssignmentClient::AssignmentClient(Assignment::Type requestAssignmentType, QStri { LogUtils::init(); - QSettings::setDefaultFormat(QSettings::IniFormat); - DependencyManager::set(); auto scriptableAvatar = DependencyManager::set(); diff --git a/assignment-client/src/AssignmentClientApp.cpp b/assignment-client/src/AssignmentClientApp.cpp index c425a239dd..cd46731acc 100644 --- a/assignment-client/src/AssignmentClientApp.cpp +++ b/assignment-client/src/AssignmentClientApp.cpp @@ -40,9 +40,9 @@ AssignmentClientApp::AssignmentClientApp(int argc, char* argv[]) : ShutdownEventListener::getInstance(); # endif + setApplicationName(BuildInfo::ASSIGNMENT_CLIENT_NAME); setOrganizationName(BuildInfo::MODIFIED_ORGANIZATION); - setOrganizationDomain("highfidelity.io"); - setApplicationName("assignment-client"); + setOrganizationDomain(BuildInfo::ORGANIZATION_DOMAIN); setApplicationVersion(BuildInfo::VERSION); // use the verbose message handler in Logging diff --git a/cmake/templates/BuildInfo.h.in b/cmake/templates/BuildInfo.h.in index 3d388a907f..579f2dc1d7 100644 --- a/cmake/templates/BuildInfo.h.in +++ b/cmake/templates/BuildInfo.h.in @@ -1,6 +1,6 @@ // // BuildInfo.h.in -// cmake/macros +// cmake/templates // // Created by Stephen Birarda on 1/14/16. // Copyright 2015 High Fidelity, Inc. @@ -11,10 +11,18 @@ #define USE_STABLE_GLOBAL_SERVICES @USE_STABLE_GLOBAL_SERVICES@ +#include + namespace BuildInfo { + // WARNING: This file has been auto-generated. + // Check cmake/templates/BuildInfo.h.in if you want to modify it. + + const QString INTERFACE_NAME = "Interface"; + const QString ASSIGNMENT_CLIENT_NAME = "assignment-client"; + const QString DOMAIN_SERVER_NAME = "domain-server"; const QString MODIFIED_ORGANIZATION = "@BUILD_ORGANIZATION@"; + const QString ORGANIZATION_DOMAIN = "highfidelity.io"; const QString VERSION = "@BUILD_VERSION@"; const QString BUILD_BRANCH = "@BUILD_BRANCH@"; const QString BUILD_GLOBAL_SERVICES = "@BUILD_GLOBAL_SERVICES@"; } - diff --git a/domain-server/src/DomainServer.cpp b/domain-server/src/DomainServer.cpp index 26c37f1918..0f4e62c52d 100644 --- a/domain-server/src/DomainServer.cpp +++ b/domain-server/src/DomainServer.cpp @@ -79,11 +79,10 @@ DomainServer::DomainServer(int argc, char* argv[]) : connect(this, &QCoreApplication::aboutToQuit, this, &DomainServer::aboutToQuit); + setApplicationName(BuildInfo::DOMAIN_SERVER_NAME); setOrganizationName(BuildInfo::MODIFIED_ORGANIZATION); - setOrganizationDomain("highfidelity.io"); - setApplicationName("domain-server"); + setOrganizationDomain(BuildInfo::ORGANIZATION_DOMAIN); setApplicationVersion(BuildInfo::VERSION); - QSettings::setDefaultFormat(QSettings::IniFormat); qDebug() << "Setting up domain-server"; diff --git a/domain-server/src/DomainServerSettingsManager.cpp b/domain-server/src/DomainServerSettingsManager.cpp index c7944bbcad..50e0efc9fa 100644 --- a/domain-server/src/DomainServerSettingsManager.cpp +++ b/domain-server/src/DomainServerSettingsManager.cpp @@ -9,6 +9,8 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include "DomainServerSettingsManager.h" + #include #include @@ -16,20 +18,19 @@ #include #include #include -#include #include #include #include -#include #include +#include #include #include #include #include #include +#include -#include "DomainServerSettingsManager.h" const QString SETTINGS_DESCRIPTION_RELATIVE_PATH = "/resources/describe-settings.json"; @@ -41,6 +42,8 @@ const QString DESCRIPTION_COLUMNS_KEY = "columns"; const QString SETTINGS_VIEWPOINT_KEY = "viewpoint"; +static const Setting::Handle JSON_SETTING_VERSION("json-settings/version", 0.0); + DomainServerSettingsManager::DomainServerSettingsManager() : _descriptionArray(), _configMap() @@ -101,9 +104,7 @@ void DomainServerSettingsManager::setupConfigMap(const QStringList& argumentList // What settings version were we before and what are we using now? // Do we need to do any re-mapping? - QSettings appSettings; - const QString JSON_SETTINGS_VERSION_KEY = "json-settings/version"; - double oldVersion = appSettings.value(JSON_SETTINGS_VERSION_KEY, 0.0).toDouble(); + double oldVersion = JSON_SETTING_VERSION.get(); if (oldVersion != _descriptionVersion) { const QString ALLOWED_USERS_SETTINGS_KEYPATH = "security.allowed_users"; @@ -299,7 +300,7 @@ void DomainServerSettingsManager::setupConfigMap(const QStringList& argumentList unpackPermissions(); // write the current description version to our settings - appSettings.setValue(JSON_SETTINGS_VERSION_KEY, _descriptionVersion); + JSON_SETTING_VERSION.set(_descriptionVersion); } QVariantMap& DomainServerSettingsManager::getDescriptorsMap() { diff --git a/interface/resources/info/ApplicationInfo.ini b/interface/resources/info/ApplicationInfo.ini deleted file mode 100644 index 1a7142cb76..0000000000 --- a/interface/resources/info/ApplicationInfo.ini +++ /dev/null @@ -1,4 +0,0 @@ -[INFO] -name=Interface -organizationName=High Fidelity -organizationDomain=highfidelity.io \ No newline at end of file diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 80e444462f..5ac46f6669 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -406,11 +406,7 @@ bool setupEssentials(int& argc, char** argv) { const char* portStr = getCmdOption(argc, constArgv, "--listenPort"); const int listenPort = portStr ? atoi(portStr) : INVALID_PORT; - // Set build version - QCoreApplication::setApplicationVersion(BuildInfo::VERSION); - - Setting::preInit(); - + Setting::init(); static const auto SUPPRESS_SETTINGS_RESET = "--suppress-settings-reset"; bool suppressPrompt = cmdOptionExists(argc, const_cast(argv), SUPPRESS_SETTINGS_RESET); @@ -423,8 +419,6 @@ bool setupEssentials(int& argc, char** argv) { DependencyManager::registerInheritance(); DependencyManager::registerInheritance(); - Setting::init(); - // Set dependencies DependencyManager::set(std::bind(&Application::getUserAgent, qApp)); DependencyManager::set(); diff --git a/interface/src/CrashHandler.cpp b/interface/src/CrashHandler.cpp index 3c5f03bef3..f3e4cbfb07 100644 --- a/interface/src/CrashHandler.cpp +++ b/interface/src/CrashHandler.cpp @@ -18,18 +18,17 @@ #include #include #include -#include #include #include #include #include "Menu.h" +#include static const QString RUNNING_MARKER_FILENAME = "Interface.running"; bool CrashHandler::checkForResetSettings(bool suppressPrompt) { - QSettings::setDefaultFormat(QSettings::IniFormat); - QSettings settings; + Settings settings; settings.beginGroup("Developer"); QVariant displayCrashOptions = settings.value(MenuOption::DisplayCrashOptions); QVariant askToResetSettingsOption = settings.value(MenuOption::AskToResetSettings); @@ -109,8 +108,7 @@ void CrashHandler::handleCrash(CrashHandler::Action action) { return; } - QSettings::setDefaultFormat(QSettings::IniFormat); - QSettings settings; + Settings settings; const QString ADDRESS_MANAGER_GROUP = "AddressManager"; const QString ADDRESS_KEY = "address"; const QString AVATAR_GROUP = "Avatar"; diff --git a/interface/src/Util.h b/interface/src/Util.h index e3938502d2..60e38ae0ec 100644 --- a/interface/src/Util.h +++ b/interface/src/Util.h @@ -14,7 +14,6 @@ #include #include -#include #include diff --git a/interface/src/main.cpp b/interface/src/main.cpp index 3c4a3fd77a..85a630ee07 100644 --- a/interface/src/main.cpp +++ b/interface/src/main.cpp @@ -15,7 +15,6 @@ #include #include #include -#include #include #include @@ -31,12 +30,13 @@ #include "MainWindow.h" #include -#ifdef HAS_BUGSPLAT #include +#ifdef HAS_BUGSPLAT #include #include #endif + int main(int argc, const char* argv[]) { #if HAS_BUGSPLAT static QString BUG_SPLAT_DATABASE = "interface_alpha"; @@ -45,7 +45,13 @@ int main(int argc, const char* argv[]) { #endif disableQtBearerPoll(); // Fixes wifi ping spikes - + + // Set application infos + QCoreApplication::setApplicationName(BuildInfo::INTERFACE_NAME); + QCoreApplication::setOrganizationName(BuildInfo::MODIFIED_ORGANIZATION); + QCoreApplication::setOrganizationDomain(BuildInfo::ORGANIZATION_DOMAIN); + QCoreApplication::setApplicationVersion(BuildInfo::VERSION); + QString applicationName = "High Fidelity Interface - " + qgetenv("USERNAME"); bool instanceMightBeRunning = true; @@ -168,7 +174,6 @@ int main(int argc, const char* argv[]) { int exitCode; { - QSettings::setDefaultFormat(QSettings::IniFormat); Application app(argc, const_cast(argv), startupTime); // If we failed the OpenGLVersion check, log it. diff --git a/libraries/auto-updater/src/AutoUpdater.h b/libraries/auto-updater/src/AutoUpdater.h index 70867e5a44..1e62ce0283 100644 --- a/libraries/auto-updater/src/AutoUpdater.h +++ b/libraries/auto-updater/src/AutoUpdater.h @@ -12,8 +12,6 @@ #ifndef hifi_AutoUpdater_h #define hifi_AutoUpdater_h - -#include #include #include #include diff --git a/libraries/networking/src/AddressManager.cpp b/libraries/networking/src/AddressManager.cpp index f7f305dcc8..5f6763db83 100644 --- a/libraries/networking/src/AddressManager.cpp +++ b/libraries/networking/src/AddressManager.cpp @@ -95,7 +95,7 @@ QUrl AddressManager::currentFacingShareableAddress() const { void AddressManager::loadSettings(const QString& lookupString) { if (lookupString.isEmpty()) { - handleUrl(currentAddressHandle.get().toString(), LookupTrigger::StartupFromSettings); + handleUrl(currentAddressHandle.get(), LookupTrigger::StartupFromSettings); } else { handleUrl(lookupString, LookupTrigger::StartupFromSettings); } diff --git a/libraries/shared/src/SettingHandle.cpp b/libraries/shared/src/SettingHandle.cpp index 13f9ea48ce..4a0ff9df71 100644 --- a/libraries/shared/src/SettingHandle.cpp +++ b/libraries/shared/src/SettingHandle.cpp @@ -19,16 +19,12 @@ const QString Settings::firstRun { "firstRun" }; -Settings::Settings() : - _manager(DependencyManager::get()), - _locker(&(_manager->getLock())) +Settings::Settings() : _manager(DependencyManager::get()) { } -Settings::~Settings() { - if (_prefixes.size() != 0) { - qFatal("Unstable Settings Prefixes: You must call endGroup for every beginGroup and endArray for every begin*Array call"); - } +QString Settings::fileName() const { + return _manager->fileName(); } void Settings::remove(const QString& key) { @@ -54,17 +50,14 @@ bool Settings::contains(const QString& key) const { } int Settings::beginReadArray(const QString & prefix) { - _prefixes.push(prefix); return _manager->beginReadArray(prefix); } void Settings::beginWriteArray(const QString& prefix, int size) { - _prefixes.push(prefix); _manager->beginWriteArray(prefix, size); } void Settings::endArray() { - _prefixes.pop(); _manager->endArray(); } @@ -73,19 +66,15 @@ void Settings::setArrayIndex(int i) { } void Settings::beginGroup(const QString& prefix) { - _prefixes.push(prefix); _manager->beginGroup(prefix); } void Settings::endGroup() { - _prefixes.pop(); _manager->endGroup(); } void Settings::setValue(const QString& name, const QVariant& value) { - if (_manager->value(name) != value) { - _manager->setValue(name, value); - } + _manager->setValue(name, value); } QVariant Settings::value(const QString& name, const QVariant& defaultValue) const { diff --git a/libraries/shared/src/SettingHandle.h b/libraries/shared/src/SettingHandle.h index 5133a9cb2a..54694dfd0a 100644 --- a/libraries/shared/src/SettingHandle.h +++ b/libraries/shared/src/SettingHandle.h @@ -14,7 +14,6 @@ #include -#include #include #include #include @@ -32,7 +31,8 @@ class Settings { public: static const QString firstRun; Settings(); - ~Settings(); + + QString fileName() const; void remove(const QString& key); QStringList childGroups() const; @@ -61,8 +61,6 @@ public: private: QSharedPointer _manager; - QWriteLocker _locker; - QStack _prefixes; }; namespace Setting { diff --git a/libraries/shared/src/SettingInterface.cpp b/libraries/shared/src/SettingInterface.cpp index 9db84055f7..1267147b7e 100644 --- a/libraries/shared/src/SettingInterface.cpp +++ b/libraries/shared/src/SettingInterface.cpp @@ -20,10 +20,245 @@ #include "SettingManager.h" #include "SharedLogging.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +QStringList splitArgs(const QString& string, int idx) { + int length = string.length(); + Q_ASSERT(length > 0); + Q_ASSERT(string.at(idx) == QLatin1Char('(')); + Q_ASSERT(string.at(length - 1) == QLatin1Char(')')); + + QStringList result; + QString item; + + for (++idx; idx < length; ++idx) { + QChar c = string.at(idx); + if (c == QLatin1Char(')')) { + Q_ASSERT(idx == length - 1); + result.append(item); + } else if (c == QLatin1Char(' ')) { + result.append(item); + item.clear(); + } else { + item.append(c); + } + } + + return result; +} + +QJsonDocument variantMapToJsonDocument(const QSettings::SettingsMap& map) { + qDebug() << Q_FUNC_INFO << map.size() << "in map"; + + QJsonObject object; + for (auto it = map.cbegin(); it != map.cend(); ++it) { + auto& key = it.key(); + auto& variant = it.value(); + auto variantType = variant.type(); + + // Switch some types so they are readable/modifiable in the json file + if (variantType == QVariant(1.0f).type()) { // float + variantType = QVariant::Double; + } + if (variantType == QVariant((quint16)0).type()) { // uint16 + variantType = QVariant::UInt; + } + + switch (variantType) { + case QVariant::Map: + case QVariant::List: + case QVariant::Hash: { + qCritical() << "Unsupported variant type" << variant.typeName(); + Q_ASSERT(false); + break; + } + + case QVariant::Invalid: + object.insert(key, QJsonValue()); + break; + case QVariant::LongLong: + case QVariant::ULongLong: + case QVariant::Int: + case QVariant::UInt: + case QVariant::Bool: + case QVariant::Double: + object.insert(key, QJsonValue::fromVariant(variant)); + break; + + case QVariant::String: { + QString result = variant.toString(); + if (result.startsWith(QLatin1Char('@'))) { + result.prepend(QLatin1Char('@')); + } + object.insert(key, result); + break; + } + + case QVariant::ByteArray: { + QByteArray a = variant.toByteArray(); + QString result = QLatin1String("@ByteArray("); + result += QString::fromLatin1(a.constData(), a.size()); + result += QLatin1Char(')'); + object.insert(key, result); + break; + } + case QVariant::Rect: { + QRect r = qvariant_cast(variant); + QString result = QLatin1String("@Rect("); + result += QString::number(r.x()); + result += QLatin1Char(' '); + result += QString::number(r.y()); + result += QLatin1Char(' '); + result += QString::number(r.width()); + result += QLatin1Char(' '); + result += QString::number(r.height()); + result += QLatin1Char(')'); + object.insert(key, result); + break; + } + case QVariant::Size: { + QSize s = qvariant_cast(variant); + QString result = QLatin1String("@Size("); + result += QString::number(s.width()); + result += QLatin1Char(' '); + result += QString::number(s.height()); + result += QLatin1Char(')'); + object.insert(key, result); + break; + } + case QVariant::Point: { + QPoint p = qvariant_cast(variant); + QString result = QLatin1String("@Point("); + result += QString::number(p.x()); + result += QLatin1Char(' '); + result += QString::number(p.y()); + result += QLatin1Char(')'); + object.insert(key, result); + break; + } + + default: { + QByteArray array; + { + QDataStream stream(&array, QIODevice::WriteOnly); + stream.setVersion(QDataStream::Qt_4_0); + stream << variant; + } + + QString result = QLatin1String("@Variant("); + result += QString::fromLatin1(array.constData(), array.size()); + result += QLatin1Char(')'); + object.insert(key, result); + break; + } + } + } + + qDebug() << Q_FUNC_INFO << object.size() << "in json"; + + return QJsonDocument(object); +} + + +QSettings::SettingsMap jsonDocumentToVariantMap(const QJsonDocument& document) { + if (!document.isObject()) { + qWarning() << "Settings file does not contain a JSON object"; + return QSettings::SettingsMap(); + } + auto object = document.object(); + qDebug() << Q_FUNC_INFO << object.size() << "in json"; + QSettings::SettingsMap map; + + for (auto it = object.begin(); it != object.end(); ++it) { + + QVariant result; + + if (!it->isString()) { + result = it->toVariant(); + } else { + auto string = it->toString(); + + if (string.startsWith(QLatin1String("@@"))) { + result = QVariant(string.mid(1)); + + } else if (string.startsWith(QLatin1Char('@'))) { + + if (string.endsWith(QLatin1Char(')'))) { + + if (string.startsWith(QLatin1String("@ByteArray("))) { + result = QVariant(string.toLatin1().mid(11, string.size() - 12)); + + } else if (string.startsWith(QLatin1String("@Variant("))) { + QByteArray a(string.toLatin1().mid(9)); + QDataStream stream(&a, QIODevice::ReadOnly); + stream.setVersion(QDataStream::Qt_4_0); + stream >> result; + + } else if (string.startsWith(QLatin1String("@Rect("))) { + QStringList args = splitArgs(string, 5); + if (args.size() == 4) { + result = QRect(args[0].toInt(), args[1].toInt(), + args[2].toInt(), args[3].toInt()); + } + + } else if (string.startsWith(QLatin1String("@Size("))) { + QStringList args = splitArgs(string, 5); + if (args.size() == 2) { + result = QSize(args[0].toInt(), args[1].toInt()); + } + + } else if (string.startsWith(QLatin1String("@Point("))) { + QStringList args = splitArgs(string, 6); + if (args.size() == 2) { + result = QPoint(args[0].toInt(), args[1].toInt()); + } + } + } + } + } + + map.insert(it.key(), result); + } + + qDebug() << Q_FUNC_INFO << map.size() << "in map"; + return map; +} + +bool readJSONFile(QIODevice& device, QSettings::SettingsMap& map) { + QJsonParseError jsonParseError; + + auto bytesRead = device.readAll(); + auto document = QJsonDocument::fromJson(bytesRead, &jsonParseError); + + if (jsonParseError.error != QJsonParseError::NoError) { + qDebug() << "Error parsing QSettings file:" << jsonParseError.errorString(); + return false; + } + + map = jsonDocumentToVariantMap(document); + + return true; +} +bool writeJSONFile(QIODevice& device, const QSettings::SettingsMap& map) { + auto document = variantMapToJsonDocument(map); + auto jsonByteArray = document.toJson(QJsonDocument::Indented); + auto bytesWritten = device.write(jsonByteArray); + return bytesWritten == jsonByteArray.size(); +} + +const auto jsonFormat = QSettings::registerFormat("json", readJSONFile, writeJSONFile); + + namespace Setting { static QSharedPointer globalManager; - - const QString Interface::FIRST_RUN { "firstRun" }; // cleans up the settings private instance. Should only be run once at closing down. void cleanupPrivateInstance() { @@ -40,30 +275,58 @@ namespace Setting { settingsManagerThread->quit(); settingsManagerThread->wait(); } + + // Sets up the settings private instance. Should only be run once at startup. preInit() must be run beforehand, + void init() { + // Set settings format + QSettings::setDefaultFormat(jsonFormat); + QSettings settings; - // Set up application settings. Should only be run once at startup. - void preInit() { - // read the ApplicationInfo.ini file for Name/Version/Domain information - QSettings::setDefaultFormat(QSettings::IniFormat); - QSettings applicationInfo(PathUtils::resourcesPath() + "info/ApplicationInfo.ini", QSettings::IniFormat); - // set the associated application properties - applicationInfo.beginGroup("INFO"); - QCoreApplication::setApplicationName(applicationInfo.value("name").toString()); - QCoreApplication::setOrganizationName(applicationInfo.value("organizationName").toString()); - QCoreApplication::setOrganizationDomain(applicationInfo.value("organizationDomain").toString()); + if (settings.allKeys().size() == 0) { + + QSettings::setDefaultFormat(QSettings::IniFormat); + QSettings iniSettings; + if (iniSettings.allKeys().size()) { + qDebug() << "No data in json settings file, trying to load old ini settings file."; + + for (auto key : iniSettings.allKeys()) { + auto variant = iniSettings.value(key); + + if (variant.type() == QVariant::String) { + auto string = variant.toString(); + if (string == "true") { + variant = true; + } else if (string == "false") { + variant = false; + } else { + bool ok; + double value = string.toDouble(&ok); + if (ok) { + variant = value; + } + } + } + settings.setValue(key, variant); + } + + qDebug() << "Loaded" << settings.allKeys().size() << "keys from ini settings file."; + } + + QSettings::setDefaultFormat(jsonFormat); + } + + + qDebug() << "First run:" << settings.contains("firstRun") << settings.value("firstRun", true); // Delete Interface.ini.lock file if it exists, otherwise Interface freezes. - QSettings settings; QString settingsLockFilename = settings.fileName() + ".lock"; QFile settingsLockFile(settingsLockFilename); if (settingsLockFile.exists()) { bool deleted = settingsLockFile.remove(); qCDebug(shared) << (deleted ? "Deleted" : "Failed to delete") << "settings lock file" << settingsLockFilename; } - } - - // Sets up the settings private instance. Should only be run once at startup. preInit() must be run beforehand, - void init() { + + // Let's set up the settings Private instance on its own thread QThread* thread = new QThread(); Q_CHECK_PTR(thread); diff --git a/libraries/shared/src/SettingInterface.h b/libraries/shared/src/SettingInterface.h index 5e23d42223..082adf3e54 100644 --- a/libraries/shared/src/SettingInterface.h +++ b/libraries/shared/src/SettingInterface.h @@ -20,14 +20,11 @@ namespace Setting { class Manager; - void preInit(); void init(); void cleanupSettings(); class Interface { public: - static const QString FIRST_RUN; - const QString& getKey() const { return _key; } bool isSet() const { return _isSet; } diff --git a/libraries/shared/src/SettingManager.cpp b/libraries/shared/src/SettingManager.cpp index a42e62c1c8..929fe2b0ff 100644 --- a/libraries/shared/src/SettingManager.cpp +++ b/libraries/shared/src/SettingManager.cpp @@ -9,12 +9,13 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include "SettingManager.h" + #include #include #include #include "SettingInterface.h" -#include "SettingManager.h" namespace Setting { @@ -32,7 +33,6 @@ namespace Setting { // Custom deleter does nothing, because we need to shutdown later than the dependency manager void Manager::customDeleter() { } - void Manager::registerHandle(Interface* handle) { const QString& key = handle->getKey(); withWriteLock([&] {