Frameworks/Porting Notes/KStandardDirs

From KDE Community Wiki

A script is available in kdesdk/kde-dev-scripts/kf5/convert-kstandarddirs.pl to port some of this.

KStandardDirs is now in kdelibs4support. Apps can keep using it, but it is recommended to use QStandardPaths instead. Note that KStandardDirs makes some assumptions about all the frameworks being installed in the same location that the frameworks themselves do not.

Also note that $KDEDIRS and $KDEHOME do not exist anymore (no matter which class you use).

The porting depends on the resource type:

    KStandardDirs "data" -> QStandardPaths::GenericDataLocation
    KStandardDirs "appdata" -> QStandardPaths::AppDataLocation // or AppLocalDataLocation
    KStandardDirs "config" -> QStandardPaths::GenericConfigLocation
    KStandardDirs "xdgdata-apps" -> QStandardPaths::ApplicationsLocation
    KStandardDirs "cache" -> QStandardPaths::GenericCacheLocation
    KStandardDirs "socket" -> QStandardPaths::RuntimeLocation

If the resource is available in QStandardPaths (i.e. for all of the above), then the porting is simple:

    KStandardDirs::locate("data", "kmyapp/my-data") -> QStandardPaths::locate(QStandardPaths::GenericDataLocation, "kmyapp/my-data")
    KStandardDirs::locate("services", "foo.desktop") -> QStandardPaths::locate(QStandardPaths::GenericDataLocation, "kde5/services/foo.desktop")
    dirs.findResource("data", relPath) -> QStandardPaths::locate(QStandardPaths::GenericDataLocation, "kmyapp/my-data")
    dirs.findDirs("data", "kconf_update") -> QStandardPaths::locateAll(QStandardPaths::GenericDataLocation, "kconf_update", QStandardPaths::LocateDirectory)
    saveLocation -> writableLocation (note that you might have to mkpath it if it doesn't exist)
    locateLocal(type, file) -> writableLocation(type) + '/' + file (you might have to mkpath the directory)
    locateLocal(tmp, file) -> QDir::tempPath() + '/' + file
    resourceDirs("xdgdata-apps") -> QStandardPaths::standardLocations(QStandardPaths::ApplicationsLocation)  (no trailing slashes anymore though)

Otherwise, you need to use GenericDataLocation and add the subdirectory name manually.

    dirs()->resourceDirs("xdgdata-icon") -> QStandardPaths::locateAll(QStandardPaths::GenericDataLocation, "icons", QStandardPaths::LocateDirectory) // xdgata-icon is the "icons" subdir under the xdg data locations
    dirs()->findAllResources("xdgdata-mime", file) -> QStandardPaths::locateAll(QStandardPaths::GenericDataLocation, "mime/" + file)
    Similarly, xdgconf-menu is QStandardPaths::GenericConfigLocation + "menus", and xdgconf-autostart is QStandardPaths::GenericConfigLocation + "autostart";
    "xdgdata-dirs" is QStandardPaths::GenericDataLocation + "desktop-directories"
    "templates" is QStandardPaths::GenericDataLocation + "templates"
    "emoticons" is QStandardPaths::GenericDataLocation + "emoticons
    "html" is QStandardPaths::GenericDataLocation + "doc/HTML"
    "sound" is QStandardPaths::GenericDataLocation + "sounds" (note the additional 's')
    "wallpaper" is QStandardPaths::GenericDataLocation + "wallpapers" (note the additional 's')
    "apps" was the kde3 "applnk" directory. Remove this compatibility code altogether, or port it to xdgdata-apps, i.e. QStandardPaths::ApplicationsLocation.
    (see kstandarddirs.cpp line 119 ff for resources that are missing here)

When the code uses wildcard filters or the Recursive flag in findAllResources, you cannot port it to one line of QStandardPaths. Either keep using KStandardDirs, or write your own filtering (QDir::entryList) or recursive listing (use QDirIterator with the Subdirectories flag). Also, check for absolute paths first, findAllResources(res, "/absolute/path") returned the path, QStandardPaths doesn't.
If NoDuplicates was used, make a unique list of relative paths first, then use locate on each one (see autostart.cpp for an example).
Example using entryList:

    QStringList files = dirs()->findAllResources("data", "foo/bar/*.desktop")

becomes:

    QStringList files;
    const QStringList dirs = QStandardPaths::locateAll(QStandardPaths::GenericDataLocation, "foo/bar", QStandardPaths::LocateDirectory);
    Q_FOREACH (const QString& dir, dirs) {
        const QStringList fileNames = QDir(dir).entryList(QStringList() << QStringLiteral("*.desktop"));
        Q_FOREACH (const QString& file, fileNames) {
            files.append(dir + '/' + file);
        }
    }

Example using QDirIterator:

    QStringList files;
    const QStringList dirs = QStandardPaths::locateAll(QStandardPaths::GenericDataLocation, "foo/bar", QStandardPaths::LocateDirectory);
    Q_FOREACH (const QString& dir, dirs) {
        QDirIterator it(dir, QStringList() << QStringLiteral("*.desktop"));
        while (it.hasNext()) {
            files.append(it.next());
        }
    }

On the other hand, findAllResources("locale", "*/entry.desktop") requires

    const QStringList localeDirs = QStandardPaths::locateAll(QStandardPaths::GenericDataLocation, QStringLiteral("locale"), QStandardPaths::LocateDirectory);
    Q_FOREACH (const QString &localeDir, localeDirs) {
        const QStringList entries = QDir(localeDir).entryList(QDir::Dirs);
        Q_FOREACH (const QString &d, entries) {
            if (QFile::exists(localeDir + '/' + d + "/entry.desktop")) {
                // ...
            }
        }
    }

KStandardDirs::findExe (and the use of the "exe" resource) can be ported to QStandardPaths::findExecutable, except when the executable comes from libexec, in which case the path should just be hardcoded using CMAKE_INSTALL_PREFIX "/" LIBEXEC_INSTALL_DIR.

The "lib" resource was not used directly in code (the linker finds shared libs, not the code).

The "module" resource, on the other hand, was used to locate plugins. KPluginLoader now uses QT_PLUGIN_PATH instead, and looks in the kf5 subdirectory. Please email [email protected] if you would need public API for this.

With KStandardDirs, applications could even define their own resource types with addResourceType() or addResourceDir(). This was like creating an alias for a directory (relative or absolute) and using that later. With QStandardPaths there is no such mechanism, just use the subdir directly in your calls to QStandardPaths::locate/locateAll. For instance, this code:

KGlobal::dirs()->addResourceType("dtd", "data", "ksgmltools2/");
KStandardDirs::locate("dtd", fileName);

becomes

QStandardPaths::locate(QStandardPaths::GenericDataLocation, "ksgmltools2/" + fileName);

For relativeLocation, see the helper method in the documentation for the method in kstandarddirs.h.