tryton 7.4.10__py3-none-any.whl → 7.6.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of tryton might be problematic. Click here for more details.

Files changed (122) hide show
  1. tryton/__init__.py +1 -1
  2. tryton/bus.py +113 -69
  3. tryton/chat.py +179 -0
  4. tryton/client.py +7 -0
  5. tryton/common/__init__.py +15 -11
  6. tryton/common/button.py +1 -1
  7. tryton/common/cellrendererfloat.py +1 -1
  8. tryton/common/cellrenderertext.py +2 -2
  9. tryton/common/common.py +91 -19
  10. tryton/common/environment.py +2 -2
  11. tryton/common/number_entry.py +12 -6
  12. tryton/common/selection.py +1 -1
  13. tryton/data/locale/bg/LC_MESSAGES/tryton.mo +0 -0
  14. tryton/data/locale/bg/LC_MESSAGES/tryton.po +26 -16
  15. tryton/data/locale/ca/LC_MESSAGES/tryton.mo +0 -0
  16. tryton/data/locale/ca/LC_MESSAGES/tryton.po +29 -18
  17. tryton/data/locale/cs/LC_MESSAGES/tryton.mo +0 -0
  18. tryton/data/locale/cs/LC_MESSAGES/tryton.po +28 -16
  19. tryton/data/locale/de/LC_MESSAGES/tryton.mo +0 -0
  20. tryton/data/locale/de/LC_MESSAGES/tryton.po +27 -18
  21. tryton/data/locale/es/LC_MESSAGES/tryton.mo +0 -0
  22. tryton/data/locale/es/LC_MESSAGES/tryton.po +25 -16
  23. tryton/data/locale/es_419/LC_MESSAGES/tryton.mo +0 -0
  24. tryton/data/locale/es_419/LC_MESSAGES/tryton.po +26 -16
  25. tryton/data/locale/et/LC_MESSAGES/tryton.mo +0 -0
  26. tryton/data/locale/et/LC_MESSAGES/tryton.po +28 -18
  27. tryton/data/locale/fa/LC_MESSAGES/tryton.mo +0 -0
  28. tryton/data/locale/fa/LC_MESSAGES/tryton.po +28 -18
  29. tryton/data/locale/fi/LC_MESSAGES/tryton.mo +0 -0
  30. tryton/data/locale/fi/LC_MESSAGES/tryton.po +25 -16
  31. tryton/data/locale/fr/LC_MESSAGES/tryton.mo +0 -0
  32. tryton/data/locale/fr/LC_MESSAGES/tryton.po +25 -16
  33. tryton/data/locale/hu/LC_MESSAGES/tryton.mo +0 -0
  34. tryton/data/locale/hu/LC_MESSAGES/tryton.po +28 -18
  35. tryton/data/locale/id/LC_MESSAGES/tryton.mo +0 -0
  36. tryton/data/locale/id/LC_MESSAGES/tryton.po +23 -16
  37. tryton/data/locale/it/LC_MESSAGES/tryton.mo +0 -0
  38. tryton/data/locale/it/LC_MESSAGES/tryton.po +29 -18
  39. tryton/data/locale/ja_JP/LC_MESSAGES/tryton.mo +0 -0
  40. tryton/data/locale/lo/LC_MESSAGES/tryton.mo +0 -0
  41. tryton/data/locale/lo/LC_MESSAGES/tryton.po +26 -18
  42. tryton/data/locale/lt/LC_MESSAGES/tryton.mo +0 -0
  43. tryton/data/locale/lt/LC_MESSAGES/tryton.po +30 -18
  44. tryton/data/locale/nl/LC_MESSAGES/tryton.mo +0 -0
  45. tryton/data/locale/nl/LC_MESSAGES/tryton.po +25 -16
  46. tryton/data/locale/pl/LC_MESSAGES/tryton.mo +0 -0
  47. tryton/data/locale/pl/LC_MESSAGES/tryton.po +31 -18
  48. tryton/data/locale/pt/LC_MESSAGES/tryton.mo +0 -0
  49. tryton/data/locale/pt/LC_MESSAGES/tryton.po +148 -177
  50. tryton/data/locale/ro/LC_MESSAGES/tryton.mo +0 -0
  51. tryton/data/locale/ro/LC_MESSAGES/tryton.po +32 -19
  52. tryton/data/locale/ru/LC_MESSAGES/tryton.mo +0 -0
  53. tryton/data/locale/ru/LC_MESSAGES/tryton.po +28 -16
  54. tryton/data/locale/sl/LC_MESSAGES/tryton.mo +0 -0
  55. tryton/data/locale/sl/LC_MESSAGES/tryton.po +33 -18
  56. tryton/data/locale/tr/LC_MESSAGES/tryton.mo +0 -0
  57. tryton/data/locale/tr/LC_MESSAGES/tryton.po +25 -16
  58. tryton/data/locale/uk/LC_MESSAGES/tryton.mo +0 -0
  59. tryton/data/locale/uk/LC_MESSAGES/tryton.po +31 -18
  60. tryton/data/locale/zh_CN/LC_MESSAGES/tryton.mo +0 -0
  61. tryton/data/locale/zh_CN/LC_MESSAGES/tryton.po +27 -18
  62. tryton/data/pixmaps/tryton/tryton-chat.svg +1 -0
  63. tryton/data/pixmaps/tryton/tryton-note.svg +1 -4
  64. tryton/gui/window/attachment.py +2 -2
  65. tryton/gui/window/board.py +1 -1
  66. tryton/gui/window/form.py +57 -10
  67. tryton/gui/window/note.py +2 -2
  68. tryton/gui/window/tabcontent.py +8 -1
  69. tryton/gui/window/view_board/action.py +1 -1
  70. tryton/gui/window/view_form/model/field.py +34 -28
  71. tryton/gui/window/view_form/model/group.py +4 -4
  72. tryton/gui/window/view_form/model/record.py +19 -4
  73. tryton/gui/window/view_form/screen/screen.py +24 -4
  74. tryton/gui/window/view_form/view/calendar_gtk/calendar_.py +1 -1
  75. tryton/gui/window/view_form/view/calendar_gtk/toolbar.py +1 -1
  76. tryton/gui/window/view_form/view/form.py +2 -1
  77. tryton/gui/window/view_form/view/form_gtk/binary.py +3 -3
  78. tryton/gui/window/view_form/view/form_gtk/calendar_.py +4 -4
  79. tryton/gui/window/view_form/view/form_gtk/char.py +42 -5
  80. tryton/gui/window/view_form/view/form_gtk/checkbox.py +3 -3
  81. tryton/gui/window/view_form/view/form_gtk/dictionary.py +53 -15
  82. tryton/gui/window/view_form/view/form_gtk/float.py +3 -7
  83. tryton/gui/window/view_form/view/form_gtk/image.py +4 -4
  84. tryton/gui/window/view_form/view/form_gtk/integer.py +1 -1
  85. tryton/gui/window/view_form/view/form_gtk/many2many.py +3 -4
  86. tryton/gui/window/view_form/view/form_gtk/many2one.py +2 -2
  87. tryton/gui/window/view_form/view/form_gtk/multiselection.py +3 -3
  88. tryton/gui/window/view_form/view/form_gtk/one2many.py +11 -8
  89. tryton/gui/window/view_form/view/form_gtk/progressbar.py +2 -2
  90. tryton/gui/window/view_form/view/form_gtk/pyson.py +3 -3
  91. tryton/gui/window/view_form/view/form_gtk/reference.py +4 -4
  92. tryton/gui/window/view_form/view/form_gtk/richtextbox.py +5 -5
  93. tryton/gui/window/view_form/view/form_gtk/selection.py +3 -3
  94. tryton/gui/window/view_form/view/form_gtk/state_widget.py +8 -6
  95. tryton/gui/window/view_form/view/form_gtk/textbox.py +4 -4
  96. tryton/gui/window/view_form/view/form_gtk/timedelta.py +3 -3
  97. tryton/gui/window/view_form/view/form_gtk/url.py +2 -2
  98. tryton/gui/window/view_form/view/form_gtk/widget.py +1 -1
  99. tryton/gui/window/view_form/view/graph_gtk/bar.py +7 -7
  100. tryton/gui/window/view_form/view/graph_gtk/graph.py +2 -2
  101. tryton/gui/window/view_form/view/graph_gtk/line.py +5 -5
  102. tryton/gui/window/view_form/view/graph_gtk/pie.py +2 -2
  103. tryton/gui/window/view_form/view/list.py +107 -52
  104. tryton/gui/window/view_form/view/list_gtk/editabletree.py +2 -2
  105. tryton/gui/window/view_form/view/list_gtk/widget.py +22 -20
  106. tryton/gui/window/view_form/view/screen_container.py +13 -1
  107. tryton/gui/window/win_csv.py +2 -2
  108. tryton/gui/window/win_export.py +9 -7
  109. tryton/gui/window/win_form.py +74 -39
  110. tryton/gui/window/win_import.py +5 -6
  111. tryton/gui/window/wizard.py +11 -11
  112. tryton/jsonrpc.py +2 -2
  113. tryton/plugins/__init__.py +0 -1
  114. tryton/pyson.py +18 -18
  115. tryton/rpc.py +7 -5
  116. {tryton-7.4.10.dist-info → tryton-7.6.1.dist-info}/METADATA +5 -5
  117. {tryton-7.4.10.dist-info → tryton-7.6.1.dist-info}/RECORD +121 -120
  118. tryton/gui/window/view_form/view/list_gtk/generictreemodel.py +0 -426
  119. {tryton-7.4.10.data → tryton-7.6.1.data}/scripts/tryton +0 -0
  120. {tryton-7.4.10.dist-info → tryton-7.6.1.dist-info}/WHEEL +0 -0
  121. {tryton-7.4.10.dist-info → tryton-7.6.1.dist-info}/licenses/LICENSE +0 -0
  122. {tryton-7.4.10.dist-info → tryton-7.6.1.dist-info}/top_level.txt +0 -0
@@ -18,7 +18,7 @@ _ = gettext.gettext
18
18
  class BinaryMixin(Widget):
19
19
 
20
20
  def __init__(self, view, attrs):
21
- super(BinaryMixin, self).__init__(view, attrs)
21
+ super().__init__(view, attrs)
22
22
  self.filename = attrs.get('filename')
23
23
 
24
24
  def toolbar(self):
@@ -148,7 +148,7 @@ class Binary(BinaryMixin, Widget):
148
148
  "Binary"
149
149
 
150
150
  def __init__(self, view, attrs):
151
- super(Binary, self).__init__(view, attrs)
151
+ super().__init__(view, attrs)
152
152
 
153
153
  self.widget = Gtk.HBox(spacing=0)
154
154
  self.wid_size = Gtk.Entry()
@@ -198,7 +198,7 @@ class Binary(BinaryMixin, Widget):
198
198
  self.open_()
199
199
 
200
200
  def display(self):
201
- super(Binary, self).display()
201
+ super().display()
202
202
  if not self.field:
203
203
  if self.wid_text:
204
204
  self.wid_text.set_text('')
@@ -20,7 +20,7 @@ class Date(Widget):
20
20
  _changed_signal = 'date-changed'
21
21
 
22
22
  def __init__(self, view, attrs, _entry=DateEntry):
23
- super(Date, self).__init__(view, attrs)
23
+ super().__init__(view, attrs)
24
24
 
25
25
  self.widget = Gtk.HBox()
26
26
  self.entry = self.mnemonic_widget = add_operators(_entry())
@@ -83,7 +83,7 @@ class Date(Widget):
83
83
  self.entry.props.format = format_
84
84
 
85
85
  def display(self):
86
- super(Date, self).display()
86
+ super().display()
87
87
  if self.field and self.record:
88
88
  value = self.field.get_client(self.record)
89
89
  else:
@@ -101,7 +101,7 @@ class Time(Date):
101
101
  _changed_signal = 'time-changed'
102
102
 
103
103
  def __init__(self, view, attrs):
104
- super(Time, self).__init__(view, attrs, _entry=TimeEntry)
104
+ super().__init__(view, attrs, _entry=TimeEntry)
105
105
  self.entry.connect('move-active', _move_active)
106
106
  self.entry.connect(
107
107
  'scroll-event',
@@ -121,7 +121,7 @@ class Time(Date):
121
121
  return self.entry.get_child()
122
122
 
123
123
  def display(self):
124
- super(Time, self).display()
124
+ super().display()
125
125
 
126
126
  def set_format(self):
127
127
  if self.field and self.record:
@@ -2,7 +2,7 @@
2
2
  # this repository contains the full copyright notices and license terms.
3
3
  import gettext
4
4
 
5
- from gi.repository import GLib, Gtk
5
+ from gi.repository import Gdk, GLib, Gtk
6
6
 
7
7
  from tryton.common import IconFactory, Tooltips
8
8
  from tryton.common.entry_position import reset_position
@@ -17,7 +17,7 @@ class Char(Widget, TranslateMixin, PopdownMixin):
17
17
  "Char"
18
18
 
19
19
  def __init__(self, view, attrs):
20
- super(Char, self).__init__(view, attrs)
20
+ super().__init__(view, attrs)
21
21
 
22
22
  self.widget = Gtk.HBox()
23
23
  self.autocomplete = bool(attrs.get('autocomplete'))
@@ -105,7 +105,7 @@ class Char(Widget, TranslateMixin, PopdownMixin):
105
105
  return value
106
106
 
107
107
  def display(self):
108
- super(Char, self).display()
108
+ super().display()
109
109
  if self.autocomplete:
110
110
  if self.record:
111
111
  if self.field_name not in self.record.autocompletion:
@@ -150,7 +150,7 @@ class Char(Widget, TranslateMixin, PopdownMixin):
150
150
  True: Gtk.SensitivityType.OFF,
151
151
  False: Gtk.SensitivityType.AUTO,
152
152
  }
153
- super(Char, self)._readonly_set(value)
153
+ super()._readonly_set(value)
154
154
  if self.autocomplete:
155
155
  entry_editable = self.entry.get_child()
156
156
  self.entry.set_button_sensitivity(sensitivity[value])
@@ -162,7 +162,7 @@ class Char(Widget, TranslateMixin, PopdownMixin):
162
162
  class Password(Char):
163
163
 
164
164
  def __init__(self, view, attrs):
165
- super(Password, self).__init__(view, attrs)
165
+ super().__init__(view, attrs)
166
166
  self.entry.props.visibility = False
167
167
 
168
168
  self.visibility_checkbox = Gtk.CheckButton()
@@ -177,3 +177,40 @@ class Password(Char):
177
177
  else:
178
178
  entry = self.entry
179
179
  entry.props.visibility = not self.entry.props.visibility
180
+
181
+
182
+ class Color(Char):
183
+
184
+ def __init__(self, view, attrs):
185
+ super().__init__(view, attrs)
186
+
187
+ self.color_button = Gtk.ColorButton()
188
+ self.color_button.connect('color-set', self.set_color)
189
+ self.color_button.set_title(
190
+ _('Select a color for "%s"') % attrs['string'])
191
+ Tooltips().set_tip(self.color_button, _("Select a color"))
192
+ self.widget.pack_start(
193
+ self.color_button, expand=False, fill=True, padding=0)
194
+
195
+ def set_color(self, button):
196
+ if self.autocomplete:
197
+ entry = self.entry.get_child()
198
+ else:
199
+ entry = self.entry
200
+ rgba = self.color_button.get_rgba()
201
+ rgb = list(map(lambda x: int(x * 255), list(rgba)[:3]))
202
+ entry.set_text('#{:02X}{:02X}{:02X}'.format(*rgb))
203
+ self._focus_out()
204
+
205
+ def _readonly_set(self, value):
206
+ super()._readonly_set(value)
207
+ self.color_button.set_sensitive(not value)
208
+
209
+ def display(self):
210
+ super().display()
211
+ if self.field and self.record:
212
+ value = self.field.get_client(self.record)
213
+ rgba = Gdk.RGBA()
214
+ if value:
215
+ rgba.parse(value)
216
+ self.color_button.set_rgba(rgba)
@@ -12,13 +12,13 @@ _ = gettext.gettext
12
12
  class CheckBox(Widget):
13
13
 
14
14
  def __init__(self, view, attrs):
15
- super(CheckBox, self).__init__(view, attrs)
15
+ super().__init__(view, attrs)
16
16
  self.widget = self.mnemonic_widget = Gtk.CheckButton()
17
17
  self.widget.connect('focus-out-event', lambda x, y: self._focus_out())
18
18
  self.widget.connect_after('toggled', self.sig_activate)
19
19
 
20
20
  def _readonly_set(self, value):
21
- super(CheckBox, self)._readonly_set(value)
21
+ super()._readonly_set(value)
22
22
  # TODO find a better solution to accept focus
23
23
  self.widget.set_sensitive(not value)
24
24
 
@@ -26,7 +26,7 @@ class CheckBox(Widget):
26
26
  self.field.set_client(self.record, self.widget.get_active())
27
27
 
28
28
  def display(self):
29
- super(CheckBox, self).display()
29
+ super().display()
30
30
  if not self.field:
31
31
  self.widget.set_active(False)
32
32
  return False
@@ -9,7 +9,7 @@ import operator
9
9
  from collections import defaultdict
10
10
  from decimal import Decimal
11
11
 
12
- from gi.repository import GLib, GObject, Gtk
12
+ from gi.repository import Gdk, GLib, GObject, Gtk
13
13
 
14
14
  from tryton.common import (
15
15
  IconFactory, Tooltips, timezoned_date, untimezoned_date)
@@ -83,6 +83,42 @@ class DictCharEntry(DictEntry):
83
83
  return self.get_value() != (value.get(self.name, '') or '')
84
84
 
85
85
 
86
+ class DictColorEntry(DictCharEntry):
87
+
88
+ def create_widget(self):
89
+ self.entry = super().create_widget()
90
+ widget = Gtk.HBox()
91
+ widget.pack_start(self.entry, expand=True, fill=True, padding=0)
92
+ self.button = Gtk.ColorButton()
93
+ self.button.connect('color-set', self.set_color)
94
+ self.button.set_title(
95
+ _('Select a color for "%s"') % self.definition['string'])
96
+ Tooltips().set_tip(self.button, _("Select a color"))
97
+ widget.pack_start(self.button, expand=False, fill=True, padding=0)
98
+ return widget
99
+
100
+ def set_color(self, button):
101
+ rgba = self.button.get_rgba()
102
+ rgb = map(lambda x: int(x * 255), list(rgba)[:3])
103
+ self.entry.set_text('#{:02X}{:02X}{:02X}'.format(*rgb))
104
+ self.parent_widget._focus_out()
105
+
106
+ def get_value(self):
107
+ return self.entry.get_text()
108
+
109
+ def set_value(self, value):
110
+ self.entry.set_text(str(value or ''))
111
+ reset_position(self.entry)
112
+ rgba = Gdk.RGBA()
113
+ if value:
114
+ rgba.parse(value)
115
+ self.button.set_rgba(rgba)
116
+
117
+ def set_readonly(self, readonly):
118
+ self.entry.set_editable(not readonly)
119
+ self.button.set_sensitive(not readonly)
120
+
121
+
86
122
  class DictBooleanEntry(DictEntry):
87
123
 
88
124
  def create_widget(self):
@@ -301,15 +337,12 @@ class DictFloatEntry(DictIntegerEntry):
301
337
  def digits(self):
302
338
  record = self.parent_widget.record
303
339
  if record:
304
- digits = record.expr_eval(self.definition.get('digits'))
305
- if not digits or any(d is None for d in digits):
306
- return
307
- return digits
340
+ return record.expr_eval(self.definition.get('digits'))
308
341
 
309
342
  @property
310
343
  def width(self):
311
344
  digits = self.digits
312
- if digits:
345
+ if digits and all(digits):
313
346
  return sum(digits)
314
347
  else:
315
348
  return 18
@@ -318,15 +351,19 @@ class DictFloatEntry(DictIntegerEntry):
318
351
  return self.widget.value
319
352
 
320
353
  def set_value(self, value):
321
- digits = self.digits
322
- if digits:
323
- self.widget.digits = digits[1]
324
- else:
325
- self.widget.digits = None
354
+ self.widget.digits = digits = self.digits
326
355
  self.widget.set_width_chars(self.width)
327
356
  if isinstance(value, (int, float, Decimal)):
328
- txt_val = locale.localize(
329
- '{0:.{1}f}'.format(value, digits[1]), True)
357
+ d = value
358
+ if not isinstance(d, Decimal):
359
+ d = Decimal(repr(d))
360
+ if digits and digits[1] is not None:
361
+ p = int(digits[1])
362
+ elif d == d.to_integral_value():
363
+ p = 0
364
+ else:
365
+ p = -int(d.as_tuple().exponent)
366
+ txt_val = locale.localize('{0:.{1}f}'.format(d, p), True)
330
367
  else:
331
368
  txt_val = ''
332
369
  self.widget.set_text(txt_val)
@@ -416,6 +453,7 @@ class DictDateEntry(DictEntry):
416
453
 
417
454
  DICT_ENTRIES = {
418
455
  'char': DictCharEntry,
456
+ 'color': DictColorEntry,
419
457
  'boolean': DictBooleanEntry,
420
458
  'selection': DictSelectionEntry,
421
459
  'multiselection': DictMultiSelectionEntry,
@@ -430,7 +468,7 @@ DICT_ENTRIES = {
430
468
  class DictWidget(Widget):
431
469
 
432
470
  def __init__(self, view, attrs):
433
- super(DictWidget, self).__init__(view, attrs)
471
+ super().__init__(view, attrs)
434
472
  self.schema_model = attrs['schema_model']
435
473
  self.fields = {}
436
474
  self.buttons = {}
@@ -603,7 +641,7 @@ class DictWidget(Widget):
603
641
  self.buttons[key] = remove_but
604
642
 
605
643
  def display(self):
606
- super(DictWidget, self).display()
644
+ super().display()
607
645
 
608
646
  if not self.field:
609
647
  return
@@ -14,15 +14,11 @@ class Float(Integer):
14
14
  @property
15
15
  def width(self):
16
16
  digits = self.digits
17
- if digits:
17
+ if digits and all(digits):
18
18
  return sum(digits)
19
19
  else:
20
20
  return self.attrs.get('width', 18)
21
21
 
22
22
  def display(self):
23
- digits = self.digits
24
- if digits:
25
- self.entry.digits = digits[1]
26
- else:
27
- self.entry.digits = None
28
- super(Float, self).display()
23
+ self.entry.digits = self.digits
24
+ super().display()
@@ -16,7 +16,7 @@ _ = gettext.gettext
16
16
  class Image(BinaryMixin, Widget):
17
17
 
18
18
  def __init__(self, view, attrs):
19
- super(Image, self).__init__(view, attrs)
19
+ super().__init__(view, attrs)
20
20
 
21
21
  self.height = int(attrs.get('height', 100))
22
22
  self.width = int(attrs.get('width', 300))
@@ -49,7 +49,7 @@ class Image(BinaryMixin, Widget):
49
49
 
50
50
  @property
51
51
  def filters(self):
52
- filters = super(Image, self).filters
52
+ filters = super().filters
53
53
  filter_image = Gtk.FileFilter()
54
54
  filter_image.set_name(_('Images'))
55
55
  for mime in ("image/png", "image/jpeg", "image/gif"):
@@ -65,7 +65,7 @@ class Image(BinaryMixin, Widget):
65
65
  self.but_clear.set_sensitive(not value)
66
66
 
67
67
  def clear(self, widget=None):
68
- super(Image, self).clear(widget=widget)
68
+ super().clear(widget=widget)
69
69
  self.update_img()
70
70
 
71
71
  def drag_motion(self, widget, context, x, y, timestamp):
@@ -110,6 +110,6 @@ class Image(BinaryMixin, Widget):
110
110
  return bool(value)
111
111
 
112
112
  def display(self):
113
- super(Image, self).display()
113
+ super().display()
114
114
  value = self.update_img()
115
115
  self.update_buttons(bool(value))
@@ -12,7 +12,7 @@ class Integer(Widget):
12
12
  "Integer"
13
13
 
14
14
  def __init__(self, view, attrs):
15
- super(Integer, self).__init__(view, attrs)
15
+ super().__init__(view, attrs)
16
16
  self.widget = Gtk.HBox()
17
17
  self.entry = self.mnemonic_widget = NumberEntry(
18
18
  monetary=attrs.get('monetary', False))
@@ -21,7 +21,7 @@ class Many2Many(Widget):
21
21
  expand = True
22
22
 
23
23
  def __init__(self, view, attrs):
24
- super(Many2Many, self).__init__(view, attrs)
24
+ super().__init__(view, attrs)
25
25
 
26
26
  self.widget = Gtk.Frame()
27
27
  self.widget.set_shadow_type(Gtk.ShadowType.NONE)
@@ -246,7 +246,6 @@ class Many2Many(Widget):
246
246
 
247
247
  def callback(result):
248
248
  if result:
249
- screen.current_record.save()
250
249
  added = 'id' in self.screen.current_record.modified_fields
251
250
  # Force a reload on next display
252
251
  self.screen.current_record.cancel()
@@ -255,7 +254,7 @@ class Many2Many(Widget):
255
254
  # Force a display to clear the CellCache
256
255
  self.screen.display()
257
256
  self._popup = False
258
- WinForm(screen, callback)
257
+ WinForm(screen, callback, save_current=True)
259
258
 
260
259
  def _sig_new(self, defaults=None):
261
260
  if self._popup:
@@ -331,7 +330,7 @@ class Many2Many(Widget):
331
330
  self._set_button_sensitive()
332
331
 
333
332
  def display(self):
334
- super(Many2Many, self).display()
333
+ super().display()
335
334
  if not self.field:
336
335
  self.screen.new_group()
337
336
  self.screen.current_record = None
@@ -22,7 +22,7 @@ class Many2One(Widget):
22
22
  default_width_chars = 12
23
23
 
24
24
  def __init__(self, view, attrs):
25
- super(Many2One, self).__init__(view, attrs)
25
+ super().__init__(view, attrs)
26
26
 
27
27
  self.widget = Gtk.HBox(spacing=0)
28
28
  self.widget.set_property('sensitive', True)
@@ -306,7 +306,7 @@ class Many2One(Widget):
306
306
 
307
307
  def display(self):
308
308
  self.changed = False
309
- super(Many2One, self).display()
309
+ super().display()
310
310
 
311
311
  self._set_button_sensitive()
312
312
  self._set_completion()
@@ -11,7 +11,7 @@ class MultiSelection(Widget, SelectionMixin):
11
11
  expand = True
12
12
 
13
13
  def __init__(self, view, attrs):
14
- super(MultiSelection, self).__init__(view, attrs)
14
+ super().__init__(view, attrs)
15
15
 
16
16
  if int(attrs.get('yexpand', self.expand)):
17
17
  self.widget = Gtk.ScrolledWindow()
@@ -51,7 +51,7 @@ class MultiSelection(Widget, SelectionMixin):
51
51
  cell.set_property('active', selection.iter_is_selected(iter_))
52
52
 
53
53
  def _readonly_set(self, readonly):
54
- super(MultiSelection, self)._readonly_set(readonly)
54
+ super()._readonly_set(readonly)
55
55
  selection = self.tree.get_selection()
56
56
  selection.set_select_function(lambda *a: not readonly)
57
57
 
@@ -101,6 +101,6 @@ class MultiSelection(Widget, SelectionMixin):
101
101
  values = self.field.get_eval(self.record)
102
102
  for value in values:
103
103
  selection.select_path(value2path[value])
104
- super(MultiSelection, self).display()
104
+ super().display()
105
105
  finally:
106
106
  selection.handler_unblock_by_func(self.changed)
@@ -22,7 +22,7 @@ class One2Many(Widget):
22
22
  expand = True
23
23
 
24
24
  def __init__(self, view, attrs):
25
- super(One2Many, self).__init__(view, attrs)
25
+ super().__init__(view, attrs)
26
26
 
27
27
  self.widget = Gtk.Frame()
28
28
  self.widget.set_shadow_type(Gtk.ShadowType.NONE)
@@ -31,7 +31,7 @@ class One2Many(Widget):
31
31
  self.widget.add(vbox)
32
32
  self._readonly = True
33
33
  self._required = False
34
- self._position = 0
34
+ self._position = None
35
35
  self._length = 0
36
36
 
37
37
  self.title_box = hbox = Gtk.HBox(homogeneous=False, spacing=0)
@@ -166,6 +166,7 @@ class One2Many(Widget):
166
166
  order=attrs.get('order'),
167
167
  row_activate=self._on_activate,
168
168
  exclude_field=attrs.get('relation_field', None),
169
+ readonly=self.view.screen.group.readonly,
169
170
  limit=None,
170
171
  context=self.view.screen.context,
171
172
  breadcrumb=breadcrumb)
@@ -304,6 +305,7 @@ class One2Many(Widget):
304
305
  r.deleted or r.removed for r in self.screen.selected_records)
305
306
  view_type = self.screen.current_view.view_type
306
307
  has_views = self.screen.number_of_views > 1
308
+ has_form = 'form' in self.attrs.get('mode', 'tree,form').split(',')
307
309
 
308
310
  self.but_switch.set_sensitive(
309
311
  (self._position or view_type == 'form') and has_views)
@@ -315,15 +317,16 @@ class One2Many(Widget):
315
317
  not self._readonly
316
318
  and self.delete_access
317
319
  and deletable
318
- and self._position))
320
+ and self._position is not None))
319
321
  self.but_undel.set_sensitive(bool(
320
322
  not self._readonly
321
323
  and not size_limit
322
324
  and undeletable
323
- and self._position))
325
+ and self._position is not None))
324
326
  self.but_open.set_sensitive(bool(
325
- self._position
326
- and self.read_access))
327
+ self._position is not None
328
+ and self.read_access
329
+ and has_form))
327
330
  self.but_next.set_sensitive(bool(
328
331
  self._length
329
332
  and not last))
@@ -338,7 +341,7 @@ class One2Many(Widget):
338
341
  and self.read_access))
339
342
  self.but_remove.set_sensitive(bool(
340
343
  not self._readonly
341
- and self._position
344
+ and self._position is not None
342
345
  and self.write_access
343
346
  and self.read_access))
344
347
  self.wid_text.set_sensitive(self.but_add.get_sensitive())
@@ -554,7 +557,7 @@ class One2Many(Widget):
554
557
  self._set_button_sensitive()
555
558
 
556
559
  def display(self):
557
- super(One2Many, self).display()
560
+ super().display()
558
561
 
559
562
  self._set_button_sensitive()
560
563
 
@@ -19,7 +19,7 @@ class ProgressBar(Widget):
19
19
  }
20
20
 
21
21
  def __init__(self, view, attrs):
22
- super(ProgressBar, self).__init__(view, attrs)
22
+ super().__init__(view, attrs)
23
23
  self.widget = self.mnemonic_widget = Gtk.ProgressBar()
24
24
  orientation, inverted = self.orientations.get(
25
25
  attrs.get('orientation', 'left_to_right'))
@@ -28,7 +28,7 @@ class ProgressBar(Widget):
28
28
  self.widget.set_show_text(True)
29
29
 
30
30
  def display(self):
31
- super(ProgressBar, self).display()
31
+ super().display()
32
32
  if not self.field:
33
33
  self.widget.set_text('')
34
34
  self.widget.set_fraction(0.0)
@@ -11,7 +11,7 @@ from .char import Char
11
11
  class PYSON(Char):
12
12
 
13
13
  def __init__(self, view, attrs):
14
- super(PYSON, self).__init__(view, attrs)
14
+ super().__init__(view, attrs)
15
15
  self.encoder = PYSONEncoder()
16
16
  self.decoder = PYSONDecoder(noeval=True)
17
17
  self.entry.connect('key-release-event', self.validate_pyson)
@@ -36,7 +36,7 @@ class PYSON(Char):
36
36
  self.field.set_client(self.record, value)
37
37
 
38
38
  def get_client_value(self):
39
- value = super(PYSON, self).get_client_value()
39
+ value = super().get_client_value()
40
40
  if value:
41
41
  value = repr(self.decoder.decode(value))
42
42
  return value
@@ -51,4 +51,4 @@ class PYSON(Char):
51
51
 
52
52
  def _focus_out(self):
53
53
  self.validate_pyson()
54
- super(PYSON, self)._focus_out()
54
+ super()._focus_out()
@@ -15,7 +15,7 @@ _ = gettext.gettext
15
15
  class Reference(Many2One, SelectionMixin, PopdownMixin):
16
16
 
17
17
  def __init__(self, view, attrs):
18
- super(Reference, self).__init__(view, attrs)
18
+ super().__init__(view, attrs)
19
19
 
20
20
  self.widget_combo = Gtk.ComboBox(has_entry=True)
21
21
  child = self.widget_combo.get_child()
@@ -54,7 +54,7 @@ class Reference(Many2One, SelectionMixin, PopdownMixin):
54
54
  combobox.stop_emission_by_name('move-active')
55
55
 
56
56
  def _set_button_sensitive(self):
57
- super(Reference, self)._set_button_sensitive()
57
+ super()._set_button_sensitive()
58
58
  self.widget_combo.get_child().set_editable(not self._readonly)
59
59
  self.widget_combo.set_button_sensitivity(
60
60
  Gtk.SensitivityType.OFF if self._readonly
@@ -129,7 +129,7 @@ class Reference(Many2One, SelectionMixin, PopdownMixin):
129
129
  model, value = value
130
130
  else:
131
131
  model, value = None, None
132
- super(Reference, self).set_text(value)
132
+ super().set_text(value)
133
133
  self.widget_combo.handler_block_by_func(self.sig_changed_combo)
134
134
  if not self.set_popdown_value(self.widget_combo, model):
135
135
  text = self.get_inactive_selection(model)
@@ -141,4 +141,4 @@ class Reference(Many2One, SelectionMixin, PopdownMixin):
141
141
  def display(self):
142
142
  self.update_selection(self.record, self.field)
143
143
  self.set_popdown(self.selection, self.widget_combo)
144
- super(Reference, self).display()
144
+ super().display()
@@ -15,7 +15,7 @@ from .textbox import TextBox
15
15
  class RichTextBox(TextBox):
16
16
 
17
17
  def __init__(self, view, attrs):
18
- super(RichTextBox, self).__init__(view, attrs)
18
+ super().__init__(view, attrs)
19
19
  self.toolbar = None
20
20
  self.tag_widgets = WeakKeyDictionary()
21
21
  self.tags = {}
@@ -32,12 +32,12 @@ class RichTextBox(TextBox):
32
32
  self.toolbar, expand=False, fill=True, padding=0)
33
33
 
34
34
  def _get_textview(self):
35
- textview = super(RichTextBox, self)._get_textview()
35
+ textview = super()._get_textview()
36
36
  register_format(textview)
37
37
  return textview
38
38
 
39
39
  def translate_widget(self):
40
- widget = super(RichTextBox, self).translate_widget()
40
+ widget = super().translate_widget()
41
41
  textview = widget.get_children()[-1].get_child()
42
42
  if self.toolbar:
43
43
  widget.pack_start(
@@ -45,7 +45,7 @@ class RichTextBox(TextBox):
45
45
  return widget
46
46
 
47
47
  def translate_widget_set_readonly(self, widget, value):
48
- super(RichTextBox, self).translate_widget_set_readonly(widget, value)
48
+ super().translate_widget_set_readonly(widget, value)
49
49
  if self.toolbar:
50
50
  toolbar = widget.get_children()[0]
51
51
  for n in range(toolbar.get_n_items()):
@@ -74,6 +74,6 @@ class RichTextBox(TextBox):
74
74
  return get_content(textview)
75
75
 
76
76
  def _readonly_set(self, value):
77
- super(RichTextBox, self)._readonly_set(value)
77
+ super()._readonly_set(value)
78
78
  if self.toolbar:
79
79
  self.toolbar.set_sensitive(not value)
@@ -11,7 +11,7 @@ from .widget import Widget
11
11
  class Selection(Widget, SelectionMixin, PopdownMixin):
12
12
 
13
13
  def __init__(self, view, attrs):
14
- super(Selection, self).__init__(view, attrs)
14
+ super().__init__(view, attrs)
15
15
 
16
16
  self.widget = Gtk.HBox(spacing=3)
17
17
  self.entry = Gtk.ComboBox(has_entry=True)
@@ -47,7 +47,7 @@ class Selection(Widget, SelectionMixin, PopdownMixin):
47
47
  combobox.stop_emission_by_name('move-active')
48
48
 
49
49
  def _readonly_set(self, value):
50
- super(Selection, self)._readonly_set(value)
50
+ super()._readonly_set(value)
51
51
  self.entry.get_child().set_editable(not value)
52
52
  self.entry.set_button_sensitivity(
53
53
  Gtk.SensitivityType.OFF if value else Gtk.SensitivityType.AUTO)
@@ -77,7 +77,7 @@ class Selection(Widget, SelectionMixin, PopdownMixin):
77
77
  # When setting no item GTK doesn't clear the entry
78
78
  self.entry.get_child().set_text('')
79
79
  return
80
- super(Selection, self).display()
80
+ super().display()
81
81
  value = self.field.get(self.record)
82
82
  if isinstance(value, (list, tuple)):
83
83
  # Compatibility with Many2One