You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
3338 lines
108 KiB
3338 lines
108 KiB
<?xml version="1.0" ?>
|
|
<!DOCTYPE book PUBLIC "-//KDE//DTD DocBook XML V4.2-Based Variant V1.1//EN" "dtd/kdex.dtd" [
|
|
<!ENTITY % addindex "INCLUDE">
|
|
<!ENTITY % English "INCLUDE" > <!-- change language only here -->
|
|
]>
|
|
|
|
<book lang="&language;">
|
|
|
|
<bookinfo>
|
|
<title>KDE Architecture Overview</title>
|
|
|
|
<date></date>
|
|
<releaseinfo></releaseinfo>
|
|
|
|
<authorgroup>
|
|
<author>
|
|
<firstname>Bernd</firstname>
|
|
<surname>Gehrmann</surname>
|
|
<affiliation><address><email>bernd@kdevelop.org</email></address></affiliation>
|
|
</author>
|
|
</authorgroup>
|
|
|
|
<copyright>
|
|
<year>2001</year>
|
|
<year>2002</year>
|
|
<holder>Bernd Gehrmann</holder>
|
|
</copyright>
|
|
|
|
<legalnotice>&FDLNotice;</legalnotice>
|
|
|
|
<abstract>
|
|
<para>This documentation gives an overview of the KDE Development Platform</para>
|
|
</abstract>
|
|
|
|
<keywordset>
|
|
<keyword>KDE</keyword>
|
|
<keyword>architecture</keyword>
|
|
<keyword>development</keyword>
|
|
<keyword>programming</keyword>
|
|
</keywordset>
|
|
|
|
</bookinfo>
|
|
|
|
<chapter id="structure">
|
|
<title>Library structure</title>
|
|
|
|
<simplesect id="structure-byname">
|
|
<title>Libraries by name</title>
|
|
|
|
<variablelist>
|
|
|
|
<varlistentry>
|
|
<term><ulink url="kdeapi:tdecore/index.html">tdecore</ulink></term>
|
|
<listitem><para>
|
|
The tdecore library is the basic application framework for every KDE based
|
|
program. It provides access to the configuration system, command line
|
|
handling, icon loading and manipulation, some special kinds inter-process
|
|
communication, file handling and various other utilities.
|
|
</para></listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><ulink url="kdeapi:tdeui/index.html">tdeui</ulink></term>
|
|
<listitem><para>
|
|
The <literal>tdeui</literal> library provides many widgets and standard
|
|
dialogs which Qt doesn't have or which have more features than their Qt
|
|
counterparts. It also includes several widgets which are subclassed
|
|
from Qt ones and are better integrated with the KDE desktop by
|
|
respecting user preferences.
|
|
</para></listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><ulink url="kdeapi:tdeio/index.html">tdeio</ulink></term>
|
|
<listitem><para>
|
|
The <literal>tdeio</literal> library contains facilities for asynchronous,
|
|
network transparent I/O and access to mimetype handling. It also provides the
|
|
KDE file dialog and its helper classes.
|
|
</para></listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><ulink url="kdeapi:kjs/index.html">kjs</ulink></term>
|
|
<listitem><para>
|
|
The <literal>kjs</literal> library provides an implementation of JavaScript.
|
|
</para></listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><ulink url="kdeapi:tdehtml/index.html">tdehtml</ulink></term>
|
|
<listitem><para>
|
|
The <literal>tdehtml</literal> library contains the TDEHTML part, a HTML browsing
|
|
widget, DOM API and parser, including interfaces to Java and JavaScript.
|
|
</para></listitem>
|
|
</varlistentry>
|
|
|
|
</variablelist>
|
|
|
|
</simplesect>
|
|
|
|
|
|
<simplesect id="structure-grouped">
|
|
<title>Grouped classes</title>
|
|
|
|
<para>
|
|
Core application skeleton - classes needed by almost every application.
|
|
</para>
|
|
|
|
<itemizedlist>
|
|
|
|
<listitem><formalpara>
|
|
<title><ulink url="kdeapi:tdecore/TDEApplication">TDEApplication</ulink></title>
|
|
<para>
|
|
Initializes and controls a KDE application.
|
|
</para>
|
|
</formalpara></listitem>
|
|
|
|
<listitem><formalpara>
|
|
<title><ulink url="kdeapi:tdecore/KUniqueApplication">KUniqueApplication</ulink></title>
|
|
<para>
|
|
Makes sure only one instance of an application can run simultaneously.
|
|
</para>
|
|
</formalpara></listitem>
|
|
|
|
<listitem><formalpara><title><ulink url="kdeapi:tdecore/TDEAboutData">TDEAboutData</ulink></title>
|
|
<para>
|
|
Holds information for the about box.
|
|
</para>
|
|
</formalpara></listitem>
|
|
|
|
<listitem><formalpara><title><ulink url="kdeapi:tdecore/TDECmdLineArgs">TDECmdLineArgs</ulink></title>
|
|
<para>
|
|
Command line argument processing.
|
|
</para>
|
|
</formalpara></listitem>
|
|
|
|
</itemizedlist>
|
|
|
|
<para>
|
|
Configuration settings - access to KDE's hierarchical configuration
|
|
database, global settings and application resources.
|
|
</para>
|
|
|
|
<itemizedlist>
|
|
|
|
<listitem><formalpara><title><ulink url="kdeapi:tdecore/TDEConfig">TDEConfig</ulink></title>
|
|
<para>
|
|
Provides access to KDE's configuration database.
|
|
</para>
|
|
</formalpara></listitem>
|
|
|
|
<listitem><formalpara><title><ulink url="kdeapi:tdecore/KSimpleConfig">KSimpleConfig</ulink></title>
|
|
<para>
|
|
Access to simple, non-hierarchical configuration files.
|
|
</para>
|
|
</formalpara></listitem>
|
|
|
|
<listitem><formalpara><title><ulink url="kdeapi:tdecore/KDesktopFile">KDesktopFile</ulink></title>
|
|
<para>
|
|
Access to <literal>.desktop</literal> files.
|
|
</para>
|
|
</formalpara></listitem>
|
|
|
|
<listitem><formalpara><title><ulink url="kdeapi:tdecore/TDEGlobalSettings">TDEGlobalSettings</ulink></title>
|
|
<para>
|
|
Convenient access to not application-specific settings.
|
|
</para>
|
|
</formalpara></listitem>
|
|
|
|
</itemizedlist>
|
|
|
|
<para>
|
|
File and URL handling - decoding of URLs, temporary files etc.
|
|
</para>
|
|
|
|
<itemizedlist>
|
|
|
|
<listitem><formalpara><title><ulink url="kdeapi:tdecore/KURL">KURL</ulink></title>
|
|
<para>
|
|
Represents and parses URLs.
|
|
</para>
|
|
</formalpara></listitem>
|
|
|
|
<listitem><formalpara><title><ulink url="kdeapi:tdecore/KTempFile">KTempFile</ulink></title>
|
|
<para>
|
|
Creates unique files for temporary data.
|
|
</para>
|
|
</formalpara></listitem>
|
|
|
|
<listitem><formalpara><title><ulink url="kdeapi:tdecore/KSaveFile">KSaveFile</ulink></title>
|
|
<para>
|
|
Allows to save files atomically.
|
|
</para>
|
|
</formalpara></listitem>
|
|
|
|
</itemizedlist>
|
|
|
|
<para>
|
|
Interprocess communication - DCOP helper classes and subprocess invocation.
|
|
</para>
|
|
|
|
<itemizedlist>
|
|
|
|
<listitem><formalpara><title><ulink url="kdeapi:tdecore/TDEProcess">TDEProcess</ulink></title>
|
|
<para>
|
|
Invokes and controls child processes.
|
|
</para>
|
|
</formalpara></listitem>
|
|
|
|
<listitem><formalpara><title><ulink url="kdeapi:tdecore/KShellProcess">KShellProcess</ulink></title>
|
|
<para>
|
|
Invokes child processes via a shell.
|
|
</para>
|
|
</formalpara></listitem>
|
|
|
|
<listitem><formalpara><title><ulink url="kdeapi:tdesu/PtyProcess">PtyProcess</ulink></title>
|
|
<para>
|
|
Communication with a child processes through a pseudo terminal.
|
|
</para>
|
|
</formalpara></listitem>
|
|
|
|
<listitem><formalpara><title><ulink url="kdeapi:tdecore/KIPC">KIPC</ulink></title>
|
|
<para>
|
|
Simple IPC mechanism using X11 ClientMessages.
|
|
</para>
|
|
</formalpara></listitem>
|
|
|
|
<listitem><formalpara><title><ulink url="kdeapi:dcop/DCOPClient">DCOPClient</ulink></title>
|
|
<para>
|
|
DCOP messaging.
|
|
</para>
|
|
</formalpara></listitem>
|
|
|
|
<listitem><formalpara><title><ulink url="kdeapi:tdecore/KDCOPPropertyProxy">KDCOPPropertyProxy</ulink></title>
|
|
<para>
|
|
A proxy class publishing Qt properties through DCOP.
|
|
</para>
|
|
</formalpara></listitem>
|
|
|
|
<listitem><formalpara><title><ulink url="kdeapi:tdeui/KDCOPActionProxy">KDCOPActionProxy</ulink></title>
|
|
<para>
|
|
A proxy class publishing a DCOP interface for actions.
|
|
</para>
|
|
</formalpara></listitem>
|
|
|
|
</itemizedlist>
|
|
|
|
<para>
|
|
Utility classes - memory management, regular expressions, string manipulation,
|
|
random numbers
|
|
</para>
|
|
|
|
<itemizedlist>
|
|
|
|
<listitem><formalpara><title><ulink url="kdeapi:tdecore/KRegExp">KRegExp</ulink></title>
|
|
<para>
|
|
POSIX regular expression matching.
|
|
</para>
|
|
</formalpara></listitem>
|
|
|
|
<listitem><formalpara><title><ulink url="kdeapi:tdecore/KStringHandler">KStringHandler</ulink></title>
|
|
<para>
|
|
An extravagant interface for string manipulation.
|
|
</para>
|
|
</formalpara></listitem>
|
|
|
|
<listitem><formalpara><title><ulink url="kdeapi:tdecore/TDEZoneAllocator">TDEZoneAllocator</ulink></title>
|
|
<para>
|
|
Efficient memory allocator for large groups of small objects.
|
|
</para>
|
|
</formalpara></listitem>
|
|
|
|
<listitem><formalpara><title><ulink url="kdeapi:tdecore/KRandomSequence">KRandomSequence</ulink></title>
|
|
<para>
|
|
Pseudo random number generator.
|
|
</para>
|
|
</formalpara></listitem>
|
|
|
|
</itemizedlist>
|
|
|
|
<para>
|
|
Keyboard accelerators - classes helping to establish consistent key bindings
|
|
throughout the desktop.
|
|
</para>
|
|
|
|
<itemizedlist>
|
|
|
|
<listitem><formalpara><title><ulink url="kdeapi:tdecore/TDEAccel">TDEAccel</ulink></title>
|
|
<para>
|
|
Collection of keyboard shortcuts.
|
|
</para>
|
|
</formalpara></listitem>
|
|
|
|
<listitem><formalpara><title><ulink url="kdeapi:tdecore/TDEStdAccel">TDEStdAccel</ulink></title>
|
|
<para>
|
|
Easy access to the common keyboard shortcut keys.
|
|
</para>
|
|
</formalpara></listitem>
|
|
|
|
<listitem><formalpara><title><ulink url="kdeapi:tdecore/TDEGlobalAccel"></ulink></title>
|
|
<para>
|
|
Collection of system-wide keyboard shortcuts.
|
|
</para>
|
|
</formalpara></listitem>
|
|
|
|
</itemizedlist>
|
|
|
|
<para>
|
|
Image processing - icon loading and manipulating.
|
|
</para>
|
|
|
|
<itemizedlist>
|
|
|
|
<listitem><formalpara><title><ulink url="kdeapi:tdecore/TDEIconLoader">TDEIconLoader</ulink></title>
|
|
<para>
|
|
Loads icons in a theme-conforming way.
|
|
</para>
|
|
</formalpara></listitem>
|
|
|
|
<listitem><formalpara><title><ulink url="kdeapi:tdecore/TDEIconTheme">TDEIconTheme</ulink></title>
|
|
<para>
|
|
Helper classes for TDEIconLoader.
|
|
</para>
|
|
</formalpara></listitem>
|
|
|
|
<listitem><formalpara><title><ulink url="kdeapi:tdecore/KPixmap">KPixmap</ulink></title>
|
|
<para>
|
|
A pixmap class with extended dithering capabilities.
|
|
</para>
|
|
</formalpara></listitem>
|
|
|
|
<listitem><formalpara><title><ulink url="kdeapi:tdeui/KPixmapEffect">KPixmapEffect</ulink></title>
|
|
<para>
|
|
Pixmap effects like gradients and patterns.
|
|
</para>
|
|
</formalpara></listitem>
|
|
|
|
<listitem><formalpara><title><ulink url="kdeapi:tdeui/KPixmapIO">KPixmapIO</ulink></title>
|
|
<para>
|
|
Fast <classname>QImage</classname> to <classname>QPixmap</classname> conversion.
|
|
</para>
|
|
</formalpara></listitem>
|
|
|
|
</itemizedlist>
|
|
|
|
<para>
|
|
Drag and Drop - drag objects for colors and URLs.
|
|
</para>
|
|
|
|
<itemizedlist>
|
|
|
|
<listitem><formalpara><title><ulink url="kdeapi:tdecore/KURLDrag">KURLDrag</ulink></title>
|
|
<para>
|
|
A drag object for URLs.
|
|
</para>
|
|
</formalpara></listitem>
|
|
|
|
<listitem><formalpara><title><ulink url="kdeapi:tdeui/KColorDrag">KColorDrag</ulink></title>
|
|
<para>
|
|
A drag object for colors.
|
|
</para>
|
|
</formalpara></listitem>
|
|
|
|
<listitem><formalpara><title><ulink url="kdeapi:tdecore/KMultipleDrag">KMultipleDrag</ulink></title>
|
|
<para>
|
|
Allows to construct drag objects from several others.
|
|
</para>
|
|
</formalpara></listitem>
|
|
|
|
</itemizedlist>
|
|
|
|
<para>
|
|
Auto-Completion
|
|
</para>
|
|
|
|
<itemizedlist>
|
|
|
|
<listitem><formalpara><title><ulink url="kdeapi:tdecore/TDECompletion">TDECompletion</ulink></title>
|
|
<para>
|
|
Generic auto-completion of strings.
|
|
</para>
|
|
</formalpara></listitem>
|
|
|
|
<listitem><formalpara><title><ulink url="kdeapi:tdeio/KURLCompletion">KURLCompletion</ulink></title>
|
|
<para>
|
|
Auto-completion of URLs.
|
|
</para>
|
|
</formalpara></listitem>
|
|
|
|
<listitem><formalpara><title><ulink url="kdeapi:tdeio/KShellCompletion">KShellCompletion</ulink></title>
|
|
<para>
|
|
Auto-completion of executables.
|
|
</para>
|
|
</formalpara></listitem>
|
|
|
|
</itemizedlist>
|
|
|
|
<para>
|
|
Widgets - widget classes for list views, rules, color selection etc.
|
|
</para>
|
|
|
|
<itemizedlist>
|
|
|
|
<listitem><formalpara><title><ulink url="kdeapi:tdeui/TDEListView">TDEListView</ulink></title>
|
|
<para>
|
|
A variant of <classname>QListView</classname> that honors KDE's system-wide settings.
|
|
</para>
|
|
</formalpara></listitem>
|
|
|
|
<listitem><formalpara><title><ulink url="kdeapi:tdeui/TDEListView">TDEListBox</ulink></title>
|
|
<para>
|
|
A variant of <classname>QListBox</classname> that honors KDE's system-wide settings.
|
|
</para>
|
|
</formalpara></listitem>
|
|
|
|
<listitem><formalpara><title><ulink url="kdeapi:tdeui/TDEListView">TDEIconView</ulink></title>
|
|
<para>
|
|
A variant of <classname>QIconView</classname> that honors KDE's system-wide settings.
|
|
</para>
|
|
</formalpara></listitem>
|
|
|
|
<listitem><formalpara><title><ulink url="kdeapi:tdeui/TDEListView">KLineEdit</ulink></title>
|
|
<para>
|
|
A variant of <classname>QLineEdit</classname> with completion support.
|
|
</para>
|
|
</formalpara></listitem>
|
|
|
|
<listitem><formalpara><title><ulink url="kdeapi:tdeui/KComboBox">KComboBox</ulink></title>
|
|
<para>
|
|
A variant of <classname>QComboBox</classname> with completion support.
|
|
</para>
|
|
</formalpara></listitem>
|
|
|
|
<listitem><formalpara><title><ulink url="kdeapi:tdeui/TDEFontCombo">TDEFontCombo</ulink></title>
|
|
<para>
|
|
A combo box for selecting fonts.
|
|
</para>
|
|
</formalpara></listitem>
|
|
|
|
<listitem><formalpara><title><ulink url="kdeapi:tdeui/KColorCombo">KColorCombo</ulink></title>
|
|
<para>
|
|
A combo box for selecting colors.
|
|
</para>
|
|
</formalpara></listitem>
|
|
|
|
<listitem><formalpara><title><ulink url="kdeapi:tdeui/KColorButton">KColorButton</ulink></title>
|
|
<para>
|
|
A button for selecting colors.
|
|
</para>
|
|
</formalpara></listitem>
|
|
|
|
<listitem><formalpara><title><ulink url="kdeapi:tdeui/KURLCombo">KURLCombo</ulink></title>
|
|
<para>
|
|
A combo box for selecting file names and URLs.
|
|
</para>
|
|
</formalpara></listitem>
|
|
|
|
<listitem><formalpara><title><ulink url="kdeapi:tdefile/KURLRequester">KURLRequester</ulink></title>
|
|
<para>
|
|
A line edit for selecting file names and URLs.
|
|
</para>
|
|
</formalpara></listitem>
|
|
|
|
<listitem><formalpara><title><ulink url="kdeapi:tdeui/KRuler">KRuler</ulink></title>
|
|
<para>
|
|
A ruler widget.
|
|
</para>
|
|
</formalpara></listitem>
|
|
|
|
<listitem><formalpara><title><ulink
|
|
url="kdeapi:tdeui/KAnimWidget">KAnimWidget</ulink></title>
|
|
<para>
|
|
animations.
|
|
</para>
|
|
</formalpara></listitem>
|
|
|
|
<listitem><formalpara><title><ulink url="kdeapi:tdeui/KNumInput">KNumInput</ulink></title>
|
|
<para>
|
|
A widget for inputting numbers.
|
|
</para>
|
|
</formalpara></listitem>
|
|
|
|
<listitem><formalpara><title><ulink url="kdeapi:tdeui/KPasswordEdit">KPasswordEdit</ulink></title>
|
|
<para>
|
|
A widget for inputting passwords.
|
|
</para>
|
|
</formalpara></listitem>
|
|
|
|
</itemizedlist>
|
|
|
|
<para>
|
|
Dialogs - full-featured dialogs for file, color and font selection.
|
|
</para>
|
|
|
|
<itemizedlist>
|
|
|
|
<listitem><formalpara><title><ulink url="kdeapi:tdefile/KFileDialog">KFileDialog</ulink></title>
|
|
<para>
|
|
A file selection dialog.
|
|
</para>
|
|
</formalpara></listitem>
|
|
|
|
<listitem><formalpara><title><ulink url="kdeapi:tdeui/KColorDialog">KColorDialog</ulink></title>
|
|
<para>
|
|
A color selection dialog.
|
|
</para>
|
|
</formalpara></listitem>
|
|
|
|
<listitem><formalpara><title><ulink url="kdeapi:tdeui/TDEFontDialog">TDEFontDialog</ulink></title>
|
|
<para>
|
|
A font selection dialog.
|
|
</para>
|
|
</formalpara></listitem>
|
|
|
|
<listitem><formalpara><title><ulink url="kdeapi:tdefile/TDEIconDialog">TDEIconDialog</ulink></title>
|
|
<para>
|
|
An icon selection dialog.
|
|
</para>
|
|
</formalpara></listitem>
|
|
|
|
<listitem><formalpara><title><ulink url="kdeapi:tdeui/KKeyDialog">KKeyDialog</ulink></title>
|
|
<para>
|
|
A dialog for editing keyboard bindings.
|
|
</para>
|
|
</formalpara></listitem>
|
|
|
|
<listitem><formalpara><title><ulink url="kdeapi:tdeui/KEditToolBar">KEditToolBar</ulink></title>
|
|
<para>
|
|
A dialog for editing toolbars.
|
|
</para>
|
|
</formalpara></listitem>
|
|
|
|
<listitem><formalpara><title><ulink url="kdeapi:tdeui/KTipDialog">KTipDialog</ulink></title>
|
|
<para>
|
|
A Tip-of-the-day dialog.
|
|
</para>
|
|
</formalpara></listitem>
|
|
|
|
<listitem><formalpara><title><ulink url="kdeapi:tdeui/TDEAboutDialog">TDEAboutDialog</ulink></title>
|
|
<para>
|
|
An about dialog.
|
|
</para>
|
|
</formalpara></listitem>
|
|
|
|
<listitem><formalpara><title><ulink url="kdeapi:tdeui/KLineEditDlg">KLineEditDlg</ulink></title>
|
|
<para>
|
|
A simple dialog for entering text.
|
|
</para>
|
|
</formalpara></listitem>
|
|
|
|
<listitem><formalpara><title><ulink url="kdeapi:tdefile/KURLRequesterDlg">KURLRequesterDlg</ulink></title>
|
|
<para>
|
|
A simple dialog for entering URLs.
|
|
</para>
|
|
</formalpara></listitem>
|
|
|
|
<listitem><formalpara><title><ulink url="kdeapi:tdeui/KMessageBox">KMessageBox</ulink></title>
|
|
<para>
|
|
A dialog for signaling errors and warnings.
|
|
</para>
|
|
</formalpara></listitem>
|
|
|
|
<listitem><formalpara><title><ulink url="kdeapi:tdeui/KPasswordDialog">KPasswordDialog</ulink></title>
|
|
<para>
|
|
A dialog for inputting passwords.
|
|
</para>
|
|
</formalpara></listitem>
|
|
|
|
</itemizedlist>
|
|
|
|
<para>
|
|
Actions and XML GUI
|
|
</para>
|
|
|
|
<itemizedlist>
|
|
|
|
<listitem><formalpara><title><ulink url="kdeapi:tdeui/TDEAction">TDEAction</ulink></title>
|
|
<para>
|
|
Abstraction for an action that can be plugged into menu bars and tool bars.
|
|
</para>
|
|
</formalpara></listitem>
|
|
|
|
<listitem><formalpara><title><ulink url="kdeapi:tdeui/TDEActionCollection">TDEActionCollection</ulink></title>
|
|
<para>
|
|
A set of actions.
|
|
</para>
|
|
</formalpara></listitem>
|
|
|
|
<listitem><formalpara><title><ulink url="kdeapi:tdeui/KXMLGUIClient">KXMLGUIClient</ulink></title>
|
|
<para>
|
|
A GUI fragment consisting of an action collection and a DOM tree representing their location in the GUI.
|
|
</para>
|
|
</formalpara></listitem>
|
|
|
|
<listitem><formalpara><title><ulink url="kdeapi:tdeparts/KPartManager">KPartManager</ulink></title>
|
|
<para>
|
|
Manages the activation of XMLGUI clients.
|
|
</para>
|
|
</formalpara></listitem>
|
|
|
|
</itemizedlist>
|
|
|
|
<para>
|
|
Plugins and Components
|
|
</para>
|
|
|
|
<itemizedlist>
|
|
|
|
<listitem><formalpara><title><ulink url="kdeapi:tdecore/KLibrary">KLibrary</ulink></title>
|
|
<para>
|
|
Represents a dynamically loaded library.
|
|
</para>
|
|
</formalpara></listitem>
|
|
|
|
<listitem><formalpara><title><ulink url="kdeapi:tdecore/KLibrary">KLibLoader</ulink></title>
|
|
<para>
|
|
Shared library loading.
|
|
</para>
|
|
</formalpara></listitem>
|
|
|
|
<listitem><formalpara><title><ulink url="kdeapi:tdecore/KLibFactory">KLibFactory</ulink></title>
|
|
<para>
|
|
Object factory in plugins.
|
|
</para>
|
|
</formalpara></listitem>
|
|
|
|
<listitem><formalpara><title><ulink url="kdeapi:tdeio/KServiceType">KServiceType</ulink></title>
|
|
<para>
|
|
Represents a service type.
|
|
</para>
|
|
</formalpara></listitem>
|
|
|
|
<listitem><formalpara><title><ulink url="kdeapi:tdeio/KService">KService</ulink></title>
|
|
<para>
|
|
Represents a service.
|
|
</para>
|
|
</formalpara></listitem>
|
|
|
|
<listitem><formalpara><title><ulink url="kdeapi:tdeio/KMimeType">KMimeType</ulink></title>
|
|
<para>
|
|
Represents a MIME type.
|
|
</para>
|
|
</formalpara></listitem>
|
|
|
|
<listitem><formalpara><title><ulink url="kdeapi:tdeio/KServiceTypeProfile">KServiceTypeProfile</ulink></title>
|
|
<para>
|
|
User preferences for MIME type mappings.
|
|
</para>
|
|
</formalpara></listitem>
|
|
|
|
<listitem><formalpara><title><ulink url="kdeapi:tdeio/KServiceTypeProfile">TDETrader</ulink></title>
|
|
<para>
|
|
Querying for services.
|
|
</para>
|
|
</formalpara></listitem>
|
|
|
|
</itemizedlist>
|
|
|
|
</simplesect>
|
|
|
|
</chapter>
|
|
|
|
|
|
|
|
<chapter id="graphics">
|
|
<title>Graphics</title>
|
|
|
|
<sect1 id="graphics-qpainter">
|
|
<title>Low-level graphics with QPainter</title>
|
|
|
|
<simplesect id="qpainter-rendering">
|
|
<title>Rendering with QPainter</title>
|
|
|
|
<para>
|
|
Qt's low level imaging model is based on the capabilities provided by X11 and
|
|
other windowing systems for which Qt ports exist. But it also extends these by
|
|
implementing additional features such as arbitrary affine transformations for
|
|
text and pixmaps.
|
|
</para>
|
|
|
|
<para>
|
|
The central graphics class for 2D painting with Qt is
|
|
<ulink url="kdeapi:qt/QPainter">QPainter</ulink>. It can
|
|
draw on a
|
|
<ulink url="kdeapi:qt/QPaintDevice">QPaintDevice</ulink>.
|
|
There are three possible paint devices implemented: One is
|
|
<ulink url="kdeapi:qt/QWidget">QWidget</ulink>
|
|
which represents a widget on the screen. The second is
|
|
<ulink url="kdeapi:qt/QPrinter">QPrinter</ulink> which
|
|
represents a printer and produces Postscript output. The third it
|
|
the class
|
|
<ulink url="kdeapi:qt/QPicture">QPicture</ulink> which
|
|
records paint commands and can save them on disk and play them back
|
|
later. A possible storage format for paint commands is the W3C standard
|
|
SVG.
|
|
</para>
|
|
|
|
<para>
|
|
So, it is possible to reuse the rendering code you use for displaying a
|
|
widget for printing, with the same features supported. Of course, in
|
|
practice, the code is used in a slightly different context. Drawing
|
|
on a widget is almost exclusively done in the paintEvent() method
|
|
of a widget class.
|
|
</para>
|
|
|
|
<programlisting>
|
|
void FooWidget::paintEvent()
|
|
{
|
|
QPainter p(this);
|
|
// Setup painter
|
|
// Use painter
|
|
}
|
|
</programlisting>
|
|
|
|
<para>
|
|
When drawing on a printer, you have to make sure to use QPrinter::newPage()
|
|
to finish with a page and begin a new one - something that naturally is not
|
|
relevant for painting widgets. Also, when printing, you may want to use the
|
|
<ulink url="kdeapi:qt/QPaintDeviceMetrics">device metrics</ulink>
|
|
in order to compute coordinates.
|
|
</para>
|
|
|
|
</simplesect>
|
|
|
|
|
|
<simplesect id="qpainter-transformations">
|
|
<title>Transformations</title>
|
|
|
|
<para>
|
|
By default, when using QPainter, it draws in the natural coordinate
|
|
system of the device used. This means, if you draw a line along the horizontal
|
|
axis with a length of 10 units, it will be painted as a horizontal line
|
|
on the screen with a length of 10 pixels. However, QPainter can apply arbitrary
|
|
affine transformations before actually rendering shapes and curves. An
|
|
affine transformation maps the x and y coordinates linearly into x' and
|
|
y' according to
|
|
</para>
|
|
|
|
<mediaobject>
|
|
<imageobject><imagedata fileref="affine-general.png"/></imageobject>
|
|
</mediaobject>
|
|
|
|
<para>
|
|
The 3x3 matrix in this equation can be set with QPainter::setWorldMatrix() and
|
|
is of type <ulink url="kdeapi:qt/QWMatrix">QWMatrix</ulink>.
|
|
Normally, this is the identity matrix, i.e. m11 and m22 are one, and the
|
|
other parameters are zero. There are basically three different groups of
|
|
transformations:
|
|
</para>
|
|
|
|
<itemizedlist>
|
|
|
|
<listitem><formalpara>
|
|
<title>Translations</title>
|
|
<para>
|
|
These move all points of an object by a fixed amount in
|
|
some direction. A translation matrix can be obtained by calling
|
|
method m.translate(dx, dy) for a QWMatrix. This corresponds to the
|
|
matrix
|
|
</para>
|
|
</formalpara>
|
|
|
|
<mediaobject>
|
|
<imageobject><imagedata fileref="affine-translate.png"/></imageobject>
|
|
</mediaobject>
|
|
|
|
</listitem>
|
|
|
|
<listitem><formalpara>
|
|
<title>Scaling</title>
|
|
<para>
|
|
These stretch or shrink the coordinates of an object, making
|
|
it bigger or smaller without distorting it. A scaling transformation
|
|
can be applied to a QWMatrix by calling m.scale(sx, sy). This corresponds
|
|
to the matrix
|
|
</para>
|
|
</formalpara>
|
|
|
|
<mediaobject>
|
|
<imageobject><imagedata fileref="affine-scale.png"/></imageobject>
|
|
</mediaobject>
|
|
|
|
<para>
|
|
By setting one of the parameters to a negative value, one can
|
|
achieve a mirroring of the coordinate system.
|
|
</para>
|
|
|
|
</listitem>
|
|
|
|
<listitem><formalpara>
|
|
<title>Shearing</title>
|
|
<para>
|
|
A distortion of the coordinate system with two
|
|
parameters. A shearing transformation can be applied by calling
|
|
m.shear(sh, sv), corresponding to the matrix
|
|
</para>
|
|
</formalpara>
|
|
|
|
<mediaobject>
|
|
<imageobject><imagedata fileref="affine-shear.png"/></imageobject>
|
|
</mediaobject>
|
|
|
|
</listitem>
|
|
|
|
<listitem><formalpara>
|
|
<title>Rotating</title>
|
|
<para>
|
|
This rotates an object. A rotation transformation can be
|
|
applied by calling m.rotate(alpha). Note that the angle has to be given
|
|
in degrees, not as mathematical angle! The corresponding matrix is
|
|
</para>
|
|
</formalpara>
|
|
|
|
<mediaobject>
|
|
<imageobject><imagedata fileref="affine-rotate.png"/></imageobject>
|
|
</mediaobject>
|
|
|
|
<para>
|
|
Note that a rotation is equivalent with a combination of
|
|
scaling and shearing.
|
|
</para>
|
|
|
|
</listitem>
|
|
|
|
</itemizedlist>
|
|
|
|
<para>
|
|
Here are some pictures that show the effect of the elementary
|
|
transformation to our masquot:
|
|
</para>
|
|
|
|
<informaltable frame="none">
|
|
<tgroup cols="3">
|
|
<tbody>
|
|
<row>
|
|
<entry><mediaobject>
|
|
<imageobject><imagedata fileref="konqi-normal.png"/></imageobject>
|
|
</mediaobject></entry>
|
|
<entry><mediaobject>
|
|
<imageobject><imagedata fileref="konqi-rotated.png"/></imageobject>
|
|
</mediaobject></entry>
|
|
<entry><mediaobject>
|
|
<imageobject><imagedata fileref="konqi-sheared.png"/></imageobject>
|
|
</mediaobject></entry>
|
|
<entry><mediaobject>
|
|
<imageobject><imagedata fileref="konqi-mirrored.png"/></imageobject>
|
|
</mediaobject></entry>
|
|
</row>
|
|
<row>
|
|
<entry>a) Normal</entry>
|
|
<entry>b) Rotated by 30 degrees</entry>
|
|
<entry>c) Sheared by 0.4</entry>
|
|
<entry>d) Mirrored</entry>
|
|
</row>
|
|
</tbody>
|
|
</tgroup>
|
|
</informaltable>
|
|
|
|
<para>
|
|
Transformations can be combined by multiplying elementary matrices. Note that
|
|
matrix operations are not commutative in general, and therefore the combined
|
|
effect of of a concatenation depends on the order in which the matrices are
|
|
multiplied.
|
|
</para>
|
|
|
|
</simplesect>
|
|
|
|
|
|
<simplesect id="qpainter-strokeattributes">
|
|
<title>Setting stroking attributes</title>
|
|
|
|
<para>
|
|
The rendering of lines, curves and outlines of polygons can be modified by
|
|
setting a special pen with QPainter::setPen(). The argument of this function is a
|
|
<ulink url="kdeapi:qt/QPen">QPen</ulink> object. The properties
|
|
stored in it are a style, a color, a join style and a cap style.
|
|
</para>
|
|
|
|
<para>
|
|
The pen style is member of the enum
|
|
<ulink url="kdeapi:qt/Qt#PenStyle-enum">Qt::PenStyle</ulink>.
|
|
and can take one of the following values:
|
|
</para>
|
|
|
|
<mediaobject>
|
|
<imageobject><imagedata fileref="penstyles.png"/></imageobject>
|
|
</mediaobject>
|
|
|
|
<para>
|
|
The join style is a member of the enum
|
|
<ulink url="kdeapi:qt/Qt#PenJoinStyle-enum">Qt::PenJoinStyle</ulink>.
|
|
It specifies how the junction between multiple lines which are attached to each
|
|
other is drawn. It takes one of the following values:
|
|
</para>
|
|
|
|
<informaltable frame="none">
|
|
<tgroup cols="3">
|
|
<tbody>
|
|
<row>
|
|
<entry><mediaobject>
|
|
<imageobject><imagedata fileref="joinmiter.png"/></imageobject>
|
|
</mediaobject></entry>
|
|
<entry><mediaobject>
|
|
<imageobject><imagedata fileref="joinbevel.png"/></imageobject>
|
|
</mediaobject></entry>
|
|
<entry><mediaobject>
|
|
<imageobject><imagedata fileref="joinround.png"/></imageobject>
|
|
</mediaobject></entry>
|
|
</row>
|
|
<row>
|
|
<entry>a) MiterJoin</entry>
|
|
<entry>c) BevelJoin</entry>
|
|
<entry>b) RoundJoin</entry>
|
|
</row>
|
|
</tbody>
|
|
</tgroup>
|
|
</informaltable>
|
|
|
|
<para>
|
|
The cap style is a member of the enum
|
|
<ulink url="kdeapi:qt/Qt#PenCapStyle-enum">Qt::PenCapStyle</ulink>and specifies how the end points of lines are drawn. It takes one of the values
|
|
from the following table:
|
|
</para>
|
|
|
|
<informaltable frame="none">
|
|
<tgroup cols="3">
|
|
<tbody>
|
|
<row>
|
|
<entry><mediaobject>
|
|
<imageobject><imagedata fileref="capflat.png"/></imageobject>
|
|
</mediaobject></entry>
|
|
<entry><mediaobject>
|
|
<imageobject><imagedata fileref="capsquare.png"/></imageobject>
|
|
</mediaobject></entry>
|
|
<entry><mediaobject>
|
|
<imageobject><imagedata fileref="capround.png"/></imageobject>
|
|
</mediaobject></entry>
|
|
</row>
|
|
<row>
|
|
<entry>a) FlatCap</entry>
|
|
<entry>b) SquareCap</entry>
|
|
<entry>c) RoundCap</entry>
|
|
</row>
|
|
</tbody>
|
|
</tgroup>
|
|
</informaltable>
|
|
|
|
</simplesect>
|
|
|
|
|
|
<simplesect id="qpainter-fillattributes">
|
|
<title>Setting fill attributes</title>
|
|
|
|
<para>
|
|
The fill style of polygons, circles or rectangles can be modified by setting
|
|
a special brush with QPainter::setBrush(). This function takes a
|
|
<ulink url="kdeapi:qt/QBrush">QBrush</ulink> object as argument.
|
|
Brushes can be constructed in four different ways:
|
|
</para>
|
|
|
|
<itemizedlist>
|
|
<listitem>
|
|
<para>QBrush::QBrush() - This creates a brush that does not fill shapes.</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>QBrush::QBrush(BrushStyle) - This creates a black brush with one of the default
|
|
patterns shown below.</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>QBrush::QBrush(const QColor &, BrushStyle) - This creates a colored brush
|
|
with one of the patterns shown below.</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>QBrush::QBrush(const QColor &, const QPixmap) - This creates a colored
|
|
brush with the custom pattern you give as second parameter.</para>
|
|
</listitem>
|
|
</itemizedlist>
|
|
|
|
<para>
|
|
A default brush style is from the enum
|
|
<ulink url="kdeapi:qt/Qt#BrushStyle-enum">Qt::BrushStyle</ulink>.
|
|
Here is a picture of all predefined patterns:
|
|
</para>
|
|
|
|
<mediaobject>
|
|
<imageobject><imagedata fileref="brushstyles.png"/></imageobject>
|
|
</mediaobject>
|
|
|
|
<para>
|
|
A further way to customize the brush behavior is to use the function
|
|
QPainter::setBrushOrigin().
|
|
</para>
|
|
|
|
</simplesect>
|
|
|
|
|
|
<simplesect id="qpainter-color">
|
|
<title>Color</title>
|
|
|
|
<para>
|
|
Colors play a role both when stroking curves and when filling shapes. In Qt,
|
|
colors are represented by the class
|
|
<ulink url="kdeapi:qt/QColor">QColor</ulink>. Qt does not support
|
|
advanced graphics features like ICC color profiles and color correction. Colors
|
|
are usually constructed by specifying their red, green and blue components, as
|
|
the RGB model is the way pixels are composed of on a monitor.
|
|
</para>
|
|
|
|
<para>
|
|
It is also possible to use hue, saturation and value. This HSV representation is
|
|
what you use in the Gtk color dialog, e.g. in GIMP. There, the hue corresponds
|
|
to the angle on the color wheel, while the saturation corresponds to the
|
|
distance from the center of the circle. The value can be chosen with a separate
|
|
slider.
|
|
</para>
|
|
|
|
</simplesect>
|
|
|
|
|
|
<simplesect id="qpainter-paintsettings">
|
|
<title>Other settings</title>
|
|
|
|
<para>
|
|
Normally, when you paint on a paint device, the pixels you draw replace those
|
|
that were there previously. This means, if you paint a certain region with
|
|
a red color and paint the same region with a blue color afterwards, only
|
|
the blue color will be visible. Qt's imaging model does not support
|
|
transparency, i.e. a way to blend the painted foreground with the background.
|
|
However, there is a simple way to combine background and foreground with
|
|
boolean operators. The method QPainter::setRasterOp() sets the used operator,
|
|
which comes from the enum
|
|
<ulink url="kdeapi:qt/Qt#RasterOp-enum">RasterOp</ulink>.
|
|
</para>
|
|
|
|
<para>
|
|
The default is CopyROP which ignores the background. Another popular choice is
|
|
XorROP. If you paint a black line with this operator on a colored image, then
|
|
the covered area will be inverted. This effect is for example used to create
|
|
the rubberband selections in image manipulation programs known as
|
|
"marching ants".
|
|
</para>
|
|
|
|
</simplesect>
|
|
|
|
|
|
<simplesect id="qpainter-primitives">
|
|
<title>Drawing graphics primitives</title>
|
|
|
|
<para>
|
|
In the following we list the elementary graphics elements supported by
|
|
QPainter. Most of them exist in several overloaded versions which take a
|
|
different number of arguments. For example, methods that deal with rectangles
|
|
usually either take a
|
|
<ulink url="kdeapi:qt/QRect">QRect</ulink> as argument or a set
|
|
of four integers.
|
|
</para>
|
|
|
|
<itemizedlist>
|
|
<listitem>
|
|
<para>Drawing a single point - drawPoint().</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>Drawing lines - drawLine(), drawLineSegments() and drawPolyLine().</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>Drawing and filling rectangles - drawRect(), drawRoundRect(),
|
|
fillRect() and eraseRect().</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>Drawing and filling circles, ellipses and parts or them -
|
|
drawEllipse(), drawArc(), drawPie and drawChord().</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>Drawing and filling general polygons - drawPolygon().</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>Drawing bezier curves - drawQuadBezier() [drawCubicBezier in Qt 3.0].</para>
|
|
</listitem>
|
|
</itemizedlist>
|
|
|
|
</simplesect>
|
|
|
|
|
|
<simplesect id="qpainter-pixmaps">
|
|
<title>Drawing pixmaps and images</title>
|
|
|
|
<para>
|
|
Qt provides two very different classes to represent images.
|
|
</para>
|
|
|
|
<para>
|
|
<ulink url="kdeapi:qt/QPixmap">QPixmap</ulink> directly corresponds
|
|
to the pixmap objects in X11. Pixmaps are server-side objects and may - on a
|
|
modern graphics card - even be stored directly in the card's memory. This makes
|
|
it <emphasis>very</emphasis> efficient to transfer pixmaps to the screen. Pixmaps also act as
|
|
an off-screen equivalent of widgets - the QPixmap class is a subclass of
|
|
QPaintDevice, so you can draw on it with a QPainter. Elementary drawing
|
|
operations are usually accelerated by modern graphics. Therefore, a common usage
|
|
pattern is to use pixmaps for double buffering. This means, instead of painting
|
|
directly on a widget, you paint on a temporary pixmap object and use the
|
|
<ulink url="kdeapi:qt/QPaintDevice#bitBlt-1">bitBlt</ulink>
|
|
function to transfer the pixmap to the widget. For complex repaints, this helps
|
|
to avoid flicker.
|
|
</para>
|
|
|
|
<para>
|
|
In contrast, <ulink url="kdeapi:qt/QImage">QImage</ulink> objects
|
|
live on the client side. Their emphasis in on providing direct access to the
|
|
pixels of the image. This makes them of use for image manipulation, and things
|
|
like loading and saving to disk (QPixmap's load() method takes QImage as
|
|
intermediate step). On the other hand, painting an image on a widget is a
|
|
relatively expensive operation, as it implies a transfer to the X server,
|
|
which can take some time, especially for large images and for remote servers.
|
|
Depending on the color depth, the conversion from QImage to QPixmap may also
|
|
require dithering.
|
|
</para>
|
|
|
|
</simplesect>
|
|
|
|
|
|
<simplesect id="qpainter-drawingtext">
|
|
<title>Drawing text</title>
|
|
|
|
<para>
|
|
Text can be drawn with one of the overloaded variants of the method
|
|
QPainter::drawText(). These draw a QString either at a given point or in a given
|
|
rectangle, using the font set by QPainter::setFont(). There is also a parameter
|
|
which takes an ORed combination of some flags from the enums
|
|
<ulink url="kdeapi:qt/Qt#AlignmentFlags-enum">Qt::AlignmentFlags</ulink>
|
|
and
|
|
<ulink url="kdeapi:qt/Qt#TextFlags-enum">Qt::TextFlags</ulink>
|
|
</para>
|
|
|
|
<para>
|
|
Beginning with version 3.0, Qt takes care of the complete text layout even for
|
|
languages written from right to left.
|
|
</para>
|
|
|
|
<para>
|
|
A more advanced way to display marked up text is the
|
|
<ulink url="kdeapi:qt/QSimpleRichText">QSimpleRichText</ulink>
|
|
class. Objects of this class can be constructed with a piece of text using
|
|
a subset of the HTML tags, which is quite rich and provides even tables.
|
|
The text style can be customized by using a
|
|
<ulink url="kdeapi/qt/QStyleSheet">QStyleSheet</ulink> (the
|
|
documentation of the tags can also be found here). Once the rich text object has
|
|
been constructed, it can be rendered on a widget or another paint device with
|
|
the QSimpleRichText::draw() method.
|
|
</para>
|
|
|
|
</simplesect>
|
|
|
|
</sect1>
|
|
|
|
|
|
<sect1 id="graphics-qcanvas">
|
|
<title>Structured graphics with QCanvas</title>
|
|
|
|
<para>
|
|
QPainter offers a powerful imaging model for painting on widgets and pixmaps.
|
|
However, it can also be cumbersome to use. Each time your widget receives
|
|
a paint event, it has to analyze the QPaintEvent::region() or
|
|
QPaintEvent::rect() which has to be redrawn. Then it has to setup a
|
|
QPainter and paint all objects which overlap with that region. For example,
|
|
image a vector graphics program which allows to drag objects like polygons,
|
|
circles and groups of them around. Each time those objects move a bit, the
|
|
widget's mouse event handler triggers a paint event for the whole area covered
|
|
by the objects in their old position and in their new position. Figuring
|
|
out the necessary redraws and doing them in an efficient way can be difficult,
|
|
and it may also conflict with the object-oriented structure of the program's
|
|
source code.
|
|
</para>
|
|
|
|
<para>
|
|
As an alternative, Qt contains the class
|
|
<ulink url="kdeapi:qt/QCanvas">QCanvas</ulink> in which
|
|
you put graphical objects like polygons, text, pixmaps. You may also provide
|
|
additional items by subclassing
|
|
<ulink url="kdeapi:qt/QCanvasItem">QCanvasItem</ulink> or
|
|
one of its more specialized subclasses. A canvas can be shown on the screen by
|
|
one or more widgets of the class
|
|
<ulink url="kdeapi:qt/QCanvas">QCanvasView</ulink> which
|
|
you have to subclass in order to handle user interactions. Qt takes care of
|
|
all repaints of objects in the view, whether they are caused by the widget
|
|
being exposed, new objects being created or modified or other things. By using
|
|
double buffering, this can be done in an efficient and flicker-free way.
|
|
</para>
|
|
|
|
<para>
|
|
Canvas items can overlap each other. In this case, the visible one depends on
|
|
the z order which can be assigned by QCanvasItem::setZ(). Items can also be
|
|
made visible or invisible. You can also provide a background to be drawn
|
|
"behind" all items and a foreground. For associating mouse events with objects,
|
|
in the canvas, there is the method QCanvas::collisions() which returns a list
|
|
of items overlapping with a given point. Here we show a screenshot of a canvas
|
|
view in action:
|
|
</para>
|
|
|
|
<mediaobject>
|
|
<imageobject><imagedata fileref="canvas.png"/></imageobject>
|
|
</mediaobject>
|
|
|
|
<para>
|
|
Here, the mesh is drawn in the background. Furthermore, there is a
|
|
QCanvasText item and a violet QCanvasPolygon. The butterfly is a
|
|
QCanvasPixmap. It has transparent areas, so you can see the underlying
|
|
items through it.
|
|
</para>
|
|
|
|
<para>
|
|
A tutorial on using QCanvas for writing sprite-based games can be
|
|
found <ulink url="http://zez.org/article/articleview/2/1/">here</ulink>.
|
|
</para>
|
|
|
|
</sect1>
|
|
|
|
|
|
<sect1 id="graphics-qglwidget">
|
|
<title>3D graphics with OpenGL</title>
|
|
|
|
<simplesect id="qglwidget-lowlevel">
|
|
<title>Low-level interface</title>
|
|
|
|
<para>
|
|
The de facto standard for rendering 3D graphics today is
|
|
<ulink url="http://www.opengl.org">OpenGL</ulink>. Implementations of this
|
|
specification come with Microsoft Windows, Mac OS X and XFree86 and often
|
|
support the hardware acceleration features offered by modern graphics cards.
|
|
OpenGL itself only deals with rendering on a specified area of the framebuffer
|
|
through a <emphasis>GL context</emphasis> and does not have any interactions
|
|
with the toolkit of the environment
|
|
</para>
|
|
|
|
<para>
|
|
Qt offers the widget <ulink url="kdeapi:qt/QGLWidget">QGLWidget</ulink>
|
|
which encapsulates a window with an associated GL context. Basically, you use it
|
|
by subclassing it and reimplementing some methods.
|
|
</para>
|
|
|
|
<itemizedlist>
|
|
|
|
<listitem><para>
|
|
Instead of reimplementing paintEvent() and using QPainter to draw the widget's
|
|
contents, you override paintGL() and use GL commands to render a scene. QLWidget
|
|
will take care of making its GL context the current one before paintGL() is
|
|
called, and it will flush afterwards.
|
|
</para></listitem>
|
|
|
|
<listitem><para>
|
|
The virtual method initializeGL() is called once before the first time resizeGL()
|
|
or paintGL() are called. This can be used to construct display lists for objects,
|
|
and make any initializations.
|
|
</para></listitem>
|
|
|
|
<listitem><para>
|
|
Instead of reimplementing resizeEvent(), you override resizeGL(). This can
|
|
be used to set the viewport appropriately.
|
|
</para></listitem>
|
|
|
|
<listitem><para>
|
|
Instead of calling update() when the state of the scene has changed - for example
|
|
when you animate it with a timer -, you should call updateGL(). This will trigger
|
|
a repaint.
|
|
</para></listitem>
|
|
|
|
</itemizedlist>
|
|
|
|
<para>
|
|
In general, QGLWidget behaves just like any other widget, i.e. for example
|
|
you can process mouse events as usual, resize the widget and combine it with
|
|
others in a layout.
|
|
</para>
|
|
|
|
<mediaobject>
|
|
<imageobject><imagedata fileref="opengl.png"/></imageobject>
|
|
</mediaobject>
|
|
|
|
<para>
|
|
Qt contains some examples of QGLWidget usage in its <literal>demo</literal>
|
|
example. A collection of tutorials can be found
|
|
<ulink url="http://www.libsdl.org/opengl/intro.html">here</ulink>,
|
|
and more information and a reference of OpenGL is available on the
|
|
<ulink url="http://www.opengl.org">OpenGL homepage</ulink>.
|
|
</para>
|
|
|
|
</simplesect>
|
|
|
|
|
|
<simplesect id="qglwidget-highlevel">
|
|
<title>High-level interfaces</title>
|
|
|
|
<para>
|
|
OpenGL is a relatively low-level interface for drawing 3D graphics. In the same
|
|
way QCanvas gives the programmer a higher-level interface which details with
|
|
objects and their properties, there are also high-level interfaces for 3D graphics.
|
|
One of the most popular is Open Inventor. Originally a technology developed by SGI,
|
|
there is today also the open source implementation
|
|
<ulink url="http://www.coin3d.org">Coin</ulink>, complemented by a toolkit binding to Qt
|
|
called SoQt.
|
|
</para>
|
|
|
|
<para>
|
|
The basic concept of Open Inventor is that of a <emphasis>scene</emphasis>.
|
|
A scene can be loaded from disk and saved in a special format closely related
|
|
to <ulink url="http://www.vrml.org">VRML</ulink>. A scene consists of a
|
|
collection of objects called <emphasis>nodes</emphasis>. Inventor already
|
|
provides a rich collection of reusable nodes, such as cubes, cylinders and
|
|
meshes, furthermore light sources, materials, cameras etc. Nodes are
|
|
represented by C++ classes and can be combined and subclassed.
|
|
</para>
|
|
|
|
<para>
|
|
An introduction to Inventor can be found
|
|
<ulink url="http://www.motifzone.com/tmd/articles/OpenInventor/OpenInventor.html">here</ulink>
|
|
(in general, you can substitute all mentions of SoXt by SoQt in this article).
|
|
</para>
|
|
|
|
</simplesect>
|
|
|
|
</sect1>
|
|
|
|
</chapter>
|
|
|
|
|
|
|
|
<chapter id="userinterface">
|
|
<title>User interface</title>
|
|
|
|
<sect1 id="userinterface-actionpattern">
|
|
<title>The action pattern</title>
|
|
|
|
<para></para>
|
|
|
|
</sect1>
|
|
|
|
|
|
<sect1 id="userinterface-xmlgui">
|
|
<title>Defining menus and toolbars in XML</title>
|
|
|
|
<simplesect id="xmlgui-intro">
|
|
<title>Introduction</title>
|
|
|
|
<para>
|
|
While the <link linkend="userinterface-actionpattern">action pattern</link>
|
|
allows to encapsulate actions triggered by the user in an object which can be
|
|
"plugged" somewhere in the menu bars or toolbars, it does not by itself solve
|
|
the problem of constructing the menus themselves. In particular, you have to
|
|
build all popup menus in C++ code and explicitly insert the actions in a
|
|
certain order, under consideration of the style guide for standard actions.
|
|
This makes it pretty difficult to allow the user to customize the menus or
|
|
change shortcuts to fit his needs, without changing the source code.
|
|
</para>
|
|
|
|
<para>
|
|
This problem is solved by a set of classes called <literal>XMLGUI</literal>.
|
|
Basically, this separates actions (coded in C++) from their appearance in menu
|
|
bars and tool bars (coded in XML). Without modifying any source code, menus
|
|
can be simply customized by adjusting an XML file. Furthermore, it helps
|
|
to make sure that standard actions (such as
|
|
<menuchoice><guimenu>File</guimenu><guimenuitem>Open</guimenuitem></menuchoice>
|
|
or <menuchoice><guimenu>Help</guimenu><guimenuitem>About</guimenuitem></menuchoice>)
|
|
appear in the locations suggested by the style guide. XMLGUI is especially
|
|
important for modular programs, where the items appearing in the menu bar may
|
|
come from many different plugins or parts.
|
|
</para>
|
|
|
|
<para>
|
|
KDE's class for toplevel windows,
|
|
<ulink url="kdeapi:tdeui/TDEMainWindow.html">TDEMainWindow</ulink>,
|
|
inherits
|
|
<ulink url="kdeapi:tdeui/KXMLGUIClient.html">KXMLGUIClient</ulink>
|
|
and therefore supports XMLGUI out of the box. All actions created within it must
|
|
have the client's <literal>actionCollection()</literal> as parent. A call to
|
|
<literal>createGUI()</literal> will then build the whole set of menu and tool
|
|
bars defined the applications XML file (conventionally with the suffix
|
|
<literal>ui.rc</literal>).
|
|
</para>
|
|
|
|
</simplesect>
|
|
|
|
|
|
<simplesect id="xmlgui-kviewexample">
|
|
<title>An example: Menu in KView</title>
|
|
|
|
<para>
|
|
In the following, we take KDE's image view <application>KView</application> as
|
|
example. It has a <literal>ui.rc</literal> file named
|
|
<filename>kviewui.rc</filename> which is installed with the
|
|
<filename>Makefile.am</filename> snippet
|
|
</para>
|
|
|
|
<programlisting>
|
|
rcdir = $(kde_datadir)/kview
|
|
rc_DATA = kviewui.rc
|
|
</programlisting>
|
|
|
|
<para>
|
|
Here is an excerpt from the <filename>kviewui.rc</filename> file. For
|
|
simplicity, we show only the definition of the <guimenu>View</guimenu> menu.
|
|
</para>
|
|
|
|
<programlisting>
|
|
<!DOCTYPE kpartgui>
|
|
<kpartgui name="kview">
|
|
<MenuBar>
|
|
<Menu name="view" >
|
|
<Action name="zoom50" />
|
|
<Action name="zoom100" />
|
|
<Action name="zoom200" />
|
|
<Action name="zoomMaxpect" />
|
|
<Separator/>
|
|
<Action name="fullscreen" />
|
|
</Menu>
|
|
</MenuBar>
|
|
</kpartgui>
|
|
</programlisting>
|
|
|
|
<para>
|
|
The corresponding part of the setup in C++ is:
|
|
</para>
|
|
|
|
<programlisting>
|
|
KStdAction::zoomIn ( this, SLOT(slotZoomIn()), actionCollection() );
|
|
KStdAction::zoomOut ( this, SLOT(slotZoomOut()), actionCollection() );
|
|
KStdAction::zoom ( this, SLOT(slotZoom()), actionCollection() );
|
|
new TDEAction ( i18n("&Half size"), ALT+Key_0,
|
|
this, SLOT(slotHalfSize()),
|
|
actionCollection(), "zoom50" );
|
|
new TDEAction ( i18n("&Normal size"), ALT+Key_1,
|
|
this, SLOT(slotDoubleSize()),
|
|
actionCollection(), "zoom100" );
|
|
new TDEAction ( i18n("&Double size"), ALT+Key_2,
|
|
this, SLOT(slotDoubleSize()),
|
|
actionCollection(), "zoom200" );
|
|
new TDEAction ( i18n("&Fill Screen"), ALT+Key_3,
|
|
this, SLOT(slotFillScreen()),
|
|
actionCollection(), "zoomMaxpect" );
|
|
new TDEAction ( i18n("Fullscreen &Mode"), CTRL+SHIFT+Key_F,
|
|
this, SLOT(slotFullScreen()),
|
|
actionCollection(), "fullscreen" );
|
|
</programlisting>
|
|
|
|
<para>
|
|
The <guimenu>View</guimenu> menu resulting from this GUI definition looks like
|
|
in this screenshot:
|
|
</para>
|
|
|
|
<mediaobject>
|
|
<imageobject><imagedata fileref="kview-menu.png"/></imageobject>
|
|
</mediaobject>
|
|
|
|
<para>
|
|
The XML file begins with a document type declaration. The DTD for kpartgui can
|
|
be found in the tdelibs sources in <filename>tdeui/kpartgui.dtd</filename>. The
|
|
outermost element of the file contains the instance name of the application as
|
|
attribute. It can also contain a version number in the form "version=2". This
|
|
is useful when you release new versions of an application with a changed menu
|
|
structure, e.g. with more features. If you bump up the version number of the
|
|
<literal>ui.rc</literal> file, KDE makes sure that any customized version of
|
|
the file is discarded and the new file is used instead.
|
|
</para>
|
|
|
|
<para>
|
|
The next line, <literal><MenuBar></literal>, contains a declaration of a
|
|
menu bar. You can also insert any number of <literal><ToolBar></literal>
|
|
declarations in order to create some tool bars. The menu contains a submenu
|
|
with the name "view". This name is already predefined, and thus you see a
|
|
translated version of the word "View" in the screenshot. If you declare your
|
|
own submenus, you have to add the title explicitly. For example,
|
|
<application>KView</application> has a submenu with the title "Image" which is
|
|
declared as follows:
|
|
</para>
|
|
|
|
<programlisting>
|
|
<Menu name="image" >
|
|
<text>&amp;Image</text>
|
|
...
|
|
</Menu>
|
|
</programlisting>
|
|
|
|
<para>
|
|
In KDE's automake framework, such titles are automatically extracted and put
|
|
into the application's <ulink url="tde-i18n-howto.html"><literal>.po</literal></ulink>
|
|
file , so it is considered by translators. Note that you have to write the
|
|
accelerator marker "&" in the form XML compliant form "&amp;".
|
|
</para>
|
|
|
|
<para>
|
|
Let us come back to the example. <application>KView</application>'s
|
|
<guimenu>View</guimenu> menu contains a couple of custom actions:
|
|
<literal>zoom50</literal>, <literal>zoom100</literal>,
|
|
<literal>zoom200</literal>, <literal>zoomMaxpect</literal> and
|
|
<literal>fullscreen</literal>, declared with a
|
|
<literal><Action></literal> element. The separator in the
|
|
screenshots corresponds to the <literal><Separator></literal> element.
|
|
</para>
|
|
|
|
<para>
|
|
You will note that some menu items do not not have a corresponding element in
|
|
the XML file. These are <emphasis>standard actions</emphasis>. Standard
|
|
actions are created by the class
|
|
<ulink url="kdeapi:tdeui/KStdAction.html">KStdAction</ulink>.
|
|
When you create such actions in your application (such as in the C++ example
|
|
above), they will automatically be inserted in a prescribed position, and
|
|
possibly with an icon and a shortcut key. You can look up these locations in
|
|
the file <filename>tdeui/ui_standards.rc</filename> in the tdelibs sources.
|
|
</para>
|
|
|
|
</simplesect>
|
|
|
|
|
|
<simplesect id="xmlgui-konqexample">
|
|
<title>An example: Toolbars in Konqueror</title>
|
|
|
|
<para>
|
|
For the discussion of toolbars, we switch to
|
|
<application>Konqueror</application>'s GUI definition. This excerpt defines
|
|
the location bar, which contains the input field for URLs.
|
|
</para>
|
|
|
|
<programlisting>
|
|
<ToolBar name="locationToolBar" fullWidth="true" newline="true" >
|
|
<text>Location Toolbar</text>
|
|
<Action name="clear_location" />
|
|
<Action name="location_label" />
|
|
<Action name="toolbar_url_combo" />
|
|
<Action name="go_url" />
|
|
</ToolBar>
|
|
</programlisting>
|
|
|
|
<para>
|
|
The first thing we notice is that there are a lot more attributes than for
|
|
menu bars. These include:
|
|
</para>
|
|
|
|
<itemizedlist>
|
|
|
|
<listitem><para>
|
|
<literal>fullWidth</literal>: Tells XMLGUI that the toolbar has the same width as the
|
|
toplevel window. Af this is "false", the toolbar only takes as much space as
|
|
necessary, and further toolbars are put in the same row.
|
|
</para></listitem>
|
|
|
|
<listitem><para>
|
|
<literal>newline</literal>: This is related to the option above. If newline is "true",
|
|
the toolbar starts a new row. Otherwise it may be put in the row together
|
|
with the previous toolbar.
|
|
</para></listitem>
|
|
|
|
<listitem><para>
|
|
<literal>noEdit</literal>: Normally toolbars can be customized by the user,
|
|
e.g. in <menuchoice><guimenu>Settings</guimenu><guimenuitem>Configure
|
|
Toolbars</guimenuitem></menuchoice> in
|
|
<application>Konqueror</application>. Setting this option to "true" marks this
|
|
toolbar as not editable. This is important for toolbars which are filled with
|
|
items at runtime, e.g. <application>Konqueror</application>'s bookmark toolbar.
|
|
</para></listitem>
|
|
|
|
<listitem><para>
|
|
<literal>iconText</literal>: Tells XMLGUI to show the text of the action next to the
|
|
icon. Normally, the text is only shown as a tooltip when the mouse cursor
|
|
remains over the icon for a while. Possible values for this attribute are
|
|
"icononly" (shows only the icon), "textonly" (shows only the text),
|
|
"icontextright" (shows the text on the right side of the icon) and
|
|
"icontextbottom" (shows the text beneath the icon).
|
|
</para></listitem>
|
|
|
|
|
|
<listitem><para>
|
|
<literal>hidden</literal>: If this is "true", the toolbar is not visible initially
|
|
and must be activated by some menu item.
|
|
</para></listitem>
|
|
|
|
|
|
<listitem><para>
|
|
<literal>position</literal>: The default for this attribute is "top", meaning that the
|
|
toolbar is positioned under the menu bar. For programs with many tools,
|
|
such as graphics programs, it may be interesting to replace this with
|
|
"left", "right" or "bottom".
|
|
</para></listitem>
|
|
|
|
</itemizedlist>
|
|
|
|
</simplesect>
|
|
|
|
|
|
<simplesect id="xmlgui-dynamical">
|
|
<title>Dynamical menus</title>
|
|
|
|
<para>
|
|
Obviously, an XML can only contain a static description of a user interface.
|
|
Often, there are menus which change at runtime. For example,
|
|
<application>Konqueror</application>'s <guimenu>Location</guimenu> menu
|
|
contains a set of items <guimenuitem>Open with Foo</guimenuitem> with the
|
|
applications able to load a file with a given MIME type. Each time the
|
|
document shown changes, the list of menu items is updated. XMLGUI is prepared
|
|
to handle such cases with the notion of <emphasis>action lists</emphasis>.
|
|
An action list is declared as one item in the XML file, but consists of
|
|
several actions which are plugged into the menu at runtime. The above example
|
|
is implemented with the following declaration in
|
|
<application>Konqueror</application>'s XML file:
|
|
</para>
|
|
|
|
<programlisting>
|
|
<Menu name="file">
|
|
<text>&amp;Location</text>
|
|
...
|
|
<ActionList name="openwith">
|
|
...
|
|
</Menu>
|
|
</programlisting>
|
|
|
|
<para>
|
|
The function <function>KXMLGUIClient::plugActionList()</function> is then used
|
|
to add actions to be displayed, whereas the function
|
|
<function>KXMLGuiClient::unplugActionList()</function> removes all
|
|
plugged actions. The routine responsible for updating looks as follows:
|
|
</para>
|
|
|
|
<programlisting>
|
|
void MainWindow::updateOpenWithActions()
|
|
{
|
|
unplugActionList("openwith");
|
|
openWithActions.clear();
|
|
for ( /* iterate over the relevant services */ ) {
|
|
TDEAction *action = new TDEAction( ...);
|
|
openWithActions.append(action);
|
|
}
|
|
plugActionList("openwith", openWithActions);
|
|
}
|
|
</programlisting>
|
|
|
|
<para>
|
|
Note that in contrast to the static actions, the ones created here are
|
|
<emphasis>not</emphasis> constructed with the action collection as parent, and
|
|
you are responsible for deleting them for yourself. The simplest way to achievethis
|
|
is by using <literal>openWithActions.setAutoDelete(true)</literal> in the above
|
|
example.
|
|
</para>
|
|
|
|
</simplesect>
|
|
|
|
|
|
<simplesect id="xmlgui-contextmenus">
|
|
<title>Context menus</title>
|
|
|
|
<para>
|
|
The examples above only contained cases where a main window's menubar and
|
|
toolbars were created. In the cases, the processes of constructing these
|
|
containers is completely hidden from you behind the
|
|
<function>createGUI()</function> call (except if you have custom containers).
|
|
However, there are cases, where you want to construct other containers and
|
|
populate them with GUI definitions from the XML file. One such example are
|
|
context menus. In order to get a pointer to a context menu, you have to
|
|
ask the client's factory for it:
|
|
</para>
|
|
|
|
<programlisting>
|
|
void MainWindow::popupRequested()
|
|
{
|
|
QWidget *w = factory()->container("context_popup", this);
|
|
QPopupMenu *popup = static_cast<QPopupMenu *>(w);
|
|
popup->exec(QCursor::pos());
|
|
}
|
|
</programlisting>
|
|
|
|
<para>
|
|
The method <function>KXMLGUIFactory::container()</function> used above looks
|
|
whether it finds a container in the XML file with the given name. Thus, a
|
|
possible definition could look as follows:
|
|
</para>
|
|
|
|
<programlisting>
|
|
...
|
|
<Menu name="context_popup">
|
|
<Action name="file_add"/>
|
|
<Action name="file_remove"/>
|
|
</Menu>
|
|
...
|
|
</programlisting>
|
|
|
|
</simplesect>
|
|
|
|
</sect1>
|
|
|
|
|
|
<sect1 id="help">
|
|
<title>Providing online help</title>
|
|
|
|
<para>
|
|
Making a program easy and intuitive to use involves a wide range of
|
|
facilities which are usually called online help. Online help has several,
|
|
partially conflicting goals: on the one, it should give the user answers
|
|
to the question "How can I do a certain task?", on the other hand it
|
|
should help the user exploring the application and finding features he
|
|
doesn't yet know about. It is important to recognize that this can only
|
|
be achieved by offering several levels of help:
|
|
</para>
|
|
|
|
<itemizedlist>
|
|
|
|
<listitem><para>
|
|
Tooltips are tiny labels that pop up over user interface elements when
|
|
the mouse remains there longer. They are especially important for tool-
|
|
bars, where icons are not always sufficient to explain the purpose of
|
|
a button.
|
|
</para></listitem>
|
|
|
|
<listitem><para>
|
|
"What's this?" help is usually a longer and richer explanation of a widget
|
|
or a menu item. It is also more clunky to use: In dialogs, it can be invoked
|
|
in two ways: either by pressing
|
|
<keycombo><keycap>Shift</keycap><keycap>F1</keycap></keycombo> or by clicking
|
|
on the question mark in the title bar (where the support of the latter depends
|
|
on the window manager). The mouse pointer then turns into an arrow with a
|
|
question mark, and the help window appears when a user interfact element has
|
|
been clicked. "What's this?" help for menu items is usually activated by a
|
|
button in the toolbar which contains an arrow and a question mark.
|
|
</para></listitem>
|
|
|
|
<listitem><para>
|
|
The problem with this approach is that the user can't see whether a widget
|
|
provides help or not. When the user activates the question mark button and
|
|
doesn't get any help window when clicking on a user interface element, he
|
|
will get frustrated very quickly.
|
|
</para>
|
|
|
|
<para>
|
|
The advantage of "What's this?" help windows as provided by Qt and KDE is that
|
|
they can contain <ulink url="kdeapi:qt/QStyleSheet">rich text</ulink>,
|
|
i.e. the may contain different fonts, bold and italic text and even images and tables.
|
|
</para>
|
|
|
|
<para>
|
|
An example of "What's this?" help:
|
|
</para>
|
|
|
|
<mediaobject>
|
|
<imageobject><imagedata fileref="whatsthis.png"/></imageobject>
|
|
</mediaobject>
|
|
|
|
</listitem>
|
|
|
|
<listitem><para>
|
|
Finally, every program should have a manual. A manual is normally viewed in
|
|
<application>KHelpCenter</application> by activating the
|
|
<guimenu>Help</guimenu> menu. That means, a complete additional application
|
|
pops up and diverts the user from his work. Consequently, consulting the
|
|
manual should only be necessary if other facilities like tooltips and what's
|
|
this help are not sufficient. Of course, a manual has the advantage that it
|
|
does not explain single, isolated aspects of the user interface. Instead, it
|
|
can explain aspects of the application in a greater context. Manuals for KDE
|
|
are written using the <ulink url="http://i18n.kde.org">DocBook</ulink> markup
|
|
language.
|
|
</para></listitem>
|
|
|
|
</itemizedlist>
|
|
|
|
<para>
|
|
From the programmer's point of view, Qt provides an easy to use API for online
|
|
help. To assign a tooltip to widget, use the
|
|
<ulink url="kdeapi:qt/QToolTip">QToolTip</ulink> class.
|
|
</para>
|
|
|
|
<programlisting>
|
|
QToolTip::add(w, i18n("This widget does something."))
|
|
</programlisting>
|
|
|
|
<para>
|
|
If the menu bars and tool bars are created using the <ulink url="actionpattern.html">
|
|
action pattern</ulink>, the string used as tooltip is derived from the first argument
|
|
of the <ulink url="kdeapi:tdeui/TDEAction.html">TDEAction</ulink> constructor:
|
|
</para>
|
|
|
|
<programlisting>
|
|
action = new TDEAction(i18n("&Delete"), "editdelete",
|
|
SHIFT+Key_Delete, actionCollection(), "del")
|
|
</programlisting>
|
|
|
|
<para>
|
|
Here it is also possible to assign a text which is shown in the status bar when the
|
|
respective menu item is highlighted:
|
|
</para>
|
|
|
|
<programlisting>
|
|
action->setStatusText(i18n("Deletes the marked file"))
|
|
</programlisting>
|
|
|
|
<para>
|
|
The API for "What's this?' help is very similar. In dialogs, use the following
|
|
code:
|
|
</para>
|
|
|
|
<programlisting>
|
|
QWhatsThis::add(w, i18n("<qt>This demonstrates <b>Qt</b>'s"
|
|
" rich text engine.<ul>"
|
|
"<li>Foo</li>"
|
|
"<li>Bar</li>"
|
|
"</ul></qt>"))
|
|
</programlisting>
|
|
|
|
<para>
|
|
For menu items, use
|
|
</para>
|
|
|
|
<programlisting>
|
|
action->setWhatsThis(i18n("Deletes the marked file"))
|
|
</programlisting>
|
|
|
|
<para>
|
|
The invocation of <application>KHelpCenter</application> is encapsulated in the
|
|
<ulink url="kdeapi:tdecore/TDEApplication">TDEApplication</ulink>
|
|
class. In order to show the manual of your application, just use
|
|
</para>
|
|
|
|
<programlisting>
|
|
kapp->invokeHelp()
|
|
</programlisting>
|
|
|
|
<para>
|
|
This displays the first page with the table of contents. When you want to
|
|
display only a certain section of the manual, you can give an additional
|
|
argument to <function>invokeHelp()</function> determining the anchor which
|
|
the browser jumps to.
|
|
</para>
|
|
|
|
</sect1>
|
|
|
|
</chapter>
|
|
|
|
|
|
|
|
<chapter id="components">
|
|
<title>Components and services</title>
|
|
|
|
<sect1 id="components-services">
|
|
<title>KDE services</title>
|
|
|
|
<simplesect id="services-whatarekdeservices">
|
|
<title>What are KDE services?</title>
|
|
|
|
<para>
|
|
The notion of a <emphasis>service</emphasis> is a central concept in KDE's
|
|
modular architecture. There is no strict technical implementation connected
|
|
with this term - services can be plugins in the form of shared libraries,
|
|
or they can be programs controlled via <ulink url="dcop.html">DCOP</ulink>.
|
|
By claiming to be of a certain <emphasis>service type</emphasis>, a service
|
|
promises to implement certain APIs or features. In C++ terms, one can think
|
|
of a service type as an abstract class, and a service as an implementation
|
|
of that interface.
|
|
</para>
|
|
|
|
<para>
|
|
The advantage of this separation is clear: An application utilizing a service
|
|
type does not have to know about possible implementations of it. It just uses
|
|
the APIs associated with the service type. In this way, the used service can be
|
|
changed without affecting the application. Also, the user can configure which
|
|
services he prefers for certain features.
|
|
</para>
|
|
|
|
<para>
|
|
Some examples:
|
|
</para>
|
|
|
|
<itemizedlist>
|
|
|
|
<listitem><para>
|
|
The HTML rendering engine used in <application>Konqueror</application> is an
|
|
embedable component that implements the service types
|
|
<literal>KParts/ReadOnlyPart</literal> and <literal>Browser/View</literal>.
|
|
</para></listitem>
|
|
<listitem><para>
|
|
In <application>TDevelop</application> HEAD, most functionality is packaged in
|
|
plugins with the service type <literal>TDevelop/Part</literal>. At startup,
|
|
all services with this type are loaded, such that you can extend the IDE in a
|
|
very flexible way.
|
|
</para></listitem>
|
|
<listitem><para>
|
|
In the icon view, <application>Konqueror</application> displays - if enabled -
|
|
thumbnail pictures of images, HTML pages, PDF and text files. This ability can
|
|
be extended. If you want it to display preview pictures of your own data files
|
|
with some MIME type, you can implement a service with service type
|
|
<classname>ThumbCreator</classname>.
|
|
</para></listitem>
|
|
|
|
</itemizedlist>
|
|
|
|
<para>
|
|
Obviously, a service is not only characterized by the service types it
|
|
implements, but also by some <emphasis>properties</emphasis>. For example, a
|
|
ThumbCreator does not only claim to implement the C++ class with the type
|
|
<classname>ThumbCreator</classname>, it also has a list of MIME types it is
|
|
responsible for. Similarly, TDevelop parts have the programming language they
|
|
support as a property. When an application requests a service type, it can
|
|
also list constraints on the properties of the service. In the above example,
|
|
when TDevelop loads the plugins for a Java project, it asks only for the
|
|
plugins which have Java as the programming language property. For this
|
|
purpose, KDE contains a full-blown CORBA-like <emphasis>trader</emphasis> with
|
|
a complex query language.
|
|
</para>
|
|
|
|
</simplesect>
|
|
|
|
|
|
<simplesect id="services-definingservicetypes">
|
|
<title>Defining service types</title>
|
|
|
|
<para>
|
|
New service types are added by installing a description of them into the
|
|
directory <filename>TDEDIR/share/servicetypes</filename>. In an automake
|
|
framework, this can be done with this <filename>Makefile.am</filename>
|
|
snippet:
|
|
</para>
|
|
|
|
<programlisting>
|
|
kde_servicetypesdir_DATA = tdeveloppart.desktop
|
|
EXTRA_DIST = $(kde_servicetypesdir_DATA)
|
|
</programlisting>
|
|
|
|
<para>
|
|
The definition <filename>tdeveloppart.desktop</filename> of a
|
|
<application>TDevelop</application> part looks as follows:
|
|
</para>
|
|
|
|
<programlisting>
|
|
[Desktop Entry]
|
|
Type=ServiceType
|
|
X-TDE-ServiceType=TDevelop/Part
|
|
Name=TDevelop Part
|
|
|
|
[PropertyDef::X-TDevelop-Scope]
|
|
Type=QString
|
|
|
|
[PropertyDef::X-TDevelop-ProgrammingLanguages]
|
|
Type=QStringList
|
|
|
|
[PropertyDef::X-TDevelop-Args]
|
|
Type=QString
|
|
</programlisting>
|
|
|
|
<para>
|
|
In addition to the usual entries, this example demonstrates how you declare
|
|
that a service has some properties. Each property definition corresponds
|
|
to a group <literal>[PropertyDef::name]</literal> in the configuration file. In
|
|
this group, the <literal>Type</literal> entry declares the type of the property.
|
|
Possible types are everything that can be stored in a
|
|
<ulink url="kdeapi:qt/QVariant">QVariant</ulink>.
|
|
</para>
|
|
|
|
</simplesect>
|
|
|
|
|
|
<simplesect id="services-defininglibraryservices">
|
|
<title>Defining shared library services</title>
|
|
|
|
<para>
|
|
Service definitions are stored in the directory
|
|
<filename>TDEDIR/share/services</filename>:
|
|
</para>
|
|
|
|
<programlisting>
|
|
kde_servicesdir_DATA = kdevdoxygen.desktop
|
|
EXTRA_DIST = $(kde_servicesdir_DATA)
|
|
</programlisting>
|
|
|
|
<para>
|
|
The content of the following example file
|
|
<filename>kdevdoxygen.desktop</filename> defines the
|
|
<literal>KDevDoxygen</literal> plugin with the service type
|
|
<literal>TDevelop/Part</literal>:
|
|
</para>
|
|
|
|
<programlisting>
|
|
[Desktop Entry]
|
|
Type=Service
|
|
Comment=Doxygen
|
|
Name=KDevDoxygen
|
|
ServiceTypes=TDevelop/Part
|
|
X-TDE-Library=libkdevdoxygen
|
|
X-TDevelop-ProgrammingLanguages=C,C++,Java
|
|
X-TDevelop-Scope=Project
|
|
</programlisting>
|
|
|
|
<para>
|
|
In addition to the usual declarations, an important entry is
|
|
<literal>X-TDE-Library</literal>. This contains the name of the libtool
|
|
library (without the <literal>.la</literal> extension). It also fixes
|
|
(with the prefix <literal>init_</literal> prepended) the name of the exported
|
|
symbol in the library which returns an object factory. For the above example,
|
|
the library must contain the following function:
|
|
</para>
|
|
|
|
<programlisting>
|
|
extern "C" {
|
|
void *init_libkdevdoxygen()
|
|
{
|
|
return new DoxygenFactory;
|
|
}
|
|
};
|
|
</programlisting>
|
|
|
|
<para>
|
|
The type of the factory class <classname>DoxygenFactory</classname> depends on
|
|
the specific service type the service implements. In our example of a TDevelop
|
|
plugin, the factory must be a <classname>KDevFactory</classname> (which
|
|
inherits <classname>KLibFactory</classname>). More common examples are
|
|
<ulink url="kdeapi:tdeparts/KParts::Factory">KParts::Factory</ulink>
|
|
which is supposed to produce
|
|
<ulink url="kdeapi:tdeparts/KParts::ReadOnlyPart">KParts::ReadOnlyPart</ulink>
|
|
objects or in most cases the generic
|
|
<ulink url="kdeapi:tdecore/KLibFactory">KLibFactory</ulink>.
|
|
</para>
|
|
|
|
</simplesect>
|
|
|
|
|
|
<simplesect id="services-usinglibraryservices">
|
|
<title>Using shared library services</title>
|
|
|
|
<para>
|
|
In order to use a shared library service in an application, you need to obtain a
|
|
<ulink url="kdeapi:tdeio/KService.html">KService</ulink> object
|
|
representing it. This is discussed in the
|
|
<ulink url="mime.html">section about MIME types</ulink> (and in a section about the
|
|
trader to be written :-)
|
|
</para>
|
|
|
|
<para>
|
|
With the <classname>KService</classname> object at hand, you can very simply
|
|
load the library and get a pointer to its factory object:
|
|
</para>
|
|
|
|
<programlisting>
|
|
KService *service = ...
|
|
QString libName = QFile::encodeName(service->library());
|
|
KLibFactory *factory = KLibLoader::self()->factory(libName);
|
|
if (!factory) {
|
|
QString name = service->name();
|
|
QString errorMessage = KLibLoader::self()->lastErrorMessage();
|
|
KMessageBox::error(0, i18n("There was an error loading service %1.\n"
|
|
"The diagnostics from libtool is:\n%2")
|
|
.arg(name).arg(errorMessage);
|
|
}
|
|
</programlisting>
|
|
|
|
<para>
|
|
From this point, the further proceeding depends again on the service type. For
|
|
generic plugins, you create objects with the method
|
|
<ulink url="kdeapi:tdecore/KLibFactory.html#ref3">KLibFactory::create()</ulink>.
|
|
For KParts, you must cast the factory pointer to the more specific KParts::Factory and use
|
|
its create() method:
|
|
</para>
|
|
|
|
<programlisting>
|
|
if (factory->inherits("KParts::Factory")) {
|
|
KParts::Factory *partFactory = static_cast<KParts::Factory*>(factory);
|
|
QObject *obj = partFactory->createPart(parentWidget, widgetName,
|
|
parent, name, "KParts::ReadOnlyPart");
|
|
...
|
|
} else {
|
|
cout << "Service does not implement the right factory" << endl;
|
|
}
|
|
</programlisting>
|
|
|
|
</simplesect>
|
|
|
|
|
|
<simplesect id="services-definingdcopservices">
|
|
<title>Defining DCOP services</title>
|
|
|
|
<para>
|
|
A DCOP service is usually implemented as a program that is started up when it is
|
|
needed. It then goes into a loop and listens for DCOP connections. The program
|
|
may be an interactive one, but it may also run completely or for a part of its
|
|
lifetime as a daemon in the background without the user noticing it. An example
|
|
for such a daemon is <literal>tdeio_uiserver</literal>, which implements user interaction
|
|
such as progress dialog for the TDEIO library. The advantage of such a centralized
|
|
daemon in this context is that e.g. the download progress for several different
|
|
files can be shown in one window, even if those downloads were initiated from
|
|
different applications.
|
|
</para>
|
|
|
|
<para>
|
|
A DCOP service is defined differently from a shared library service. Of course,
|
|
it doesn't specify a library, but instead an executable. Also, DCOP services
|
|
do not specify a ServiceType line, because usually they are started by their
|
|
name. As additional properties, it contains two lines:
|
|
</para>
|
|
|
|
<para>
|
|
<literal>X-DCOP-ServiceType</literal> specifies the way the service is
|
|
started. The value <literal>Unique</literal> says that the service must not be
|
|
started more than once. This means, if you try to start this service (e.g. via
|
|
<ulink url="kdeapi:tdecore/TDEApplication.html#startServiceByName">
|
|
TDEApplication::startServiceByName()</ulink>, KDE looks whether it is already
|
|
registered with DCOP and uses the running service. If it is not registered yet,
|
|
KDE will start it up and wait until is registered. Thus, you can immediately
|
|
send DCOP calls to the service. In such a case, the service should be implemented
|
|
as a
|
|
<ulink url="kdeapi:tdecore/KUniqueApplication.html">KUniqueApplication</ulink>.
|
|
</para>
|
|
|
|
<para>
|
|
The value <literal>Multi</literal> for <literal>X-DCOP-ServiceType</literal> says that multiple
|
|
instances of the service can coexist, so every attempt to start the service
|
|
will create another process. As a last possibility the value <literal>None</literal>
|
|
can be used. In this case, a start of the service will not wait until it
|
|
is registered with DCOP.
|
|
</para>
|
|
|
|
<para>
|
|
<literal>X-TDE-StartupNotify</literal> should normally be set to false. Otherwise, when
|
|
the program is started, the task bar will show a startup notification, or, depending
|
|
on the user's settings, the cursor will be changed.
|
|
</para>
|
|
|
|
<para>
|
|
Here is the definition of <literal>tdeio_uiserver</literal>:
|
|
</para>
|
|
|
|
<programlisting>
|
|
[Desktop Entry]
|
|
Type=Service
|
|
Name=tdeio_uiserver
|
|
Exec=tdeio_uiserver
|
|
X-DCOP-ServiceType=Unique
|
|
X-TDE-StartupNotify=false
|
|
</programlisting>
|
|
|
|
</simplesect>
|
|
|
|
|
|
<simplesect id="services-usingdcopservices">
|
|
<title>Using DCOP services</title>
|
|
|
|
<para>
|
|
A DCOP service is started with one of several methods in the TDEApplication
|
|
class:
|
|
</para>
|
|
|
|
<programlisting>
|
|
DCOPClient *client = kapp->dcopClient();
|
|
client->attach();
|
|
if (!client->isApplicationRegistered("tdeio_uiserver")) {
|
|
QString error;
|
|
if (TDEApplication::startServiceByName("tdeio_uiserver", QStringList(), &error))
|
|
cout << "Starting kioserver failed with message " << error << endl;
|
|
}
|
|
...
|
|
QByteArray data, replyData;
|
|
QCString replyType;
|
|
QDataStream arg(data, IO_WriteOnly);
|
|
arg << true;
|
|
if (!client->call("tdeio_uiserver", "UIServer", "setListMode(bool)",
|
|
data, replyType, replyData))
|
|
cout << "Call to tdeio_uiserver failed" << endl;
|
|
...
|
|
</programlisting>
|
|
|
|
<para>
|
|
Note that the example of a DCOP call given here uses explicit marshalling
|
|
of arguments. Often you will want to use a stub generated by dcopidl2cpp
|
|
instead, because it is much simpler and less error prone.
|
|
</para>
|
|
|
|
<para>
|
|
In the example given here, the service was started "by name", i.e. the
|
|
first argument to <function>TDEApplication::startServiceByName()</function> is
|
|
the name is appearing in the <literal>Name</literal> line of the desktop
|
|
file. An alternative is to use
|
|
<function>TDEApplication::startServiceByDesktopName()</function>, which takes
|
|
the file name of its desktop file as argument, i.e. in this case
|
|
<literal>"tdeio_uiserver.desktop"</literal>.
|
|
</para>
|
|
|
|
<para>
|
|
All these calls take a list of URLs as a second argument, which is given
|
|
to the service on the command line. The third argument is a pointer to a
|
|
<classname>QString</classname>. If starting the service fails, this argument
|
|
is set to a translated error message.
|
|
</para>
|
|
|
|
</simplesect>
|
|
|
|
</sect1>
|
|
|
|
|
|
<sect1 id="components-mime">
|
|
<title>MIME types</title>
|
|
|
|
<simplesect id="mime-whataremimetypes">
|
|
<title>What are MIME types?</title>
|
|
|
|
<para>
|
|
MIME types are used to describe the content type of files or data
|
|
chunks. Originally they were introduced in order to allow sending around image
|
|
or sound files etc. by e-mail (MIME stands for "Multipurpose Internet Mail
|
|
Extensions"). Later this system was also used by web browsers to determine how
|
|
to present data sent by a web server to the user. For example, an HTML page
|
|
has a MIME type "text/html", a postscript file "application/postscript". In
|
|
KDE, this concept is used at a variety of places:
|
|
</para>
|
|
|
|
<itemizedlist>
|
|
|
|
<listitem><para>
|
|
In <application>Konqueror</application>'s icon view, files are represented by
|
|
icons. Each MIME type has a certain associated icon shown here.
|
|
</para></listitem>
|
|
|
|
<listitem><para>
|
|
When you click onto a file icon or a file name in
|
|
<application>Konqueror</application>, either the file is shown in an embedded
|
|
view, or an application associated with the file type is opened.
|
|
</para></listitem>
|
|
|
|
<listitem><para>
|
|
When you drag and drop some data from one application to another (or
|
|
within the same application), the drop target may choose to accept only
|
|
certain data types. Furthermore, it will handle image data different
|
|
from textual data.
|
|
</para></listitem>
|
|
|
|
<listitem><para>
|
|
Clipboard data has a MIME type. Traditionally, X programs only handle
|
|
pixmaps or texts, but with Qt, there are no restrictions on the data type.
|
|
</para></listitem>
|
|
|
|
</itemizedlist>
|
|
|
|
<para>
|
|
From the above examples, it is clear that MIME handling is a complex issue.
|
|
First, it is necessary to establish a mapping from file names to MIME types.
|
|
KDE goes one step further in allowing even file contents to be mapped to
|
|
MIME types, for cases in which the file name is not available. Second, it
|
|
is necessary to map MIME types to applications or libraries which can view
|
|
or edit a file with a certain type, or create a thumbnail picture for it.
|
|
</para>
|
|
|
|
<para>
|
|
There is a variety of APIs to figure out the MIME type of data or files. In
|
|
general, there is a certain speed/reliability trade-off you have to make. You
|
|
can find out the type of a file by examining only its file name (i.e. in most
|
|
cases the file name extension). For example, a file
|
|
<filename>foo.jpg</filename> is normally "image/jpeg". In cases where the
|
|
extension is stripped off this is not safe, and you actually have to look at
|
|
the contents of the file. This is of course slower, in particular for files
|
|
that have to be downloaded via HTTP first. The content-based method is based
|
|
on the file <filename>TDEDIR/share/mimelnk/magic</filename> and therefore
|
|
difficult to extend. But in general, MIME type information can easily be made
|
|
available to the system by installing a <literal>.desktop</literal> file, and
|
|
it is efficiently and conveniently available through the KDE libraries.
|
|
</para>
|
|
|
|
</simplesect>
|
|
|
|
|
|
<simplesect id="mime-definingmimetypes">
|
|
<title>Defining MIME types</title>
|
|
|
|
<para>
|
|
Let us define a type <literal>"application/x-foo"</literal> for our new
|
|
<application>foobar</application> program. To this end, you have to write a
|
|
file <filename>foo.desktop</filename> and install it into
|
|
<filename>TDEDIR/share/mimelnk/application</filename>. (This is the usual
|
|
location, which may differ between distributions). This can be done by adding
|
|
this to the <filename>Makefile.am</filename>:
|
|
</para>
|
|
|
|
<programlisting>
|
|
mimedir = $(kde_mimedir)/application
|
|
mime_DATA = foo.desktop
|
|
EXTRA_DIST = $(mime_DATA)
|
|
</programlisting>
|
|
|
|
<para>
|
|
The file <filename>foo.desktop</filename> should look as follows:
|
|
</para>
|
|
|
|
<programlisting>
|
|
[Desktop Entry]
|
|
Type=MimeType
|
|
MimeType=application/x-foo
|
|
Icon=fooicon
|
|
Patterns=*.foo;
|
|
DefaultApp=foobar
|
|
Comment=Foo Data File
|
|
Comment[de]=Foo Datei
|
|
</programlisting>
|
|
|
|
<para>
|
|
The <literal>"Comment"</literal> entry is supposed to be translated. Since the
|
|
<filename>.desktop</filename> file specifies an icon, you should also install
|
|
an icon <filename>fooicon.png</filename>, which represents the file e.g. in
|
|
<application>Konqueror</application>.
|
|
</para>
|
|
|
|
<para>
|
|
In the KDE libraries, such a type definition is mapped to an instance of the
|
|
class <ulink url="kdeapi:tdeio/KMimeType.html">KMimeType</ulink>.
|
|
Use this like in the following example:
|
|
</para>
|
|
|
|
<programlisting>
|
|
KMimeType::Ptr type = KMimeType::mimeType("application/x-foo");
|
|
cout << "Type: " << type->name() < endl;
|
|
cout << "Icon: " << type->icon() < endl;
|
|
cout << "Comment: " << type->icon() < endl;
|
|
QStringList patterns = type->patterns();
|
|
QStringList::ConstIterator it;
|
|
for (it = patterns.begin(); it != patterns.end(); ++it)
|
|
cout << "Pattern: " << (*it) << endl;
|
|
</programlisting>
|
|
|
|
</simplesect>
|
|
|
|
|
|
<simplesect id="mime-determiningmimetypes">
|
|
<title>Determining the MIME type of data</title>
|
|
|
|
<para>
|
|
The fast method for determining the type of a file is
|
|
<function>KMimeType::findByURL()</function>. This looks for the URL string and
|
|
in most cases determines the type from the extension. For certain protocols
|
|
(e.g. http, man, info), this mechanism is not used. For example, CGI scripts
|
|
on web servers written in Perl often have the extension
|
|
<literal>.pl</literal>, which would indicate a
|
|
<literal>"text/x-perl"</literal> type. However, we file delivered by the
|
|
server is the output of this script, which is normally HTML. For such a case,
|
|
<function>KMimeType::findByURL()</function> returns the MIME type
|
|
<literal>"application/octet-stream"</literal> (available through
|
|
<function>KMimeType::defaultMimeType()</function>), which indicates a failure
|
|
to find out the type.
|
|
</para>
|
|
|
|
<programlisting>
|
|
KMimeType::Ptr type = KMimeType::findByURL("/home/bernd/foobar.jpg");
|
|
if (type->name() == KMimeType::defaultMimeType())
|
|
cout << "Could not find out type" << endl;
|
|
else
|
|
cout << "Type: " << type->name() << endl;
|
|
</programlisting>
|
|
|
|
<para>
|
|
(this method has some more arguments, but these are undocumented, so simply
|
|
forget about them.)
|
|
</para>
|
|
|
|
<para>
|
|
You may want to find out a MIME from the contents of file instead of
|
|
the file name. This is more reliable, but also slower, as it requires
|
|
reading a part of the file. This is done with the
|
|
<ulink url="kdeapi:tdeio/KMimeMagic.html">KMimeMagic</ulink>
|
|
class, which has different error handling:
|
|
</para>
|
|
|
|
<programlisting>
|
|
KMimeMagicResult *result = KMimeMagic::self()->findFileType("/home/bernd/foobar.jpg");
|
|
if (!result || !result->isValid())
|
|
cout << "Could not find out type" << endl;
|
|
else
|
|
cout << "Type: " << result->mimeType() << endl;
|
|
</programlisting>
|
|
|
|
<para>
|
|
As a variant of this function, you can also determine the type of a memory
|
|
chunk. This is e.g. used in <application>Kate</application> in order to find
|
|
out the highlighting mode:
|
|
</para>
|
|
|
|
<programlisting>
|
|
QByteArray array;
|
|
...
|
|
KMimeMagicResult *result = KMimeMagic::self()->findBufferType(array);
|
|
if (!result || !result->isValid())
|
|
cout << "Could not find out type" << endl;
|
|
else
|
|
cout << "Type: " << result->mimeType() << endl;
|
|
</programlisting>
|
|
|
|
<para>
|
|
Of course, even KMimeMagic is only able to determine a file type from the
|
|
contents of a local file. For remote files, there is a further possibility:
|
|
</para>
|
|
|
|
<programlisting>
|
|
KURL url("http://developer.kde.org/favicon.ico");
|
|
QString type = TDEIO::NetAccess::mimetype(url);
|
|
if (type == KMimeType::defaultMimeType())
|
|
cout << "Could not find out type" << endl;
|
|
else
|
|
cout << "Type: " << type << endl;
|
|
</programlisting>
|
|
|
|
<para>
|
|
This starts a TDEIO job to download a part of the file and check this.
|
|
Note that this function is perhaps quite slow and blocks the program. Normally
|
|
you will only want to use this if <function>KMimeType::findByURL()</function>
|
|
has returned <literal>"application/octet-stream"</literal>.
|
|
</para>
|
|
|
|
<para>
|
|
On the other hand, if you do not want to block your application, you can also
|
|
explicitly start the TDEIO job and connect to some of its signals:
|
|
</para>
|
|
|
|
<programlisting>
|
|
void FooClass::findType()
|
|
{
|
|
KURL url("http://developer.kde.org/favicon.ico");
|
|
TDEIO::MimetypeJob *job = TDEIO::mimetype(url);
|
|
connect( job, SIGNAL(result(TDEIO::Job*)),
|
|
this, SLOT(mimeResult(TDEIO::Job*)) );
|
|
}
|
|
|
|
void FooClass::mimeResult(TDEIO::Job *job)
|
|
{
|
|
if (job->error())
|
|
job->showErrorDialog();
|
|
else
|
|
cout << "MIME type: " << ((TDEIO::MimetypeJob *)job)->mimetype() << endl;
|
|
}
|
|
</programlisting>
|
|
|
|
</simplesect>
|
|
|
|
|
|
<simplesect id="mime-mappingmimetypes">
|
|
<title>Mapping a MIME type to an application or service</title>
|
|
|
|
<para>
|
|
When an application is installed, it installs a <literal>.desktop</literal>
|
|
file which contains a list of MIME types this application can load. Similarly,
|
|
components like KParts make this information available by their service
|
|
<literal>.desktop</literal> files. So in general, there are several programs
|
|
and components which can process a given MIME type. You can obtain such a list
|
|
from the class <classname>KServiceTypeProfile</classname>:
|
|
</para>
|
|
|
|
<programlisting>
|
|
KService::OfferList offers = KServiceTypeProfile::offers("text/html", "Application");
|
|
KService::OfferList::ConstIterator it;
|
|
for (it = offers.begin(); it != offers.end(); ++it) {
|
|
KService::Ptr service = (*it);
|
|
cout << "Name: " << service->name() << endl;
|
|
}
|
|
</programlisting>
|
|
|
|
<para>
|
|
The return value of this function is a list of service offers. A
|
|
<classname>KServiceOffer</classname> object packages a KService::Ptr together
|
|
with a preference number. The list returned by
|
|
<function>KServiceTypeProfile::offers()</function> is ordered by the user's
|
|
preference. The user can change this by calling <command>"keditfiletype
|
|
text/html"</command> or choosing <guimenuitem>Edit File Type</guimenuitem> on
|
|
<application>Konqueror</application>'s context menu on a HTML file.
|
|
</para>
|
|
|
|
<para>
|
|
In the above example, an offer list of the applications supporting
|
|
<literal>text/html</literal> was requested. This will - among others - contain
|
|
HTML editors like <application>Quanta Plus</application>. You can also replace
|
|
the second argument <literal>"Application"</literal> by
|
|
<literal>"KParts::ReadOnlyPart"</literal>. In that case, you get a list of
|
|
embedable components for presenting HTML content, for example TDEHTML.
|
|
</para>
|
|
|
|
<para>
|
|
In most cases, you are not interested in the list of all service offers
|
|
for a combination of MIME type and service type. There is a convenience
|
|
function which gives you only the service offer with the highest preference:
|
|
</para>
|
|
|
|
<programlisting>
|
|
KService::Ptr offer = KServiceTypeProfile::preferredService("text/html", "Application");
|
|
if (offer)
|
|
cout << "Name: " << service->name() << endl;
|
|
else
|
|
cout << "No appropriate service found" << endl;
|
|
</programlisting>
|
|
|
|
<para>
|
|
For even more complex queries, there is a full-blown CORBA-like
|
|
<ulink url="kdeapi:tdeio/TDETrader.html">trader</ulink>.
|
|
</para>
|
|
|
|
<para>
|
|
In order to run an application service with some URLs, use
|
|
<ulink url="kdeapi:tdeio/KRun.html">KRun</ulink>:
|
|
</para>
|
|
|
|
<programlisting>
|
|
KURL::List urlList;
|
|
urlList << "http://www.ietf.org/rfc/rfc1341.txt?number=1341";
|
|
urlList << "http://www.ietf.org/rfc/rfc2046.txt?number=2046";
|
|
KRun::run(offer.service(), urlList);
|
|
</programlisting>
|
|
|
|
</simplesect>
|
|
|
|
|
|
<simplesect id="mime-misc">
|
|
<title>Miscellaneous</title>
|
|
|
|
<para>
|
|
In this section, we want to list some APIs which are loosely related
|
|
to the previous discussion.
|
|
</para>
|
|
|
|
<para>
|
|
Getting an icon for a URL. This looks for the type of the URL
|
|
and returns the associated icon.
|
|
</para>
|
|
|
|
<programlisting>
|
|
KURL url("ftp://ftp.kde.org/pub/incoming/wibble.c");
|
|
QString icon = KMimeType::iconForURL(url);
|
|
</programlisting>
|
|
|
|
<para>
|
|
Running a URL. This looks for the type of the URL and starts the
|
|
user's preferred program associated with this type.
|
|
</para>
|
|
|
|
<programlisting>
|
|
KURL url("http://dot.kde.org");
|
|
new KRun(url);
|
|
</programlisting>
|
|
|
|
</simplesect>
|
|
|
|
</sect1>
|
|
|
|
|
|
<sect1 id="nettransparency">
|
|
<title>Network transparency</title>
|
|
|
|
<simplesect id="nettransparency-intro">
|
|
<title>Introduction</title>
|
|
|
|
<para>
|
|
In the age of the world wide web, it is of essential importance that desktop
|
|
applications can access resources over the internet: they should be able to
|
|
download files from a web server, write files to an ftp server or read mails
|
|
from a web server. Often, the ability to access files regardless of their
|
|
location is called <emphasis>network transparency</emphasis>.
|
|
</para>
|
|
|
|
<para>
|
|
In the past, different approaches to this goals were implemented. The old NFS
|
|
file system is an attempt to implement network transparency on the level of
|
|
the POSIX API. While this approach works quite well in local, closely coupled
|
|
networks, it does not scale for resources to which access is unreliable and
|
|
possibly slow. Here, <emphasis>asynchronicity</emphasis> is important. While
|
|
you are waiting for your web browser to download a page, the user interface
|
|
should not block. Also, the page rendering should not begin when the page is
|
|
completely available, but should updated regularly as data comes in.
|
|
</para>
|
|
|
|
<para>
|
|
In the KDE libraries, network transparency is implemented in the TDEIO API. The
|
|
central concept of this architecture is an IO <emphasis>job</emphasis>. A job
|
|
may copy, or delete files or similar things. Once a job is started, it works
|
|
in the background and does not block the application. Any communication from
|
|
the job back to the application - like delivering data or progress information
|
|
- is done integrated with the Qt event loop.
|
|
</para>
|
|
|
|
<para>
|
|
Background operation is achieved by starting <emphasis>ioslaves</emphasis> to
|
|
perform certain tasks. ioslaves are started as separate processes and are
|
|
communicated with through UNIX domain sockets. In this way, no multi-threading
|
|
is necessary and unstable slaves can not crash the application that uses them.
|
|
</para>
|
|
|
|
<para>
|
|
File locations are expressed by the widely used URLs. But in KDE, URLs do not
|
|
only expand the range of addressable files beyond the local file system. It
|
|
also goes in the opposite direction - e.g. you can browse into tar archives.
|
|
This is achieved by nesting URLs. For example, a file in a tar archive on
|
|
a http server could have the URL
|
|
</para>
|
|
|
|
<programlisting>
|
|
http://www-com.physik.hu-berlin.de/~bernd/article.tgz#tar:/paper.tex
|
|
</programlisting>
|
|
|
|
</simplesect>
|
|
|
|
|
|
<simplesect id="nettransparency-usingkio">
|
|
<title>Using TDEIO</title>
|
|
|
|
<para>
|
|
In most cases, jobs are created by calling functions in the TDEIO namespace.
|
|
These functions take one or two URLs as arguments, and possible other
|
|
necessary parameters. When the job is finished, it emits the signal
|
|
<literal>result(TDEIO::Job*)</literal>. After this signal has been emitted, the job
|
|
deletes itself. Thus, a typical use case will look like this:
|
|
</para>
|
|
|
|
<programlisting>
|
|
void FooClass::makeDirectory()
|
|
{
|
|
SimpleJob *job = TDEIO::mkdir(KURL("file:/home/bernd/tdeiodir"));
|
|
connect( job, SIGNAL(result(TDEIO::Job*)),
|
|
this, SLOT(mkdirResult(TDEIO::Job*)) );
|
|
}
|
|
|
|
void FooClass::mkdirResult(TDEIO::Job *job)
|
|
{
|
|
if (job->error())
|
|
job->showErrorDialog();
|
|
else
|
|
cout << "mkdir went fine" << endl;
|
|
}
|
|
</programlisting>
|
|
|
|
<para>
|
|
Depending on the type of the job, you may connect also to other
|
|
signals.
|
|
</para>
|
|
|
|
<para>
|
|
Here is an overview over the possible functions:
|
|
</para>
|
|
|
|
<variablelist>
|
|
|
|
<varlistentry><term>TDEIO::mkdir(const KURL &url, int permission)</term>
|
|
<listitem><para>
|
|
Creates a directory, optionally with certain permissions.
|
|
</para></listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry><term>TDEIO::rmdir(const KURL &url)</term>
|
|
<listitem><para>
|
|
Removes a directory.
|
|
</para></listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry><term>TDEIO::chmod(const KURL &url, int permissions)</term>
|
|
<listitem><para>
|
|
Changes the permissions of a file.
|
|
</para></listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry><term>TDEIO::rename(const KURL &src, const KURL &dest,
|
|
bool overwrite)</term>
|
|
<listitem><para>
|
|
Renames a file.
|
|
</para></listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry><term>TDEIO::symlink(const QString &target, const KURL &dest,
|
|
bool overwrite, bool showProgressInfo)</term>
|
|
<listitem><para>
|
|
Creates a symbolic link.
|
|
</para></listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry><term>TDEIO::stat(const KURL &url, bool showProgressInfo)</term>
|
|
<listitem><para>
|
|
Finds out certain information about the file, such as size, modification
|
|
time and permissions. The information can be obtained from
|
|
TDEIO::StatJob::statResult() after the job has finished.
|
|
</para></listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry><term>TDEIO::get(const KURL &url, bool reload, bool showProgressInfo)</term>
|
|
<listitem><para>
|
|
Transfers data from a URL.
|
|
</para></listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry><term>TDEIO::put(const KURL &url, int permissions, bool overwrite,
|
|
bool resume, bool showProgressInfo)</term>
|
|
<listitem><para>
|
|
Transfers data to a URL.
|
|
</para></listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry><term>TDEIO::http_post(const KURL &url, const QByteArray &data,
|
|
bool showProgressInfo)</term>
|
|
<listitem><para>Posts data. Special for HTTP.
|
|
</para></listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry><term>TDEIO::mimetype(const KURL &url, bool showProgressInfo)</term>
|
|
<listitem><para>
|
|
Tries to find the MIME type of the URL. The type can be obtained from
|
|
TDEIO::MimetypeJob::mimetype() after the job has finished.
|
|
</para></listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry><term>TDEIO::file_copy(const KURL &src, const KURL &dest, int permissions,
|
|
bool overwrite, bool resume, bool showProgressInfo)</term>
|
|
<listitem><para>
|
|
Copies a single file.
|
|
</para></listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry><term>TDEIO::file_move(const KURL &src, const KURL &dest, int permissions,
|
|
bool overwrite, bool resume, bool showProgressInfo)</term>
|
|
<listitem><para>
|
|
Renames or moves a single file.
|
|
</para></listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry><term>TDEIO::file_delete(const KURL &url, bool showProgressInfo)</term>
|
|
<listitem><para>
|
|
Deletes a single file.
|
|
</para></listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry><term>TDEIO::listDir(const KURL &url, bool showProgressInfo)</term>
|
|
<listitem><para>
|
|
Lists the contents of a directory. Each time some new entries are known, the
|
|
signal TDEIO::ListJob::entries() is emitted.
|
|
</para></listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry><term>TDEIO::listRecursive(const KURL &url, bool showProgressInfo)</term>
|
|
<listitem><para>
|
|
Similar to the listDir() function, but this one is recursive.
|
|
</para></listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry><term>TDEIO::copy(const KURL &src, const KURL &dest, bool showProgressInfo)</term>
|
|
<listitem><para>
|
|
Copies a file or directory. Directories are copied recursively.
|
|
</para></listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry><term>TDEIO::move(const KURL &src, const KURL &dest, bool showProgressInfo)</term>
|
|
<listitem><para>
|
|
Moves or renames a file or directory.
|
|
</para></listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry><term>TDEIO::del(const KURL &src, bool shred, bool showProgressInfo)</term>
|
|
<listitem><para>
|
|
Deletes a file or directory.
|
|
</para></listitem>
|
|
</varlistentry>
|
|
|
|
</variablelist>
|
|
|
|
</simplesect>
|
|
|
|
|
|
<simplesect id="nettransparency-direntries">
|
|
<title>Directory entries</title>
|
|
|
|
<para>
|
|
Both the TDEIO::stat() and TDEIO::listDir() jobs return their results as a type
|
|
UDSEntry, UDSEntryList resp. The latter is defined as QValueList<UDSEntry>.
|
|
The acronym UDS stands for "Universal directory service". The principle behind
|
|
it is that the a directory entry only carries the information which an ioslave
|
|
can provide, not more. For example, the http slave does not provide any
|
|
information about access permissions or file owners.
|
|
Instead, a UDSEntry is a list of UDSAtoms. Each atom provides a specific piece
|
|
of information. It consists of a type stored in m_uds and either an integer
|
|
value in m_long or a string value in m_str, depending on the type.
|
|
</para>
|
|
|
|
<para>
|
|
The following types are currently defined:
|
|
</para>
|
|
|
|
<itemizedlist>
|
|
|
|
<listitem><para>
|
|
UDS_SIZE (integer) - Size of the file.
|
|
</para></listitem>
|
|
|
|
<listitem><para>
|
|
UDS_USER (string) - User owning the file.
|
|
</para></listitem>
|
|
|
|
<listitem><para>
|
|
UDS_GROUP (string) - Group owning the file.
|
|
</para></listitem>
|
|
|
|
<listitem><para>
|
|
UDS_NAME (string) - File name.
|
|
</para></listitem>
|
|
|
|
<listitem><para>
|
|
UDS_ACCESS (integer) - Permission rights of the file, as e.g. stored
|
|
by the libc function stat() in the st_mode field.
|
|
</para></listitem>
|
|
|
|
<listitem><para>
|
|
UDS_FILE_TYPE (integer) - The file type, as e.g. stored by stat() in the
|
|
st_mode field. Therefore you can use the usual libc macros like S_ISDIR to
|
|
test this value. Note that the data provided by ioslaves corresponds to
|
|
stat(), not lstat(), i.e. in case of symbolic links, the file type here is
|
|
the type of the file pointed to by the link, not the link itself.
|
|
</para></listitem>
|
|
|
|
<listitem><para>
|
|
UDS_LINK_DEST (string) - In case of a symbolic link, the name of the file
|
|
pointed to.
|
|
</para></listitem>
|
|
|
|
<listitem><para>
|
|
UDS_MODIFICATION_TIME (integer) - The time (as in the type time_t) when the
|
|
file was last modified, as e.g. stored by stat() in the st_mtime field.
|
|
</para></listitem>
|
|
|
|
<listitem><para>
|
|
UDS_ACCESS_TIME (integer) - The time when the file was last accessed, as
|
|
e.g. stored by stat() in the st_atime field.
|
|
</para></listitem>
|
|
|
|
<listitem><para>
|
|
UDS_CREATION_TIME (integer) - The time when the file was created, as e.g.
|
|
stored by stat() in the st_ctime field.
|
|
</para></listitem>
|
|
|
|
<listitem><para>
|
|
UDS_URL (string) - Provides a URL of a file, if it is not simply the
|
|
the concatenation of directory URL and file name.
|
|
</para></listitem>
|
|
|
|
<listitem><para>
|
|
UDS_MIME_TYPE (string) - MIME type of the file
|
|
</para></listitem>
|
|
|
|
<listitem><para>
|
|
UDS_GUESSED_MIME_TYPE (string) - MIME type of the file as guessed by the
|
|
slave. The difference to the previous type is that the one provided here
|
|
should not be taken as reliable (because determining it in a reliable way
|
|
would be too expensive). For example, the KRun class explicitly checks the
|
|
MIME type if it does not have reliable information.
|
|
</para></listitem>
|
|
|
|
</itemizedlist>
|
|
|
|
<para>
|
|
Although the way of storing information about files in a
|
|
<classname>UDSEntry</classname> is flexible and practical from the ioslave
|
|
point of view, it is a mess to use for the application programmer. For
|
|
example, in order to find out the MIME type of the file, you have to iterate
|
|
over all atoms and test whether <literal>m_uds</literal> is
|
|
<literal>UDS_MIME_TYPE</literal>. Fortunately, there is an API which is a lot
|
|
easier to use: the class <classname>KFileItem</classname>.
|
|
</para>
|
|
|
|
</simplesect>
|
|
|
|
|
|
<simplesect id="nettransparency-syncuse">
|
|
<title>Synchronous usage</title>
|
|
|
|
<para>
|
|
Often, the asynchronous API of TDEIO is too complex to use and therefore
|
|
implementing full asynchronicity is not a priority. For example, in a program
|
|
that can only handle one document file at a time, there is little that can be
|
|
done while the program is downloading a file anyway. For these simple cases,
|
|
there is a mucher simpler API in the form of a set of static functions in
|
|
TDEIO::NetAccess. For example, in order to copy a file, use
|
|
</para>
|
|
|
|
<programlisting>
|
|
KURL source, target;
|
|
source = ...;
|
|
target = ...
|
|
TDEIO::NetAccess::copy(source, target);
|
|
</programlisting>
|
|
|
|
<para>
|
|
The function will return after the complete copying process has finished. Still,
|
|
this method provides a progress dialog, and it makes sure that the application
|
|
processes repaint events.
|
|
</para>
|
|
|
|
<para>
|
|
A particularly interesting combination of functions is
|
|
<function>download()</function> in combination with
|
|
<function>removeTempFile()</function>. The former downloads a file from given
|
|
URL and stores it in a temporary file with a unique name. The name is stored
|
|
in the second argument. <emphasis>If</emphasis> the URL is local, the file is
|
|
not downloaded, and instead the second argument is set to the local file
|
|
name. The function <function>removeTempFile()</function> deletes the file
|
|
given by its argument if the file is the result of a former download. If that
|
|
is not the case, it does nothing. Thus, a very easy to use way of loading
|
|
files regardless of their location is the following code snippet:
|
|
</para>
|
|
|
|
<programlisting>
|
|
KURL url;
|
|
url = ...;
|
|
QString tempFile;
|
|
if (TDEIO::NetAccess::download(url, tempFile) {
|
|
// load the file with the name tempFile
|
|
TDEIO::NetAccess::removeTempFile(tempFile);
|
|
}
|
|
</programlisting>
|
|
|
|
</simplesect>
|
|
|
|
|
|
<simplesect id="nettransparency-metadata">
|
|
<title>Meta data</title>
|
|
|
|
<para>
|
|
As can be seen above, the interface to IO jobs is quite abstract and does not
|
|
consider any exchange of information between application and IO slave that
|
|
is protocol specific. This is not always appropriate. For example, you may give
|
|
certain parameters to the HTTP slave to control its caching behavior or
|
|
send a bunch of cookies with the request. For this need, the concept of meta
|
|
data has been introduced. When a job is created, you can configure it by adding
|
|
meta data to it. Each item of meta data consists of a key/value pair. For
|
|
example, in order to prevent the HTTP slave from loading a web page from its
|
|
cache, you can use:
|
|
</para>
|
|
|
|
<programlisting>
|
|
void FooClass::reloadPage()
|
|
{
|
|
KURL url("http://www.kdevelop.org/index.html");
|
|
TDEIO::TransferJob *job = TDEIO::get(url, true, false);
|
|
job->addMetaData("cache", "reload");
|
|
...
|
|
}
|
|
</programlisting>
|
|
|
|
<para>
|
|
The same technique is used in the other direction, i.e. for communication from
|
|
the slave to the application. The method
|
|
<function>Job::queryMetaData()</function> asks for the value of the certain
|
|
key delivered by the slave. For the HTTP slave, one such example is the key
|
|
<literal>"modified"</literal>, which contains a (stringified representation of)
|
|
the date when the web page was last modified. An example how you can use this
|
|
is the following:
|
|
</para>
|
|
|
|
<programlisting>
|
|
void FooClass::printModifiedDate()
|
|
{
|
|
KURL url("http://developer.kde.org/documentation/kde2arch/index.html");
|
|
TDEIO::TransferJob *job = TDEIO::get(url, true, false);
|
|
connect( job, SIGNAL(result(TDEIO::Job*)),
|
|
this, SLOT(transferResult(TDEIO::Job*)) );
|
|
}
|
|
|
|
void FooClass::transferResult(TDEIO::Job *job)
|
|
{
|
|
QString mimetype;
|
|
if (job->error())
|
|
job->showErrorDialog();
|
|
else {
|
|
TDEIO::TransferJob *transferJob = (TDEIO::TransferJob*) job;
|
|
QString modified = transferJob->queryMetaData("modified");
|
|
cout << "Last modified: " << modified << endl;
|
|
}
|
|
</programlisting>
|
|
|
|
</simplesect>
|
|
|
|
|
|
<simplesect id="nettransparency-scheduling">
|
|
<title>Scheduling</title>
|
|
|
|
<para>
|
|
When using the TDEIO API, you usually do not have to cope with the details of
|
|
starting IO slaves and communicating with them. The normal use case is to
|
|
start a job and with some parameters and handle the signals the jobs emits.
|
|
</para>
|
|
|
|
<para>
|
|
Behind the curtains, the scenario is a lot more complicated. When you create a
|
|
job, it is put in a queue. When the application goes back to the event loop,
|
|
TDEIO allocates slave processes for the jobs in the queue. For the first jobs
|
|
started, this is trivial: an IO slave for the appropriate protocol is started.
|
|
However, after the job (like a download from an http server) has finished, it
|
|
is not immediately killed. Instead, it is put in a pool of idle slaves and
|
|
killed after a certain time of inactivity (current 3 minutes). If a new request
|
|
for the same protocol and host arrives, the slave is reused. The obvious
|
|
advantage is that for a series of jobs for the same host, the cost for creating
|
|
new processes and possibly going through an authentication handshake is saved.
|
|
</para>
|
|
|
|
<para>
|
|
Of course, reusing is only possible when the existing slave has already finished
|
|
its previous job. when a new request arrives while an existing slave process is
|
|
still running, a new process must be started and used. In the API usage in the
|
|
examples above, there are no limitation for creating new slave processes: if you
|
|
start a consecutive series of downloads for 20 different files, then TDEIO will
|
|
start 20 slave processes. This scheme of assigning slaves to jobs is called
|
|
<emphasis>direct</emphasis>. It not always the most appropriate scheme, as it
|
|
may need much memory and put a high load on both the client and server machines.
|
|
</para>
|
|
|
|
<para>
|
|
So there is a different way. You can <emphasis>schedule</emphasis> jobs. If
|
|
you do this, only a limited number (currently 3) of slave processes for a
|
|
protocol will be created. If you create more jobs than that, they are put in a
|
|
queue and are processed when a slave process becomes idle. This is done as
|
|
follows:
|
|
</para>
|
|
|
|
<programlisting>
|
|
KURL url("http://developer.kde.org/documentation/kde2arch/index.html");
|
|
TDEIO::TransferJob *job = TDEIO::get(url, true, false);
|
|
TDEIO::Scheduler::scheduleJob(job);
|
|
</programlisting>
|
|
|
|
<para>
|
|
A third possibility is <emphasis>connection oriented</emphasis>. For example,
|
|
for the IMAP slave, it does not make any sense to start multiple processes for
|
|
the same server. Only one IMAP connection at a time should be enforced. In
|
|
this case, the application must explicitly deal with the notion of a slave. It
|
|
has to deallocate a slave for a certain connection and then assign all jobs
|
|
which should go through the same connection to the same slave. This can again
|
|
be easily achieved by using the TDEIO::Scheduler:
|
|
</para>
|
|
|
|
<programlisting>
|
|
KURL baseUrl("imap://bernd@albert.physik.hu-berlin.de");
|
|
TDEIO::Slave *slave = TDEIO::Scheduler::getConnectedSlave(baseUrl);
|
|
|
|
TDEIO::TransferJob *job1 = TDEIO::get(KURL(baseUrl, "/INBOX;UID=79374"));
|
|
TDEIO::Scheduler::assignJobToSlave(slave, job1);
|
|
|
|
TDEIO::TransferJob *job2 = TDEIO::get(KURL(baseUrl, "/INBOX;UID=86793"));
|
|
TDEIO::Scheduler::assignJobToSlave(slave, job2);
|
|
|
|
...
|
|
|
|
TDEIO::Scheduler::disconnectSlave(slave);
|
|
</programlisting>
|
|
|
|
<para>
|
|
You may only disconnect the slave after all jobs assigned to it are guaranteed
|
|
to be finished.
|
|
</para>
|
|
|
|
</simplesect>
|
|
|
|
|
|
<simplesect id="nettransparency-definingslaves">
|
|
<title>Defining an ioslave</title>
|
|
|
|
<para>
|
|
In the following we discuss how you can add a new ioslave to the system.
|
|
In analogy to services, new ioslaves are advertised to the system by
|
|
installing a little configuration file. The following Makefile.am
|
|
snippet installs the ftp protocol:
|
|
</para>
|
|
|
|
<programlisting>
|
|
protocoldir = $(kde_servicesdir)
|
|
protocol_DATA = ftp.protocol
|
|
EXTRA_DIST = $(mime_DATA)
|
|
</programlisting>
|
|
|
|
<para>
|
|
The contents of the file ftp.protocol is as follows:
|
|
</para>
|
|
|
|
<programlisting>
|
|
[Protocol]
|
|
exec=tdeio_ftp
|
|
protocol=ftp
|
|
input=none
|
|
output=filesystem
|
|
listing=Name,Type,Size,Date,Access,Owner,Group,Link,
|
|
reading=true
|
|
writing=true
|
|
makedir=true
|
|
deleting=true
|
|
Icon=ftp
|
|
</programlisting>
|
|
|
|
<para>
|
|
The <literal>"protocol"</literal> entry defines for which protocol this slave
|
|
is responsible. <literal>"exec"</literal> is (in contrast what you would
|
|
expect naively) the name of the library that implements the slave. When the
|
|
slave is supposed to start, the <command>"tdeinit"</command> executable is
|
|
started which in turn loads this library into its address space. So in
|
|
practice, you can think of the running slave as a separate process although it
|
|
is implemented as library. The advantage of this mechanism is that it saves a
|
|
lot of memory and reduces the time needed by the runtime linker.
|
|
</para>
|
|
|
|
<para>
|
|
The "input" and "output" lines are not used currently.
|
|
</para>
|
|
|
|
<para>
|
|
The remaining lines in the <literal>.protocol</literal> file define which
|
|
abilities the slave has. In general, the features a slave must implement are
|
|
much simpler than the features the TDEIO API provides for the application. The
|
|
reason for this is that complex jobs are scheduled to a couple of subjobs. For
|
|
example, in order to list a directory recursively, one job will be started for
|
|
the toplevel directory. Then for each subdirectory reported back, new subjobs
|
|
are started. A scheduler in TDEIO makes sure that not too many jobs are active
|
|
at the same time. Similarly, in order to copy a file within a protocol that
|
|
does not support copying directly (like the <literal>ftp:</literal> protocol),
|
|
TDEIO can read the source file and then write the data to the destination
|
|
file. For this to work, the <literal>.protocol</literal> must advertise the
|
|
actions its slave supports.
|
|
</para>
|
|
|
|
<para>
|
|
Since slaves are loaded as shared libraries, but constitute standalone programs,
|
|
their code framework looks a bit different from normal shared library plugins.
|
|
The function which is called to start the slave is called
|
|
<function>kdemain()</function>. This function does some initializations and
|
|
then goes into an event loop and waits for requests by the application using
|
|
it. This looks as follows:
|
|
</para>
|
|
|
|
<programlisting>
|
|
extern "C" { int kdemain(int argc, char **argv); }
|
|
|
|
int kdemain(int argc, char **argv)
|
|
{
|
|
TDELocale::setMainCatalogue("tdelibs");
|
|
TDEInstance instance("tdeio_ftp");
|
|
(void) TDEGlobal::locale();
|
|
|
|
if (argc != 4) {
|
|
fprintf(stderr, "Usage: tdeio_ftp protocol "
|
|
"domain-socket1 domain-socket2\n");
|
|
exit(-1);
|
|
}
|
|
|
|
FtpSlave slave(argv[2], argv[3]);
|
|
slave.dispatchLoop();
|
|
return 0;
|
|
}
|
|
</programlisting>
|
|
|
|
</simplesect>
|
|
|
|
|
|
<simplesect id="nettransparency-implementingslaves">
|
|
<title>Implementing an ioslave</title>
|
|
|
|
<para>
|
|
Slaves are implemented as subclasses of <classname>TDEIO::SlaveBase</classname>
|
|
(FtpSlave in the above example). Thus, the actions listed in the
|
|
<literal>.protocol</literal> correspond to certain virtual functions in
|
|
<classname>TDEIO::SlaveBase</classname> the slave implementation must
|
|
reimplement. Here is a list of possible actions and the corresponding virtual
|
|
functions:
|
|
</para>
|
|
|
|
<variablelist>
|
|
|
|
<varlistentry><term>reading - Reads data from a URL</term>
|
|
<listitem><para>void get(const KURL &url)</para></listitem></varlistentry>
|
|
|
|
<varlistentry><term>writing - Writes data to a URL and create the file if it does not exist yet.</term>
|
|
<listitem><para>void put(const KURL &url, int permissions, bool overwrite, bool resume)</para></listitem></varlistentry>
|
|
|
|
<varlistentry><term>moving - Renames a file.</term>
|
|
<listitem><para>void rename(const KURL &src, const KURL &dest, bool overwrite)</para></listitem></varlistentry>
|
|
|
|
<varlistentry><term>deleting - Deletes a file or directory.</term>
|
|
<listitem><para>void del(const KURL &url, bool isFile)</para></listitem></varlistentry>
|
|
|
|
<varlistentry><term>listing - Lists the contents of a directory.</term>
|
|
<listitem><para>void listDir(const KURL &url)</para></listitem></varlistentry>
|
|
|
|
<varlistentry><term>makedir - Creates a directory.</term>
|
|
<listitem><para>void mkdir(const KURL &url, int permissions)</para></listitem></varlistentry>
|
|
|
|
</variablelist>
|
|
|
|
<para>
|
|
Additionally, there are reimplementable functions not listed in the <literal>.protocol</literal>
|
|
file. For these operations, TDEIO automatically determines whether they are supported
|
|
or not (i.e. the default implementation returns an error).
|
|
</para>
|
|
|
|
<variablelist>
|
|
|
|
<varlistentry><term>Delivers information about a file, similar to the C function stat().</term>
|
|
<listitem><para>void stat(const KURL &url)</para></listitem></varlistentry>
|
|
|
|
<varlistentry><term>Changes the access permissions of a file.</term>
|
|
<listitem><para>void chmod(const KURL &url, int permissions)</para></listitem></varlistentry>
|
|
|
|
<varlistentry><term>Determines the MIME type of a file.</term>
|
|
<listitem><para>void mimetype(const KURL &url)</para></listitem></varlistentry>
|
|
|
|
<varlistentry><term>Copies a file.</term>
|
|
<listitem><para>copy(const KURL &url, const KURL &dest, int permissions, bool overwrite)</para></listitem></varlistentry>
|
|
|
|
<varlistentry><term>Creates a symbolic link.</term>
|
|
<listitem><para>void symlink(const QString &target, const KURL &dest, bool overwrite)</para></listitem></varlistentry>
|
|
|
|
</variablelist>
|
|
|
|
<para>
|
|
All these implementation should end with one of two calls: If the operation
|
|
was successful, they should call <literal>finished()</literal>. If an error has occurred,
|
|
<literal>error()</literal> should be called with an error code as first argument and a
|
|
string in the second. Possible error codes are listed as enum
|
|
<type>TDEIO::Error</type>. The second argument is usually the URL in
|
|
question. It is used e.g. in <function>TDEIO::Job::showErrorDialog()</function>
|
|
in order to parameterize the human-readable error message.
|
|
</para>
|
|
|
|
<para>
|
|
For slaves that correspond to network protocols, it might be interesting to
|
|
reimplement the method <function>SlaveBase::setHost()</function>. This is
|
|
called to tell the slave process about the host and port, and the user name
|
|
and password to log in. In general, meta data set by the application can be
|
|
queried by <function>SlaveBase::metaData()</function>. You can check for the
|
|
existence of meta data of a certain key with
|
|
<function>SlaveBase::hasMetaData()</function>.
|
|
</para>
|
|
|
|
</simplesect>
|
|
|
|
|
|
<simplesect id="nettransparency-communication">
|
|
<title>Communicating back to the application</title>
|
|
|
|
<para>
|
|
Various actions implemented in a slave need some way to communicate data back
|
|
to the application using the slave process:
|
|
</para>
|
|
|
|
<itemizedlist>
|
|
|
|
<listitem><para>
|
|
<function>get()</function> sends blocks of data. This is done with
|
|
<function>data()</function>, which takes a <classname>QByteArray</classname>
|
|
as argument. Of course, you do not need to send all data at once. If you send
|
|
a large file, call <function>data()</function> with smaller data blocks, so
|
|
the application can process them. Call <function>finished()</function> when
|
|
the transfer is finished.
|
|
</para></listitem>
|
|
|
|
<listitem><para>
|
|
<function>listDir()</function> reports information about the entries of a
|
|
directory. For this purpose, call <function>listEntries()</function> with a
|
|
<classname>TDEIO::UDSEntryList</classname> as argument. Analogously to
|
|
<function>data()</function>, you can call this several times. When you are
|
|
finished, call <function>listEntry()</function> with the second argument set
|
|
to true. You may also call <function>totalSize()</function> to report the
|
|
total number of directory entries, if known.
|
|
</para></listitem>
|
|
|
|
<listitem><para>
|
|
<function>stat()</function> reports information about a file like size, MIME
|
|
type, etc. Such information is packaged in a
|
|
<classname>TDEIO::UDSEntry</classname>, which will be discussed below. Use
|
|
<function>statEntry()</function> to send such an item to the application.
|
|
</para></listitem>
|
|
|
|
<listitem><para>
|
|
<function>mimetype()</function> calls <function>mimeType()</function> with a
|
|
string argument.
|
|
</para></listitem>
|
|
|
|
<listitem><para>
|
|
<function>get()</function> and <function>copy()</function> may want to provide
|
|
progress information. This is done with the methods
|
|
<function>totalSize()</function>, <function>processedSize()</function>,
|
|
<function>speed()</function>. The total size and processed size are reported
|
|
as bytes, the speed as bytes per second.
|
|
</para></listitem>
|
|
|
|
<listitem><para>
|
|
You can send arbitrary key/value pairs of meta data with
|
|
<function>setMetaData()</function>.
|
|
</para></listitem>
|
|
|
|
</itemizedlist>
|
|
|
|
</simplesect>
|
|
|
|
|
|
<simplesect id="nettransparency-interacting">
|
|
<title>Interacting with the user</title>
|
|
|
|
<para>
|
|
Sometimes a slave has to interact with the user. Examples include informational
|
|
messages, authentication dialogs and confirmation dialogs when a file is about
|
|
to be overwritten.
|
|
</para>
|
|
|
|
<itemizedlist>
|
|
|
|
<listitem><para>
|
|
<function>infoMessage()</function> - This is for informational feedback, such
|
|
as the message "Retrieving data from <host>" from the http slave, which
|
|
is often displayed in the status bar of the program. On the application side,
|
|
this method corresponds to the signal
|
|
<function>TDEIO::Job::infoMessage()</function>.
|
|
</para></listitem>
|
|
|
|
<listitem><para>
|
|
<function>warning()</function> - Displays a warning in a message box with
|
|
<function>KMessageBox::information()</function>. If a message box is still
|
|
open from a former call of warning() from the same slave process, nothing
|
|
happens.
|
|
</para></listitem>
|
|
|
|
<listitem><para>
|
|
<function>messageBox()</function> - This is richer than the previous
|
|
method. It allows to open a message box with text and caption and some
|
|
buttons. See the enum <type>SlaveBase::MessageBoxType</type> for reference.
|
|
</para></listitem>
|
|
|
|
<listitem><para>
|
|
<function>openPassDlg()</function> - Opens a dialog for the input of user name
|
|
and password.
|
|
</para></listitem>
|
|
|
|
</itemizedlist>
|
|
|
|
</simplesect>
|
|
|
|
</sect1>
|
|
|
|
</chapter>
|
|
|
|
|
|
|
|
<appendix id="misc">
|
|
<title>Licensing</title>
|
|
|
|
&underFDL;
|
|
&underGPL;
|
|
|
|
</appendix>
|
|
|
|
</book>
|