tryton 6.6.8__py3-none-any.whl → 6.8.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.
- tryton/__init__.py +1 -1
- tryton/action/main.py +32 -43
- tryton/bus.py +2 -0
- tryton/client.py +3 -0
- tryton/common/button.py +3 -1
- tryton/common/common.py +55 -43
- tryton/common/datetime_.py +14 -2
- tryton/common/domain_inversion.py +10 -10
- tryton/common/domain_parser.py +5 -2
- tryton/common/popup_menu.py +7 -0
- tryton/common/selection.py +3 -1
- tryton/config.py +22 -5
- tryton/data/locale/bg/LC_MESSAGES/tryton.mo +0 -0
- tryton/data/locale/bg/LC_MESSAGES/tryton.po +45 -39
- tryton/data/locale/ca/LC_MESSAGES/tryton.mo +0 -0
- tryton/data/locale/ca/LC_MESSAGES/tryton.po +41 -35
- tryton/data/locale/cs/LC_MESSAGES/tryton.mo +0 -0
- tryton/data/locale/cs/LC_MESSAGES/tryton.po +46 -39
- tryton/data/locale/de/LC_MESSAGES/tryton.mo +0 -0
- tryton/data/locale/de/LC_MESSAGES/tryton.po +41 -35
- tryton/data/locale/es/LC_MESSAGES/tryton.mo +0 -0
- tryton/data/locale/es/LC_MESSAGES/tryton.po +41 -35
- tryton/data/locale/es_419/LC_MESSAGES/tryton.mo +0 -0
- tryton/data/locale/es_419/LC_MESSAGES/tryton.po +171 -167
- tryton/data/locale/et/LC_MESSAGES/tryton.mo +0 -0
- tryton/data/locale/et/LC_MESSAGES/tryton.po +47 -39
- tryton/data/locale/fa/LC_MESSAGES/tryton.mo +0 -0
- tryton/data/locale/fa/LC_MESSAGES/tryton.po +46 -38
- tryton/data/locale/fi/LC_MESSAGES/tryton.mo +0 -0
- tryton/data/locale/fi/LC_MESSAGES/tryton.po +38 -32
- tryton/data/locale/fr/LC_MESSAGES/tryton.mo +0 -0
- tryton/data/locale/fr/LC_MESSAGES/tryton.po +42 -36
- tryton/data/locale/hu/LC_MESSAGES/tryton.mo +0 -0
- tryton/data/locale/hu/LC_MESSAGES/tryton.po +44 -34
- tryton/data/locale/id/LC_MESSAGES/tryton.mo +0 -0
- tryton/data/locale/id/LC_MESSAGES/tryton.po +40 -34
- tryton/data/locale/it/LC_MESSAGES/tryton.mo +0 -0
- tryton/data/locale/it/LC_MESSAGES/tryton.po +44 -34
- tryton/data/locale/ja_JP/LC_MESSAGES/tryton.mo +0 -0
- tryton/data/locale/lo/LC_MESSAGES/tryton.mo +0 -0
- tryton/data/locale/lo/LC_MESSAGES/tryton.po +46 -38
- tryton/data/locale/lt/LC_MESSAGES/tryton.mo +0 -0
- tryton/data/locale/lt/LC_MESSAGES/tryton.po +47 -37
- tryton/data/locale/nl/LC_MESSAGES/tryton.mo +0 -0
- tryton/data/locale/nl/LC_MESSAGES/tryton.po +41 -35
- tryton/data/locale/pl/LC_MESSAGES/tryton.mo +0 -0
- tryton/data/locale/pl/LC_MESSAGES/tryton.po +45 -35
- tryton/data/locale/pt/LC_MESSAGES/tryton.mo +0 -0
- tryton/data/locale/pt/LC_MESSAGES/tryton.po +46 -38
- tryton/data/locale/ro/LC_MESSAGES/tryton.mo +0 -0
- tryton/data/locale/ro/LC_MESSAGES/tryton.po +50 -48
- tryton/data/locale/ru/LC_MESSAGES/tryton.mo +0 -0
- tryton/data/locale/ru/LC_MESSAGES/tryton.po +45 -39
- tryton/data/locale/sl/LC_MESSAGES/tryton.mo +0 -0
- tryton/data/locale/sl/LC_MESSAGES/tryton.po +47 -38
- tryton/data/locale/tr/LC_MESSAGES/tryton.mo +0 -0
- tryton/data/locale/tr/LC_MESSAGES/tryton.po +39 -33
- tryton/data/locale/uk/LC_MESSAGES/tryton.mo +0 -0
- tryton/data/locale/uk/LC_MESSAGES/tryton.po +43 -35
- tryton/data/locale/zh_CN/LC_MESSAGES/tryton.mo +0 -0
- tryton/data/locale/zh_CN/LC_MESSAGES/tryton.po +45 -35
- tryton/data/pixmaps/tryton/tryton-icon.svg +1 -0
- tryton/gui/main.py +54 -61
- tryton/gui/window/dblogin.py +27 -10
- tryton/gui/window/form.py +21 -53
- tryton/gui/window/infobar.py +9 -4
- tryton/gui/window/log.py +95 -0
- tryton/gui/window/view_board/action.py +0 -4
- tryton/gui/window/view_form/model/field.py +36 -14
- tryton/gui/window/view_form/model/record.py +22 -9
- tryton/gui/window/view_form/screen/screen.py +45 -76
- tryton/gui/window/view_form/view/calendar_.py +24 -11
- tryton/gui/window/view_form/view/calendar_gtk/toolbar.py +6 -5
- tryton/gui/window/view_form/view/form.py +14 -5
- tryton/gui/window/view_form/view/form_gtk/many2many.py +10 -1
- tryton/gui/window/view_form/view/form_gtk/many2one.py +1 -0
- tryton/gui/window/view_form/view/form_gtk/one2many.py +7 -7
- tryton/gui/window/view_form/view/form_gtk/textbox.py +0 -2
- tryton/gui/window/view_form/view/form_gtk/widget.py +8 -10
- tryton/gui/window/view_form/view/list_form.py +61 -5
- tryton/gui/window/view_form/view/list_gtk/editabletree.py +13 -3
- tryton/gui/window/view_form/view/list_gtk/widget.py +97 -27
- tryton/gui/window/win_form.py +6 -5
- tryton/rpc.py +13 -15
- tryton/tests/test_common.py +46 -0
- tryton/tests/test_common_domain_parser.py +24 -24
- {tryton-6.6.8.dist-info → tryton-6.8.1.dist-info}/METADATA +6 -6
- {tryton-6.6.8.dist-info → tryton-6.8.1.dist-info}/RECORD +92 -89
- {tryton-6.6.8.data → tryton-6.8.1.data}/scripts/tryton +0 -0
- {tryton-6.6.8.dist-info → tryton-6.8.1.dist-info}/LICENSE +0 -0
- {tryton-6.6.8.dist-info → tryton-6.8.1.dist-info}/WHEEL +0 -0
- {tryton-6.6.8.dist-info → tryton-6.8.1.dist-info}/top_level.txt +0 -0
|
@@ -422,10 +422,7 @@ class Screen:
|
|
|
422
422
|
self.filter_widget = None
|
|
423
423
|
self.order = None
|
|
424
424
|
self.__group.add_fields(fields)
|
|
425
|
-
|
|
426
|
-
self.current_record = group[0]
|
|
427
|
-
else:
|
|
428
|
-
self.current_record = None
|
|
425
|
+
self.current_record = None
|
|
429
426
|
for name, views in fields_views.items():
|
|
430
427
|
self.__group.fields[name].views.update(views)
|
|
431
428
|
self.__group.exclude_field = self.exclude_field
|
|
@@ -452,14 +449,14 @@ class Screen:
|
|
|
452
449
|
def record_notify(self, notifications):
|
|
453
450
|
for window in self.windows:
|
|
454
451
|
if isinstance(window, InfoBar):
|
|
455
|
-
window.info_bar_refresh()
|
|
452
|
+
window.info_bar_refresh('notification')
|
|
456
453
|
for type_, message in notifications:
|
|
457
454
|
type_ = {
|
|
458
455
|
'info': Gtk.MessageType.INFO,
|
|
459
456
|
'warning': Gtk.MessageType.WARNING,
|
|
460
457
|
'error': Gtk.MessageType.ERROR,
|
|
461
458
|
}.get(type_, Gtk.MessageType.WARNING)
|
|
462
|
-
window.info_bar_add(message, type_)
|
|
459
|
+
window.info_bar_add(message, type_, 'notification')
|
|
463
460
|
|
|
464
461
|
def record_message(self, position, size, max_size, record_id):
|
|
465
462
|
for window in self.windows:
|
|
@@ -486,7 +483,7 @@ class Screen:
|
|
|
486
483
|
return self.__current_record
|
|
487
484
|
|
|
488
485
|
def __set_current_record(self, record):
|
|
489
|
-
if self.__current_record == record:
|
|
486
|
+
if self.__current_record == record and record:
|
|
490
487
|
return
|
|
491
488
|
self.__current_record = record
|
|
492
489
|
if record:
|
|
@@ -789,11 +786,6 @@ class Screen:
|
|
|
789
786
|
if not self.group.delete(records):
|
|
790
787
|
return False
|
|
791
788
|
|
|
792
|
-
top_record = records[0]
|
|
793
|
-
top_group = top_record.group
|
|
794
|
-
idx = top_group.index(top_record)
|
|
795
|
-
path = top_record.get_path(self.group)
|
|
796
|
-
|
|
797
789
|
for record in records:
|
|
798
790
|
# set current model to None to prevent __select_changed
|
|
799
791
|
# to save the previous_model as it can be already deleted.
|
|
@@ -815,15 +807,7 @@ class Screen:
|
|
|
815
807
|
record.parent.save(force_reload=False)
|
|
816
808
|
record.destroy()
|
|
817
809
|
|
|
818
|
-
|
|
819
|
-
record = top_group[idx - 1]
|
|
820
|
-
path = path[:-1] + ((path[-1][0], record.id,),)
|
|
821
|
-
else:
|
|
822
|
-
path = path[:-1]
|
|
823
|
-
if path:
|
|
824
|
-
self.current_record = self.group.get_by_path(path)
|
|
825
|
-
elif len(self.group):
|
|
826
|
-
self.current_record = self.group[0]
|
|
810
|
+
self.current_record = None
|
|
827
811
|
self.set_cursor()
|
|
828
812
|
self.display()
|
|
829
813
|
return True
|
|
@@ -840,40 +824,43 @@ class Screen:
|
|
|
840
824
|
|
|
841
825
|
def set_tree_state(self):
|
|
842
826
|
view = self.current_view
|
|
843
|
-
if view.view_type not in
|
|
827
|
+
if view.view_type not in {'tree', 'form', 'list-form'}:
|
|
844
828
|
return
|
|
845
829
|
if id(view) in self.tree_states_done:
|
|
846
830
|
return
|
|
847
831
|
if view.view_type == 'form' and self.tree_states_done:
|
|
848
832
|
return
|
|
849
|
-
if (view.view_type
|
|
850
|
-
and not view.attributes.get('tree_state', False)):
|
|
833
|
+
if (view.view_type in {'tree', 'list-form'}
|
|
834
|
+
and not int(view.attributes.get('tree_state', False))):
|
|
851
835
|
# Mark as done to not set later when the view_type change
|
|
852
836
|
self.tree_states_done.add(id(view))
|
|
853
837
|
parent = self.parent.id if self.parent else None
|
|
854
838
|
if parent is not None and parent < 0:
|
|
855
839
|
return
|
|
856
840
|
expanded_nodes, selected_nodes = [], []
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
841
|
+
if view.view_type in {'tree', 'list-form'}:
|
|
842
|
+
state = self.tree_states[parent][view.children_field]
|
|
843
|
+
if state:
|
|
844
|
+
expanded_nodes, selected_nodes = state
|
|
845
|
+
if (state is None
|
|
846
|
+
and CONFIG['client.save_tree_state']
|
|
847
|
+
and int(view.attributes.get('tree_state', False))):
|
|
848
|
+
json_domain = self.get_tree_domain(parent)
|
|
849
|
+
try:
|
|
850
|
+
expanded_nodes, selected_nodes = RPCExecute('model',
|
|
851
|
+
'ir.ui.view_tree_state', 'get',
|
|
852
|
+
self.model_name, json_domain,
|
|
853
|
+
view.children_field)
|
|
854
|
+
expanded_nodes = json.loads(expanded_nodes)
|
|
855
|
+
selected_nodes = json.loads(selected_nodes)
|
|
856
|
+
except RPCException:
|
|
857
|
+
logger.warn(
|
|
858
|
+
'Unable to get view tree state for %s',
|
|
859
|
+
self.model_name)
|
|
860
|
+
self.tree_states[parent][view.children_field] = (
|
|
861
|
+
expanded_nodes, selected_nodes)
|
|
862
|
+
if view.view_type == 'tree':
|
|
863
|
+
view.expand_nodes(expanded_nodes)
|
|
877
864
|
view.select_nodes(selected_nodes)
|
|
878
865
|
else:
|
|
879
866
|
if selected_nodes:
|
|
@@ -909,9 +896,12 @@ class Screen:
|
|
|
909
896
|
self.current_record)
|
|
910
897
|
self.tree_states[parent][view.children_field] = (
|
|
911
898
|
[], [[path]])
|
|
912
|
-
elif view.view_type
|
|
913
|
-
view.
|
|
914
|
-
|
|
899
|
+
elif view.view_type in {'tree', 'list-form'}:
|
|
900
|
+
if view.view_type == 'tree':
|
|
901
|
+
view.save_width()
|
|
902
|
+
paths = view.get_expanded_paths()
|
|
903
|
+
else:
|
|
904
|
+
paths = []
|
|
915
905
|
selected_paths = view.get_selected_paths()
|
|
916
906
|
self.tree_states[parent][view.children_field] = (
|
|
917
907
|
paths, selected_paths)
|
|
@@ -959,7 +949,7 @@ class Screen:
|
|
|
959
949
|
if (self.current_record
|
|
960
950
|
and self.current_record in self.current_record.group):
|
|
961
951
|
pass
|
|
962
|
-
elif self.group and self.current_view.view_type
|
|
952
|
+
elif self.group and self.current_view.view_type == 'form':
|
|
963
953
|
self.current_record = self.group[0]
|
|
964
954
|
else:
|
|
965
955
|
self.current_record = None
|
|
@@ -986,19 +976,7 @@ class Screen:
|
|
|
986
976
|
|
|
987
977
|
def _get_next_record(self, test=False):
|
|
988
978
|
view = self.current_view
|
|
989
|
-
if view.view_type
|
|
990
|
-
range_ = view.treeview.get_visible_range()
|
|
991
|
-
if range_ and not test:
|
|
992
|
-
start, end = range_
|
|
993
|
-
vadjustment = view.treeview.get_vadjustment()
|
|
994
|
-
vadjustment.set_value(
|
|
995
|
-
vadjustment.props.value + vadjustment.props.page_increment)
|
|
996
|
-
model = view.treeview.get_model()
|
|
997
|
-
iter_ = model.get_iter(end)
|
|
998
|
-
return model.get_value(iter_, 0)
|
|
999
|
-
else:
|
|
1000
|
-
return self.group[-1]
|
|
1001
|
-
elif (view.view_type == 'form'
|
|
979
|
+
if (view.view_type in {'tree', 'form'}
|
|
1002
980
|
and self.current_record
|
|
1003
981
|
and self.current_record.group):
|
|
1004
982
|
group = self.current_record.group
|
|
@@ -1073,19 +1051,7 @@ class Screen:
|
|
|
1073
1051
|
|
|
1074
1052
|
def _get_prev_record(self, test=False):
|
|
1075
1053
|
view = self.current_view
|
|
1076
|
-
if view.view_type
|
|
1077
|
-
range_ = view.treeview.get_visible_range()
|
|
1078
|
-
if range_ and not test:
|
|
1079
|
-
start, end = range_
|
|
1080
|
-
vadjustment = view.treeview.get_vadjustment()
|
|
1081
|
-
vadjustment.set_value(
|
|
1082
|
-
vadjustment.props.value - vadjustment.props.page_increment)
|
|
1083
|
-
model = view.treeview.get_model()
|
|
1084
|
-
iter_ = model.get_iter(start)
|
|
1085
|
-
return model.get_value(iter_, 0)
|
|
1086
|
-
else:
|
|
1087
|
-
return self.group[0]
|
|
1088
|
-
elif (view.view_type == 'form'
|
|
1054
|
+
if (view.view_type in {'tree', 'form'}
|
|
1089
1055
|
and self.current_record
|
|
1090
1056
|
and self.current_record.group):
|
|
1091
1057
|
group = self.current_record.group
|
|
@@ -1183,7 +1149,9 @@ class Screen:
|
|
|
1183
1149
|
|
|
1184
1150
|
@property
|
|
1185
1151
|
def listed_records(self):
|
|
1186
|
-
if self.current_view
|
|
1152
|
+
if (self.current_view
|
|
1153
|
+
and self.current_view.view_type in {
|
|
1154
|
+
'tree', 'calendar', 'list-form'}):
|
|
1187
1155
|
return self.current_view.listed_records
|
|
1188
1156
|
elif self.current_record:
|
|
1189
1157
|
return [self.current_record]
|
|
@@ -1209,7 +1177,8 @@ class Screen:
|
|
|
1209
1177
|
def get_buttons(self):
|
|
1210
1178
|
'Return active buttons for the current view'
|
|
1211
1179
|
def is_active(record, button):
|
|
1212
|
-
if
|
|
1180
|
+
if (record.readonly
|
|
1181
|
+
or button.attrs.get('type', 'class') == 'instance'):
|
|
1213
1182
|
return False
|
|
1214
1183
|
states = record.expr_eval(button.attrs.get('states', {}))
|
|
1215
1184
|
return not (states.get('invisible') or states.get('readonly'))
|
|
@@ -41,21 +41,10 @@ class CalendarXMLViewParser(XMLViewParser):
|
|
|
41
41
|
self.parse(child)
|
|
42
42
|
goocalendar = Calendar_(
|
|
43
43
|
self.view.attributes, self.view, self.calendar_fields)
|
|
44
|
-
scrolledwindow = Gtk.ScrolledWindow()
|
|
45
|
-
scrolledwindow.add(goocalendar)
|
|
46
44
|
toolbar = Toolbar(goocalendar)
|
|
47
|
-
self.view.widget.pack_start(
|
|
48
|
-
toolbar, expand=False, fill=False, padding=0)
|
|
49
|
-
self.view.widget.pack_start(
|
|
50
|
-
scrolledwindow, expand=True, fill=True, padding=0)
|
|
51
45
|
self.view.widgets['goocalendar'] = goocalendar
|
|
52
46
|
self.view.widgets['toolbar'] = toolbar
|
|
53
47
|
|
|
54
|
-
if attributes.get('height') or attributes.get('width'):
|
|
55
|
-
scrolledwindow.set_size_request(
|
|
56
|
-
int(attributes.get('width', -1)),
|
|
57
|
-
int(attributes.get('height', -1)))
|
|
58
|
-
|
|
59
48
|
def _parse_field(self, node, attributes):
|
|
60
49
|
self.calendar_fields.append(attributes)
|
|
61
50
|
|
|
@@ -85,6 +74,25 @@ class ViewCalendar(View):
|
|
|
85
74
|
goocalendar.connect('day-pressed', self.on_day_pressed)
|
|
86
75
|
goocalendar.connect('day-activated', self.on_day_activated)
|
|
87
76
|
|
|
77
|
+
self.widget.pack_start(toolbar, expand=False, fill=False, padding=0)
|
|
78
|
+
vp = Gtk.Viewport()
|
|
79
|
+
vp.set_shadow_type(Gtk.ShadowType.NONE)
|
|
80
|
+
vp.add(goocalendar)
|
|
81
|
+
self.scroll = scroll = Gtk.ScrolledWindow()
|
|
82
|
+
scroll.add(vp)
|
|
83
|
+
scroll.set_policy(
|
|
84
|
+
Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC)
|
|
85
|
+
scroll.set_placement(Gtk.CornerType.TOP_LEFT)
|
|
86
|
+
viewport = Gtk.Viewport()
|
|
87
|
+
viewport.set_shadow_type(Gtk.ShadowType.ETCHED_IN)
|
|
88
|
+
viewport.add(scroll)
|
|
89
|
+
self.widget.pack_start(viewport, expand=True, fill=True, padding=0)
|
|
90
|
+
|
|
91
|
+
if self.attributes.get('height') or self.attributes.get('width'):
|
|
92
|
+
scroll.set_size_request(
|
|
93
|
+
int(self.attributes.get('width', -1)),
|
|
94
|
+
int(self.attributes.get('height', -1)))
|
|
95
|
+
|
|
88
96
|
def on_page_changed(self, goocalendar, day, toolbar):
|
|
89
97
|
toolbar.update_displayed_date()
|
|
90
98
|
if goocalendar.update_domain():
|
|
@@ -170,3 +178,8 @@ class ViewCalendar(View):
|
|
|
170
178
|
|
|
171
179
|
def get_fields(self):
|
|
172
180
|
return []
|
|
181
|
+
|
|
182
|
+
@property
|
|
183
|
+
def listed_records(self):
|
|
184
|
+
event_store = self.widgets['goocalendar'].event_store
|
|
185
|
+
return [e.record for e in event_store.get_events()]
|
|
@@ -108,28 +108,29 @@ class Toolbar(Gtk.Toolbar):
|
|
|
108
108
|
self.insert(blank_widget, -1)
|
|
109
109
|
|
|
110
110
|
day_button = Gtk.RadioToolButton()
|
|
111
|
-
day_button.set_label(_(
|
|
111
|
+
day_button.set_label(_("Day"))
|
|
112
112
|
day_button.connect("clicked", self.on_day_button_clicked)
|
|
113
113
|
day_button.add_accelerator(
|
|
114
114
|
"clicked", self.accel_group, Gdk.KEY_d,
|
|
115
115
|
Gdk.ModifierType.MODIFIER_MASK, Gtk.AccelFlags.VISIBLE)
|
|
116
|
-
self.insert(day_button, -1)
|
|
117
116
|
|
|
118
117
|
week_button = Gtk.RadioToolButton.new_from_widget(day_button)
|
|
119
|
-
week_button.set_label(_(
|
|
118
|
+
week_button.set_label(_("Week"))
|
|
120
119
|
week_button.connect("clicked", self.on_week_button_clicked)
|
|
121
120
|
week_button.add_accelerator(
|
|
122
121
|
"clicked", self.accel_group, Gdk.KEY_w,
|
|
123
122
|
Gdk.ModifierType.MODIFIER_MASK, Gtk.AccelFlags.VISIBLE)
|
|
124
|
-
self.insert(week_button, -1)
|
|
125
123
|
|
|
126
124
|
month_button = Gtk.RadioToolButton.new_from_widget(week_button)
|
|
127
|
-
month_button.set_label_widget(Gtk.Label(label=_(
|
|
125
|
+
month_button.set_label_widget(Gtk.Label(label=_("Month")))
|
|
128
126
|
month_button.connect("clicked", self.on_month_button_clicked)
|
|
129
127
|
month_button.add_accelerator(
|
|
130
128
|
"clicked", self.accel_group, Gdk.KEY_m,
|
|
131
129
|
Gdk.ModifierType.MODIFIER_MASK, Gtk.AccelFlags.VISIBLE)
|
|
130
|
+
|
|
132
131
|
self.insert(month_button, -1)
|
|
132
|
+
self.insert(week_button, -1)
|
|
133
|
+
self.insert(day_button, -1)
|
|
133
134
|
buttons = {
|
|
134
135
|
'month': month_button,
|
|
135
136
|
'week': week_button,
|
|
@@ -279,13 +279,18 @@ class FormXMLViewParser(XMLViewParser):
|
|
|
279
279
|
return
|
|
280
280
|
vbox = VBox(attrs=attributes)
|
|
281
281
|
if attributes.get('string'):
|
|
282
|
+
attributes.setdefault('xexpand', 0)
|
|
283
|
+
attributes.setdefault('xalign', 0)
|
|
284
|
+
attributes.setdefault('yalign', 0.5)
|
|
282
285
|
label = Label(label=attributes['string'], attrs=attributes)
|
|
283
286
|
label.set_halign(get_align(
|
|
284
|
-
attributes
|
|
285
|
-
bool(attributes.get('xexpand'
|
|
287
|
+
attributes['xalign'],
|
|
288
|
+
bool(attributes.get('xexpand'))))
|
|
286
289
|
label.set_valign(get_align(
|
|
287
|
-
attributes
|
|
288
|
-
bool(attributes.get('yexpand'
|
|
290
|
+
attributes['yalign'],
|
|
291
|
+
bool(attributes.get('yexpand'))))
|
|
292
|
+
label.props.xalign = float(attributes['xalign'])
|
|
293
|
+
label.props.yalign = float(attributes['yalign'])
|
|
289
294
|
vbox.pack_start(label, expand=True, fill=True, padding=0)
|
|
290
295
|
self.view.state_widgets.append(label)
|
|
291
296
|
if name:
|
|
@@ -303,13 +308,17 @@ class FormXMLViewParser(XMLViewParser):
|
|
|
303
308
|
attributes['xalign'] = 0.0
|
|
304
309
|
|
|
305
310
|
attributes.setdefault('xexpand', 0)
|
|
311
|
+
attributes.setdefault('xalign', 1)
|
|
312
|
+
attributes.setdefault('yalign', 0.5)
|
|
306
313
|
label = Label(label=attributes.get('string', ''), attrs=attributes)
|
|
307
314
|
label.set_halign(get_align(
|
|
308
|
-
attributes
|
|
315
|
+
attributes['xalign'],
|
|
309
316
|
bool(attributes.get('xexpand'))))
|
|
310
317
|
label.set_valign(get_align(
|
|
311
318
|
attributes.get('yalign', 0.5),
|
|
312
319
|
bool(attributes.get('yexpand'))))
|
|
320
|
+
label.props.xalign = float(attributes['xalign'])
|
|
321
|
+
label.props.yalign = float(attributes['yalign'])
|
|
313
322
|
label.set_angle(int(attributes.get('angle', 0)))
|
|
314
323
|
self.view.state_widgets.append(label)
|
|
315
324
|
self.container.add(label, attributes)
|
|
@@ -72,6 +72,9 @@ class Many2Many(Widget):
|
|
|
72
72
|
self.but_add.set_relief(Gtk.ReliefStyle.NONE)
|
|
73
73
|
hbox.pack_start(self.but_add, expand=False, fill=False, padding=0)
|
|
74
74
|
|
|
75
|
+
self.label = Gtk.Label(label='(_/0)')
|
|
76
|
+
hbox.pack_start(self.label, expand=False, fill=False, padding=0)
|
|
77
|
+
|
|
75
78
|
self.but_remove = Gtk.Button(can_focus=False)
|
|
76
79
|
tooltips.set_tip(self.but_remove, _('Remove selected record'))
|
|
77
80
|
self.but_remove.connect('clicked', self._sig_remove)
|
|
@@ -279,8 +282,14 @@ class Many2Many(Widget):
|
|
|
279
282
|
not self._readonly
|
|
280
283
|
and self._position))
|
|
281
284
|
|
|
282
|
-
def record_message(self, position, *args):
|
|
285
|
+
def record_message(self, position, size, *args):
|
|
283
286
|
self._position = position
|
|
287
|
+
name = str(position) if position else '_'
|
|
288
|
+
selected = len(self.screen.selected_records)
|
|
289
|
+
if selected > 1:
|
|
290
|
+
name += '#%i' % selected
|
|
291
|
+
name = '(%s/%s)' % (name, common.humanize(size))
|
|
292
|
+
self.label.set_text(name)
|
|
284
293
|
self._set_button_sensitive()
|
|
285
294
|
|
|
286
295
|
def display(self):
|
|
@@ -62,7 +62,7 @@ class One2Many(Widget):
|
|
|
62
62
|
self.but_pre.set_relief(Gtk.ReliefStyle.NONE)
|
|
63
63
|
hbox.pack_start(self.but_pre, expand=False, fill=False, padding=0)
|
|
64
64
|
|
|
65
|
-
self.label = Gtk.Label(label='(0
|
|
65
|
+
self.label = Gtk.Label(label='(_/0)')
|
|
66
66
|
hbox.pack_start(self.label, expand=False, fill=False, padding=0)
|
|
67
67
|
|
|
68
68
|
self.but_next = Gtk.Button(can_focus=False)
|
|
@@ -511,12 +511,12 @@ class One2Many(Widget):
|
|
|
511
511
|
def record_message(self, position, size, *args):
|
|
512
512
|
self._position = position
|
|
513
513
|
self._length = size
|
|
514
|
-
if
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
name
|
|
518
|
-
|
|
519
|
-
self.label.set_text(
|
|
514
|
+
name = str(position) if position else '_'
|
|
515
|
+
selected = len(self.screen.selected_records)
|
|
516
|
+
if selected > 1:
|
|
517
|
+
name += '#%i' % selected
|
|
518
|
+
name = '(%s/%s)' % (name, common.humanize(size))
|
|
519
|
+
self.label.set_text(name)
|
|
520
520
|
self._set_button_sensitive()
|
|
521
521
|
|
|
522
522
|
def display(self):
|
|
@@ -16,7 +16,7 @@ _ = gettext.gettext
|
|
|
16
16
|
|
|
17
17
|
class Widget(object):
|
|
18
18
|
expand = False
|
|
19
|
-
default_width_chars =
|
|
19
|
+
default_width_chars = 8
|
|
20
20
|
|
|
21
21
|
def __init__(self, view, attrs):
|
|
22
22
|
super(Widget, self).__init__()
|
|
@@ -204,17 +204,15 @@ class TranslateDialog(NoModal):
|
|
|
204
204
|
widget.set_vexpand(self.widget.expand)
|
|
205
205
|
widget.set_hexpand(True)
|
|
206
206
|
grid.attach(widget, 1, i, 1, 1)
|
|
207
|
-
editing = Gtk.
|
|
207
|
+
editing = Gtk.ToggleButton(label=_("Edit"))
|
|
208
208
|
editing.connect('toggled', self.editing_toggled, widget)
|
|
209
209
|
editing.props.sensitive = not readonly
|
|
210
|
-
tooltips.set_tip(editing, _('Edit'))
|
|
211
210
|
grid.attach(editing, 2, i, 1, 1)
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
self.widgets[language['code']] = (widget, editing, fuzzy)
|
|
211
|
+
if value != fuzzy_value:
|
|
212
|
+
fuzzy = Gtk.Label(_("Fuzzy"))
|
|
213
|
+
widget_class(fuzzy, 'warning', True)
|
|
214
|
+
grid.attach(fuzzy, 4, i, 1, 1)
|
|
215
|
+
self.widgets[language['code']] = (widget, editing)
|
|
218
216
|
|
|
219
217
|
tooltips.enable()
|
|
220
218
|
vbox = Gtk.VBox()
|
|
@@ -241,7 +239,7 @@ class TranslateDialog(NoModal):
|
|
|
241
239
|
def response(self, win, response):
|
|
242
240
|
if response == Gtk.ResponseType.OK:
|
|
243
241
|
for code, widget in self.widgets.items():
|
|
244
|
-
widget, editing
|
|
242
|
+
widget, editing = widget
|
|
245
243
|
if not editing.get_active():
|
|
246
244
|
continue
|
|
247
245
|
value = self.widget.translate_widget_get(widget)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# This file is part of Tryton. The COPYRIGHT file at the top level of
|
|
2
2
|
# this repository contains the full copyright notices and license terms.
|
|
3
|
-
from gi.repository import Gio, GObject, Gtk
|
|
3
|
+
from gi.repository import Gio, GLib, GObject, Gtk
|
|
4
4
|
|
|
5
5
|
from tryton.common import common
|
|
6
6
|
|
|
@@ -119,6 +119,10 @@ class ViewListForm(View):
|
|
|
119
119
|
return [
|
|
120
120
|
self._model.get_item(r.get_index()).record for r in selected_rows]
|
|
121
121
|
|
|
122
|
+
@property
|
|
123
|
+
def listed_records(self):
|
|
124
|
+
return list(self._model.group)
|
|
125
|
+
|
|
122
126
|
def group_list_changed(self, group, action, *args):
|
|
123
127
|
if action == 'record-added':
|
|
124
128
|
record, position = args
|
|
@@ -135,17 +139,69 @@ class ViewListForm(View):
|
|
|
135
139
|
self._select_show_row(idx)
|
|
136
140
|
break
|
|
137
141
|
|
|
138
|
-
def
|
|
139
|
-
|
|
142
|
+
def get_selected_paths(self):
|
|
143
|
+
return [[r.id] for r in self.selected_records]
|
|
144
|
+
|
|
145
|
+
def select_nodes(self, nodes):
|
|
146
|
+
if not nodes:
|
|
140
147
|
return
|
|
141
|
-
|
|
148
|
+
nodes = {n[0] for n in nodes}
|
|
149
|
+
self.listbox.handler_block_by_func(self.select_nodes)
|
|
150
|
+
self.listbox.unselect_all()
|
|
151
|
+
for idx, view_form in enumerate(self._view_forms):
|
|
152
|
+
if view_form.record.id in nodes:
|
|
153
|
+
row = self.listbox.get_row_at_index(idx)
|
|
154
|
+
if not row:
|
|
155
|
+
continue
|
|
156
|
+
self.listbox.select_row(row)
|
|
157
|
+
self.listbox.handler_unblock_by_func(self.select_nodes)
|
|
158
|
+
|
|
159
|
+
def _row_selected(self, listbox, row):
|
|
160
|
+
previous_record = self.record
|
|
161
|
+
if (previous_record
|
|
162
|
+
and previous_record not in previous_record.group):
|
|
163
|
+
previous_record = None
|
|
164
|
+
|
|
165
|
+
if row:
|
|
166
|
+
self.record = self._model.get_item(row.get_index()).record
|
|
167
|
+
else:
|
|
168
|
+
self.record = None
|
|
169
|
+
|
|
170
|
+
def go_previous():
|
|
171
|
+
self.record = previous_record
|
|
172
|
+
self.set_cursor()
|
|
173
|
+
|
|
174
|
+
def save():
|
|
175
|
+
if not previous_record.destroyed:
|
|
176
|
+
if not previous_record.save():
|
|
177
|
+
go_previous()
|
|
178
|
+
|
|
179
|
+
def pre_validate():
|
|
180
|
+
if not previous_record.destroyed:
|
|
181
|
+
if not previous_record.pre_validate():
|
|
182
|
+
go_previous()
|
|
183
|
+
|
|
184
|
+
if previous_record and previous_record != self.record:
|
|
185
|
+
if not self.screen.parent:
|
|
186
|
+
if not previous_record.validate(self.get_fields()):
|
|
187
|
+
go_previous()
|
|
188
|
+
return True
|
|
189
|
+
GLib.idle_add(save)
|
|
190
|
+
elif self.screen.pre_validate:
|
|
191
|
+
GLib.idle_add(pre_validate)
|
|
142
192
|
|
|
143
193
|
@common.idle_add
|
|
144
194
|
def _select_show_row(self, index):
|
|
145
195
|
# translate_coordinates requires that both widgets are realized
|
|
146
196
|
if not self.listbox.get_realized():
|
|
147
197
|
return
|
|
148
|
-
|
|
198
|
+
# unselect_all triggers a loop in _row_selected if the record is not
|
|
199
|
+
# valid
|
|
200
|
+
self.listbox.handler_block_by_func(self._select_show_row)
|
|
201
|
+
try:
|
|
202
|
+
self.listbox.unselect_all()
|
|
203
|
+
finally:
|
|
204
|
+
self.listbox.handler_unblock_by_func(self._select_show_row)
|
|
149
205
|
row = self.listbox.get_row_at_index(index)
|
|
150
206
|
if not row or not row.get_realized():
|
|
151
207
|
return
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
# This file is part of Tryton. The COPYRIGHT file at the top level of
|
|
2
2
|
# this repository contains the full copyright notices and license terms.
|
|
3
3
|
import gettext
|
|
4
|
+
import logging
|
|
4
5
|
from itertools import chain, cycle, islice
|
|
5
6
|
|
|
6
7
|
from gi.repository import Gdk, GLib, Gtk
|
|
@@ -9,6 +10,7 @@ from tryton.common import MODELACCESS
|
|
|
9
10
|
from tryton.common.datetime_ import Date, Time
|
|
10
11
|
|
|
11
12
|
_ = gettext.gettext
|
|
13
|
+
logger = logging.getLogger(__name__)
|
|
12
14
|
|
|
13
15
|
|
|
14
16
|
def focusable_cells(column, editable=True):
|
|
@@ -51,7 +53,14 @@ class TreeView(Gtk.TreeView):
|
|
|
51
53
|
if not column.name:
|
|
52
54
|
continue
|
|
53
55
|
widget = self.view.get_column_widget(column)
|
|
54
|
-
|
|
56
|
+
try:
|
|
57
|
+
record.load(column.name, process_exception=False)
|
|
58
|
+
except Exception:
|
|
59
|
+
logger.error(
|
|
60
|
+
f"Error loading '{column.name}' for {record}",
|
|
61
|
+
exc_info=True)
|
|
62
|
+
return (None, None)
|
|
63
|
+
field = record.group.fields[column.name]
|
|
55
64
|
field.state_set(record, states=('readonly', 'invisible'))
|
|
56
65
|
invisible = field.get_state_attrs(record).get('invisible', False)
|
|
57
66
|
if not column.get_visible():
|
|
@@ -83,7 +92,8 @@ class EditableTreeView(TreeView):
|
|
|
83
92
|
|
|
84
93
|
def on_quit_cell(
|
|
85
94
|
self, current_record, column, renderer, value, callback=None):
|
|
86
|
-
|
|
95
|
+
current_record.load(column.name, process_exception=False)
|
|
96
|
+
field = current_record.group.fields[column.name]
|
|
87
97
|
widget = self.view.get_column_widget(column)
|
|
88
98
|
|
|
89
99
|
# The value has not changed and is valid ... do nothing.
|
|
@@ -271,7 +281,7 @@ class EditableTreeView(TreeView):
|
|
|
271
281
|
create=(event.keyval == Gdk.KEY_F3), value=value,
|
|
272
282
|
callback=callback)
|
|
273
283
|
else:
|
|
274
|
-
field = record[column.name]
|
|
284
|
+
field = record.group.fields[column.name]
|
|
275
285
|
if isinstance(entry, Gtk.Entry):
|
|
276
286
|
entry.set_max_length(int(field.attrs.get('size', 0)))
|
|
277
287
|
record.modified_fields.setdefault(column.name)
|