Unsolved QSettings path adds extra subdirectory for organization
-
Hi All,
Using Windows 10 with Qt5.5. Trying to place an ini file into a reasonable (portable, predictable, not hard-coded) location but QSettings is being tricky. When I call the static method QSettings::setPath, it works fine except that it adds the organization name from QCoreApplication unnecessarily. I'm adding the organization name already using QStandardPaths::AppDataLocation (which by default has the organization in it, in Win10 at least), then QSettings is also appending the organization name to whatever path I set resulting it it being there twice:
QCoreApplication::setOrganizationName("MyCompany"); QCoreApplication::setApplicationName("MyApplication"); QSettings::setDefaultFormat(QSettings::IniFormat); QSettings::setPath(QSettings::defaultFormat(), QSettings::UserScope, QStandardPaths::writableLocation(QStandardPaths::AppDataLocation)); qDebug() << "QstdPaths AppDataLocation=" << QStandardPaths::writableLocation(QStandardPaths::AppDataLocation); QSettings settings; qDebug() << "INI Path:" << settings.fileName();
Output:
QstdPaths AppDataLocation= "C:/Users/mark/AppData/Roaming/MyCompany/MyApplication" INI Path: "C:/Users/mark/AppData/Roaming/MyCompany/MyApplication/MyCompany/MyApplication.ini"
I thought that using setPath would actually set the path I want, and not add stuff to it that I didn't ask for. Is this because I'm using the default constructor for QSettings? That's what I would like to do because it is the cleanest (that was the point of setting the organization name and application name at the QCoreApplication level, as the docs say that's what I should do if I want to use the default constructor for QSettings). Is there some way around this?
-
Hi,
That's a point you should rather bring to the interest mailing list. You'll find there Qt's developers/maintainers. This forum is more user oriented.
-
@SGaist I posted in a development forum... How is this a user issue? I'm not sure I understand. I'm looking for help using QSettings in a desktop application. Could you please clarify what is this list you directed me to?
-
The behaviour you are seeing is what I'd expect, though I can understand how it's counter-intuitive at first glance.
Basically, your
setPath
call is setting the top-level-settings-path toAppDataLocation
, and as per the docs, this is "an application-specific directory" - in your case, it'sC:/Users/mark/AppData/Roaming/MyCompany/MyApplication
. The fact that this is application-specific is somethingQSettings::setPath
knows nothing about, and it makes no assumptions about it.Then, when QSettings read / writes files, it dutifully prepends the organisation and application name, since it has no guarantees that you've done that already with the path you've added in (who's to say MyCompany isn't both the name of your application's organisation, and the name of your disk / directory / mount / symlink?).
However, I can see valid reasoning for it the be the way you'd expect too.
Putting the rightness / wrongness aside, a few additional thoughts...
- instead of using
QStandardPaths::AppDataLocation
, why not useQStandardPaths::GenericDataLocation
? - why are you calling
QSettings::setPath
anyway? the default value on Windows is%COMMON_APPDATA%\<orgname>\<app name>.ini
which sounds more in line with what you want?
Depending on what you're trying to do, there might be a case for adding a
QSettings::setPath
overload / alternative that works the way you expected. Perhaps that's some of why @SGaist suggested the mailing list.Cheers.
- instead of using
-
As @Paul-Colby correctly analyzed, your use case might involve internals of Qt which is usually outside the scope of this forum which is about using Qt rather than developing Qt itself.
Note that there's nothing wrong discussing implementation details and potential bugs/feature. But the place where you'll find the developers/maintainers of Qt is on the mailing list hence my suggestion.
-
It sounds like you're saying this is just a bit of weirdness from Qt that I should either work around or take it up with the Qt developers, am I right?
I have tried other QStandardPaths, but I can't find a combination that matches our legacy (non-Qt Windows-only) apps that just use %APPDATA%\<AppName>\<AppName>.ini to store their settings. I could of course do that in Qt, but I'm trying to make this work for Linux and Mac too.
The default %COMMON_APPDATA%\<orgname>\<app name>.ini convention makes perfect sense to me, but I don't always get to decide... There are requirements to follow.
So I guess I'll try something else. Overloading setPath sounds like a workable option... thanks for that!
-
No, I'm just saying that your use case is unusual but could interest the devs. Anyway, it's way clearer now that you added that you have a legacy application to handle.
Note that you don't need to do special modifications to QSettings, you could just use the constructor that takes a file path. That way, you can build said path as you need on the platforms you support.
If your application is meant to replace the other one, you could provide a "migration path" where you move the actual settings file to a more suitable place that avoids you to fiddle with the path like you need to do now.
-
Or... when in doubt change the requirements! I have successfully argued my case and the default is OK.
Using the constructor with the path is also an option yeah... I didn't actually test that. Overloading setPath is probably overkill in this case but I might do it anyway, just in case I have similar issues when I get around to testing this on Mac/Linux.
One more question about QSettings though... Is it acceptable to store the settings object as a private member variable and just call the QSettings constructor once (in the constructor of my MainWindow for example)? All of the examples I've seen call the constructor in each function that uses it and just keeps it as a local stack variable, but is there reason for that? I know its a Monstate object and all of the QSettings objects share the same state, but why call the constructor every time you need it?
-
Because the example follows usually this pattern: load at startup and store at end of the application.