[IMP] documentation of addons structure and namespacing
[odoo/odoo.git] / doc / source / development.rst
1 OpenERP Web Core and standard addons
2 ====================================
3
4 * General organization and core ideas (design philosophies)
5 * Internal documentation, autodoc, Python and JS domains
6 * QWeb code documentation/description
7 * Documentation of the OpenERP APIs and choices taken based on that?
8 * Style guide and coding conventions (PEP8? More)
9 * Test frameworks in JS?
10
11 Standard Views
12 --------------
13
14 Search View
15 +++++++++++
16
17 The OpenERP search view really is a sub-view, used in support of views
18 acting on collections of records (list view or graph view, for
19 instance).
20
21 Its main goal is to collect information from its widgets (themselves
22 collecting information from the users) and make those available to the
23 rest of the client.
24
25 The search view's root is :js:class:`~openerp.base.SearchView`. This
26 object should never need to be created or managed directly, its
27 lifecycle should be driven by the
28 :js:class:`~openerp.base.ViewManager`.
29
30 .. TODO: insert SearchView constructor here
31
32 The search view defines a number of internal and external protocols to
33 communicate with the objects around and within it. Most of these
34 protocols are informal, and types available for inheritance are more
35 mixins than mandatory.
36
37 Events
38 """"""
39
40 ``on_loaded``
41
42   .. TODO: method openerp.base.SearchView.on_loaded
43
44   Fires when the search view receives its view data (the result of
45   ``fields_view_get``). Hooking up before the event allows for
46   altering view data before it can be used.
47
48   By the time ``on_loaded`` is done, the search view is guaranteed to
49   be fully set up and ready to use.
50
51 ``on_search``
52
53   .. TODO: method openerp.base.SearchView.on_search
54
55   Event triggered after a user asked for a search. The search view
56   fires this event after collecting all input data (contexts, domains
57   and group_by contexts). Note that the search view does *not* merge
58   those (or therwise evaluate them), they are returned as provided by
59   the various inputs within the view.
60
61 ``on_clear``
62
63   .. TODO: method openerp.base.SearchView.on_clear
64
65   Triggered after a user asked for a form clearing.
66
67 Input management
68 """"""""""""""""
69
70 An important concept in the search view is that of input. It is both
71 an informal protocol and an abstract type that can be inherited from.
72
73 Inputs are widgets which can contain user data (a char widget for
74 instance, or a selection box). They are able of action and of
75 reaction:
76
77 .. _views-search-registration:
78
79 ``registration``
80
81   This is an input action. Inputs have to register themselves to the
82   main view (which they receive as a constructor argument). This is
83   performed by pushing themselves on the
84   :js:attr:`openerp.base.SearchView.inputs` array.
85
86 ``get_context``
87
88   An input reaction. When it needs to collect contexts, the view calls
89   ``get_context()`` on all its inputs.
90
91   Inputs can react in the following manners:
92
93   * Return a context (an object), this is the "normal" response if the
94     input holds a value.
95
96   * Return a falsy value (generally ``null``). This value indicates
97     the input does not contain any value and will not take part in the
98     research.
99
100   * Raise :js:class:`openerp.base.search.Invalid` to indicate that it
101     holds a value but this value can not be used in the search
102     (because it is incorrectly formatted or nonsensical). Raising
103     :js:class:`~openerp.base.search.Invalid` is guaranteed to cancel
104     the search process.
105
106     :js:class:`~openerp.base.search.Invalid` takes three mandatory
107     arguments: an indentifier (a name for instance), the invalid value
108     and a validation message indicating the issue.
109
110 ``get_domain``
111
112   The second input reaction, the possible behaviors of inputs are the
113   same as for ``get_context``.
114
115 The :js:class:`openerp.base.search.Input` type implements registration
116 on its own, but its implementations of ``get_context`` and
117 ``get_domain`` simply raise errors and *have* to be overridden.
118
119 One last action is for filters, as an activation order has to be kept
120 on them for some controls (establish the correct grouping sequence for
121 instance).
122
123 To that end, filters can call
124 :js:func:`openerp.base.Search.do_toggle_filter`, providing themselves
125 as first argument.
126
127 Filters calling :js:func:`~openerp.base.Search.do_toggle_filter` also
128 need to implement a method called
129 :js:func:`~openerp.base.search.Filter.is_enabled`, which the search
130 view will use to know the current status of the filter.
131
132 The search view automatically triggers a search after calls to
133 :js:func:`~openerp.base.Search.do_toggle_filter`.
134
135 Life cycle
136 """"""""""
137
138 The search view has a pretty simple and linear life cycle, in three main steps:
139
140 :js:class:`init <openerp.base.SearchView>`
141
142   Nothing interesting happens here
143
144 :js:func:`~openerp.base.SearchView.start`
145
146   Called by the main view's creator, this is the main initialization
147   step for the list view.
148
149   It begins with a remote call to fetch the view's descriptors
150   (``fields_view_get``).
151
152   Once the remote call is complete, the ``on_loaded`` even happens,
153   holding three main operations:
154
155   :js:func:`~openerp.base.SearchView.make_widgets`
156
157     Builds and returns the top-level widgets of the search
158     view. Because it returns an array of widget lines (a 2-dimensional
159     matrix of widgets) it should be called recursively by container
160     widgets (:js:class:`openerp.base.search.Group` for instance).
161
162   :js:func:`~openerp.base.search.Widget.render`
163
164     Called by the search view on all top-level widgets. Container
165     widgets should recursively call this method on their own children
166     widgets.
167
168     Widgets are provided with a mapping of ``{name: value}`` holding
169     default values for the search view. They can freely pick their
170     initial values from there, but must pass the mapping to their
171     children widgets if they have any.
172
173   :js:func:`~openerp.base.search.Widget.start`
174
175     The last operation of the search view startup is to initialize all
176     its widgets in order. This is again done recursively (the search
177     view starts its children, which have to start their own children).
178
179 :js:func:`~openerp.base.SearchView.stop`
180
181   Used before discarding a search view, allows the search view to
182   disable its events and pass the message to its own widgets,
183   gracefully shutting down the whole view.
184
185 Widgets
186 """""""
187
188 In a search view, the widget is simply a unit of display.
189
190 All widgets must be able to react to three events, which will be
191 called in this order:
192
193 :js:func:`~openerp.base.search.Widget.render`
194
195   Called with a map of default values. The widget must return a
196   ``String``, which is its HTML representation. That string can be
197   empty (if the widget should not be represented).
198
199   Widgets are responsible for asking their children for rendering, and
200   for passing along the default values.
201
202 :js:func:`~openerp.base.search.Widget.start`
203
204   Called without arguments. At this point, the widget has been fully
205   rendered and can set its events up, if any.
206
207   The widget is responsible for starting its children, if it has any.
208
209 :js:func:`~openerp.base.search.Widget.stop`
210
211   Gives the widget the opportunity to unbind its events, remove itself
212   from the DOM and perform any other cleanup task it may have.
213
214   Event if the widget does not do anything itself, it is responsible
215   for shutting down its children.
216
217 An abstract type is available and can be inherited from, to simplify
218 the implementation of those tasks:
219
220 .. TODO: insert Widget here
221
222 .. remember to document all methods
223
224 Inputs
225 """"""
226
227 The search namespace (``openerp.base.search``) provides two more
228 abstract types, used to implement input widgets:
229
230 * :js:class:`openerp.base.search.Input` is the most basic input type,
231   it only implements :ref:`input registration
232   <views-search-registration>`.
233
234   If inherited from, descendant classes should not call its
235   implementations of ``get_context`` and ``get_domain``.
236
237 * :js:class:`openerp.base.search.Field` is used to implement more
238   "field" widgets (which allow the user to input potentially complex
239   values).
240
241   It provides various services for its subclasses:
242
243   * Sets up the field attributes, using attributes from the field and
244     the view node.
245
246   * It fills the widget with :js:class:`~openerp.base.search.Filter`
247     if the field has any child filter.
248
249   * It automatically generates an identifier based on the field type
250     and the field name, using
251     :js:func:`~openerp.base.search.Widget.make_id`.
252
253   * It sets up a basic (overridable)
254     :js:attr:`~opererp.base.search.Field.template` attribute, combined
255     with the previous tasks, this makes subclasses of
256     :js:class:`~openerp.base.search.Field` render themselves "for
257     free".
258
259   * It provides basic implementations of ``get_context`` and
260     ``get_domain``, both hinging on the subclasses implementing
261     ``get_value()`` (which should return a correct, converted
262     Javascript value):
263
264     :js:func:`~openerp.base.search.Field.get_context`
265
266         Checks if the field has a non-``null`` and non-empty
267         (``String``) value, and that the field has a ``context`` attr.
268
269         If both conditions are fullfilled, returns the context.
270
271     :js:func:`~openerp.base.search.Field.get_domain`
272
273         Only requires that the field has a non-``null`` and non-empty
274         value.
275
276         If the field has a ``filter_domain``, returns it
277         immediately. Otherwise, builds a context using the field's
278         name, the field :js:attr:`~openerp.base.search.Field.operator`
279         and the field value, and returns it.
280
281 .. TODO: insert Input, Field, Filter, and just about every Field subclass
282
283 Internal API Doc
284 ----------------
285
286 Python
287 ++++++
288
289 These classes should be moved to other sections of the doc as needed,
290 probably.
291
292 .. automodule:: openerpweb.openerpweb
293     :members: JsonRequest
294
295     See also: :class:`~openerpweb.openerpweb.OpenERPSession`,
296     :class:`~openerpweb.openerpweb.OpenERPModel`
297
298 .. automodule:: base.controllers.main
299     :members:
300     :undoc-members:
301
302 Testing
303 -------
304
305 Python
306 ++++++
307
308 Testing for the OpenERP Web core is similar to :ref:`testing addons
309 <addons-testing>`: the tests live in ``openerpweb.tests``, unittest2_
310 is the testing framework and tests can be run via either unittest2
311 (``unit2 discover``) or via nose_ (``nosetests``).
312
313 Tests for the OpenERP Web core can also be run using ``setup.py
314 test``.
315
316
317 .. _unittest2:
318     http://www.voidspace.org.uk/python/articles/unittest2.shtml
319
320 .. _nose:
321     http://somethingaboutorange.com/mrl/projects/nose/1.0.0/