Difference between revisions of "Development/Tutorials/Using KConfig XT"

Jump to: navigation, search
(.kcfg DTD Structure: tooltips)
m (.kcfgc files: Changing link to API documentation to version 4.12 instead of 4.0)
 
(25 intermediate revisions by 14 users not shown)
Line 1: Line 1:
{{Template:I18n/Language Navigation Bar|Development/Tutorials/Using_KConfig_XT}}
+
 
 
{{TutorialBrowser|
 
{{TutorialBrowser|
  
 
series=KConfig|
 
series=KConfig|
  
pre=[[../KConfig|Introduction to KConfig]]|
+
pre=[[../KConfig|Introduction to KConfig]]<br>[[../CMake|Introduction to CMake]]|
  
 
next=None|
 
next=None|
Line 18: Line 18:
  
 
This tutorial introduces the main concepts of the KconfigXT  
 
This tutorial introduces the main concepts of the KconfigXT  
configuration framework and shows how to efficiently use it in applications. It assumes that the reader has already developed a KDE application and is familiar with KConfig. A basic understanding of XML and concepts behind DTDs is also required.
+
configuration framework and shows how to efficiently use it in applications. It assumes that the reader has already developed a KDE application and is familiar with KConfig. A basic understanding of XML and concepts behind XML Schema is also required.
 
    
 
    
 
The main idea behind KConfig XT is to make the life of application developers  
 
The main idea behind KConfig XT is to make the life of application developers  
Line 31: Line 31:
 
{{note|In this tutorial more advanced and optional features of KConfig XT and their descriptions are marked by ''italic text''. If you decide to skip them during the first reading, be sure to come back to them at some point. }}
 
{{note|In this tutorial more advanced and optional features of KConfig XT and their descriptions are marked by ''italic text''. If you decide to skip them during the first reading, be sure to come back to them at some point. }}
  
== .kcfg DTD Structure ==
+
== .kcfg Structure ==
  
The structure of the {{path|.kcfg}} file is described by its DTD (kcfg.xsd - available from
+
The structure of the {{path|.kcfg}} file is described by its XML Schema (kcfg.xsd - available from
[http://www.kde.org/standards/kcfg/1.0/kcfg.xsd here] (please note that browsers do not display DTDs in a visual form,
+
[http://www.kde.org/standards/kcfg/1.0/kcfg.xsd here] or [https://projects.kde.org/projects/kde/kdelibs/repository/revisions/master/entry/kdecore/kconfig_compiler/kcfg.xsd from the kdecore library] ). Please go through it before you go any further.   
download the DTD directly and view it like a text file) or the kdecore  
+
library). Please go through it before you go any further.   
+
  
 
Lets create a simple .kcfg file. Please reference the code below as we go through each step.
 
Lets create a simple .kcfg file. Please reference the code below as we go through each step.
  
<code xml>
+
<syntaxhighlight lang="xml">
 
<?xml version="1.0" encoding="UTF-8"?>
 
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE kcfg SYSTEM
+
<kcfg xmlns="http://www.kde.org/standards/kcfg/1.0"
    "http://www.kde.org/standards/kcfg/1.0/kcfg.xsd">
+
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
<kcfg>
+
      xsi:schemaLocation="http://www.kde.org/standards/kcfg/1.0
  <kcfgfile name="kjotsrc"/>
+
                          http://www.kde.org/standards/kcfg/1.0/kcfg.xsd" >
 
   <include>kglobalsettings.h</include>
 
   <include>kglobalsettings.h</include>
 +
  <kcfgfile name="kjotsrc"/>
 
   <group name="kjots">
 
   <group name="kjots">
 
     <entry name="SplitterSizes" type="IntList">
 
     <entry name="SplitterSizes" type="IntList">
Line 71: Line 70:
 
   </group>
 
   </group>
 
</kcfg>
 
</kcfg>
</code>
+
</syntaxhighlight>
  
 
* Use your favorite code editor to open a your_application_name{{path|.kcfg}} file (of course replacing your_application_name with the name of the application you want to convert to KConfig XT).
 
* Use your favorite code editor to open a your_application_name{{path|.kcfg}} file (of course replacing your_application_name with the name of the application you want to convert to KConfig XT).
Line 81: Line 80:
 
* The remaining entries in the XML file are grouped by the tag &lt;group&gt; which describes the corresponding groups in the configuration file.
 
* The remaining entries in the XML file are grouped by the tag &lt;group&gt; which describes the corresponding groups in the configuration file.
 
*#The individual entries must have at least a name or a key. The key is used as the key in the config file. The name is used to create accessor and modifier functions. If &lt;key&gt; is not given, the name is used as the config file key. If &lt;key&gt; is given, but not &lt;name&gt;, the name is constructed by removing all spaces from the &lt;key&gt; contents.
 
*#The individual entries must have at least a name or a key. The key is used as the key in the config file. The name is used to create accessor and modifier functions. If &lt;key&gt; is not given, the name is used as the config file key. If &lt;key&gt; is given, but not &lt;name&gt;, the name is constructed by removing all spaces from the &lt;key&gt; contents.
*# Always add label, tooltip and whatsthis tags to your application in which you describe the configuration options. The label tag is used for short descriptions of the entry, while tooltip and whatsthis contains more verbose documentation. ''It's important for tools like KConfigEditor which can be used by systems administrators to setup machines over on the network.''
+
*# Always add &lt;label&gt;, &lt;tooltip&gt; and &lt;whatsthis&gt; tags to your application in which you describe the configuration options. The &lt;label&gt; tag is used for short descriptions of the entry, while &lt;tooltip&gt; and &lt;whatsthis&gt; contains more verbose documentation. ''It's important for tools like KConfigEditor which can be used by systems administrators to setup machines over on the network. Note that this tags will be ignored unless you provide SetUserTexts=true option in your .kcfgc file (see section on it below)''
 
*# An entry must also have a type. The allowed types are: String, Url, StringList, Font, Rect, Size, Color, Point, Int, UInt, Bool, Double, DateTime, Int64, UInt64 and Password. '' Besides those basic type the following special types are supported and include:''
 
*# An entry must also have a type. The allowed types are: String, Url, StringList, Font, Rect, Size, Color, Point, Int, UInt, Bool, Double, DateTime, Int64, UInt64 and Password. '' Besides those basic type the following special types are supported and include:''
 
*#* Path - This is a string that is specially treated as a file-path. In particular paths in the home directory are prefixed with $HOME when being stored in the configuration file.
 
*#* Path - This is a string that is specially treated as a file-path. In particular paths in the home directory are prefixed with $HOME when being stored in the configuration file.
 
*#* Enum - This indicates an enumeration. The possible enum values should be provided via the &lt;choices&gt; tag. Enum values are accessed as integers by the application but stored as string in the configuration file. This makes it possible to add more values at a later date without breaking compatibility.
 
*#* Enum - This indicates an enumeration. The possible enum values should be provided via the &lt;choices&gt; tag. Enum values are accessed as integers by the application but stored as string in the configuration file. This makes it possible to add more values at a later date without breaking compatibility.
*#* IntList - This indicates a list of integers. This information is provided to the application as QValueList&lt;int&gt;. Useful for storing QSplitter geometries.
+
*#* IntList - This indicates a list of integers. This information is provided to the application as QList&lt;int&gt;. Useful for storing QSplitter geometries.
 
*#* PathList - List of Path elements.
 
*#* PathList - List of Path elements.
 
*# The min and max tags can be set to limit the value of the integer-type options.
 
*# The min and max tags can be set to limit the value of the integer-type options.
Line 108: Line 107:
 
#* ItemAccessors - relates to the above item, if member variables are public then it might make little sense to generate accessors. By default they are generated,
 
#* ItemAccessors - relates to the above item, if member variables are public then it might make little sense to generate accessors. By default they are generated,
 
#* Mutators - similar to the above one, but applies to the mutator methods,
 
#* Mutators - similar to the above one, but applies to the mutator methods,
#* GlobalEnums - specifies whether enums should be class wide of whether they should be always explicitly prefixed with their type name,
+
#* GlobalEnums - specifies whether enums should be class wide or whether they should be always explicitly prefixed with their type name,
 
#* UseEnumTypes - specifies whether enum values should be passed as type int or as their enum type in the return value of accessor functions and the arguments of mutator and signal functions.
 
#* UseEnumTypes - specifies whether enum values should be passed as type int or as their enum type in the return value of accessor functions and the arguments of mutator and signal functions.
 +
#* SetUserTexts - specifies whether &lt;label&gt;, &lt;tooltip&gt; and &lt;whatsthis&gt; tags should be processed. This allows tools like KConfigDialog make use of these tags. By default this tags are ignored
  
For details see the description of kconfig_compiler: [http://api.kde.org/4.0-api/kdelibs-apidocs/kdecore/html/kconfig_compiler.html]
+
For details see the description of kconfig_compiler: [http://api.kde.org/4.12-api/kdelibs-apidocs/kdecore/html/kconfig_compiler.html]
  
 
== Adjusting the CMakeLists.txt file ==
 
== Adjusting the CMakeLists.txt file ==
  
 
After creating the .kcfg and .kcfgc files the next step is to adjust the  
 
After creating the .kcfg and .kcfgc files the next step is to adjust the  
build to let kconfig_compiler generate the required class at compile time. Fortunately doing this is trivial and requires only one step, adding this line to the CMakeLists.txt file example:
+
build to let kconfig_compiler generate the required class at compile time. For in-source builds, doing this is trivial and requires only one step, adding this two lines to the CMakeLists.txt file example (asuming your files are named settings.kcfg and settings.kcfgc):
 +
<syntaxhighlight lang="cmake">
 +
kde4_add_kcfg_files(<project name>_SRCS settings.kcfgc)
 +
install(FILES settings.kcfg DESTINATION ${KCFG_INSTALL_DIR})
 +
</syntaxhighlight>
 +
Alternatively, if a .moc file needs to be generated before compiling the generated source code, use
 +
<syntaxhighlight lang="cmake">
 +
kde4_add_kcfg_files(<project name>_SRCS GENERATE_MOC settings.kcfgc)
 +
install(FILES settings.kcfg DESTINATION ${KCFG_INSTALL_DIR})
 +
</syntaxhighlight>
 +
This assures that the configuration class is properly generated (<tt>kde4_add_kcfg_files</tt>) and that the .kcfg is installed so it can be used by tools like the KConfigEditor (<tt>install</tt>).
  
kde4_add_kcfg_files(<project name>_SRCS settings.kcfgc)
+
=== Out-of-source builds ===
  
Alternatively, if a .moc file needs to be generated before compiling the generated source code, use
+
Out-of-source builds require one more step.
  
kde4_add_kcfg_files(<project name>_SRCS GENERATE_MOC settings.kcfgc)
+
'''The problem:''' In out-of-source builds, the code that is generated by kconfig_compiler is saved in the build tree. So how can we still include the header generated by kconfig_compiler with a simple <tt>#include "settings.h"</tt>?
  
This assures that the configuration class is properly generated and that the .kcfg is installed so it can be used by tools like  
+
'''The solution:''' Probably you have yet a line similar to the following line in your CMakeLists.txt:
the KConfigEditor.
+
<syntaxhighlight lang="cmake">
 +
include_directories(${QT_INCLUDE} ${KDE4_INCLUDES})
 +
</syntaxhighlight>
 +
Add the variable ''CMAKE_CURRENT_BINARY_DIR'', so that you get something like this:
 +
<syntaxhighlight lang="cmake">
 +
include_directories(${QT_INCLUDE} ${KDE4_INCLUDES} ${CMAKE_CURRENT_BINARY_DIR})
 +
</syntaxhighlight>
 +
Notice that you should call <tt>include_directories</tt> only once in your project. (When you call <tt>include_directories</tt> in your base source directory, but than call it another time in a subdirectory (added by <tt>add_subdirectory</tt>), then the second call will be ignored.)
  
 
== Use and Dialogs ==
 
== Use and Dialogs ==
Line 134: Line 151:
 
The use will depend on whether you have added the <tt>Singleton=true</tt> entry to your .kcfgc file.  
 
The use will depend on whether you have added the <tt>Singleton=true</tt> entry to your .kcfgc file.  
  
One the nicest features of the KConfig XT is its seamless integration with the Qt  
+
One of the nicest features of the KConfig XT is its seamless integration with the Qt  
 
Designer generated dialogs. You can do that by using {{class|KConfigDialog}}. The  
 
Designer generated dialogs. You can do that by using {{class|KConfigDialog}}. The  
 
steps to do that are as follows:  
 
steps to do that are as follows:  
Line 140: Line 157:
 
# Create the KConfigDialog and pass the instance of your configuration data as one of the arguments. The construct would look like the following example:
 
# Create the KConfigDialog and pass the instance of your configuration data as one of the arguments. The construct would look like the following example:
 
   
 
   
<code cppqt>
+
<syntaxhighlight lang="cpp-qt">
 
KConfigDialog* dialog = new KConfigDialog(  
 
KConfigDialog* dialog = new KConfigDialog(  
 
         this, "settings", YourAppSettings::self() );
 
         this, "settings", YourAppSettings::self() );
</code>
+
</syntaxhighlight>
  
 
assuming that YourAppSettings is the value of the ClassName variable from the kcfgc file and the settings class is a singelton.
 
assuming that YourAppSettings is the value of the ClassName variable from the kcfgc file and the settings class is a singelton.
# In Qt Designer create widgets which should be used to configure your options. In order to make those widgets interact with the kcfg you have name each one of them using the following scheme:
+
# In Qt Designer create widgets which should be used to configure your options. In order to make those widgets interact with the kcfg you have to name each one of them using the following scheme:
 
## Prefix the Name of the widget which should control one of the options with "kcfg_"
 
## Prefix the Name of the widget which should control one of the options with "kcfg_"
 
## Append the "name" attribute value from your kcfg file which corresponds to option the given widget should control.
 
## Append the "name" attribute value from your kcfg file which corresponds to option the given widget should control.
Line 157: Line 174:
 
With the following example.kcfg file:  
 
With the following example.kcfg file:  
  
<code xml>
+
<syntaxhighlight lang="xml">
 
<?xml version="1.0" encoding="UTF-8"?>
 
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE kcfg SYSTEM
+
<kcfg xmlns="http://www.kde.org/standards/kcfg/1.0"
    "http://www.kde.org/standards/kcfg/1.0/kcfg.dtd">
+
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
<kcfg> <kcfgfile name="examplerc"/>
+
      xsi:schemaLocation="http://www.kde.org/standards/kcfg/1.0
 +
                          http://www.kde.org/standards/kcfg/1.0/kcfg.xsd" >
 +
  <kcfgfile name="examplerc"/>
 
   <group name="network">
 
   <group name="network">
 
     <entry name="ServerName" type="String">
 
     <entry name="ServerName" type="String">
Line 174: Line 193:
 
   </group>
 
   </group>
 
</kcfg>
 
</kcfg>
</code>
+
</syntaxhighlight>
  
And here's how to actually use the generated class. for the given kcfgc file.
+
And here's how to actually use the generated class for the given kcfgc file.
  
<code ini>
+
<syntaxhighlight lang="ini">
 
File=example.kcfg  
 
File=example.kcfg  
 
ClassName=ExampleSettings  
 
ClassName=ExampleSettings  
 
Singleton=true  
 
Singleton=true  
 
Mutators=true
 
Mutators=true
</code>
+
</syntaxhighlight>
  
 
The header files wouldn't change, but the cpp files must now contain the  
 
The header files wouldn't change, but the cpp files must now contain the  
 
following code to access and store the configuration data :
 
following code to access and store the configuration data :
  
<code cppqt>
+
<syntaxhighlight lang="cpp-qt">
 
...
 
...
 
#include <ExampleSettings.h>  
 
#include <ExampleSettings.h>  
Line 196: Line 215:
 
         m_port    = ExampleSettings::port();  
 
         m_port    = ExampleSettings::port();  
 
}  
 
}  
void ExampleClass:saveSettings() {  
+
void ExampleClass::saveSettings() {  
 
         ExampleSettings::setServerName( m_server );  
 
         ExampleSettings::setServerName( m_server );  
 
         ExampleSettings::setPort( m_port );  
 
         ExampleSettings::setPort( m_port );  
         ExampleSettings::writeConfig();  
+
         ExampleSettings::self()->writeConfig();  
 
}
 
}
</code>
+
</syntaxhighlight>
 +
 
 +
self() returns the current instance of the object. You need to call writeConfig() this way, since it's a virtual method.
  
 
To add a dialog you need to create a Qt Designer widget with the widget names
 
To add a dialog you need to create a Qt Designer widget with the widget names
Line 211: Line 232:
 
And you can use the dialog with the following code:
 
And you can use the dialog with the following code:
  
<code cppqt>
+
<syntaxhighlight lang="cpp-qt">
//An instance of your dialog could be already created and could be
+
// An instance of your dialog could be already created and could be
 
// cached, in which case you want to display the cached dialog  
 
// cached, in which case you want to display the cached dialog  
 
// instead of creating another one
 
// instead of creating another one
Line 227: Line 248:
 
dialog->addPage( confWdg, i18n("Example"), "example" );  
 
dialog->addPage( confWdg, i18n("Example"), "example" );  
 
   
 
   
//User edited the configuration - update your local copies of the  
+
// User edited the configuration - update your local copies of the  
//configuration data  
+
// configuration data  
 
connect( dialog, SIGNAL(settingsChanged()),  
 
connect( dialog, SIGNAL(settingsChanged()),  
 
         this, SLOT(updateConfiguration()) );  
 
         this, SLOT(updateConfiguration()) );  
 
   
 
   
 
dialog->show();
 
dialog->show();
</code>
+
</syntaxhighlight>
  
And that's all it takes. You can have a look at [http://websvn.kde.org/trunk/KDE/kdegames/kreversi KReversi] and [http://websvn.kde.org/trunk/KDE/kdegames/ktron/ KTron] code in the [http://websvn.kde.org/trunk/KDE/kdegames kdegames module] to see a live example of KConfig XT!
+
And that's all it takes. You can have a look at [https://projects.kde.org/projects/kde/kdegames/kreversi/repository KReversi] and [https://projects.kde.org/projects/kde/kdegames/kmines/repository KMines] code in the [https://projects.kde.org/projects/kde/kdegames kdegames module] to see a live example of KConfig XT!
  
 
== Common Pitfalls and Tips ==
 
== Common Pitfalls and Tips ==
Line 242: Line 263:
 
* Always try to add both the &lt;label&gt;, &lt;whatsthis&gt; and &lt;tooltip&gt; tags to each entry.
 
* Always try to add both the &lt;label&gt;, &lt;whatsthis&gt; and &lt;tooltip&gt; tags to each entry.
 
* Putting the MemberVariables=public in your .kcfgc is usually a bad idea - you'll avoid accidental changes to those members by using the aggregation and forcing the use of the mutators.
 
* Putting the MemberVariables=public in your .kcfgc is usually a bad idea - you'll avoid accidental changes to those members by using the aggregation and forcing the use of the mutators.
* If your application doesn't have one central object (created before and destructed after; all others) then always put the Singleton=true entry in your .kcfgs file.
+
* If your application doesn't have one central object (created before and destructed after all others) then always put the Singleton=true entry in your .kcfgs file.
 +
 
 +
== Additional References ==
 +
 
 +
* [http://dot.kde.org/2005/07/07/cornelius-schumacher-kconfig-xt Cornelius Schumacher on KConfig XT (KDE.news)]
 +
* [http://www.usenix.org/event/usenix04/tech/freenix/full_papers/faure/faure_html/node8.html#SECTION00044200000000000000 KDE Kontact: An Application Integration Framework - KConfig XT]
 
[[Category:C++]]
 
[[Category:C++]]

Latest revision as of 22:17, 17 January 2014

Using KConfig XT
Tutorial Series   KConfig
Previous   Introduction to KConfig
Introduction to CMake
What's Next   None
Further Reading   The KDE Configuration Compiler (KDE 4)
The KDE Configuration Compiler (KDE 3)

Contents

[edit] Using KConfig XT

Original Author: Zack Rusin <zack@kde.org>

This tutorial introduces the main concepts of the KconfigXT configuration framework and shows how to efficiently use it in applications. It assumes that the reader has already developed a KDE application and is familiar with KConfig. A basic understanding of XML and concepts behind XML Schema is also required.

The main idea behind KConfig XT is to make the life of application developers easier while making the administration of large KDE installations more manageable. The four basic parts of the new framework are:

  • KConfigSkeleton - a class in the libkdecore library which grants a more flexible access to the configuration options,
  • XML file containing information about configuration options (the .kcfg file)
  • An ini like file which provides the code generation options (the .kcfgc file)
  • kconfig_compiler - which generates C++ source code from .kcfg and .kcfgc files. The generated class is based on KConfigSkeleton and provides an API for the application to access its configuration data.
noframe
 
Note
In this tutorial more advanced and optional features of KConfig XT and their descriptions are marked by italic text. If you decide to skip them during the first reading, be sure to come back to them at some point.

[edit] .kcfg Structure

The structure of the .kcfg file is described by its XML Schema (kcfg.xsd - available from here or from the kdecore library ). Please go through it before you go any further.

Lets create a simple .kcfg file. Please reference the code below as we go through each step.

<?xml version="1.0" encoding="UTF-8"?>
<kcfg xmlns="http://www.kde.org/standards/kcfg/1.0"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xsi:schemaLocation="http://www.kde.org/standards/kcfg/1.0
                          http://www.kde.org/standards/kcfg/1.0/kcfg.xsd" >
  <include>kglobalsettings.h</include>
  <kcfgfile name="kjotsrc"/>
  <group name="kjots">
    <entry name="SplitterSizes" type="IntList">
      <label>How the main window is divided.</label>
    </entry>
    <entry name="Width" type="Int">
      <label>Width of the main window.</label>
      <default>600</default>
    </entry>
    <entry name="Height" type="Int">
      <label>Height of the main window.</label>
      <default>400</default>
    </entry>
    <entry name="OpenBooks" type="StringList">
      <label>All books that are opened.</label>
    </entry>
    <entry name="CurrentBook" type="String">
      <label>The book currently opened.</label>
    </entry>
    <entry name="Font" type="Font">
      <label>The font used to display the contents of books.</label>
      <default code="true">KGlobalSettings::generalFont()</default>
    </entry>
  </group>
</kcfg>
  • Use your favorite code editor to open a your_application_name.kcfg file (of course replacing your_application_name with the name of the application you want to convert to KConfig XT).
  • Start that file by opening the <kcfgfile> tag which controls which KConfig file the data will be stored in. There are three possibilities:
    1. If the <kcfgfile> tag has no attributes the generated code will use the application's default KConfig file (normally $HOME/.kde/config/<appname>rc).
    2. The "name" attribute is used to manually specify a file name. If the value assigned to "name" is not an absolute file path, the file will be created in the default KDE config directory (normally $HOME/.kde/config).
    3. If you would like to be able to specify the config file at construction time, use <kcfgfile arg="true">. This causes the constructor of the generated class to take a KSharedConfig::Ptr as an argument, allowing you to construct multiple instances pointing to different files.
  • Add the optional <include> tags which may contain C++ header files that are needed to compile the code required to compute the default values.
  • The remaining entries in the XML file are grouped by the tag <group> which describes the corresponding groups in the configuration file.
    1. The individual entries must have at least a name or a key. The key is used as the key in the config file. The name is used to create accessor and modifier functions. If <key> is not given, the name is used as the config file key. If <key> is given, but not <name>, the name is constructed by removing all spaces from the <key> contents.
    2. Always add <label>, <tooltip> and <whatsthis> tags to your application in which you describe the configuration options. The <label> tag is used for short descriptions of the entry, while <tooltip> and <whatsthis> contains more verbose documentation. It's important for tools like KConfigEditor which can be used by systems administrators to setup machines over on the network. Note that this tags will be ignored unless you provide SetUserTexts=true option in your .kcfgc file (see section on it below)
    3. An entry must also have a type. The allowed types are: String, Url, StringList, Font, Rect, Size, Color, Point, Int, UInt, Bool, Double, DateTime, Int64, UInt64 and Password. Besides those basic type the following special types are supported and include:
      • Path - This is a string that is specially treated as a file-path. In particular paths in the home directory are prefixed with $HOME when being stored in the configuration file.
      • Enum - This indicates an enumeration. The possible enum values should be provided via the <choices> tag. Enum values are accessed as integers by the application but stored as string in the configuration file. This makes it possible to add more values at a later date without breaking compatibility.
      • IntList - This indicates a list of integers. This information is provided to the application as QList<int>. Useful for storing QSplitter geometries.
      • PathList - List of Path elements.
    4. The min and max tags can be set to limit the value of the integer-type options.
    5. An entry can optionally have a default value which is used as default when the value isn't specified in any config file. Default values are interpreted as literal constant values. If a default value needs to be computed or if it needs to be obtained from a function call, the <default> tag should contain the code="true" attribute. The contents of the <default> tag is then considered to be a C++ expression.
    6. Additional code for computing default values can be provided via the <code> tag. The contents of the <code> tag is inserted as-is. A typical use for this is to compute a common default value which can then be referenced by multiple entries that follow.
    7. Optionally, the hidden option can also be added to the <entry>. The possible values are true and false.

[edit] .kcfgc files

After creating a .kcfg file create a .kcfgc file which describes the C++ file generation options. The .kcfgc file is a simple ini file with the typical "entry=value" format. To create a simple .kcfgc file follow these steps:

  1. Open a new file in your favorite text editor.
  2. Start it with the "File=your_application_name.kcfg" entry which specifies where the configuration options for your application are stored.
  3. Add the "ClassName=YourConfigClassName" entry which specifies the name of the class that will be generated from the .kcfg file. Remember that the generated class will be derived from KConfigSkeleton. PLease make sure that YourConfigClassName is not a class name already used in your application. Save this file under yourconfigclassname.kcfgc. This will ensure the generation of the yourconfigclassname.{h,cpp} files where your configuration class will reside.
  4. Add any additional entries, which your application might need. Those additional entries include:
    • NameSpace - specifies the namespace in which the generated config class should reside,
    • Inherits - if you need the generated class to inherit your custom class,
    • Singleton - if the configuration class should be a singleton,
    • MemberVariables - specifies the access to the member variables, default is private,
    • ItemAccessors - relates to the above item, if member variables are public then it might make little sense to generate accessors. By default they are generated,
    • Mutators - similar to the above one, but applies to the mutator methods,
    • GlobalEnums - specifies whether enums should be class wide or whether they should be always explicitly prefixed with their type name,
    • UseEnumTypes - specifies whether enum values should be passed as type int or as their enum type in the return value of accessor functions and the arguments of mutator and signal functions.
    • SetUserTexts - specifies whether <label>, <tooltip> and <whatsthis> tags should be processed. This allows tools like KConfigDialog make use of these tags. By default this tags are ignored

For details see the description of kconfig_compiler: [1]

[edit] Adjusting the CMakeLists.txt file

After creating the .kcfg and .kcfgc files the next step is to adjust the build to let kconfig_compiler generate the required class at compile time. For in-source builds, doing this is trivial and requires only one step, adding this two lines to the CMakeLists.txt file example (asuming your files are named settings.kcfg and settings.kcfgc):

kde4_add_kcfg_files(<project name>_SRCS settings.kcfgc)
install(FILES settings.kcfg DESTINATION ${KCFG_INSTALL_DIR})

Alternatively, if a .moc file needs to be generated before compiling the generated source code, use

kde4_add_kcfg_files(<project name>_SRCS GENERATE_MOC settings.kcfgc)
install(FILES settings.kcfg DESTINATION ${KCFG_INSTALL_DIR})

This assures that the configuration class is properly generated (kde4_add_kcfg_files) and that the .kcfg is installed so it can be used by tools like the KConfigEditor (install).

[edit] Out-of-source builds

Out-of-source builds require one more step.

The problem: In out-of-source builds, the code that is generated by kconfig_compiler is saved in the build tree. So how can we still include the header generated by kconfig_compiler with a simple #include "settings.h"?

The solution: Probably you have yet a line similar to the following line in your CMakeLists.txt:

include_directories(${QT_INCLUDE} ${KDE4_INCLUDES})

Add the variable CMAKE_CURRENT_BINARY_DIR, so that you get something like this:

include_directories(${QT_INCLUDE} ${KDE4_INCLUDES} ${CMAKE_CURRENT_BINARY_DIR})

Notice that you should call include_directories only once in your project. (When you call include_directories in your base source directory, but than call it another time in a subdirectory (added by add_subdirectory), then the second call will be ignored.)

[edit] Use and Dialogs

After making all of the above changes you're ready to use KConfig XT. The kconfig_compiler generated header file will have the name equal to the name of the .kcfg file but with a ".h" extension. Simply include that file wherever you want to access your configuration options.

The use will depend on whether you have added the Singleton=true entry to your .kcfgc file.

One of the nicest features of the KConfig XT is its seamless integration with the Qt Designer generated dialogs. You can do that by using KConfigDialog. The steps to do that are as follows:

  1. Create the KConfigDialog and pass the instance of your configuration data as one of the arguments. The construct would look like the following example:
KConfigDialog* dialog = new KConfigDialog( 
         this, "settings", YourAppSettings::self() );

assuming that YourAppSettings is the value of the ClassName variable from the kcfgc file and the settings class is a singelton.

  1. In Qt Designer create widgets which should be used to configure your options. In order to make those widgets interact with the kcfg you have to name each one of them using the following scheme:
    1. Prefix the Name of the widget which should control one of the options with "kcfg_"
    2. Append the "name" attribute value from your kcfg file which corresponds to option the given widget should control.
  2. Add the Qt Designer generated widget to the KConfigDialog.
  3. Show the dialog when you're done.

[edit] Example

Here's an example usage of KConfig XT for the application named Example. With the following example.kcfg file:

<?xml version="1.0" encoding="UTF-8"?>
<kcfg xmlns="http://www.kde.org/standards/kcfg/1.0"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xsi:schemaLocation="http://www.kde.org/standards/kcfg/1.0
                          http://www.kde.org/standards/kcfg/1.0/kcfg.xsd" >
  <kcfgfile name="examplerc"/>
  <group name="network">
    <entry name="ServerName" type="String">
      <label>Defines the sample server.</label>
    </entry>
    <entry name="Port" type="Int">
      <label>Defines the server port</label>
      <default>21</default>
      <min>20</min>
      <max>990</max>
    </entry>
  </group>
</kcfg>

And here's how to actually use the generated class for the given kcfgc file.

File=example.kcfg 
ClassName=ExampleSettings 
Singleton=true 
Mutators=true

The header files wouldn't change, but the cpp files must now contain the following code to access and store the configuration data :

...
#include <ExampleSettings.h> 
... 
void ExampleClass::readConfig() { 
        m_server  = ExampleSettings::serverName(); 
        m_port    = ExampleSettings::port(); 
} 
void ExampleClass::saveSettings() { 
        ExampleSettings::setServerName( m_server ); 
        ExampleSettings::setPort( m_port ); 
        ExampleSettings::self()->writeConfig(); 
}

self() returns the current instance of the object. You need to call writeConfig() this way, since it's a virtual method.

To add a dialog you need to create a Qt Designer widget with the widget names corresponding to the names of the options they should edit and prefixed with "kcfg_". It could be something along the lines of:

Kconfigxt.png

And you can use the dialog with the following code:

// An instance of your dialog could be already created and could be
// cached, in which case you want to display the cached dialog 
// instead of creating another one
if ( KConfigDialog::showDialog( "settings" ) )
  return; 
 
// KConfigDialog didn't find an instance of this dialog, so lets
// create it : 
KConfigDialog* dialog = new KConfigDialog(this, "settings",
                                          ExampleSettings::self()); 
ExampleDesignerWidget* confWdg =  
                  new ExampleDesignerWidget( 0, "Example" ); 
 
dialog->addPage( confWdg, i18n("Example"), "example" ); 
 
// User edited the configuration - update your local copies of the 
// configuration data 
connect( dialog, SIGNAL(settingsChanged()), 
         this, SLOT(updateConfiguration()) ); 
 
dialog->show();

And that's all it takes. You can have a look at KReversi and KMines code in the kdegames module to see a live example of KConfig XT!

[edit] Common Pitfalls and Tips

  • Do not forget to add the "type" attribute to the "entry" tag in your .kcfg file.
  • Always try to add both the <label>, <whatsthis> and <tooltip> tags to each entry.
  • Putting the MemberVariables=public in your .kcfgc is usually a bad idea - you'll avoid accidental changes to those members by using the aggregation and forcing the use of the mutators.
  • If your application doesn't have one central object (created before and destructed after all others) then always put the Singleton=true entry in your .kcfgs file.

[edit] Additional References


This page was last modified on 17 January 2014, at 22:17. This page has been accessed 33,644 times. Content is available under Creative Commons License SA 3.0 as well as the GNU Free Documentation License 1.2.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V.Legal