Запретить QSettings от добавления имени организации к пути, установленному QSettings::setPath()
Есть ли способ установить фактический путь по умолчанию QSettings
хранение (с именем файла или без него) и предотвращение QSettings
от добавления таких вещей, как название организации к этому пути? Это с требованием, что дальнейшее использование QSettings
оставайтесь прежними и не знаете пути хранения настроек.
Рассмотрим вариант использования. В моем основном у меня есть следующий код:
QApplication a(argc, argv);
...
QCoreApplication::setApplicationName(APP_NAME);
QCoreApplication::setOrganizationDomain(MY_DOMAIN);
QCoreApplication::setOrganizationName(MY_ORGANIZATION);
QCoreApplication::setApplicationVersion(APP_VERSION);
...
a.exec();
и во всем моем проекте я использую QSettings
как это:
QSettings settings;
settings.setValue(somePath, someValue);
someOtherValue = settings.value(someOtherPath, someDefault);
Теперь у меня есть требование сделать приложение переносимым. Поэтому я изменяю код в основном на это:
QApplication a(argc, argv);
...
QCoreApplication::setApplicationName(APP_NAME);
QCoreApplication::setOrganizationDomain(MY_DOMAIN);
QCoreApplication::setOrganizationName(MY_ORGANIZATION);
QCoreApplication::setApplicationVersion(APP_VERSION);
if (PORTABLE) {
QSettings::setDefaultFormat(QSettings::IniFormat);
QString settingsPath = a.applicationDirPath() + "/settings";
QSettings::setPath(QSettings::defaultFormat(), QSettings::UserScope, settingsPath);
QSettings::setPath(QSettings::defaultFormat(), QSettings::SystemScope, settingsPath);
}
...
a.exec();
Но вместо настроек пишутся в APP_PATH/settings/
фактическое местоположение становится APP_PATH/settings/ORGANIZATION_NAME/
что, на мой взгляд, слишком уродливо.
Я хотел бы настроить QSettings
хранить настройки в определенном месте. Пользовательский код не должен знать об изменении места хранения. Идеально настроенный QSettings
в основном, и использовать объекты, построенные с конструктором по умолчанию в дальнейшем.
Я обнаружил, что только QSettings(const QString &fileName, QSettings::Format format, QObject *parent = nullptr)
Конструктор может быть использован, чтобы действительно установить место хранения. Все остальные конструкторы продолжают добавлять вещи в путь. И поскольку я не хочу, чтобы пользовательский код знал о переносимости приложения, использование разных конструкторов каждый раз не вариант.
Я думал о подклассе QSettings
вроде как это исправить setPath()
:
class Settings : public QSettings {
private:
static QString mPath = "";
public:
Settings(QObject *parent = nullptr) :
QSettings(
mPath.isEmpty() ?
QSettings() :
QSettings(mPath, Settings::defaultFormat, parent)
)
{}
static void setPath(QSettings::Format format, QSettings::Scope scope, const QString &path)
{
mPath = path;
QSettings::setPath(format, scope, path);
}
}
но это невозможно, потому что QSettings
не имеет конструктора копирования. Строительство базы с QSettings(mPath, Settings::defaultFormat, parent)
в любом случае, но установка mPath
путь по умолчанию, если он не был установлен, тоже не может быть, потому что нет способа получить значение по умолчанию QSettings
путь хранения (есть setPath
, но нет getPath
; есть getFileName
и нет setFileName
; получение "пути" из fileName подвержено ошибкам, потому что Qt добавляет некоторую "магию", такую как имя организации, к "пути" для получения fileName, и эта "магия" на самом деле не задокументирована).
Итак, единственные решения, которые я придумал, это:
- Создание фабрики, которая знает о переносимости приложения, создает
QSettings
Объект в куче с соответствующим конструктором, и возвращает указатель на него. У этого есть обратная сторона необходимости управлять памятью этого динамически сконструированного объекта, следовательно, необоснованно добавленная сложность. Также он добавляет другую сущность, которая зависит от переносимости приложения. - Делать, как указано выше, но синглтон. Это также добавляет лишнюю сложность при решении очень простой проблемы. Также в этом случае
QSettings
Объект будет существовать в течение всего времени жизни приложения.
Так что у меня есть ощущение, что я определенно что-то здесь упускаю, и мне интересно, есть ли более простое решение этой проблемы.
Примечание: в настоящее время я решил эту проблему, установив название своей организации на "настройки", если приложение переносимо, поэтому настройки приложения хранятся в файле APP_FOLDER/settings/APP_NAME.ini. Грязный хак, но спасает много сложности. Во всяком случае, я нигде не использую название организации.
1 ответ
Я понимаю, что вы, по сути, хотите QSettings
быть построенным одним из двух способов в зависимости от того, был ли установлен конкретный путь.
Вместо того, чтобы наследовать от QSettings
Вы можете создать класс с перегруженным указателем на член ->
оператор, который возвращает указатель на QSettings
пример. Таким образом, инициализация QSettings
можно отложить до использования и использовать любую информацию, которая была установлена.
class settings {
public:
static void set_path (QSettings::Format format, QSettings::Scope scope, const QString &path)
{
s_path = path;
QSettings::setPath(format, scope, path);
}
QSettings *operator-> ()
{
return get_settings();
}
private:
QSettings *get_settings ()
{
if (!m_settings) {
if (s_path.isEmpty()) {
m_settings = std::make_unique<QSettings>();
} else {
m_settings = std::make_unique<QSettings>(s_path, QSettings::defaultFormat());
}
}
return m_settings.get();
}
static QString s_path;
std::unique_ptr<QSettings> m_settings;
};
QString settings::s_path = "";
При использовании с настройками / значениями по умолчанию...
settings settings;
std::cout << "\nsettings file path is [" << settings->fileName() << "]";
Выше приведено что-то вроде...
settings file path is [/home/<user>/.config/Unknown Organization/appname.conf]
Установка желаемого пути явно с помощью...
settings::set_path(QSettings::defaultFormat(), QSettings::SystemScope, app.applicationDirPath() + "/settings.ini");
settings settings;
std::cout << "\nsettings file path is [" << settings->fileName() << "]";
дает...
settings file path is [/home/<user>/scratch/settings.ini]