Запретить 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, и эта "магия" на самом деле не задокументирована).

Итак, единственные решения, которые я придумал, это:

  1. Создание фабрики, которая знает о переносимости приложения, создает QSettings Объект в куче с соответствующим конструктором, и возвращает указатель на него. У этого есть обратная сторона необходимости управлять памятью этого динамически сконструированного объекта, следовательно, необоснованно добавленная сложность. Также он добавляет другую сущность, которая зависит от переносимости приложения.
  2. Делать, как указано выше, но синглтон. Это также добавляет лишнюю сложность при решении очень простой проблемы. Также в этом случае 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]
Другие вопросы по тегам