File: so.txt

package info (click to toggle)
gaphor 0.17.2-1
  • links: PTS, VCS
  • area: main
  • in suites: jessie, jessie-kfreebsd
  • size: 4,552 kB
  • ctags: 3,629
  • sloc: python: 23,713; xml: 222; makefile: 112; sh: 1
file content (152 lines) | stat: -rw-r--r-- 5,850 bytes parent folder | download
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
Service Oriented Architecture
=============================

Gaphor has a service oriented architecture. What does this mean? Well, Gaphor
is build as a set of small islands (services). Each island provides a specific
piece of functionality. For example: a service is responsible for 
loading/saving models, another for the menu structure, yet another service
handles the undo system.

Service are defined as `Egg entry points <http://peak.telecommunity.com/
DevCenter/setuptools#dynamic-discovery-of-services-and-plugins>`_.
With entry points applications can register functionality for specific 
purposes. Entry points are grouped in so called *entry point groups*.
For example the `console_scripts` entry point group is used to start
an application from the command line. 

Entry points, as well as all major components in Gaphor, are defined around
`Zope interfaces <http://www.zope.org/Products/ZopeInterface>`_. An interface
defines specific methods and attributes that should be implemented by the class.

Entry point groups
------------------

Gaphor defines two entry point groups:

 * gaphor.services
 * gaphor.uicomponents

Services are used to add functionality to the application.
Plug-ins should also be defined as services. E.g.::

    entry_points = {
        'gaphor.services': [
            'xmi_export = gaphor.plugins.xmiexport:XMIExport',
        ],
    },

There is a thin line between a service and a plug-in. A service typically
performs some basic need for the applications (such as the element factory 
or the undo mechanism). A plug-in is more of an add-on. For example a plug-in
can depend on external libraries or provide a cross-over function between
two applications.

Interfaces
----------

Each service (and plug-in) should implement the `gaphor.interfaces.IService`
interface:

.. autoclass:: gaphor.interfaces.IService
   :members:

UI components is another piece of cake. The ``gaphor.uicomponents`` entry
point group is used to define windows and user interface functionality. 
A UI component should implement the `gaphor.ui.interfaces.IUIComponent`
interface:

.. autoclass:: gaphor.ui.interfaces.IUIComponent
   :members:

Typically a service and UI component would like to present some actions to the
user, by means of menu entries. Every service and UI component can advertise
actions by implementing the ``gaphor.interfaces.IActionProvider`` interface:

.. autoclass:: gaphor.interfaces.IActionProvider
   :members:


Example plugin
~~~~~~~~~~~~~~

A small example is provided by means of the `Hello world plugin`.
Take a look at the files at `Github <https://github.com/amolenaar/gaphor.plugins.helloworld>`_.

The `setup.py <https://github.com/amolenaar/gaphor.plugins.helloworld/blob/master/setup.py>`_ 
file contains an entry point::

    entry_points = {
        'gaphor.services': [
            'helloworld = gaphor.plugins.helloworld:HelloWorldPlugin',
        ]
    }

This refers to the class ``HelloWorldPlugin`` in package/module 
`gaphor.plugins.helloworld <https://github.com/amolenaar/gaphor.plugins.helloworld/blob/master/gaphor/plugins/helloworld/__init__.py>`_.

Also notice that, since the package is defined as ``gaphor.plugins``, which is
also a package in the default gaphor distribution, each package level contains
a special statement in its ``__init__.py`` that tells setuptools
its namespace declaration:::

   __import__('pkg_resources').declare_namespace(__name__)

Here is a stripped version of the hello world class::

    from zope import interface
    from gaphor.interfaces import IService, IActionProvider
    from gaphor.core import _, inject, action, build_action_group


    class HelloWorldPlugin(object):

        interface.implements(IService, IActionProvider)  # 1.

        gui_manager = inject('gui_manager')              # 2.

        menu_xml = """                                   # 3.
          <ui>
            <menubar name="mainwindow">
              <menu action="help">
                <menuitem action="helloworld" />
              </menu>
            </menubar>
          </ui>
        """

        def __init__(self):
            self.action_group = build_action_group(self) # 4.

        def init(self, app):                             # 5.
            self._app = app

        def shutdown(self):                              # 6.
            pass

        @action(name='helloworld',                       # 7.
                label=_('Hello world'),
                tooltip=_('Every application ...'))
        def helloworld_action(self):
            main_window = self.gui_manager.main_window   # 8.
            pass # gtk code left out 

1. As stated before, a plugin should implement the ``IService`` interface. 
   It also implements ``IActionProvider``, saying it has some actions to
   be performed by the user.
2. The plugin depends on the ``gui_manager`` service. The ``gui_manager`` can
   be referenced as a normal attribute. The first time it's accessed the
   dependency to the ``gui_manager`` is resolved.
3. As part of the ``IActionProvider`` interface an attribute ``menu_xml``
   should be defined that contains some menu xml
   (see http://developer.gnome.org/doc/API/2.0/gtk/GtkUIManager.html#XML-UI).
4. ``IActionProvider`` also requires an ``action_group`` attribute (containing
   a ``gtk.ActionGroup``). This action group is created on instantiation.
   The actions itself are defined with an ``action`` decorator (see 7).
5. Each ``IService`` has an ``init(app)`` method...
6. ... and a ``shutdown()`` method. Those can be used to create and detach
   event handlers for example.
7. The action that can be invoked. The action is defined and will be picked
   up by ``build_action_group()`` (see 4.)
8. The main window is retrieved from the ``gui_manager``. At this point the
   "inject'ed" gui-manager reference is resolved.