File: PluginAPI.rst

package info (click to toggle)
kupfer 329-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 5,352 kB
  • sloc: python: 37,681; makefile: 88; sh: 78; xml: 3
file content (1069 lines) | stat: -rw-r--r-- 34,719 bytes parent folder | download | duplicates (3)
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
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
=================
Kupfer Plugin API
=================

.. contents:: :depth: 2


Introduction
============

Kupfer is a Python program that allows loading extension modules
at runtime. A plugin is equivalent to one Python module implemented
as one ``.py`` file or as a Python package.

The ``kupfer`` package is organized as follows::

    kupfer/
        obj/
        ui/
        core/
        plugin/
            core/__init__.py
            applications.py
            ...
        support/
        ...

Plugins live in the package ``kupfer.plugin``. Kupfer also includes
directories called ``kupfer/plugins`` from ``$XDG_DATA_DIRS``, which
typically means ``/usr/share/kupfer/plugins`` and
``$HOME/.local/share/kupfer/plugins``. These directories are
transparently included into the kupfer package, so the user has multiple
choices of where to install plugins.

The Plugin File
:::::::::::::::

A kupfer plugin is a ``.py`` file with some special attributes.

It starts like this (an imagined example)::

    __kupfer_name__ = _("Cool X-Documents")
    __kupfer_sources__ = ("DocumentSource", )
    __kupfer_text_sources__ = ()
    __kupfer_actions__ = ("Open", )
    __description__ = _("Documents from the X program")
    __version__ = "1"
    __author__ = "Tom Author"

All these special variables must be defined before any other code in the
module (even imports). 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__ = ()
    __kupfer_action_generators__ = ()
    __kupfer_contents__ = ()

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``

If an example plugin declares::

    __kupfer_sources__ = ("DocumentSource", )

it will later in the file define the class ``DocumentSource``::

    from kupfer.objects import Source

    class DocumentSource (Source):
        def __init__(self):
            Source.__init__(self, _("Cool X-Documents"))

        def get_items(self):
            ...
        # later we will see what we can do here!


Ok, this looks simple. So what are Leaves, Sources and Actions?


A **Leaf** is an object, it represents a program or a file, or a text or
something else. Every type of Leaf has different possibilities, and you
can define new Leaves. Example: a ``FileLeaf`` represents a file on the
disk.

A **Source** produces a collection of Leaves, so it makes Kupfer know
about new objects. For example, it can provide all the FileLeaves for a
particular folder.

An **Action** is the part where something happens, an action is applied
to a Leaf, and something happens. For example, *Open* can be an
action that works with all ``FileLeaf``.


A Short Working Example
:::::::::::::::::::::::

The very simplest thing we can do is to provide an action on
objects that already exist in Kupfer. These actions appear in the
right-hand actions pane in kupfer, when an object of the right type is
selected.

The complete python code for the plugin:

.. code:: python

    __kupfer_name__ = _("Image Viewer")
    __kupfer_actions__ = ("View", )
    __description__ = _("View images quickly")
    __version__ = ""
    __author__ = "Tom Author"


    from gi.repository import Gtk

    from kupfer.obj import Action, FileLeaf

    class View (Action):
        def __init__(self):
            super().__init__(_("View"))

        def item_types(self):
            yield FileLeaf

        def valid_for_item(self, fileobj):
            return fileobj.object.endswith(".jpg")

        def activate(self, fileobj):
            image_widget = Gtk.Image.new_from_file(fileobj.object)
            image_widget.show()
            window = Gtk.Window()
            window.add(image_widget)
            window.present()


That is all. What we did was the following:

* Declare a plugin called "Image Viewer" with an action class ``View``.
* Every string inside ``_("")`` is translatable
* ``View`` declares that it works with ``FileLeaf``
* ``View`` only accepts ``FileLeaf`` that end with '.jpg'
* ``View`` defines a method ``activate`` that when called, will use gtk
  to show the file in a window

.. note::

    Kupfer uses a simplified programming style of composition and
    cooperative superclasses.

    You normally never call a superclass implementation inside a method
    that you define, with the exception of ``__init__``.

    On the other hand, there are superclass methods that should not be
    overridden. For example, ``KupferObject.get_pixbuf`` is never
    overridden, instead you implement ``KupferObject.get_icon_name``.


Reference
=========

Below follows a complete summary. To accompany this reference, you can
read kupfer's inline module documentation with pydoc, by doing the
following in the source directory::

    $ pydoc kupfer.obj

or equivalently::

    $ python
    >>> help("kupfer.obj")

KupferObject
::::::::::::

``class KupferObject`` implements the things that are common to all objects:
*name*, *description*, *icon*, *thumbnail* and *name aliases*.


``__init__(self, name)``
    This is called when you call ``Leaf.__init__``, or ``Source.__init__``,
    and so on in your object's ``__init__`` method.

    The name parameter must be a unicode string. An object can not
    change name after it has called __init__.

``get_description(self)``
    Return a longer user-visible unicode string that
    describes the object.

``get_icon_name(self)``
    Return a string of one icon name for the object.

    The icon name should preferably be in the `Icon Naming
    Specification`_

    .. _`Icon Naming Specification`: \
        http://standards.freedesktop.org/icon-naming-spec/icon-naming-spec-latest.html


``get_gicon(self)``
    Return a GIcon (GIO icon) object. This takes precedence
    over the icon name, if it is defined.

``get_thumbnail(self, width, height)``
    Implement ``get_thumbnail`` to return a GdkPixbuf object of the
    requested size that is a thumbnail of the object. If applicable.

``get_pixbuf(self, x)``
    This should not be redefined. Define ``get_icon_name`` and/or
    ``get_gicon`` instead.

``get_icon(self)``
    This should not be redefined. Define ``get_icon_name`` and/or
    ``get_gicon`` instead.

``repr_key(self)``
    Return an object whose str() will be used in the __repr__,
    self is returned by default.
    This value is used to differentiate and recognize objects.
    Override this if the objects type and name is not enough
    to differentiate it from other objects.

``__repr__``
    This should not be redefined. Define ``repr_key`` instead.

``kupfer_add_alias(self, alias)``
    This should not be redefined, but can be called by the object
    to add an alternate name to the object.


KupferObject Attributes
.......................

``KupferObject.rank_adjust``
    A number to adjust the ranking of a certain object. Should only
    be used on Actions. Should be set in the range -10 to -1 for actions
    that apply to many objects but not default for any.

``KupferObject.fallback_icon_name``
    Used as a the class' fallback for icon name. Do not change this.


Leaf
::::

``class Leaf`` inherits from KupferObject.

A Leaf represents an object that the user will want to act on. Examples
are a file, an application or a free-text query (TextLeaf).

This defines, in addition to KupferObject:

``__init__(self, obj, name)``
    The default implementation of ``__init__`` stores the parameter
    ``obj`` into ``self.object`` and passes ``name`` up to
    ``KupferObject.__init__``.

    ``obj`` can be any data that the Leaf represents. ``name`` must be
    a unicode string.

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

``get_actions()``
    Return a sequence of Actions that always apply to the Leaf. These
    are "built-in" actions.

``__hash__`` and ``__eq__``
    Leaves are hashable, can be members in a set, and duplicates are
    recognized (and removed); this is essential so that equivalent
    Leaves from different sources are recognized.

    These methods need normally not be overridden.

    By default leaves are equal if both the name and the ``Leaf.object``
    attribute are the same.

``has_content()`` and ``content_source()``
    A leaf can contain something, like a folder contains files or a
    music album songs.

    If the Leaf should have content, it should override ``has_content``
    to return ``True`` and define ``content_source()`` to return
    an instance of a Source.

    A Leaf may decide dynamically if it has content or not.


Action
::::::

``class Action`` inherits from KupferObject.

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.

An action is either a `Subject + Verb`:t: action: It needs one object,
this is the direct object.

Or it is a `Subject + Verb + Object`:t: action: It needs two objects,
one direct object ("obj") and one indirect object ("iobj").

Action defines, in addition to KupferObject:


Activate: Carrying Out the Action
.................................

``activate(self, obj)``
    Called to perform the action if the action is a normal
    `Subject + Verb`:t: action.

``activate(self, obj, iobj)``
    Called to perform the action if the action is a three-way
    `Subject + Verb + Object`:t: action. (That is, ``requires_object``
    returns ``True``)

``activate_multiple(self, objects)``
    ..

``activate_multiple(self, objects, iobjects)``
    If implemented, ``activate_multiple`` is called with preference over
    ``activate(self, obj, iobj)`` or ``activate(self, obj)`` as
    appropriate.

    Implement ``activate_multiple`` to handle multiple objects on either
    side in a smart way.

    You should implement ``activate_multiple`` if it is possible to do
    something better than the equivalent of repeating ``activate``
    *n* times for *n* objects.

``activate`` and ``activate_multiple`` also receive a keyword argument
called ``ctx`` if the action defines ``wants_context(self)`` to return
``True``. See ``wants_context`` below for more information.


Determining Eligible Objects
............................

``item_types(self)``
    This method should return a sequence of all Leaf types
    that the action can apply to (direct object).

``valid_for_item(self, item)``
    This method is called for each potential direct object
    of the correct type.
    Return True if the object is compatible with the action.

    By default always returns ``True``.

``requires_object(self)``
    Return ``True`` if the action is a `Subject + Verb + Object`:t:
    action and requires both a direct and an indirect object.

    If ``requires_object`` returns ``True``,  then you must also
    define (at least) ``object_types``.

``object_types(self)``
    Return a sequence of all Leaf types that are valid for the action's
    indirect object.

``object_source(self, 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. ``for_item`` is the direct object.

``object_source_and_catalog(self, for_item)``
    If the action has an object source, by default only that source is
    used for indirect objects. Return ``True`` here to use both the
    custom source and the whole catalog.

``valid_object(self, iobj, 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. Return ``True`` if it can be used.

Auxiliary Method ``wants_context(self)``
........................................

``wants_context(self)``
    Return ``True`` if ``activate`` should receive an ``ExecutionToken``
    as the keyword argument ``ctx``. This allows posting late
    (after-the-fact) results and errors, as well as allowing access to
    the GUI environment.

    ``wants_context`` defaults to ``False`` which corresponds to
    the old protocol without ``ctx``.

So instead of ``activate(self, obj)``, the method should be implemented
as ``activate(self, obj, ctx)``.

The object passed as ``ctx`` has the following interface:

``ctx.register_late_result(result_object)``
    Register the ``result_object`` as a late result. It must be a
    ``Leaf`` or a ``Source``.

``ctx.register_late_error(exc_info=None)``
    Register an asynchronous error. (For synchronous errors, simply raise
    an ``OperationError`` inside ``activate``.)

    For asynchronous errors, call ``register_late_error``. If
    ``exc_info`` is ``None``, the current exception is used.
    If ``exc_info`` is an ``OperationError`` instance, then it is used
    as error. Otherwise, a tuple like ``sys.exc_info()`` can be passed.

``ctx.environment``
    The environment object, which has the following methods:

    ``get_timestamp(self)``
        Return the current event timestamp

    ``get_startup_notification_id(self)``
        Make and return a startup notification id

    ``get_display(self)``
        Return the display name (i.e ``:0.0``)

    ``present_window(self, window)``
        Present ``window`` (a ``Gtk.Window``) on the current
        workspace and monitor using the current event time.


Auxiliary Action Methods
........................

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

``is_factory(self)``
    Return ``True`` if the return value of ``activate`` is a source
    that should be displayed immediately.

``has_result(self)``
    Return ``True`` if the action's return value in ``activate`` should
    be selected.

``is_async(self)``
    Return ``True`` if the action returns a ``Task`` object conforming to
    ``kupfer.task.Task`` from ``activate``. The task will be executed
    asynchronously in Kupfer's task queue.

``repr_key(self)``
    Override this to define a unique key for the action,
    if you need to differentiate between different instances of the
    same Action class.

Class Attributes
................

The attribute ``action_accelerator`` is ``None`` by default but
can be a single letter string to suggest a default accelerator for
this action. Actions that act like the default open should use ``"o"``.


Source
::::::

``class Source`` inherits from KupferObject.

A Source understands specific data and delivers Leaves for it.

A Source subclass must at a minimum implement ``__init__``,
``get_items`` and ``provides``.

``Source`` defines, in addition to ``KupferObject``:

``__init__(self, names)``
    You must call this method with a unicode name in the subclass
    ``__init__(self)``.

``get_items(self)``
    Your source should define ``get_items`` to return a sequence
    of leaves which are its items; the return value is cached and used
    until ``mark_for_update`` is called.

    Often, implementing ``get_items`` in the style of a generator (using
    ``yield``) is the most convenient.

    The Leaves shall be returned in natural order (most relevant first),
    or if sorting is required, return in any order and define
    ``should_sort_lexically``.

``get_leaves(self)``
    ``get_leaves`` must not be overridden, define ``get_items``
    instead.

``provides(self)``
    Return a sequence of all precise Leaf types the Source may contain.

    Often, the Source contains Leaves of only one type, in that case
    the implementation is written simply as ``yield ThatLeafType``.

``should_sort_lexically(self)``
    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).

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

``finalize(self)``
    This method is called before the Source is disabled (shutdown or
    plugin deactivated).

``get_leaf_repr(self)``
    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.

``get_items_forced(self)``
    Like ``get_items``, called when a refresh is forced. By default
    it just calls ``get_items``.

``mark_for_update(self)``
    Should not be overridden. Call ``mark_for_update`` in the source to
    mark it so that it is refreshed by calling ``get_items``.

``repr_key(self)``
    Define to a unique key if you need to differentiate between sources
    of the same class. Normally only used with Sources from factory
    actions or from decorator sources.

``toplevel_source(self)``
    If applicable, the source can return a different source to represent
    it and its objects in the top level of the catalog. The default
    implementation returns ``self`` which is normally what you want.

``is_dynamic(self)``
    Return ``True`` if the Source should not be cached. This is almost
    never used.


Saving Source configuration data
................................

These methods are must be implemented if the Source needs to save
user-produced configuration data.

``config_save_name(self)``
    Return the name key to save the data under. This should almost
    always be literally ``return __name__``

``config_save(self)``
    Implement this to return a datastructure that succintly but
    perfectly represents the configuration data. The returned
    value must be a composition of simple types, that is, nested
    compositions of ``dict``, ``list``, ``str`` etc.

    This is called after ``finalize`` is called on the source.

``config_restore(self, state)``
    The ``state`` parameter is passed in as the saved return value
    of ``config_save``. ``config_restore`` is called before
    ``initialize`` is called on the Source.


Content Decorators
..................

A content-decorating source provides content to a Leaf, where it does
not control the Leaf. An example is the recent documents content
decorator, that provides document collections as content to
applications.

A normal Source listed in ``__kupfer_sources__`` will be eligible for
content decoration as well if it implements the needed methods.
Otherwise content-only sources are listed in ``__kupfer_contents__``.


``@classmethod decorates_type(cls)``
    Return the type of Leaf that can be decorated. You must also
    implement ``decorate_item``.

``@classmethod decorate_item(cls, leaf)``
    Return an instance of a Source (normally of the same type as the
    content decorator itself) that is the content for the object
    ``leaf``.  Return ``None`` if not applicable.

    Sources returned from ``decorate_item`` go into the common Source
    pool. The new source instance will not be used if the returned
    instance is equivalent (as defined by class and ``reepr_key``
    above).


Source Attributes
.................

``Source.source_user_reloadable = False``
    Set to ``True`` if the source should have a user-visible
    *Rescan* action. Normally you much prefer to use change
    notifications so that this is not necessary.

``Source.source_prefer_sublevel = False``
    Set to ``True`` to not export its objects to the top level by
    default. Normally you don't wan't to change this.

``Source.source_use_cache =  True``
    If ``True``, the source can be pickled to disk to save its
    cached items until the next time the launcher is started.

``Source.source_scan_interval``
    Set inteval in secounds between refresh source by
    ``PeriodicRescanner``. Background process check and refresh all
    sounrces every 60 secounds but not often than
    ``source_scan_interval``.
    Sources marked to reload are refresh in next refresh run.

``Source.last_scan``
    Object attribute keep information about last rescan time.

``Source._version``
    Internal number that is ``1`` by default. Update this number in
    ``__init__`` to invalidate old versions of cache files.


TextSource
::::::::::

TextSource inherits from KupferObject.

A text source returns items for a given text string, it is much like a
simplified version of Source. At a minimum, a TextSource subclass must
implement ``get_text_items`` and ``provides``.

``__init__(self, name)``
    Override as ``__init__(self)`` to provide a unicode name for the
    source.

``get_text_items(self, text)``
    Return a sequence of Leaves for the unicode string ``text``.

``provides(self)``
    Return a sequence of the Leaf types it may contain

``get_rank(self)``
    Return a static rank score for text output of this source.


ActionGenerator
:::::::::::::::

ActionGenerator inherits from object.

ActionGenerator is a helper object that can be declared in
``__kupfer_action_generators__``. It allows generating action objects
dynamically.

``get_actions_for_leaf(self, leaf)``
    Return a sequence of Action objects appropriate for this Leaf

.. note::

    The ``ActionGenerator`` should not perform any expensive
    computation, and not access any slow media (files, network) when
    returning actions.  Such expensive checks must postponed and be
    performed in each Action's ``valid_for_item`` method.


The Plugin Runtime
::::::::::::::::::

.. topic:: How a plugin is activated

    1. The plugin module is imported into Kupfer.

       If an error occurs, the loading fails and the plugin is disabled.
       If the error raised is an ImportError then Kupfer report it as a
       dependency problem.

    2. Kupfer will initialize a ``kupfer.plugin_support.PluginSettings``
       object if it exists (see next section)

    3. Kupfer will call the module-level function
       ``initialize_plugin(name)`` if it exists.

    4. Kupfer instantiates the declared sources and actions and insert
       sources, actions, content decorators, action generators and text
       sources into the catalog.

.. topic:: When a plugin is deactivated

    When the plugin is disabled, the module-level function
    ``finalize_plugin(name)`` is called if it exists. [It is not yet
    final whether this function is called at shutdown or only when
    hot-unplugging plugins.]

kupfer.plugin_support
:::::::::::::::::::::

This module provides important API for several plugin features.

PluginSettings
..............

To use user-settable configuration parameters, use:

.. code:: python

    __kupfer_settings__ = plugin_support.PluginSettings(
        {
            "key" : "frobbers",
            "label": _("Number of frobbers"),
            "type": int,
            "value": 9,
        },
    )

Where ``PluginSettings`` takes a variable argument list of config
parameter descriptions. The configuration values are accessed with
``__kupfer_settings__[key]`` where ``key`` is from the parameter
description. Notice that ``__kupfer_settings__`` is not updated with
the user values until the plugin is properly initialized.

``PluginSettings`` is read-only but supports the GObject signal
``plugin-setting-changed (key, value)`` when values change.

Supported parameter types:

``str``
    Simple string value that used Entry for enter value.
    When addidtional parameter ``"multiline": True`` is provided,
    multiline TextView is used in GUI to enter value.

    Setting can provide ``alternatives`` - list of possible
    values to choose. Alternatives may by simple list of strings - then
    value displayed is equal to value used internally, or as list of
    tuples (<value id>, <value title>). In this case GUI use ComboBox
    widget.

    Setting can provide ``helper`` that determine how value is entered
    in preferences dialog.
    Supported helpers are: ``choose_directory`` and ``choose_file``.

    ``alternatives``, ``multiline`` and ``helper`` can't be use
    together.

``int``
    Allow user to enter numeric value.

    Additional parameters: ``min`` and ``max`` can be provided to limit
    entered value.

``bool``
    Use checkbox for parameter.

``list``
    Setting value is list of strings. Additional parameter ``helper``
    must be provided to determine how values are entered.

    For now only supported is ``choose_directory`` helper that allow
    user to select one or more directories.

``plugin_support.UserNamePassword``
    Form used to enter user credentials.



check_dbus_support and check_keyring_support
............................................

``plugin_support`` provides the convenience functions
``check_dbus_support()`` and ``check_keyring_support()`` that raise the
appropriate error if a dependency is missing.


Alternatives
............

Alternatives are mutually exclusive features where the user must select
which to use. Each category permits one choice.

.. topic:: Categories of Alternatives

    :``terminal``:      the terminal used for running programs that require
                        terminal
    :``icon_renderer``: method used to look up icon names
    :``editor``:        editor used by *Edit* action

Each category has a specific format of required data that is defined in
``kupfer/plugin_support.py``. A plugin should use the function
``kupfer.plugin_support.register_alternative(caller, category_key, id_, **kwargs)``
to register their implementations of new alternatives. The arguments are:

.. topic:: ``register_alternative(caller, category_key, id_, ** kwargs)``

    :``caller``:       the name of the calling plugin, is always ``__name__``
    :``category_key``: one of the above categories
    :``id_``:          the plugin's identifier for the alternative
    :`kwargs`:         key-value pairs defining the alternative

    ``register_alternative`` is normally called in the plugin's
    ``initialize_plugin(..)`` function.

.. topic:: Fields requried for the category ``terminal``

    :``name``:              unicode visible name
    :``argv``:              argument list: list of strings
    :``exearg``:            the execute-flag as a byte string (``""`` when N/A)
    :``desktopid``:         the likely application id as a string
    :``startup_notify``:    whether to use startup notification as boolean

.. topic:: Fields required for the category ``icon_renderer``

    :``name``:              unicode visible name
    :``renderer``:          an object with an interface just like
                            ``kupfer.icons.IconRenderer``

.. topic:: Fields requried for the category ``editor``

    :``name``:              unicode visible name
    :``argv``:              argument list: list of trings
    :``terminal``:          whether to launch application in terminal as boolean



Plugin Packages, Resources and Distribution
:::::::::::::::::::::::::::::::::::::::::::

A plugin is a Python module–either a single python file or a folder with
an ``__init__.py`` file (a package module). In the latter case, the
whole of the plugin can be defined inside ``__init__.py``, or it can be
split into several modules. Kupfer will look for all the description
variables (like ``__kupfer_name__``) in ``__init__.py``.

.. topic:: Plugin-installed custom icons

    A package module may include custom icons as .svg files. The icon files
    must be declared in a file inside the python package called
    ``icon-list``.

    * Each line is a tab-separated field list, with the icon name in
      the first column and the filename (relative to the plugin package)
      in the second column.
    * Lines can be commented with a leading ``#``
    * If a literal ``!override`` appears in the third column, the icon
      is installed even if it overrides the currently used GTK icon
      theme.


Plugins may be installed into any of the ``kupfer/plugins`` data
directories. Package modules can also be installed and used as ``.zip``
files, so they too can be distributed as single files.


Example Plugins
===============

I want to specifically highlight certain files in Kupfer that are good
to read as examples.

+ Custom Leaf and Action: the common case of creating a custom
  ``Leaf`` type and defining its default ``Open`` action, see
  ``kupfer/plugin/notes.py``
+ Content decoration: making content for objects, see
  ``kupfer/plugin/archiveinside.py`` (*Deep Archives* plugin)
+ Asynchronous error reporting: see ``kupfer/plugin/volumes.py``, action
  *Unmount*



Reference to the ``kupfer`` Package
===================================

There are several modules inside the ``kupfer`` package that a plugin
can reuse.

.. topic:: ``kupfer.config``

    ..

.. topic:: ``kupfer.obj.representation``

    This module does not need to be imported just to implement the
    interface it defines.

    ``TextRepresentation``
        ``get_text_representation``
            If a Leaf has a text representation (used for
            copy-to-clipboard), it should implement this method
            and return a string.

    ``UriListRepresentation``
        ``get_urilist_representation``
            If a Leaf has a uri-list representation (used for
            copy-to-clipboard), it should implement this method
            and return a list of strings.

.. topic:: ``kupfer.obj``

    ``kupfer.obj`` includes the basic objects such as ``Leaf``,
    ``Action``, ``Source`` etc.

    ``FileLeaf``, ``AppLeaf``, ``TextLeaf`` etc.
        The basic re-usable types live here

    ``OperationError``
        Exception type for user-visible errors in action execution.
        Raise ``OperationError`` with a unicode localized error message
        inside ``Action.activate`` to notify the user of a serious
        error.

        Specialized versions exist in ``kupfer.obj.exceptions``: Such as
        ``NotAvailableError(toolname)``,
        ``NoMultiError()``

    Other, rarely used object should be imported from kupfer.obj
    sub-packages, ie:

    ``kupfe.obj.contacts``
        Module provide leaves definition for contacts (emails, im etc)
        that can be used in plugins supporting email clients and
        similar software where is some kind of "address book".
        Contact leaves can be grouped.

    ``kupfe.obj.helplib``
        ``PicklingHelperMixin`` helper for save and load object state

        ``FilesystemWatchMixin`` allow active monitoring file changes
        and update objects state

    ``kupfe.obj.fileactions``
        Actions operating on files (``Open``). Usually not need to be
        used in plugins.

    ``kupfer.obj.hosts``
        Define ``HostLeaf`` and ``HostServiceLeaf`` than can be used
        for define service on given host (ie. ssh, www etc).
        This leaves can be grouped by host.

.. topic:: ``kupfer.runtimehelper``

   Module provide support for async results.

.. topic:: ``kupfer.support.datatools``

   Caching object and decorators.

   ``LruCache``
      Least-recentrly-used cache with defined max size.

   ``simple_cache``
      Function decorator that remember only one last result and
      call wrapped function when argumets was changed.

   ``evaluate_once``
      Function decorator that call wrapped function once and always
      return the same result.

.. topic:: ``kupfer.support.fileutils``

    Support function related to files and directories.

.. topic:: ``kupfer.support.kupferstring``

    Kupfer and python internall use unicode strings. Files, command
    results etc may use other text representation (bytes).
    When you handle byte strings that is text, you must convert it to
    unicode as soon as possible. You only know the encoding depending
    on the source of the byte string.

    ``tounicode``
        decode UTF-8 or unicode object into unicode.

    ``tolocale(ustr)``
        coerce unicode ``ustr`` into a locale-encoded bytestring.

    ``fromlocale(lstr)``
        decode locale-encoded bytestring ``lstr`` to a unicode object.

    ``localesort``
        sort collection of string in locale lexical order.

.. topic:: ``kupfer.support.pretty``

   Methods than can be used for debugging - logging: ``print_info``,
   ``print_debug``, ``print_exc`` and ``print_error``.

   Module also define ``OutputMixin`` that may be included in action,
   source and leaves objects and provide methods like ``output_info``,
   ``output_exc``, ``output_debug`` and ``output_error``.

.. topic:: ``kupfer.support.system``

    System related functions like ``get_hostname``, ``get_homedir`` and
    ``get_application_filename``.

.. topic:: ``kupfer.support.task``

    Allow run some task in background.

.. topic:: ``kupfer.support.textutils``

   Methods for text parsing / extracting.

.. topic:: ``kupfer.support.validators``

   Check if text is valid email, url etc.

.. topic:: ``kupfer.support.weaklib``

   Define some object and function useful to create callback with
   weak references, e.g. ``dbus_signal_connect_weakly``,
   ``gobject_connect_weakly``.

.. topic:: ``kupfer.ui.uiutils``

    ``show_notification(title, text='', icon_name='', nid=0)``
        Show a notification. If a previous return value is passed as
        ``nid``, try to replace that previous notification.

        Returns a notification identifier, or None if notifications
        are not supported.

    ``show_text_result(title, text, ctx)``
        Open window with text result.

.. topic:: ``kupfer.launch``

    ``spawn_async(argv)``
        Spawn a child process, returning True if successfully started.

    ``spawn_in_terminal(argv)``
        Run commands in terminal.

    ``show_path(path)``
        ..

    ``show_url(url)``
        Display with default viewer for ``path`` or ``url``.

    ``get_display_path_for_bytestring(filepath)``
        ``get_display_path_for_bytestring`` returns a user-displayable
        text representation as a string.


.. topic:: ``kupfer.core``

    The module ``kupfer.core`` can not be used by plugins.


.. vim: ft=rst tw=72 et sts=4 sw=4
.. this document best viewed with rst2html