TDEConfig XT Tutorial

From Trinity Desktop Project Wiki
Jump to: navigation, search

This tutorial will introduce you to the main concepts of the TDEConfig XT configuration framework and will show you how to efficiently use it in your application.

This tutorial assumes that reader has already developed a TDE application and is familiar with TDEConfig. Basic understanding of XML and concepts behind DTD's is also required.

In this tutorial the more advanced and optional features of TDEConfig XT and their descriptions are marked by italic text. If you'll decide to skip them during the first reading, make sure you'll come back to them at some point.

Generic overview

The main idea behind TDEConfig XT is to make the life of application developers easier while making the administration of large TDE installations more manageable.

The four basic parts of the new framework are:

  • TDEConfigSkeleton - a class in the tdecore 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)
  • tdeconfig_compiler - which generates C++ source code from .kcfg and .kcfgs files. The generated class is based on TDEConfigSkeleton and provides an API for the application to access its configuration data.

DTD Structure of a .kcfg file

The structure of the .kcfg file is described by its DTD (kcfg.dtd - available from here (please note that browsers do not display DTD's in a visual form, 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.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE kcfg SYSTEM "http://www.kde.org/standards/kcfg/1.0/kcfg.dtd">
<kcfg> 
  <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>
  1. 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 TDEConfig XT).
  2. Start that file by opening the <kcfgfile> tag which contains the name attribute with the value corresponding to the actual TDEConfig file which it describes. (The actual TDEConfig file are the rc files).
  3. Add the optional <include> tags which may contain C++ header files that are needed to compile the code required to compute the default values.
  4. 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 name is used to create accessor and modifier functions. It's also used as the key in the config file. If <key> is given, but not <name>, the name is constructed by removing all spaces from the <key> contents.
  2. Always add a label or a whatsthis tags to your application in which you describe the configuration options. The label tag is used for short descriptions of the entry, while whatsthis contains more verbose documentation. It's important for tools which can be used by systems administrators to setup machines over on the network.
  3. An entry must also have a type. The list of allowable types is specified in the DTD and loosely follows the list of types supported by the TQVariant with exception of the clearly binary types (e.g. Pixmap, Image...) which are not supported.

Here is a list of the types that tdeconfig_compiler supports:

Type (stored as) Example Default value Notes
String
const TQString &
Hello, world! (empty string)
StringList
const TQStringList &
konqueror,konsole,kopete TQStringList() The values are delimited with comma (,).
Font
const TQFont &
Tahoma,11,-1,5,75,0,0,0,0,0 TDEGlobalSettings::generalFont()
Rect
const TQRect &
TQRect()
Size
const TQSize &
800,600 TQSize() Size is defined as a width, height pair.
Color
const TQColor &
128,0,128 TQColor() Color is defined as an RGB value.
Point
const TQPoint &
10,10 TQPoint() Size is defined as a X,Y coordinates pair.
Int
int
42 0
UInt
uint
42 0
Bool
bool
true false
Double
double
3.14 0.0
DateTime
const TQDateTime &
TQDateTime()
Int64
TQ_INT64
42 0
UInt64
TQ_UINT64
42 0
IntList
const TQValueList<int> &
1,2,4,8,33 const TQValueList<int>() This indicates a list of integers. This information is provided to the application as TQValueList<int>. Useful for storing TQSplitter geometries.
Enum
int
-- 0 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.
Path
const TQString &
/home/konqui/Documents/document.txt (empty string) 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.
PathList
const TQStringList &
/etc/data1,/etc/data2 TQStringList() The values are delimited with comma (,).
Password
const TQString &
12345 (empty string) Avoid storing passwords in config files. Use TDE Wallet instead!!!

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 (see the Examples column for examples of acceptable 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.

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.

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

  • Open a new file in your favorite text editor.
  • Start it with the File=your_application_name.kcfg entry which specifies where the configuration options for your application are stored.
  • 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 TDEConfigSkeleton. 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.
  • Add any additional entries, which your application might need.

This is a list of keys understood by tdeconfig_compiler:

Key Type (default value) Description
NameSpace String Specifies the namespace in which the generated config class should reside.
ClassName String Specifies the name of the class that will be generated from the .kcfg file
Inherits String If you need the generated class to inherit your custom class.
Singleton Boolean (false) If the configuration class should be a singleton.
Visibility String Specifies the visibility of the generated class.
MemberVariables String Specifies the access to the member variables, default is private. A special value is "dpointer", which stores members in a private class, accessed privately by a pointer d.
ItemAccessors Boolean (false) 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 StringList List of properties for which to generate mutators. The special value "true" generates mutators for all properties. By default no mutators are generated.
GlobalEnums Boolean (false) Specifies whether the enums should be class wide of whether they should be always explicitly prefixed with their type name.
CustomAdditions Boolean (false) If enabled, it looks for a special source file with addons which can be used to add extra functions and variables to the class. The name of the file consists from the filename of the .kcfgc file, minus the extension, plus the string "_addons.h".
IncludeFiles StringList This is a list of files to be included in the class source.
SetUserTexts Boolean (false) This enables internationalization for the <label> and <whatsthis> elements.

Adjusting the CMakeLists.txt

The only thing you have to do is to add your .kcfgc file to your program's sources.

For example, this is an excerpt from the CMakeLists.txt for the Kicker taskbar:

set( ${target}_SRCS
  taskbarsettings.kcfgc taskcontainer.cpp taskbar.cpp
  taskbarcontainer.cpp taskbarcontainer.skel
)

tde_add_library( ${target} SHARED AUTOMOC
  SOURCES ${${target}_SRCS}
  # [...]
)


Use and Dialogs

After making all of the above changes you're ready to use TDEConfig XT. The tdeconfig_compiler generated header file will have the name equal to the value you've specified in the kcfgc ClassName attribute plus the ".h" extension. Simply include that file whereever 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 the nicest features of the TDEConfig 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:

  • Create the TDEConfigDialog and pass the instance of your configuration data as one of the arguments. The construct would look like the following example:
TDEConfigDialog* dialog = new TDEConfigDialog( 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.
  • In TQt 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:
    • 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.
  • Add the TQt Designer generated widget to the TDEConfigDialog.
  • Show the dialog when you're done.

Example

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

<?xml version="1.0" encoding="UTF-8"?> 
<!DOCTYPE kcfg SYSTEM"http://www.kde.org/standards/kcfg/1.0/kcfg.dtd"> 
<kcfg> <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> 
    </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::writeConfig(); 
}

To add a dialog you need to create a TQt 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:

Kcdialog.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 ( TDEConfigDialog::showDialog( "settings" ) ) 
        return; 
 
//TDEConfigDialog didn't find an instance of this dialog, so lets create it : 
TDEConfigDialog* dialog = new TDEConfigDialog( 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 KTron code in the tdegames module to see a live example of TDEConfig XT!

Final remarks

TDEConfig XT is a very easy, extensible and flexible configuration framework. Hopefully this tutorial will make this great framework more understandable for you.

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> and <whatsthis> tags to each entry.
  • Try to use the code specifiers in the .kcfg as seldom as possible. We might soon deprecate them.
  • 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.


Copyright notice

Originally written by Zack Rusin <zack@kde.org>

Tutorial imported from KDE Developer Documentation.