Skip to content

KDE Frameworks – Part 3

Thursday, 26 May 2022 | KDAB on Qt


Every sizable project has a ‘utils’ file or folder that contains functionality that is needed more than once but too small to be a library. KDE is no different, except we want to share our ‘utils’ folder across hundreds of projects. This is where the KCoreAddons framework comes into play. The name comes from the fact that it consists of addons to QtCore, extending existing functionality from it or implementing things that are missing. Let’s look at what it offers.

Plugin Support

Plugins are a common architectural element in applications that, for example, allow for third-party extensions. Qt offers a cross-platform means of building binary plugins, QPluginLoader. KCoreAddons offers some additional functionality for loading plugins based on QPluginLoader.

We often want to list all available plugins to, for example, provide a UI for configuring them. To list all plugins in $QT_PLUGIN_PATH/myplugins, we would write code like this:

QSet<QString> plugins;

QStringList dirs = QCoreApplication::libraryPaths();

for (QString dir : dirs) {
    QDirIterator it(dir + “/myplugins”, QDir::Files);

    while (it.hasNext()) {
        it.next();

        if (!plugins.contains(it->fileName())) {
            plugins << it->fileName();
        }
    }
}

Not too bad, albeit a bit verbose. However, if we want it to work properly on Android, we’d need extra code; plugin naming and loading work differently there. The handling of static plugins would require extra code, too.

KCoreAddons offers a convenient function that abstracts away all of the boring details and edge-cases:

QVector<KPluginMetaData> plugins = KPluginMetaData::findPlugins("myplugins");

KPluginMetaData contains a parsed version of the plugin’s JSON metadata (QPluginLoader::metaData()). It offers convenient support for common metadata keys, such as information about the plugin’s author and license, but can be used to read arbitrary metadata.

The plugins can then be loaded using the familiar QPluginLoader:

for (const KPluginMetaData &plugin : plugins) {
    QPluginLoader loader(plugin.fileName());
    MyInterface *iface = qobject_cast<MyInterface *>(plugin.instance());
}

This works great for many use-cases. However, sometimes you want to create multiple instances of MyInterface. This is something that QPluginLoader does not allow. KPluginFactory comes to the rescue, here.

To use it, we need to define our interface and implementation in a particular way:

// myinterface.h

class MyInterface : public QObject
{
    MyInterface(QObject *parent, const KPluginMetaData &metaData, const QVariantList &args);
}


// myimpl1.cpp

#include “myinterface.h”

#include <KPluginFactory>

class MyImpl1 : public MyInterface {

MyImpl1(QObject *parent, const KPluginMetaData &metaData, const QVariantList &args)
    : MyInterface(parent, metadata, args)
{
}

}

K_PLUGIN_CLASS_WITH_JSON(MyImpl1, “metadata.json”)

#include “myplugin.moc”

metaData gives access to the plugin’s JSON metadata from within the instance.
args allows passing additional arguments while creating the instance, which is useful for per-instance configuration.

Now, an instance can be created using the following:

KPluginMetaData metaData(“myinterface/myimpl1”);
QObject *parent = …;
QVariantList args = …;
KPluginFactory::Result result = KPluginFactory::instantiatePlugin<MyInterface>(metaData, parent, args);

if (result) {
    MyInterface *instance = result.plugin
} else {
    qDebug() << “could not load plugin” << result.errorText
}

instantiatePlugin returns a result object that contains the instantiated plugin (if successful) and information about what went wrong otherwise.

KUser

Sometimes, you want to query some information about the user of your software to, for example, greet them with their full name. KUser provides a cross-platform way to query information about user accounts that are on the system.

KUser user; // The current user

qDebug() << “Hello” << user.fullName();

KFormat

Displaying data to the user is the bread-and-butter of many applications. The way the data is formatted and presented can make or break the overall user experience. The KFormat class helps with formatting values, date and time information, and durations in a visually-appealing way.

For instance, when displaying the date of an event, we may want to show “Yesterday” or “Last Tuesday,” if the event happened recently, and the exact date, if the event happened further in the past:

QDate date = …;

KFormat format;

qDebug() << format.formatRelativeDate(date, QLocale::LongFormat);

When displaying durations, we may want to show the value in a textual way instead of e.g., raw milliseconds:

KFormat format;

qDebug() << format.formatSpelloutDuration(62005); // prints “1 minute and 2 seconds”

When showing the size of a file, we are usually not interested in full precision; an approximation is often enough. Furthermore, files come in a wide range of sizes, from bytes to gigabytes. Depending on the size, we want to choose an appropriate prefix (e.g. kB or GB). This is where formatByteSize is useful:

QFile file(…);

KFormat format;

// prints “1.4 MB
qDebug() << format.formatByteSize(file.size(), 1, KFormat::MetricBinaryDialect);

formatByteSize allows the tweaking of things like precision, prefix, and unit dialect (e.g. MiB vs MB).

KStringHandler

KStringHandler offers useful useful helper functions for string manipulation. For example, the lsqueeze/csqueeze/rsqueeze functions allow limiting a string to a specified length, adding ellipsis (“…”) where needed.

// prints “KDE is … awesome”
qDebug() << KStringHandler::csqueeze(“KDE is really awesome”, 19);

KStringHandler::capwords capitalizes every word in a sentence:

// prints “The Quick Brown Fox Jumped Over The Lazy Bridge.”
qDebug() << KStringHandler::capwords(“The quick brown fox jumped over the lazy bridge.”);

Many More Useful Features…

This is just the tip of the iceberg. KCoreAddons offers many more useful features for application developers. For the full list, please consult the API documentation.

KCoreAddons is supported on Linux, Windows, macOS, Android, and FreeBSD. You can find the source code on KDE’s Gitlab instance.

Stay tuned for the next KDE Frameworks introduction post!

If you missed parts one and two of this blog series, please take a look at those as well.

About KDAB

If you like this article and want to read similar material, consider subscribing via our RSS feed.

Subscribe to KDAB TV for similar informative short video content.

KDAB provides market leading software consulting and development services and training in Qt, C++ and 3D/OpenGL. Contact us.

The post KDE Frameworks – Part 3 appeared first on KDAB.