1 OpenERP Web Core and standard addons
2 ====================================
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?
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
21 Its main goal is to collect information from its widgets (themselves
22 collecting information from the users) and make those available to the
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`.
30 .. TODO: insert SearchView constructor here
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.
42 .. TODO: method openerp.base.SearchView.on_loaded
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.
48 By the time ``on_loaded`` is done, the search view is guaranteed to
49 be fully set up and ready to use.
53 .. TODO: method openerp.base.SearchView.on_search
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.
63 .. TODO: method openerp.base.SearchView.on_clear
65 Triggered after a user asked for a form clearing.
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.
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
77 .. _views-search-registration:
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.
88 An input reaction. When it needs to collect contexts, the view calls
89 ``get_context()`` on all its inputs.
91 Inputs can react in the following manners:
93 * Return a context (an object), this is the "normal" response if the
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
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
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.
112 The second input reaction, the possible behaviors of inputs are the
113 same as for ``get_context``.
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.
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
123 To that end, filters can call
124 :js:func:`openerp.base.Search.do_toggle_filter`, providing themselves
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.
132 The search view automatically triggers a search after calls to
133 :js:func:`~openerp.base.Search.do_toggle_filter`.
138 The search view has a pretty simple and linear life cycle, in three main steps:
140 :js:class:`init <openerp.base.SearchView>`
142 Nothing interesting happens here
144 :js:func:`~openerp.base.SearchView.start`
146 Called by the main view's creator, this is the main initialization
147 step for the list view.
149 It begins with a remote call to fetch the view's descriptors
150 (``fields_view_get``).
152 Once the remote call is complete, the ``on_loaded`` even happens,
153 holding three main operations:
155 :js:func:`~openerp.base.SearchView.make_widgets`
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).
162 :js:func:`~openerp.base.search.Widget.render`
164 Called by the search view on all top-level widgets. Container
165 widgets should recursively call this method on their own children
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.
173 :js:func:`~openerp.base.search.Widget.start`
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).
179 :js:func:`~openerp.base.SearchView.stop`
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.
188 In a search view, the widget is simply a unit of display.
190 All widgets must be able to react to three events, which will be
191 called in this order:
193 :js:func:`~openerp.base.search.Widget.render`
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).
199 Widgets are responsible for asking their children for rendering, and
200 for passing along the default values.
202 :js:func:`~openerp.base.search.Widget.start`
204 Called without arguments. At this point, the widget has been fully
205 rendered and can set its events up, if any.
207 The widget is responsible for starting its children, if it has any.
209 :js:func:`~openerp.base.search.Widget.stop`
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.
214 Event if the widget does not do anything itself, it is responsible
215 for shutting down its children.
217 An abstract type is available and can be inherited from, to simplify
218 the implementation of those tasks:
220 .. TODO: insert Widget here
222 .. remember to document all methods
227 The search namespace (``openerp.base.search``) provides two more
228 abstract types, used to implement input widgets:
230 * :js:class:`openerp.base.search.Input` is the most basic input type,
231 it only implements :ref:`input registration
232 <views-search-registration>`.
234 If inherited from, descendant classes should not call its
235 implementations of ``get_context`` and ``get_domain``.
237 * :js:class:`openerp.base.search.Field` is used to implement more
238 "field" widgets (which allow the user to input potentially complex
241 It provides various services for its subclasses:
243 * Sets up the field attributes, using attributes from the field and
246 * It fills the widget with :js:class:`~openerp.base.search.Filter`
247 if the field has any child filter.
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`.
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
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
264 :js:func:`~openerp.base.search.Field.get_context`
266 Checks if the field has a non-``null`` and non-empty
267 (``String``) value, and that the field has a ``context`` attr.
269 If both conditions are fullfilled, returns the context.
271 :js:func:`~openerp.base.search.Field.get_domain`
273 Only requires that the field has a non-``null`` and non-empty
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.
281 .. TODO: insert Input, Field, Filter, and just about every Field subclass
289 These classes should be moved to other sections of the doc as needed,
292 .. automodule:: openerpweb.openerpweb
293 :members: JsonRequest
295 See also: :class:`~openerpweb.openerpweb.OpenERPSession`,
296 :class:`~openerpweb.openerpweb.OpenERPModel`
298 .. automodule:: base.controllers.main
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``).
313 Tests for the OpenERP Web core can also be run using ``setup.py
318 http://www.voidspace.org.uk/python/articles/unittest2.shtml
321 http://somethingaboutorange.com/mrl/projects/nose/1.0.0/