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

    From KDE TechBase
    mNo edit summary
    No edit summary
     
    (36 intermediate revisions by 4 users not shown)
    Line 1: Line 1:
    {{Template:I18n/Language Navigation Bar|Development/Tutorials/KConfig}}
     


    {{TutorialBrowser (de)|
    {{TutorialBrowser (de)|
    Line 14: Line 14:


    }}
    }}
    {{improve (de)}}


    == Zusammenfassung ==
    == Zusammenfassung ==




    Dieser Artikel beschäftigt sich mir dem KDE Einstellungdaten-System, angefangen mit einer Übersicht über die Grundlagen des Aufbaus 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 Gruppen Profile) Integration fort.
    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.


    == Grundlagen des Aufbaus ==
    == 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.
    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.


    TODO:
    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.


    This keeps all KDE applications consistent in their handling of configurations while alleviating each and every application author to build such a system on their own from scratch, which can be a highly error prone exercise.
    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.


    A KConfig object represents a single configuration object. Each configuration object is referenced by its unique name and may be actually read from multiple local or remote files or services. Each application has a default configuration object associated with it and there is also a global configuration object.


    These configuration objects are broken down into a two level hierarchy: groups and keys. A configuration object can have any number of groups and each group can have one or more keys with associated values.
    Die gespeicherten Werte können aus beliebig vielen verschiedenen Datentypen bestehen. Sie werden gespeichert und abgerufen als das Objekt selbst. Zum Beispiel wird ein {{qt|QObject}}-Objekt direkt einem Konfigurationsobjekt übergeben, wenn es einen Farbwert speichert und wenn ein Farbwert abgerufen wird, wird ein {{qt|QObject}}-Objekt zurückgegeben.


    Values stored may be of any number of data types. They are stored and retreived as the objects themselves. For example, a {{qt|QObject}} object is passed to a config object directly when storing a color value and when retreived a {{qt|QObject}} object is returned. Applications themselves therefore generally do not have to perform serialization and deserialization of objects themselves.
    Anwendungen selbst müssen sich deshalb nicht um das Gliedern und Entgliedern von Objekten kümmern.


    == The KConfig Class ==
    == Die KConfig Klasse ==


    The {{class|KConfig}} object is used to access a given configuration object. There are a number of ways to create a config object:
    Das {{class|KConfig}}-Objekt wird benutzt um ein bestehendes Konfigurationsobjekt anzusteuern. Es gibt eine Reihe von Möglichkeiten ein Konfigurationsobjekt zu erstellen.


    <code cppqt n>
    <syntaxhighlight lang="cpp-qt" line>
    // a plain old read/write config object
    // ein einfaches, altes lesen/schreiben Konfigurationsobjekt
    KConfig config("myapprc");
    KConfig config("myapprc");


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


    // not merged with global values
    // nicht mit globalen Werten verflochten
    KConfig globalFree( "localsrc", KConfig::NoGlobals );
    KConfig globalFree( "localsrc", KConfig::NoGlobals );


    // not merged with globals or the $KDEDIRS hierarchy
    // nicht mit globalen Werten orde der $KDEDIRS Hierarchie verflochten
    KConfig simpleConfig( "simplerc", KConfig::SimpleConfig );
    KConfig simpleConfig( "simplerc", KConfig::SimpleConfig );


    // config specific to a component, in this case a plugin
    // Komponenten-spezifische Konfiguration, in diesem Fall ein Plugin
    KConfig pluginConfig( componentData(), "pluginrc" );
    KConfig pluginConfig( componentData(), "pluginrc" );


    // outside the standard config resource
    // Ausserhalb der normalen Konfigurations-Ressource
    KConfig dataResource( "data", "myapp/somefile" );
    KConfig dataResource( "data", "myapp/somefile" );
    </code>
    </syntaxhighlight>


    The KConfig object create on line 2 is a regular config object. We can read values from it, write new entries and ask for various properties of the object.  This object will be loaded from the config resource as determined by {{class|KStandardDirs}}, meaning that every instance of the <tt>myapprc</tt> object in each of the directories in the config resource hierarchy will be merged to create the values seen in this object. This is how system wide and per-user/group profiles are generated and supported and it all happens transparently to the application itself.


    {{tip|For more information on how the merging works, see the [[KDE System Administration/KDE_Filesystem_Hierarchy|KDE Filesystem Hierarchy]] article.}}
    {{note (de)|wie soll "merged" in den folgenden Fällen übersetzt werden? <br> <tt>"verschmolzen" oder "verflochten"</tt> <br> der Anwendung selber transparent" tönt auch nicht sehr gut}}


    On line 6 we open a specific local file, this case {{path|/etc/kderc}}. This performs no merging of values and expects an INI style file.
    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 {{class|KStandardDirs}} bestimmt wird, das heisst, dass jede Instanz des <tt>myapprc</tt>-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.


    Line 9 sees the creation of a configuration object that is not merged with the global <tt>kdeglobals</tt> configuration object, while the configuration file on line 12 is additionally not merged with any files in the <tt>$KDEDIRS</tt> hierarchy. This can noticeably improve performance in the case where one is simply reading values out of a simple configuration for which global values are not meaningful.


    Line 15 creates a configuration object using the {{class|KComponentData}} object that belongs to a plugin or other component. The plugin may have a different set of directories defined in its {{class|KStandardDirs}} and this is a way of ensuring that {{class|KConfig}} respects this.
    {{tip| Für mehr Informationen, wie das Verschmelzen funktioniert, siehe diesen Artikel über die [[KDE System Administration/KDE_Filesystem_Hierarchy|KDE Dateisystem Hierarchie]].}}


    Finally on line 18 we see the creation of a configuration object that does not exist in the <tt>config</tt> resource but rather in the application <tt>data</tt> resource. You may use any resource that {{class|KStandardDirs}} is aware of, including ones that are added at runtime.
    Auf Zeile 6 öffnen wir eine bestimmte Lokale Datei, in diesem Fall {{path|/etc/kderc}}. Das führt kein Verschmelzen von Werten aus und erwartet eine Datei im INI Format.


    === Special Configuration Objects ===
    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.


    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:
    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.


    <code cppqt n>
    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.
     
    === Spezielle Konfigurationsobjekte ===
     
    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:
     
    <syntaxhighlight lang="cpp-qt" line>
    #include <KComponentData>
    #include <KComponentData>
    #include <KConfig>
    #include <KConfig>
    Line 82: Line 90:
    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>
    </syntaxhighlight>


    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>
    <syntaxhighlight lang="cpp-qt" line>
    #include <KConfig>
    #include <KConfig>


    Line 97: Line 105:
         KConfig config;
         KConfig config;
    }
    }
    </code>
    </syntaxhighlight>


    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>.


    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.
    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.


    === Commonly Useful Methods ===
    === Allgemein nützliche Methoden ===


    To save the current state of the configuration object we call the <tt>sync()</tt> 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. <tt>sync()</tt> merges changes performed concurrently by other processes - local changes have priority, though.
    Um den momentanen Zustand des Konfigurationsobjektes zu speichern, rufen wir die <tt>sync()</tt>-Methode auf. Diese Methode wird also aufgerufen, wenn ein Objekt zerstört wird. Falls keine Änderungen gemacht wurden, oder die Ressource weist sich als nicht beschreibbar aus (Wenn der Benutzer zum Beispiel nicht genug Rechte hat, um die Datei zu bearbeiten), dann wird keine Beschäftigung der Festplatte hervorgerufen. <tt>sync()</tt> verschmilzt Änderungen die gleichzeitig von anderen Prozessen ausgeführt werden - lokale Änderungen haben aber trotzdem Vorrang.


    If we want to make sure that we have the latest values from disk we can call <tt>reparseConfiguration()</tt> which calls <tt>sync()</tt> and then reloads the data from disk.
    Wenn wir sicher gehen wollen, dass wir die aktuellsten Werte von der Festplatte haben, dann rufen wir <tt>reparseConfiguration()</tt> auf, welches <tt>sync()</tt> aufruft und dann die Daten von der Festplatte aktualisiert.


    If we need to prevent the config object from saving already made modifications to disk we need to call <tt>markAsClean()</tt>. A particular use case for this is rolling back the configuration to the on-disk state by calling <tt>markAsClean()</tt> followed by <tt>reparseConfiguration()</tt>.
    Falls wir verhindern müssen, dass das Konfigurationsobjekt bereits gemachte Änderungen nicht auf die Festplatte speichert, müssen wir <tt>markAsClean()</tt> aufrufen. Ein besonderer Anwendungsfall ist es, die Konfiguration zum Festplatten-Zustand zurückzusetzen indem man <tt>markAsClean()</tt> gefolgt von <tt>reparseConfiguration()</tt> aufruft.


    Listing all groups in a configuration object is as simple as calling <tt>groupList()</tt> as in this code snippet:
    Alle Gruppen in einem Konfigurationsobjekt aufzurufen ist so einfach wie hier in diesem Code-Abschnitt <tt>groupList()</tt> aufzurufen.


    <code cppqt n>
    <syntaxhighlight lang="cpp-qt" line>
    KConfig* config = KGlobal::mainComponent().config();
    KConfig* config = KGlobal::mainComponent().config();


    Line 119: Line 127:
         kDebug() << "next group:" << group;
         kDebug() << "next group:" << group;
    }
    }
    </code>
    </syntaxhighlight>


    == KSharedConfig ==
    == KSharedConfig ==


    The {{class|KSharedConfig}} class is a reference counted version of {{class|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.  
    Die {{class|KSharedConfig}} Klasse ist eine Referenz-gezählte Version von {{class|KConfig}}. Darum stellt es eine Möglichkeit bereit, das selbe Konfigurationsobjekt von unterschiedlichen Orten zu referenzieren ohne zusätzlich die Objekte trennen zu müssen oder sich um die Synchronisation des Schreibvorgangs zu kümmern, selbst wenn das Konfigurationsobjekt von verschiedenen Code-Pfaden aktualisiert wird.


    Accessing a {{class|KSharedConfig}} object is as easy as this:
    Auf ein {{class|KSharedConfig}}-Objekt zuzugreifen ist so einfach wie das hier:


    <code cppqt n>
    <syntaxhighlight lang="cpp-qt" line>
    KSharedConfigPtr config = KSharedConfig::openConfig();
    KSharedConfigPtr config = KSharedConfig::openConfig();
    </code>
    </syntaxhighlight>


    <tt>openConfig()</tt> take the same parameters as {{class|KConfig}}'s constructors do, allowing one to define which configuration file to open, flags to control merging and non-<tt>config</tt> resources.
    <tt>openConfig()</tt> nimmt die selben Parameter wie {{class|KConfig}}'s Konstruktoren, was es einem ermöglicht zu definieren, welche Konfigurationsdatei zu öffnen und Markierungen das Verschmelzen von nicht-<tt>config</tt>-Ressourcen zu kontrollieren.


    {{class|KSharedConfig}} is generally recommended over using {{class|KConfig}} itself, and the object returned from {{class|KComponentData}} is indeed a {{class|KSharedConfig}} object.
    Es wird grundsätzlich empfohlen {{class|KSharedConfig}} anstatt {{class|KConfig}} selbst zu benutzen, und auch das Objekt, das von {{class|KComponentData}} zurückgegeben wird ist in der Tat ein {{class|KSharedConfig}}-Objekt.


    == KConfigGroup ==
    == 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:
    Nun da wir ein Konfigurationsobjekt haben, ist der nächste Schritt es tatsächlich zu nutzen. Das erste, das wir tun müssen, ist zu bestimmen, auf welche Gruppe von Schlüssel-/Wertepaare wir in unserem Objekt zugreifen wollen. Wir tun das, indem wir ein KConfigGroup-Objekt erstellen.


    <code cppqt n>
    <syntaxhighlight lang="cpp-qt" line>
    KConfig config;
    KConfig config;
    KConfigGroup generalGroup( &config, "General" );
    KConfigGroup generalGroup( &config, "General" );
    KConfigGroup colorsGroup = config.group( "Colors" ); // ... or a bit differently ...
    KConfigGroup colorsGroup = config.group( "Colors" ); // ...oder so ähnlich...
    </code>
    </syntaxhighlight>


    You can pass {{class|KConfig}} or {{class|KSharedConfig}} objects to {{class|KConfigGroup}}.
    Man kann{{class|KConfigGroup}} {{class|KConfig}}- oder {{class|KSharedConfig}}-Objekte übergeben.


    Config groups can be nested as well:
    Konfigurationsgruppen können ebenfalls verschachtelt werden.


    <code cppqt n>
    <syntaxhighlight lang="cpp-qt" line>
    KConfigGroup subGroup1( &generalGroup, "LessGeneral" );
    KConfigGroup subGroup1( &generalGroup, "LessGeneral" );
    KConfigGroup subGroup2 = colorsGroup.group( "Dialogs" );
    KConfigGroup subGroup2 = colorsGroup.group( "Dialogs" );
    </code>
    </syntaxhighlight>


    == Reading Entries ==
    == Lesen von Einträgen ==


    With a {{class|KConfigGroup}} object in hand reading entries is now quite straight forward:
    Wenn man erst einmal ein {{class|KConfigGroup}}-Objekt erstellt hat, ist das Lesen von Einträgen ziemlich einfach:


    <code cppqt n>
    <syntaxhighlight lang="cpp-qt" line>
    QString accountName = generalGroup.readEntry( "Account",
    QString accountName = generalGroup.readEntry( "Account",
                                                   QString() );
                                                   QString() );
    Line 167: Line 175:
    QString path = generalGroup.readPathEntry( "SaveTo",
    QString path = generalGroup.readPathEntry( "SaveTo",
                                               defaultPath );
                                               defaultPath );
    </code>
    </syntaxhighlight>


    As can be seen from the above, you can mix reads from different {{class|KConfigGroup}} objects created on the same {{class|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 {{qt|QVariant}} to make this magic happen.
    Wie man hier oben sehen kann, kann man Lesevorgänge von verschiedenen {{class|KConfigGroup}}-Objekten, die auf dem selben {{class|KConfig}}-Objekt erstellt wurden, problemlos mischen. Die Lese-Methoden nehmen den Schlüssel, der Gross- und Kleinschreibung unterscheidet, als erstes Argument und den Standardwert als zweites Argument. Dieses Argument bestimmt auch welche Art von Daten, also z.B. eine Farbe in Zeile 3, erwartet wird und auch die Art von Objekt, die zurückgegeben werden soll.Das zurückgegebene Objekt wird in eine {{qt|QVariant}} gepackt um diese Hexerei zu ermöglichen.  


    There are a couple of special read methods, including <tt>readPathEntry</tt> which returns a file system path. It is vital that one uses <tt>readPathEntry</tt> if it is a path as this enables such features as roaming profiles to work properly.
    Es gibt eine Anzahl von speziellen Methoden, zum Beispiel <tt>readPathEntry</tt>, das einen Datei-Systempfad zurückgibt. Es ist entscheidend, dass man <tt>readPathEntry</tt> benutzt, wenn man nach einem Pfad fragt, das es Funktionen wie Erreichbarkeits-Profile ermöglicht richtig zu funktionieren.


    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.
    Wenn kein solcher Schlüssel im Konfigurationsobjekt existiert, dann wird stattdessen der Standardwert zurückgegeben. Falls es eine lokalisierte (d.h. in eine andere Sprache übersetzte) Version für den Schlüssel gibt, die der eingestellten Sprache entspricht, dann wird diese zurückgegeben.


    == Writing Entries ==
    == Schreiben neuer Einträge ==


    Setting new values is similarly straightforward:
    Neue Werte zu definieren ist ähnlich einfach:


    <code cppqt n>
    <syntaxhighlight lang="cpp-qt" line>
    generalGroup.writeEntry( "Account", accountName );
    generalGroup.writeEntry( "Account", accountName );
    generalGroup.writePathEntry( "SaveTo", savePath );
    generalGroup.writePathEntry( "SaveTo", savePath );
    colorGroup.writeEntry( "background", color );
    colorGroup.writeEntry( "background", color );
    generalGroup.config()->sync();
    generalGroup.config()->sync();
    </code>
    </syntaxhighlight>


    Note the use of <tt>writePathEntry</tt> and how the type of object we use, such as {{qt|QColor}} on line 3, dictates how the data is serialized. Additionally, once we are done writing entries, <tt>sync()</tt> 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 <tt>sync()</tt> if necessary.
    Beachten sie die Benutzung von <tt>writePathEntry</tt> und wie die Art von Objekt, das wir benutzen, wie zum Beispiel {{qt|QColor}} auf Zeile 3, bestimmt, wie die Daten angeordnet werden. Zusätzlich, wenn wir mit den Einträgen fertig sind, muss <tt>sync()</tt> auf das Konfigurationsobjekt ausgeführt werden, um es auf die Festplatte zu speichern. Man kann auch einfach warten, bis das Objekt zerstört wird, was falls nötig automatisch einen <tt>sync()</tt> auslöst.


    == KDesktopFile: A Special Case ==
    == KDesktopFile: Ein besonderer Fall ==


    When is a configuration file not a configuration file? When it is a [http://freedesktop.org/wiki/Standards_2fdesktop_2dentry_2dspec 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.
    Wann ist eine Konfigurationsdatei keine Konfigurationsdatei? Wenn es eine [http://freedesktop.org/wiki/Standards_2fdesktop_2dentry_2dspec Desktop-Datei] ist. Diese Dateien, die im Grunde genommen Konfigurationsdateien sind, werden benutzt um Einträge für Anwendungsmenüs, Dateitypen, Plugins und verschiedene Services.


    When accessing a .desktop file, one should instead use the {{class|KDesktopFile}} class which, while a {{class|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.
    Wenn auf eine .desktop Datei zugegriffen wird, sollte man stattdessen die  {{class|KDesktopFile}}-Klasse verwenden, die, während eine {{class|KConfig}}-Klasse über alle oben genannten Ressourcen verfügt, über eine Anzahl von Methoden verfügt, um das Zugreifen auf Standard-Attribute dieser Dateien konsistent und zuverlässig zu machen.


    == Kiosk: Lockdown and User/Group Profiles ==
    == Kiosk: Abriegelung und Benutzer-/Gruppenprofile ==


    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.
    KConfig stellt eine Reihe von leistungsstarken Abriegelungs- und Konfigurations-Definitionen bereit, insgesamt als "Kiosk" bekannt, worauf viele System-Administratoren und -Integratoren basieren. Während ein Grossteil dieses Systems der Anwendung transparent bereitgestellt wird, ist es möglich dass man den Schreib/Lese-Status eines Konfigurationsobjekts prüfen will.


    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:
    Einträge in Konfigurationsobjekten die mithilfe von Kiosk abgeriegelt sind, werden "unveränderlich" genannt. Eine Anwendung kann nach der Unveränderlichkeit von ganzen Konfigurationsobjekten, Gruppen oder Schlüsseln, wie in diesem Beispiel gezeigt, fragen:


    <code cppqt n>
    <syntaxhighlight lang="cpp-qt" line>
    KConfig* config = KGlobal::config();
    KConfig* config = KGlobal::config();


    if ( config->isImmutable() ) {
    if ( config->isImmutable() ) {
         kDebug() << "configuration object is immutable";
         kDebug() << "Konfigurationsobjekt ist unveränderlich";
    }
    }


    KConfigGroup group(config, "General");
    KConfigGroup group(config, "General");
    if ( group.isImmutable() ) {
    if ( group.isImmutable() ) {
         kDebug() << "group General is immutable";
         kDebug() << "Die Gruppe 'General' ist unveränderlich";
    }
    }


    if ( group.entryIsImmutable("URL") ) {
    if ( group.entryIsImmutable("URL") ) {
         kDebug() << "URL entry in group General is immutable";
         kDebug() << "Der URL Eintrag in der Gruppe 'General' ist unveränderlich";
    }
    }
    </code>
    </syntaxhighlight>


    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.
    Das kann in gewissen Situationen, wo eine Aktion ausgeführt werden soll, falls ein Objekt unveränderlich ist.


    == KConfig XT ==
    == 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.
    Es gibt einen Weg, gewisse Anwendungsfälle von KConfig einfacher, schneller und zuverlässiger zu  machen: KConfig XT. Im Bestimmten kann KConfig XT bei Hauptanwendungs- oder Plug-In-Konfigurationsobjekten und bei Konfigurationsdialogen und anderen Benutzeroberflächen mit diesen Werten sehr hilfreich sein. Es dokumentiert gleichzeitig auch alle verfügbaren Konfigurations-Optionen, was alle System-Administratoren und -Integratoren, die KDE benutzen so viel glücklicher macht.
     


    [[../Using_KConfig_XT|The next tutorial in the KConfig series covers what KConfig XT is and how to use it.]]
    [[../Using_KConfig_XT_(de)|Die nächste Anleitung handelt über KConfig XT und seine Verwendung.]]

    Latest revision as of 15:46, 14 July 2012


    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.

    Anwendungen selbst müssen sich deshalb nicht um das Gliedern und Entgliedern von Objekten kümmern.

    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.


    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:

    #include <KComponentData>
    #include <KConfig>
    #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:

    #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.

    Allgemein nützliche Methoden

    Um den momentanen Zustand des Konfigurationsobjektes zu speichern, rufen wir die sync()-Methode auf. Diese Methode wird also aufgerufen, wenn ein Objekt zerstört wird. Falls keine Änderungen gemacht wurden, oder die Ressource weist sich als nicht beschreibbar aus (Wenn der Benutzer zum Beispiel nicht genug Rechte hat, um die Datei zu bearbeiten), dann wird keine Beschäftigung der Festplatte hervorgerufen. sync() verschmilzt Änderungen die gleichzeitig von anderen Prozessen ausgeführt werden - lokale Änderungen haben aber trotzdem Vorrang.

    Wenn wir sicher gehen wollen, dass wir die aktuellsten Werte von der Festplatte haben, dann rufen wir reparseConfiguration() auf, welches sync() aufruft und dann die Daten von der Festplatte aktualisiert.

    Falls wir verhindern müssen, dass das Konfigurationsobjekt bereits gemachte Änderungen nicht auf die Festplatte speichert, müssen wir markAsClean() aufrufen. Ein besonderer Anwendungsfall ist es, die Konfiguration zum Festplatten-Zustand zurückzusetzen indem man markAsClean() gefolgt von reparseConfiguration() aufruft.

    Alle Gruppen in einem Konfigurationsobjekt aufzurufen ist so einfach wie hier in diesem Code-Abschnitt groupList() aufzurufen.

    KConfig* config = KGlobal::mainComponent().config();
    
    foreach ( const QString& group, config.groupList() ) {
        kDebug() << "next group:" << group;
    }
    

    KSharedConfig

    Die KSharedConfig Klasse ist eine Referenz-gezählte Version von KConfig. Darum stellt es eine Möglichkeit bereit, das selbe Konfigurationsobjekt von unterschiedlichen Orten zu referenzieren ohne zusätzlich die Objekte trennen zu müssen oder sich um die Synchronisation des Schreibvorgangs zu kümmern, selbst wenn das Konfigurationsobjekt von verschiedenen Code-Pfaden aktualisiert wird.

    Auf ein KSharedConfig-Objekt zuzugreifen ist so einfach wie das hier:

    KSharedConfigPtr config = KSharedConfig::openConfig();
    

    openConfig() nimmt die selben Parameter wie KConfig's Konstruktoren, was es einem ermöglicht zu definieren, welche Konfigurationsdatei zu öffnen und Markierungen das Verschmelzen von nicht-config-Ressourcen zu kontrollieren.

    Es wird grundsätzlich empfohlen KSharedConfig anstatt KConfig selbst zu benutzen, und auch das Objekt, das von KComponentData zurückgegeben wird ist in der Tat ein KSharedConfig-Objekt.

    KConfigGroup

    Nun da wir ein Konfigurationsobjekt haben, ist der nächste Schritt es tatsächlich zu nutzen. Das erste, das wir tun müssen, ist zu bestimmen, auf welche Gruppe von Schlüssel-/Wertepaare wir in unserem Objekt zugreifen wollen. Wir tun das, indem wir ein KConfigGroup-Objekt erstellen.

    KConfig config;
    KConfigGroup generalGroup( &config, "General" );
    KConfigGroup colorsGroup = config.group( "Colors" ); // ...oder so ähnlich...
    

    Man kannKConfigGroup KConfig- oder KSharedConfig-Objekte übergeben.

    Konfigurationsgruppen können ebenfalls verschachtelt werden.

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

    Lesen von Einträgen

    Wenn man erst einmal ein KConfigGroup-Objekt erstellt hat, ist das Lesen von Einträgen ziemlich einfach:

    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 );
    

    Wie man hier oben sehen kann, kann man Lesevorgänge von verschiedenen KConfigGroup-Objekten, die auf dem selben KConfig-Objekt erstellt wurden, problemlos mischen. Die Lese-Methoden nehmen den Schlüssel, der Gross- und Kleinschreibung unterscheidet, als erstes Argument und den Standardwert als zweites Argument. Dieses Argument bestimmt auch welche Art von Daten, also z.B. eine Farbe in Zeile 3, erwartet wird und auch die Art von Objekt, die zurückgegeben werden soll.Das zurückgegebene Objekt wird in eine QVariant gepackt um diese Hexerei zu ermöglichen.

    Es gibt eine Anzahl von speziellen Methoden, zum Beispiel readPathEntry, das einen Datei-Systempfad zurückgibt. Es ist entscheidend, dass man readPathEntry benutzt, wenn man nach einem Pfad fragt, das es Funktionen wie Erreichbarkeits-Profile ermöglicht richtig zu funktionieren.

    Wenn kein solcher Schlüssel im Konfigurationsobjekt existiert, dann wird stattdessen der Standardwert zurückgegeben. Falls es eine lokalisierte (d.h. in eine andere Sprache übersetzte) Version für den Schlüssel gibt, die der eingestellten Sprache entspricht, dann wird diese zurückgegeben.

    Schreiben neuer Einträge

    Neue Werte zu definieren ist ähnlich einfach:

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

    Beachten sie die Benutzung von writePathEntry und wie die Art von Objekt, das wir benutzen, wie zum Beispiel QColor auf Zeile 3, bestimmt, wie die Daten angeordnet werden. Zusätzlich, wenn wir mit den Einträgen fertig sind, muss sync() auf das Konfigurationsobjekt ausgeführt werden, um es auf die Festplatte zu speichern. Man kann auch einfach warten, bis das Objekt zerstört wird, was falls nötig automatisch einen sync() auslöst.

    KDesktopFile: Ein besonderer Fall

    Wann ist eine Konfigurationsdatei keine Konfigurationsdatei? Wenn es eine Desktop-Datei ist. Diese Dateien, die im Grunde genommen Konfigurationsdateien sind, werden benutzt um Einträge für Anwendungsmenüs, Dateitypen, Plugins und verschiedene Services.

    Wenn auf eine .desktop Datei zugegriffen wird, sollte man stattdessen die KDesktopFile-Klasse verwenden, die, während eine KConfig-Klasse über alle oben genannten Ressourcen verfügt, über eine Anzahl von Methoden verfügt, um das Zugreifen auf Standard-Attribute dieser Dateien konsistent und zuverlässig zu machen.

    Kiosk: Abriegelung und Benutzer-/Gruppenprofile

    KConfig stellt eine Reihe von leistungsstarken Abriegelungs- und Konfigurations-Definitionen bereit, insgesamt als "Kiosk" bekannt, worauf viele System-Administratoren und -Integratoren basieren. Während ein Grossteil dieses Systems der Anwendung transparent bereitgestellt wird, ist es möglich dass man den Schreib/Lese-Status eines Konfigurationsobjekts prüfen will.

    Einträge in Konfigurationsobjekten die mithilfe von Kiosk abgeriegelt sind, werden "unveränderlich" genannt. Eine Anwendung kann nach der Unveränderlichkeit von ganzen Konfigurationsobjekten, Gruppen oder Schlüsseln, wie in diesem Beispiel gezeigt, fragen:

    KConfig* config = KGlobal::config();
    
    if ( config->isImmutable() ) {
        kDebug() << "Konfigurationsobjekt ist unveränderlich";
    }
    
    KConfigGroup group(config, "General");
    if ( group.isImmutable() ) {
        kDebug() << "Die Gruppe 'General' ist unveränderlich";
    }
    
    if ( group.entryIsImmutable("URL") ) {
        kDebug() << "Der URL Eintrag in der Gruppe 'General' ist unveränderlich";
    }
    

    Das kann in gewissen Situationen, wo eine Aktion ausgeführt werden soll, falls ein Objekt unveränderlich ist.

    KConfig XT

    Es gibt einen Weg, gewisse Anwendungsfälle von KConfig einfacher, schneller und zuverlässiger zu machen: KConfig XT. Im Bestimmten kann KConfig XT bei Hauptanwendungs- oder Plug-In-Konfigurationsobjekten und bei Konfigurationsdialogen und anderen Benutzeroberflächen mit diesen Werten sehr hilfreich sein. Es dokumentiert gleichzeitig auch alle verfügbaren Konfigurations-Optionen, was alle System-Administratoren und -Integratoren, die KDE benutzen so viel glücklicher macht.


    Die nächste Anleitung handelt über KConfig XT und seine Verwendung.