1
<section id="ctrl-write" xmlns:xi="http://www.w3.org/2001/XInclude">
2
<title>Writing Controls</title>
4
<section><title>Important Rules!</title>
6
<para>Before you start publishing controls, please thoroughly read these
7
rules. They make both your and the users' lives easier.</para>
10
<listitem>Before writing a new control, please check if the functionality
11
you need has already been implemented by somebody else. There's no point
12
in having two or more controls with different interfaces doing the same
15
<listitem>If there already is a control doing what you want, but you want
16
to make a more efficient implementation, please implement the interfaces
17
of the other control to ensure backwards compatibility.</listitem>
19
<listitem><emphasize>Never</emphasize> put applet-specific functionality
20
into a control! Controls are meant to be shared among applets.</listitem>
22
<listitem>Never publish a control without obeying rules 1 - 3!</listitem>
30
<section><title>Anatomy of Controls</title>
32
<para>Controls are Python classes derived from the <literal>Control</literal>
33
base class and from the interfaces which they implement. The base class
34
can be loaded from <literal>libdesklets.controls</literal>:</para>
37
from libdesklets.controls import Control
40
<para>Each control has its own directory, which at least consists of the
41
<filename>__init__.py</filename> file. That file initializes the control
42
and provides a function <function>get_class()</function> returning the
43
main class (not an instance of the class) of the control.</para>
45
<para>The typical directory structure of a control looks like:</para>
52
<para>The control directory has to include all interface files from which the
54
By convention, the filenames of interface files start with an
55
"<filename>I</filename>" to distinguish them from regular files.
56
The file <filename>__init__.py</filename> is also mandatory. If neccessary,
57
a control can also include other files as well, which are loaded by the
58
initialization file. You should, however, keep in mind to design controls
59
as generic as possible.</para>
64
<section><title>Deriving from Interfaces</title>
66
<para>Every control implements one or more interfaces. Since an interface
67
is a simple Python class, you just have to derive your control from the
68
interface classes:</para>
71
from libdesklets.controls import Control
72
from IMyInterface import IMyInterface
74
class MyControl(Control, IMyInterface):
78
Control.__init__(self)
84
def get_class(): return MyControl
87
<para>Because interfaces are implementation-less, there is no
88
super-constructor to invoke for them.</para>
90
<para>Always remember to derive from the <literal>Control</literal> class and
91
to invoke its constructor to get a valid control class.</para>
97
<section><title>Implementing Properties</title>
99
<para>Every property in the interfaces must be implemented by creating
100
appropriate <literal>property</literal> objects.</para>
102
<para>Python's <literal>property</literal> constructor takes four arguments,
103
of which are all optional. From the Python inline help:</para>
105
<programlisting><![CDATA[
106
property(fget=None, fset=None, fdel=None, doc=None) -> property attribute
108
# fget is a function to be used for getting an attribute value. Likewise,
109
# fset is a function for setting an attribute and fdel is a function for
110
# deleting an attribute. Typical use is to define a managed attribute x:
112
def getx(self): return self.__x
113
def setx(self, value): self.__x = value
114
def delx(self): del self.__x
115
x = property(getx, setx, delx, "I'm the 'x' property.")
118
<para>The <literal>fdel</literal> argument is not needed for controls.
119
If a property is not readable, you also omit the <literal>fget</literal>
120
argument or set it to <literal>None</literal>. Likewise, for non-writable
121
properties, omit the <literal>fset</literal> argument. The read-write
122
permissions must match those
123
<link linkend="ctrl-write-interface-declare">declared by the interfaces.</link>
126
<para>The <literal>doc</literal> argument can be used for describing the
127
property in human-readable form. It is highly recommended to give a
128
useful description for every property. Doing so makes it easier for
129
others to use your control.</para>
134
<section><title>Methods of the Control Class</title>
136
<para>The <literal>Control</literal> class provides you with all you need for
137
writing compliant controls. The following methods can be used inside
140
<informaltable frame="topbot">
145
<entry>Method Name</entry>
146
<entry>Arguments</entry>
147
<entry>Description</entry>
153
<entry valign="top">__init__</entry>
154
<entry valign="top"></entry>
155
<entry valign="top">The constructor of the <literal>Control</literal>.
156
This always has to be called as the super-constructor within the
160
<entry valign="top">_add_timer</entry>
162
<para>interval: integer</para>
163
<para>callback: function</para>
166
<entry valign="top">This is a convenience function for adding a timeout
167
handler which gets called after <literal>interval</literal> milliseconds.
168
If the <literal>callback</literal> function returns
169
<literal>True</literal>, the callback will be called again after the
170
next timeout. This method returns an ID which can be used with
171
<function>_remove_timer()</function> to remove the timer again.</entry>
174
<entry valign="top">_remove_timer</entry>
176
<para>ident: integer</para>
178
<entry valign="top">Removes the timer with the given ID
179
<literal>ident</literal>.</entry>
182
<entry valign="top">_shutdown</entry>
183
<entry valign="top"></entry>
184
<entry valign="top">This is a hook method which can be overridden in
185
order to perform cleanup operations before the control is being closed.
189
<entry valign="top">_update</entry>
191
<para>prop: string</para>
193
<entry valign="top">Notifies observers of property <literal>prop</literal>
194
that the value has changed. You have to call this method whenever
195
a property which is watchable using
196
<link linkend="ctrl-use-watch"><function>bind()</function></link>
198
Of course it does not make sense for all properties to be watchable.
199
Always call this method <emphasize>after</emphasize> the change has
200
actually taken place.</entry>