~vcs-imports/kupfer/master-new

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
======
kupfer
======

:Author: Ulrik Sverdrup
:Date: Sunday,  1 November 2009
:Revision: $Id$
:Homepage: http://kaizer.se/wiki/kupfer

.. contents::

Kupfer internals
================

Building blocks
---------------

Kupfer's architecture is built around objects that can be acted on by
actions. Kupfer's basic concept for understanding objects is in
``kupfer/obj/base.py``. The basic building block is ``KupferObject``.

Further built-in objects are defined in all of the ``kupfer/obj``
package, most importantly in ``kupfer/obj/objects.py``.

.. note::

    This document is a Work in progress.

    If you have questions, just email them away directly to me.


KupferObject
............

base class for basic user-visible constructs, this defines:

* A way to get the object's name
* A way to get the object's description
* A way to get the object's icon

This is the base object for the following four very important base
classes:

* Leaf
* Action
* Source
* TextSource

Below follows a summary. For complete information, you should read
kupfer's python interface documentation: go to the directory containing
the kupfer module and do::

    $ pydoc2.6 kupfer.obj.base

or equivalently::

    >>> import kupfer.obj.base
    >>> help(kupfer.obj.base.KupferObject)
    >>> help(kupfer.obj.base)

Leaf
....

A Leaf represents an object that the user will want to summon and
act on. An example is a file, an application, a window or a Free-text
query (TextLeaf).

This defines, in addition to KupferObject:

``Leaf.object``
    ``Leaf.object`` is the represented object, which is the
    implementation-specific internal data.

``get_actions()``
    Returns the *builtin* Actions for a Leaf; builtin Actions are such
    that do not apply generally, but only to Leaves defined in a
    particular module or Plugin.

``__hash__`` and ``__eq__``
    Leaves are hashable, can be members in a set, and duplicates are
    recognized (and removed); this is essensial so that equivalent
    Leaves from different sources are recognized. By default duplicates
    are recognized if both the name and the ``Leaf.object`` property are
    the same.

``has_content()`` and ``content_source()``
    These methods are used to find out if the object contain anything,
    like a folder contains files or a music album songs.

Action
......

An Action represents a command using a direct object and an optional
indirect object. One example is ``kupfer.obj.fileactions.Open`` that
will open its direct object (which must be a file), with its default
viewer.

Actions are the most versatile parts of Kupfer, since they can define
ways to use objects together. They also have to decide, which types of
Leaves they apply to, and if they apply to a given Leaf.

Action defines, in addition to KupferObject:

``activate(leaf, obj)``
    Called to perform its effect on a Leaf, where ``obj`` is the
    (optional) indirect object.

``item_types()``
    This method returns all the types of Leaves that the action
    applies to (direct object).
``valid_for_item(item)``
    Return whether action applies to ``item`` or not, which is of
    one of the types returned by ``item_type.``

``requires_object()``
    Whether this action uses an indirect object or not. If the Action
    requires an indirect object, it must also define (at least)
    ``object_types``.
``object_types()``
    Return all the types of Leaves that are valid for the action's
    indirect object.
``object_source(for_item)``
    If the action's indirect objects should not be picked from the full
    catalog, but from a defined source, return an instance of the Source
    here, else return None.
``valid_object(obj, for_item)``
    This method, if defined,  will be called for each indirect object
    (with the direct object as ``for_item``), to decide if it can be
    used.

Some auxiliary methods tell Kupfer about how to handle the action:

``is_factory()``
    If the action returns content, return a collection of new items.
``has_result()``
    If the action's return value in activate should treated as the new
    selection.
``is_async()``
    If the action returns a ``Task`` object conforming to
    ``kupfer.task.Task``. The task will be executed asynchronously in
    Kupfer's task queue.

Source
......

A Source understands specific data and delivers Leaves for it. For
example DirectorySource, that will give FileLeaves for contents of a
directory.

This defines, in addition to KupferObject:

``get_items()``
    Source subclasses should define ``get_items`` to return its items;
    the items are cached automatically until ``mark_for_update`` is
    called.
``is_dynamic()``
    Return ``True`` if the Source should not be cached. A source should
    almost never be dynamic.
``should_sort_lexically()``
    Return ``True`` if the Source's leaves should be sorted
    alphabethically. If not sorted lexically, ``get_items`` should yield
    leaves in order of the most relevant object first (for example the
    most recently used).
``provides()``
    Return a sequence of all precise Leaf types the Source may contain

``initialize()``
    Called when the source should be made ready to use. This is where it
    should register for external change callbacks, for example.

``get_leaf_repr()``
    Return a Leaf that represents the Source, if applicable; for example
    the DirectorySource is represented by a FileLeaf for the directory.
``__hash__`` and ``__eq__``
    Sources are hashable, and equivalents are recognized just like
    Leaves, and the central SourceController manages them so that there
    are no duplicates in the application.

TextSource
..........

A text source returns items for a given text string, it is much like a
simplified version of Source.

``get_text_items(text)``
    Return items for the given query.
``provides()``
    Return a sequence of the Leaf types it may contain

Strings
-------

Kupfer deals with PyGTK a lot, which always returns UTF-8-encoded
strings (almost always). However Kupfer works internally with unicode
strings; only then does slicing, lowercasing etc work across other than
ascii charsets.
Kupfer accepts UTF-8-encoded strings as well as unicode objects for the
most parts, but all internals should be unicode. Note that the gettext
function ``_()`` will return a unicode string.

Plugins
-------

A kupfer plugin is a python module with special module attributes

Here is an example from ``kupfer.plugin.applications``::

    __kupfer_name__ = _("Applications")
    __kupfer_sources__ = ("AppSource", )
    __kupfer_text_sources__ = ()
    __kupfer_actions__ = ("OpenWith", )
    __description__ = _("All applications and preferences")
    __version__ = ""
    __author__ = "Ulrik Sverdrup <ulrik.sverdrup@gmail.com>"

For a plugin, the following attributes are required::

    __kupfer_name__ (Localized name of plugin)
    __description__ (Localized description of plugin)
    __version__
    __author__

For the plugin to do anything, the following attributes may be defined::

    __kupfer_sources__ = ()
    __kupfer_text_sources__ = ()
    __kupfer_actions__ = ()

They should be tuples of *names* of classes in the module:

* all sources have to be subclasses of ``kupfer.objects.Source``
* all text sources have to be subclasses of ``kupfer.objects.TextSource``
* all actions have to be subclasses of ``kupfer.objects.Action``

The plugin should not do **anything at all** upon module load, except
loading its required modules. Load modules without try/except;
ImportErrors will be caught by the plugin loader and the plugin disabled

Look in ``contrib/`` and in ``kupfer/plugin/`` for using the existing
plugins as example

Guidelines and Policy
=====================

Contributing
------------

You can clone git from its official repository at git.gnome.org, see:

    http://git.gnome.org/browse/kupfer/

You can structure your changes into a series of commits in git. A series
of well disposed changes is easy to review. Write a sufficient commit
log message for each change. Do not fear writing down details about
why the change is implemented as it is, if there are multiple
alternatives. Also, if you forsee any future possibilites or problems,
please describe them in the commit log.

It is not easy to write good commit messgages, because writing is an
art. It is however essensial, and only by trying it, can you improve.

You may publish your changes by sending an email to the mailing list,
<kupfer-list@gnome.org>. You can attach your changes as patches, or you
may also just attach a link to your published git repository.

You can find kupfer's git repository in github.com and fork it there,
for easy publication of your changes.

If you suggest your changes for inclusion into Kupfer, make sure you
have read the whole *Guidelines and Policy* chapter of this manual. And
take care to structure your changes, do not fear asking for advice. Good
Luck!


Icon Guidelines
---------------

Consider the following:

* A Leaf is an object, a metaphor for a physical thing. It can have as
  detailed icon as is possible.

* An Action is a verb, a command that can be carried out. Choose its
  name with care. The icon should be simple, maybe assign the action
  to a category, rather than trying to illustrate the action itself.
  For example, all text display actions use the "bold style" icon, in
  some icon themes simply a bold "A".

.. important::

    Actions should have stylized, simple icons. Leaves and Sources
    should have detailed, specific icons.


Coding style
------------

Kupfer python code is indented with tabs, which is a bit uncommon. (My
editor is set to tabs of size four.) Otherwise, if you want to
contribute to kupfer keep in mind that

* Python code should be clear
* Kupfer is a simple project. Do simple first. [#simple]_

Python's general style guideline is called `PEP 8`_, and you should
programmers should read it. The advice given there is very useful when
coding for Kupfer.

.. _`PEP 8`: http://www.python.org/dev/peps/pep-0008/

.. [#simple] Writing simple code is more important than you think.
             Read your diff (changes) when you are finished writing a
             feature. Can you make it more simple to read? If you can
             make it simpler, often a more effective algorithm comes out
             of it at the same time. All optimizations have a price,
             and unless you measure the difference, abstain from
             optimizations.


Specific Points
---------------

Using ``rank_adjust``
.....................

A declaration like this can modify the ranking of an object::

    class MyAction (Action):
        rank_adjust = -5
        ...

1. Often, this is useless. Don't use it, let Kupfer learn which actions
   are important.

2. If the action is destructive, the adjust should be negative. Never
   positive. For example *Move to Trash* has a negative 10
   ``rank_adjust``.

3. If the action is very general, and applies to almost everything but
   still should never be the default for anything, the adjust should be
   negative.


Using ``super(..)``
...................

Many of kupfer plugin code uses super statements such as::

    super(RecentsSource, self).__init__(_("Recent items"))

We have learnt that it is not so practical. Therefore, when writing new
code, you should however use the following style::

    Source.__init__(self, _("Recent items"))

Why? Because the second version is easier to copy! If you copy the whole
class and rename it, which you often do to create new plugins, the
second version does not need to be updated -- you are probably using the
same superclass.


Localization
============

kupfer is translated using gettext and it is managed in the build system
using ``intltool``. Translation messages are located in the ``po/``
directory.

Kupfer's localizations are listed among GNOME's modules. Its homepage
is:

    http://l10n.gnome.org/module/kupfer/

You can download the latest version of your language's translation file
there, if Kupfer is already translated to your language.


To create a new translation
---------------------------

Go into the directory ``po``

1. Add the language code ``$LANG`` to the file ``LINGUAS``
2. Run ``intltool-update --pot``, and copy ``untitled.pot`` to ``$LANG.po``
3. Edit and check the whole file header: 

   + Write in yourself as author
   + Check ``plurals`` (copy from a language that you know uses the same
     number of plural forms, or look up in GNOME's translation pages.)
   + Replace everything written in CAPS

Fill in the charset used; Kupfer translations *must* use the UTF-8 encoding.

When the header is filled-in, go to `To update or check an existing
translation`_


To update or check an existing translation
------------------------------------------

Go to your Kupfer source directory.

Here we will call your language ``$LANG``. You should use a two or
four-letter code for your language instead of ``$LANG``, for example
"de" for German or "pt_BR" for Brazilian Portuguese.

Go to the translation directory ``po``::

    cd po/

To update and check the translation file, run::

    intltool-update $LANG

Now check and edit ``$LANG.po``. Search for all messages marked "fuzzy",
and remove the word "fuzzy" from them when they are done.

Continue running ``intltool-update $LANG`` and check that you have 0
fuzzy and 0 untranslated, then you're finished.

This will also check consistency of the file, so that you know that all
your syntax is correct.

If you want to send in the translation to a repository, or as a patch,
you can use git if you have a checked-out copy of kupfer::

    git add po/$LANG.po
    git commit -m "$LANG: Updated translation"

    # now we create a patch out of the latest change
    git format-patch HEAD^

You can send the patch, or the whole file, to the mailing list
kupfer-list@gnome.org.

To try the new translation
--------------------------

Make sure the translation is listed in ``po/LINGUAS``.

To try it, you have to install kupfer with ``./waf install``, then you
can run kupfer as normal.

.. note::

    If you run ``./kupfer-run`` from the source directory it won't
    find the installed translations unless you make a symlink called
    ``locale`` to the installed location (for example
    ``~/.local/share/locale`` if install prefix was ``~/.local``)::

        $ ln -s ~/.local/share/locale


Copyright
=========

The program Kupfer is released under the
`GNU General Public Licence v3`:t: (or at your option, any later
version). Please see the main program file for more information.

This documentation is released under the same terms as the main
program. The documentation sources are available inside the Kupfer
source distribution.

Copyright 2009, Ulrik Sverdrup <ulrik.sverdrup@gmail.com>

.. vim: ft=rst tw=72 et sts=4
.. this document best viewed with::
        rst2pdf Manual.rst && xdg-open Manual.pdf