Creating custom widgets
Creating custom widgets
Presenter Notes
Make the server aware
- PROBLEM: The tryton server validates the widget
- SOLUTION: We have to make the server aware of the new widget
- You just have to inherit from ir.ui.view and override the get_rng
class method.
Presenter Notes
The tryton architecture
- form & tree & graph
- gui/window/view_form/view/form_gtk
- gui/window/view_form/view/list_gtk
- gui/window/view_form/view/graph_gtk
- field & widget
- gui/window/view_form/model/field.py
- gui/window/view_form/view/form_gtk/*
- record & group
- gui/window/view_form/model/record.py
- gui/window/view_form/model/group.py
Presenter Notes
Form Widget
Presenter Notes
Methods to set data into the form
- in the widget a call to display
- in the field a call to get_client
- GTk code to do the required stuffs
Presenter Notes
Example of char.py
def display(self, record, field):
super(Char, self).display(record, field)
if record and self.autocomplete:
…
elif self.autocomplete:
…
# Set size
if self.autocomplete:
…
else:
…
if record:
…
else:
…
if not field:
value = ''
else:
value = field.get_client(record)
if not self.autocomplete:
self.entry.set_text(value)
else:
…
Presenter Notes
super().display
Set differents states of the widget
def display(self, record, field):
if not field:
self._readonly_set(self.attrs.get('readonly', True))
self.invisible_set(self.attrs.get('invisible', False))
return
self._readonly_set(self.attrs.get('readonly',
field.get_state_attrs(record).get('readonly', False)))
if self.attrs.get('readonly',
field.get_state_attrs(record).get('readonly', False)):
self.color_set('readonly')
elif not field.get_state_attrs(record).get('valid', True):
self.color_set('invalid')
elif field.get_state_attrs(record).get('required', False):
self.color_set('required')
else:
self.color_set('normal')
self.invisible_set(self.attrs.get('invisible',
field.get_state_attrs(record).get('invisible', False)))
Presenter Notes
Methods to get data from the form
- on the widget focus-out a call to set_value
- inside set_value a computation of the GTK widget content
- in the widget set_value method a call to the field's
set_client
- in the field set_client the record is updated
Presenter Notes
Example with the char widget
In the GTk widget:
def set_value(self, record, field):
entry = self.entry.get_child() if self.autocomplete else self.entry
value = entry.get_text() or self._default_value
return field.set_client(record, value)
In the field:
def set_client(self, record, value, force_change=False):
previous_value = self.get(record)
self.set(record, value)
if previous_value != self.get(record):
record.modified_fields.setdefault(self.name)
record.signal('record-modified')
self.sig_changed(record)
record.validate(softvalidation=True)
record.signal('record-changed')
elif force_change:
self.sig_changed(record)
record.validate(softvalidation=True)
record.signal('record-changed')
Presenter Notes
Plugging your widget in the client
Add your field in gui/window/view_form/model/field.py
self.set(record, filename)
return self.get(record)
+
+class DictField(CharField):
+
+ _default = {}
+
+
TYPES = {
'char': CharField,
'sha': CharField,
@@ -941,4 +947,5 @@
'time': TimeField,
'one2one': O2OField,
'binary': BinaryField,
+ 'dict': DictField,
}
Presenter Notes
Plugging your widget in the client
Add your widget in gui/window/view_form/view/form_gtk/parser.py
@@ -547,6 +548,7 @@
from progressbar import ProgressBar
from one2one import One2One
from richtextbox import RichTextBox
+from dictionary import DictWidget
WIDGETS_TYPE = {
@@ -576,4 +578,5 @@
'progressbar': (ProgressBar, 1, False, False),
'one2one': (One2One, 1, False, False),
'richtext': (RichTextBox, 1, True, True),
+ 'dict': (DictWidget, 1, False, False),
}
The number is useless.
The first boolean represent the yexpand property.
The second boolean represent the yfill property.
Presenter Notes
Tree widget
Presenter Notes
Adding a tree widget
In gui/window/view_form/view/list_gtk/parser.py you can add a class to
represent in the list view your widget.
class Geometry(Char):
def __init__(self, field_name, model_name, treeview, attrs=None):
super(Geometry, self).__init__(field_name, model_name, treeview,
attrs=attrs)
def get_textual_value(self, record):
val = record[self.field_name].get_client(record)
return val.wkt if val else ''
get_textual_value will return the value that must be displayed in the cell.
value_from_text will set the value in the record from the text of the cell.
You can also define your own CellRenderer, they are examples in common/.
Presenter Notes
Table of Contents
Help
Help
Table of Contents
t
Exposé
ESC
Full screen slides
e
Presenter View
p
Source Files
s
Slide Numbers
n
Toggle screen blanking
b
Show/hide slide context
c
Notes
2
Help
h
Creating custom widgets
Presenter Notes
Make the server aware
- PROBLEM: The tryton server validates the widget
- SOLUTION: We have to make the server aware of the new widget
- You just have to inherit from ir.ui.view and override the get_rng class method.
Presenter Notes
The tryton architecture
- form & tree & graph
- gui/window/view_form/view/form_gtk
- gui/window/view_form/view/list_gtk
- gui/window/view_form/view/graph_gtk
- field & widget
- gui/window/view_form/model/field.py
- gui/window/view_form/view/form_gtk/*
- record & group
- gui/window/view_form/model/record.py
- gui/window/view_form/model/group.py
Presenter Notes
Form Widget
Presenter Notes
Methods to set data into the form
- in the widget a call to display
- in the field a call to get_client
- GTk code to do the required stuffs
Presenter Notes
Example of char.py
def display(self, record, field): super(Char, self).display(record, field) if record and self.autocomplete: … elif self.autocomplete: … # Set size if self.autocomplete: … else: … if record: … else: … if not field: value = '' else: value = field.get_client(record) if not self.autocomplete: self.entry.set_text(value) else: …
Presenter Notes
super().display
Set differents states of the widget
def display(self, record, field): if not field: self._readonly_set(self.attrs.get('readonly', True)) self.invisible_set(self.attrs.get('invisible', False)) return self._readonly_set(self.attrs.get('readonly', field.get_state_attrs(record).get('readonly', False))) if self.attrs.get('readonly', field.get_state_attrs(record).get('readonly', False)): self.color_set('readonly') elif not field.get_state_attrs(record).get('valid', True): self.color_set('invalid') elif field.get_state_attrs(record).get('required', False): self.color_set('required') else: self.color_set('normal') self.invisible_set(self.attrs.get('invisible', field.get_state_attrs(record).get('invisible', False)))
Presenter Notes
Methods to get data from the form
- on the widget focus-out a call to set_value
- inside set_value a computation of the GTK widget content
- in the widget set_value method a call to the field's set_client
- in the field set_client the record is updated
Presenter Notes
Example with the char widget
In the GTk widget:
def set_value(self, record, field): entry = self.entry.get_child() if self.autocomplete else self.entry value = entry.get_text() or self._default_value return field.set_client(record, value)
In the field:
def set_client(self, record, value, force_change=False): previous_value = self.get(record) self.set(record, value) if previous_value != self.get(record): record.modified_fields.setdefault(self.name) record.signal('record-modified') self.sig_changed(record) record.validate(softvalidation=True) record.signal('record-changed') elif force_change: self.sig_changed(record) record.validate(softvalidation=True) record.signal('record-changed')
Presenter Notes
Plugging your widget in the client
Add your field in gui/window/view_form/model/field.py
self.set(record, filename)
return self.get(record)
+
+class DictField(CharField):
+
+ _default = {}
+
+
TYPES = {
'char': CharField,
'sha': CharField,
@@ -941,4 +947,5 @@
'time': TimeField,
'one2one': O2OField,
'binary': BinaryField,
+ 'dict': DictField,
}
Presenter Notes
Plugging your widget in the client
Add your widget in gui/window/view_form/view/form_gtk/parser.py
@@ -547,6 +548,7 @@ from progressbar import ProgressBar from one2one import One2One from richtextbox import RichTextBox +from dictionary import DictWidget WIDGETS_TYPE = { @@ -576,4 +578,5 @@ 'progressbar': (ProgressBar, 1, False, False), 'one2one': (One2One, 1, False, False), 'richtext': (RichTextBox, 1, True, True), + 'dict': (DictWidget, 1, False, False), }
The number is useless. The first boolean represent the yexpand property. The second boolean represent the yfill property.
Presenter Notes
Tree widget
Presenter Notes
Adding a tree widget
In gui/window/view_form/view/list_gtk/parser.py you can add a class to represent in the list view your widget.
class Geometry(Char): def __init__(self, field_name, model_name, treeview, attrs=None): super(Geometry, self).__init__(field_name, model_name, treeview, attrs=attrs) def get_textual_value(self, record): val = record[self.field_name].get_client(record) return val.wkt if val else ''
get_textual_value will return the value that must be displayed in the cell. value_from_text will set the value in the record from the text of the cell.
You can also define your own CellRenderer, they are examples in common/.
Presenter Notes
Table of Contents
Help
| Table of Contents | t |
|---|---|
| Exposé | ESC |
| Full screen slides | e |
| Presenter View | p |
| Source Files | s |
| Slide Numbers | n |
| Toggle screen blanking | b |
| Show/hide slide context | c |
| Notes | 2 |
| Help | h |