Development/Tutorials/KConfig (de): Difference between revisions

From KDE TechBase
Line 81: Line 81:
Zeile 9 erzeugt ein Konfigurationsobjekt, dass nicht mit dem globalen <tt>kdeglobals</tt>-Konfigurationsobjekt verflochten ist,  während das Konfigurationsobjekt auf Zeile 12 zusätzlich mit keinem der Dateien in der <tt>$KDEDIRS</tt>-Hierarchie verflochten ist. Das kann die Leistung spürbar verbessern, falls man einfach nur Werte aus einer einfachen Konfuguration liest und globale Werte keine Rolle spielen.
Zeile 9 erzeugt ein Konfigurationsobjekt, dass nicht mit dem globalen <tt>kdeglobals</tt>-Konfigurationsobjekt verflochten ist,  während das Konfigurationsobjekt auf Zeile 12 zusätzlich mit keinem der Dateien in der <tt>$KDEDIRS</tt>-Hierarchie verflochten ist. Das kann die Leistung spürbar verbessern, falls man einfach nur Werte aus einer einfachen Konfuguration liest und globale Werte keine Rolle spielen.


Zeile 15 erzeugt ein Konfigurationsobjekt unter Benutzung des {{class|KComponentData}}-Objekts das zu einem Plugin oder einer anderen Komponente gehört. Das Plugin kann verschiedene Ordner haben, die in seinen {{class|KStandardDirs}} definiert sind und das ist eine Möglichkeit sich zu versichern, dass {{class|KConfig}} das respektiert.
Zeile 15 erzeugt ein Konfigurationsobjekt unter Benutzung des {{class|KComponentData}}-Objekts das zu einem Plugin oder einer anderen Komponente gehört. Das Plugin kann verschiedene Ordner aufweisen, die in seinen {{class|KStandardDirs}} definiert sind und das ist eine Möglichkeit sich zu versichern, dass {{class|KConfig}} das respektiert.


Und schliesslich auf Zeile 18 erzeugen wir ein Konfigurationsobjekt, das nicht in der <tt>config</tt>-Ressource sondern in der <tt>data</tt>-Ressource existiert. Man kann kann auf diese Weise jede Ressource verwenden, von denen {{class|KStandardDirs}} weiss, auch solche die während der Laufzeit hinzugefügt werden.
Und schliesslich auf Zeile 18 erzeugen wir ein Konfigurationsobjekt, das nicht in der <tt>config</tt>-Ressource sondern in der <tt>data</tt>-Ressource existiert. Man kann kann auf diese Weise jede Ressource verwenden, von denen {{class|KStandardDirs}} Kenntnis hat, auch solche die während der Laufzeit hinzugefügt werden.


{{note (de)|Der Rest muss noch übersetzt werden}}
=== Spezielle Konfigurationsobjekte ===
 
=== Special Configuration Objects ===


Each application has its own configuration object that uses the name provided to {{class|KAboutData}} appended with "rc" as its name. So an app named "myapp" would have the default configuration object of "myapprc". This configuration file can be retrieved in this way:
Jede Anwendung hat sein eigenes Konfigurationsobjekt das den Namen benutzt, der von {{class|KAboutData}} bereitgestellt wird mit angehängtem "rc". Also hätte eine Anwendung mit dem Namen "myapp" das Standard-Konfigurationsobjekt "myapprc". Dieses Konfigurationsobjekt kann auf diese Weise aufgerufen werden:


<code cppqt n>
<code cppqt n>
Line 98: Line 96:
MyClass::MyClass()
MyClass::MyClass()
{
{
     // note that this is actually a KSharedConfig
     // beachten sie, dass dies eigentlich ein KSharedConfig ist
     // more on that class in a bit!
     // mehr über diese Klasse siehe weiter unten
     KConfig* config = KGlobal::config();
     KConfig* config = KGlobal::config();
}
}
</code>
</code>


The default configuration object for the application is accessed when no name is specified when creating a {{class|KConfig}} object. So we could also do this instead:
Auf das Standard-Konfigurationsobjekt für die Anwendung wird zugegriffen, wenn kein Name definiert wurde, als das {{class|KConfig}}-Objekt erzeugt wurde. Also könnten wir stattdessen auch das tun:


<code cppqt n>
<code cppqt n>
Line 115: Line 113:
</code>
</code>


Additionally, each component may have its own configuration object. This is generally accessed via the plugin's <tt>componentData()</tt> rather than <tt>{{class|KGlobal}}::mainComponent()</tt>.
Zusätzlich könnte jede Komponente sein eigenes Konfigurationsobjekt haben. Auf dieses wird normalerweise durch die <tt>componentData()</tt> des Plugins zugegriffen, anstatt durch die <tt>{{class|KGlobal}}::mainComponent()</tt>.
 
Und schliesslich gibt es noch ein globales Konfigurationsobjekt, <tt>kdeglobals</tt>, das von jeder Anwendung verwendet wird. Es enthält Informationen wie die Standard-Tatenkombinationen für verschiedene Aktionen. Es wird in das Konfigurationsobjekt "gemischt" wenn der <tt>KConfig::IncludeGlobals</tt> Bitschalter dem {{class|KConfig}} Konstruktor übergeben wird, was standardmässig der Fall ist.


Finally there is a global configuration object, <tt>kdeglobals</tt>, that is shared by every application. It holds such information as the default application shortcuts for various actions. It is "blended" into the configuration object if the <tt>KConfig::IncludeGlobals</tt> flag is passed to the {{class|KConfig}} constructor, which is the default.
{{note (de)|Der Rest muss noch übersetzt werden}}


=== Commonly Useful Methods ===
=== Commonly Useful Methods ===

Revision as of 13:07, 2 January 2008


Development/Tutorials/KConfig


Einführung in KConfig
Anleitungsserie   KConfig
Voriges Kapitel   Keine
Nächstes Kapitel   Benutzen von KConfig XT
Weiterführende Texte   Keine
Navigation   Deutsche Startseite
noframe
noframe

Dieser Abschnitt muss verbessert werden: Bitte hilf mit, verwirrende Abschnitte zu bereinigen und Abschnitte zu reparieren die ein todo beinhalten


Warnung



Zusammenfassung

Dieser Artikel beschäftigt sich mir dem KDE Einstellungdaten-System, angefangen mit einer Übersicht über den grundlegenden Aufbau aus der Sicht eines Entwicklers. Es wirft ausserdem einen Blick auf jede der Klassen, die für die Entwicklung von Anwendungen relevant sind und fährt dann mit kiosk (Benutzer- und Gruppenprofile) Integration fort.

Grundlegender Aufbau

KConfig ist ausgelegt um das Konzept vom eigentlichen Speichern und Auffinden von Konfigurationsdaten hinter eine Programmierschnittstelle zu abstrahieren die es ermöglicht, auf einfache Weise Informationen abzurufen und zu setzen. Wo oder in welcher Form Daten gespeichert werden ist für eine Anwendung die KConfig benutzt irrelevant.

Das behält alle KDE Anwendungen konsistent in ihrer Art, Konfigurationen handzuhaben und nimmt einem Anwendungs-Entwickler die Arbeit so ein System von Grund auf neu zu schreiben, was ein sehr fehleranfälliger Prozess sein kann.

Jedes KConfig Objekt verkörpert ein einziges Konfigurationsobjekt. Jedes Konfigurationsobjekt ist durch seinen einzigartigen Namen gekennzeichnet und kann von mehreren lokalen oder externen Daten oder Services gelesen werden. Jede Anwendung hat standardmässig ein zugehöriges Konfigurationsobjekt und es gibt auch ein globales Konfigurationsobjekt.

Diese Konfigurationsobjekte sind nach einer zweistufigen Hierarchie getrennt: Gruppen und Schlüssel. Ein Konfigurationsobjekt kann eine beliebige Anzahl an Gruppen haben und jede Gruppe kann einen oder mehrere Schlüssel mit zugehörigen Werten haben.


Die gespeicherten Werte können aus beliebig vielen verschiedenen Datentypen bestehen. Sie werden gespeichert und abgerufen als das Objekt selbst. Zum Beispiel wird ein QObject-Objekt direkt einem Konfigurationsobjekt übergeben, wenn es einen Farbwert speichert und wenn ein Farbwert abgerufen wird, wird ein QObject-Objekt zurückgegeben.

noframe
noframe
deserialization entgliedern?
"do not have to perform serialization and deserialization of objects themselves"
Anmerkung


Anwendungen selbst müssen darum normalerweise Objekte nicht selber gliedern und entgliedern.

Applications themselves therefore generally do not have to perform serialization and deserialization of objects themselves.

Die KConfig Klasse

Das KConfig-Objekt wird benutzt um ein bestehendes Konfigurationsobjekt anzusteuern. Es gibt eine Reihe von Möglichkeiten ein Konfigurationsobjekt zu erstellen.

// ein einfaches, altes lesen/schreiben Konfigurationsobjekt KConfig config("myapprc");

// eine bestimmte Datei im Dateisystem // currently must be an INI style file KConfig fullPath("/etc/kderc");

// nicht mit globalen Werten verflochten KConfig globalFree( "localsrc", KConfig::NoGlobals );

// nicht mit globalen Werten orde der $KDEDIRS Hierarchie verflochten KConfig simpleConfig( "simplerc", KConfig::SimpleConfig );

// Komponenten-spezifische Konfiguration, in diesem Fall ein Plugin KConfig pluginConfig( componentData(), "pluginrc" );

// Ausserhalb der normalen Konfigurations-Ressource KConfig dataResource( "data", "myapp/somefile" );


noframe
noframe
wie soll "merged" in den folgenden Fällen übersetzt werden?
"verschmolzen" oder "verflochten"
der Anwendung selber transparent" tönt auch nicht sehr gut
Anmerkung


Das Kconfig Objekt, das wir auf Zeile 2 erstellen ist ein gewöhnliches Konfigurationsobjekt. Wir können Werte aus ihm lesen, neue Einträge schreiben und nach verschiedenen Eigenschaften des Objekts fragen. Dieses Objekt wird aus der Konfigurations-Ressource geladen, wie es durch KStandardDirs bestimmt wird, das heisst, dass jede Instanz des myapprc-Objekts in jedem der Ordner in der Konfigurations-Ressourcen-Hierarchie verschmolzen werden um die Werte zu erzeugen, die in diesem Objekt gesehen werden. So werden Systemweite und pro-Benutzer/Gruppen Profile erstellt und unterstützt. Das alles geschieht der Anwendung selber transparent.


Tip
Für mehr Informationen, wie das Verschmelzen funktioniert, siehe diesen Artikel über die KDE Dateisystem Hierarchie.


noframe
noframe
Ist das so gemeint mit "expects an INI style file"
On line 6 we open a specific local file, this case /etc/kderc. This performs no merging of values and expects an INI style file.
Anmerkung


Auf Zeile 6 öffnen wir eine bestimmte Lokale Datei, in diesem Fall /etc/kderc. Das führt kein verschmelzen von Werten aus und erwartet eine Datei im INI Format.

Zeile 9 erzeugt ein Konfigurationsobjekt, dass nicht mit dem globalen kdeglobals-Konfigurationsobjekt verflochten ist, während das Konfigurationsobjekt auf Zeile 12 zusätzlich mit keinem der Dateien in der $KDEDIRS-Hierarchie verflochten ist. Das kann die Leistung spürbar verbessern, falls man einfach nur Werte aus einer einfachen Konfuguration liest und globale Werte keine Rolle spielen.

Zeile 15 erzeugt ein Konfigurationsobjekt unter Benutzung des KComponentData-Objekts das zu einem Plugin oder einer anderen Komponente gehört. Das Plugin kann verschiedene Ordner aufweisen, die in seinen KStandardDirs definiert sind und das ist eine Möglichkeit sich zu versichern, dass KConfig das respektiert.

Und schliesslich auf Zeile 18 erzeugen wir ein Konfigurationsobjekt, das nicht in der config-Ressource sondern in der data-Ressource existiert. Man kann kann auf diese Weise jede Ressource verwenden, von denen KStandardDirs Kenntnis hat, auch solche die während der Laufzeit hinzugefügt werden.

Spezielle Konfigurationsobjekte

Jede Anwendung hat sein eigenes Konfigurationsobjekt das den Namen benutzt, der von KAboutData bereitgestellt wird mit angehängtem "rc". Also hätte eine Anwendung mit dem Namen "myapp" das Standard-Konfigurationsobjekt "myapprc". Dieses Konfigurationsobjekt kann auf diese Weise aufgerufen werden:

  1. include <KComponentData>
  2. include <KConfig>
  3. include <KGlobal>

MyClass::MyClass() {

   // beachten sie, dass dies eigentlich ein KSharedConfig ist
   // mehr über diese Klasse siehe weiter unten
   KConfig* config = KGlobal::config();

}

Auf das Standard-Konfigurationsobjekt für die Anwendung wird zugegriffen, wenn kein Name definiert wurde, als das KConfig-Objekt erzeugt wurde. Also könnten wir stattdessen auch das tun:

  1. include <KConfig>

MyClass::MyClass() {

   KConfig config;

}

Zusätzlich könnte jede Komponente sein eigenes Konfigurationsobjekt haben. Auf dieses wird normalerweise durch die componentData() des Plugins zugegriffen, anstatt durch die KGlobal::mainComponent().

Und schliesslich gibt es noch ein globales Konfigurationsobjekt, kdeglobals, das von jeder Anwendung verwendet wird. Es enthält Informationen wie die Standard-Tatenkombinationen für verschiedene Aktionen. Es wird in das Konfigurationsobjekt "gemischt" wenn der KConfig::IncludeGlobals Bitschalter dem KConfig Konstruktor übergeben wird, was standardmässig der Fall ist.

noframe
noframe
Der Rest muss noch übersetzt werden
Anmerkung


Commonly Useful Methods

To save the current state of the configuration object we call the sync() method. This method is also called when the object is destroyed. If no changes have been made or the resource reports itself as non-writable (such as in the case of the user not having write permissions to the file) then no disk activity occurs. sync() merges changes performed concurrently by other processes - local changes have priority, though.

If we want to make sure that we have the latest values from disk we can call reparseConfiguration() which calls sync() and then reloads the data from disk.

If we need to prevent the config object from saving already made modifications to disk we need to call markAsClean(). A particular use case for this is rolling back the configuration to the on-disk state by calling markAsClean() followed by reparseConfiguration().

Listing all groups in a configuration object is as simple as calling groupList() as in this code snippet:

KConfig* config = KGlobal::mainComponent().config();

foreach ( const QString& group, config.groupList() ) {

   kDebug() << "next group:" << group;

}

KSharedConfig

The KSharedConfig class is a reference counted version of KConfig. It thus provides a way to reference the same configuration object from multiple places in your application without the extra overhead of separate objects or concerns about syncronizing writes to disk even if the configuration object is updated from multiple code paths.

Accessing a KSharedConfig object is as easy as this:

KSharedConfigPtr config = KSharedConfig::openConfig();

openConfig() take the same parameters as KConfig's constructors do, allowing one to define which configuration file to open, flags to control merging and non-config resources.

KSharedConfig is generally recommended over using KConfig itself, and the object returned from KComponentData is indeed a KSharedConfig object.

KConfigGroup

Now that we have a configuration object, the next step is to actually use it. The first thing we must do is to define which group of key/value pairs we wish to access in the object. We do this by creating a KConfigGroup object:

KConfig config; KConfigGroup generalGroup( &config, "General" ); KConfigGroup colorsGroup = config.group( "Colors" ); // ... or a bit differently ...

You can pass KConfig or KSharedConfig objects to KConfigGroup.

Config groups can be nested as well:

KConfigGroup subGroup1( &generalGroup, "LessGeneral" ); KConfigGroup subGroup2 = colorsGroup.group( "Dialogs" );

Reading Entries

With a KConfigGroup object in hand reading entries is now quite straight forward:

QString accountName = generalGroup.readEntry( "Account",

                                             QString() );

QColor color = colorsGroup.readEntry( "background",

                                     Qt::white );

QStringList list = generalGroup.readEntry( "List",

                                          QStringList() );

QString path = generalGroup.readPathEntry( "SaveTo",

                                          defaultPath );

As can be seen from the above, you can mix reads from different KConfigGroup objects created on the same KConfig object. The read methods take the key, which is case sensitive, as the first argument and the default value as the second argument. This argument controls what kind of data, e.g. a color in line 3 above, is to be expected as well as the type of object returned. The returned object is wrapped in a QVariant to make this magic happen.

There are a couple of special read methods, including readPathEntry which returns a file system path. It is vital that one uses readPathEntry if it is a path as this enables such features as roaming profiles to work properly.

If no such key currently exists in the configuration object, the default value is returned instead. If there is a localized (e.g. translated into another language) entry for the key that matches the current locale, that is returned.

Writing Entries

Setting new values is similarly straightforward:

generalGroup.writeEntry( "Account", accountName ); generalGroup.writePathEntry( "SaveTo", savePath ); colorGroup.writeEntry( "background", color ); generalGroup.config()->sync();

Note the use of writePathEntry and how the type of object we use, such as QColor on line 3, dictates how the data is serialized. Additionally, once we are done writing entries, sync() must be called on the config object for it to be saved to disk. We can also simply wait for the object to be destroyed, which triggers an automatic sync() if necessary.

KDesktopFile: A Special Case

When is a configuration file not a configuration file? When it is a desktop file. These files, which are essentially configuration files at their heart, are used to describe entries for application menus, mimetypes, plugins and various services.

When accessing a .desktop file, one should instead use the KDesktopFile class which, while a KConfig class offering all the capabilities described above, offers a set of methods designed to make accessing standard attributes of these files consistent and reliable.

Kiosk: Lockdown and User/Group Profiles

KConfig provides a powerful set of lockdown and configuration definition capabilities, collectively known as "Kiosk", that many system administrators and system integrators rely on. While most of this framework is provided transparently to the application, there is occassion when an application will want to check on the read/write status of a configuration object.

Entries in configuration objects that are locked down using the kiosk facilities are said to be immutable. An application can check for immutability of entire configuration objects, groups or keys as shown in this example:

KConfig* config = KGlobal::config();

if ( config->isImmutable() ) {

   kDebug() << "configuration object is immutable";

}

KConfigGroup group(config, "General"); if ( group.isImmutable() ) {

   kDebug() << "group General is immutable";

}

if ( group.entryIsImmutable("URL") ) {

   kDebug() << "URL entry in group General is immutable";

}

This can be useful in particular situations where an action should be taken when an item is immutable. For instance, the KDE panels will not offer configuration options to the user or allow them to otherwise change the order of applets and icons when the panel's configuration object is marked as immutable.

KConfig XT

There is a way to make certain use cases of KConfig easier, faster and more reliable: KConfig XT. In particular, for main application or plugin configuration objects and when syncing configuration dialogs and other interfaces with these values, KConfig XT can help immensely. It also simultaneously documents the configuration options available, which makes every sys admin and system integrator that uses KDE that much more happy.

The next tutorial in the KConfig series covers what KConfig XT is and how to use it.