Remove SignalEvent usage

We register on the screen the windows and on the group the screens to which
events must be sent.

The window of Screen can be a tab, a dialog or even a widget like for One2Many.
They must just have a method with the proper name to receive the corresponding
events.
The group_list_changed event is dedicated to synchronisation of the Gtk
TreeView and ListBox models.

issue11059
review395151002
This commit is contained in:
Cédric Krier committed 2022-01-02 13:53:27 +01:00
1 parent 5798a57eab
commit 642870837e
17 files changed
+191 -288

No files matched your search

-1
View File
@@ -884,7 +884,6 @@ class Main(Gtk.Application):
for i in range(len(self.pages)):
if self.pages[i].widget == page_widget:
page = self.pages.pop(i)
page.signal_unconnect(self)
break
self.notebook.remove_page(page_id)
+1 -2
View File
@@ -7,14 +7,13 @@ import xml.dom.minidom
from tryton.common import MODELNAME, RPCException, RPCExecute
from tryton.gui import Main
from tryton.gui.window.view_board import ViewBoard
from tryton.signal_event import SignalEvent
from .tabcontent import TabContent
_ = gettext.gettext
class Board(SignalEvent, TabContent):
class Board(TabContent):
'Board'
def __init__(self, model, name='', **attributes):
+24 -37
View File
@@ -27,14 +27,13 @@ from tryton.gui.window.revision import Revision
from tryton.gui.window.view_form.screen import Screen
from tryton.gui.window.win_export import WinExport
from tryton.gui.window.win_import import WinImport
from tryton.signal_event import SignalEvent
from .tabcontent import TabContent
_ = gettext.gettext
class Form(SignalEvent, TabContent):
class Form(TabContent):
"Form"
def __init__(self, model, res_id=None, name='', **attributes):
@@ -52,21 +51,12 @@ class Form(SignalEvent, TabContent):
self.screen = Screen(self.model, breadcrumb=[self.name], **attributes)
self.screen.widget.show()
self.screen.windows.append(self)
self.create_tabcontent()
self.set_buttons_sensitive()
self.screen.signal_connect(self, 'record-message',
self._record_message)
self.screen.signal_connect(self, 'record-modified',
lambda *a: GLib.idle_add(self._record_modified, *a))
self.screen.signal_connect(self, 'record-saved', self._record_saved)
self.screen.signal_connect(
self, 'resources',
lambda screen, resources: self.update_resources(resources))
self.attachment_screen = None
if res_id not in (None, False):
@@ -127,8 +117,6 @@ class Form(SignalEvent, TabContent):
return id(self)
def destroy(self):
super(Form, self).destroy()
self.screen.signal_unconnect(self)
self.screen.destroy()
def sig_attach(self, widget=None):
@@ -223,13 +211,13 @@ class Form(SignalEvent, TabContent):
but_prev.connect('clicked', lambda *a: screen.display_prev())
but_next.connect('clicked', lambda *a: screen.display_next())
def update_label(screen, data):
position, length = data[:2]
label.set_text('(%s/%s)' % (position or '_', length))
but_prev.set_sensitive(position and position > 1)
but_next.set_sensitive(position and position < length)
class Preview():
def record_message(self, position, length, *args):
label.set_text('(%s/%s)' % (position or '_', length))
but_prev.set_sensitive(position and position > 1)
but_next.set_sensitive(position and position < length)
screen.windows.append(Preview())
screen.signal_connect(self, 'record-message', update_label)
vbox.pack_start(screen.widget, expand=True, fill=True, padding=0)
return vbox
@@ -612,10 +600,8 @@ class Form(SignalEvent, TabContent):
None, None, menu_position, None, 0,
Gtk.get_current_event_time())
def _record_message(self, screen, signal_data):
name = '_'
if signal_data[0]:
name = str(signal_data[0])
def record_message(self, position, size, max_size, record_id):
name = str(position) if position else '_'
for button_id in ('print', 'relate', 'email', 'open', 'save',
'attach'):
button = self.buttons[button_id]
@@ -626,11 +612,10 @@ class Form(SignalEvent, TabContent):
action_type = 'print'
can_be_sensitive |= any(
b.attrs.get('keyword', 'action') == action_type
for b in screen.get_buttons())
for b in self.screen.get_buttons())
elif button_id == 'save':
can_be_sensitive &= not self.screen.readonly
button.props.sensitive = (bool(signal_data[0])
and can_be_sensitive)
button.props.sensitive = bool(position) and can_be_sensitive
button_switch = self.buttons['switch']
button_switch.props.sensitive = self.screen.number_of_views > 1
@@ -639,23 +624,25 @@ class Form(SignalEvent, TabContent):
menu_save = self.menu_buttons['save']
menu_save.props.sensitive = not self.screen.readonly
msg = name + ' / ' + str(signal_data[1])
if (signal_data[1] < signal_data[2]
msg = name + ' / ' + str(size)
if (size < max_size
and self.screen.limit is not None
and signal_data[2] > self.screen.limit):
msg += _(' of ') + str(signal_data[2])
and max_size > self.screen.limit):
msg += _(' of ') + str(max_size)
self.status_label.set_text(msg)
self.message_info()
self.activate_save()
self.refresh_attachment_preview()
def _record_modified(self, screen, signal_data):
# As it is called via idle_add, the form could have been destroyed in
# the meantime.
if self.widget_get().props.window:
self.activate_save()
def record_modified(self):
def _record_modified():
# As it is called via idle_add, the form could have been destroyed
# in the meantime.
if self.widget_get().props.window:
self.activate_save()
GLib.idle_add(_record_modified)
def _record_saved(self, screen, signal_data):
def record_saved(self):
self.activate_save()
self.refresh_resources()
+7 -10
View File
@@ -13,18 +13,16 @@ from tryton.config import CONFIG
from tryton.gui.window.view_form.screen import Screen
from tryton.gui.window.win_form import WinForm
from tryton.pyson import PYSONDecoder
from tryton.signal_event import SignalEvent
_ = gettext.gettext
class Action(SignalEvent):
class Action:
def __init__(self, attrs=None, context=None):
if context is None:
context = {}
def __init__(self, view, attrs=None):
super(Action, self).__init__()
self.name = attrs['name']
self.view = view
try:
self.action = RPCExecute('model', 'ir.action.act_window', 'get',
@@ -45,7 +43,7 @@ class Action(SignalEvent):
ctx.update(rpc.CONTEXT)
ctx['_user'] = rpc._USER
decoder = PYSONDecoder(ctx)
action_ctx = context.copy()
action_ctx = self.view.context.copy()
action_ctx.update(
decoder.decode(self.action.get('pyson_context') or '{}'))
ctx.update(action_ctx)
@@ -90,10 +88,9 @@ class Action(SignalEvent):
context_model=self.action['context_model'],
context_domain=self.action['context_domain'],
row_activate=self.row_activate)
self.screen.windows.append(self)
vbox.pack_start(
self.screen.widget, expand=True, fill=True, padding=0)
self.screen.signal_connect(self, 'record-message',
self._active_changed)
if attrs.get('string'):
self.title.set_text(attrs['string'])
@@ -134,8 +131,8 @@ class Action(SignalEvent):
def display(self):
self.screen.search_filter(self.screen.screen_container.get_text())
def _active_changed(self, *args):
self.signal('active-changed')
def record_message(self, *args):
self.view.active_changed(self)
def _get_active(self):
if self.screen and self.screen.current_record:
+3 -5
View File
@@ -24,9 +24,7 @@ class BoardXMLViewParser(FormXMLViewParser):
def _parse_action(self, node, attributes):
attributes.setdefault('yexpand', True)
attributes.setdefault('yfill', True)
action = Action(attributes, self.view.context)
action.signal_connect(
self.view, 'active-changed', self.view._active_changed)
action = Action(self.view, attributes)
self.view.actions.append(action)
self.container.add(action.widget, attributes)
@@ -42,7 +40,7 @@ class ViewBoard(object):
self.state_widgets = []
self.xml_parser(self, None, {}).parse(xml)
self.widget.show_all()
self._active_changed(None)
self.active_changed(None)
def widget_get(self):
return self.widget
@@ -53,7 +51,7 @@ class ViewBoard(object):
for state_widget in self.state_widgets:
state_widget.state_set(None)
def _active_changed(self, event_action, *args):
def active_changed(self, event_action):
for action in self.actions:
if action == event_action:
continue
+10 -46
View File
@@ -155,15 +155,13 @@ class Field(object):
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')
record.set_modified(self.name)
elif force_change:
self.sig_changed(record)
record.validate(softvalidation=True)
record.signal('record-changed')
record.set_modified()
def get_client(self, record):
return self.get(record)
@@ -564,29 +562,6 @@ class O2MField(Field):
def __init__(self, attrs):
super(O2MField, self).__init__(attrs)
def _group_changed(self, group, record):
if not record.parent:
return
# Store parent as it could be removed by validation
parent = record.parent
parent.modified_fields.setdefault(self.name)
self.sig_changed(parent)
parent.validate(softvalidation=True)
parent.signal('record-changed')
def _group_list_changed(self, group, signal):
if group.model_name == group.parent.model_name:
group.parent.group.signal('group-list-changed', signal)
def _group_cleared(self, group, signal):
if group.model_name == group.parent.model_name:
group.parent.signal('group-cleared')
def _record_modified(self, group, record):
if not record.parent:
return
record.parent.signal('record-modified')
def _set_default_value(self, record, fields=None):
if record.value.get(self.name) is not None:
return
@@ -603,14 +578,6 @@ class O2MField(Field):
if not fields and record.model_name == self.attrs['relation']:
group.fields = record.group.fields
record.value[self.name] = group
self._connect_value(group)
def _connect_value(self, group):
group.signal_connect(group, 'group-changed', self._group_changed)
group.signal_connect(group, 'group-list-changed',
self._group_list_changed)
group.signal_connect(group, 'group-cleared', self._group_cleared)
group.signal_connect(group, 'record-modified', self._record_modified)
def get_client(self, record):
self._set_default_value(record)
@@ -720,7 +687,7 @@ class O2MField(Field):
new_record.set(vals, signal=False)
group.append(new_record)
# Trigger signal only once with the last record
new_record.signal('record-changed')
group.record_modified()
def set(self, record, value, _default=False):
group = record.value.get(self.name)
@@ -728,7 +695,7 @@ class O2MField(Field):
if group is not None:
fields = group.fields.copy()
# Unconnect to prevent infinite loop
group.signal_unconnect(group)
group.parent = None
group.destroy()
elif record.model_name == self.attrs['relation']:
fields = record.group.fields
@@ -740,9 +707,10 @@ class O2MField(Field):
self._set_default_value(record, fields=fields)
group = record.value[self.name]
group.signal_unconnect(group)
# Prevent to trigger group-cleared
group.parent = None
self._set_value(record, value, default=_default)
self._connect_value(group)
group.parent = record
def set_client(self, record, value, force_change=False):
# domain inversion could try to set None as value
@@ -757,15 +725,13 @@ class O2MField(Field):
modified = set(previous_ids) != set(value)
self._set_value(record, value, modified=modified)
if modified:
record.modified_fields.setdefault(self.name)
record.signal('record-modified')
self.sig_changed(record)
record.validate(softvalidation=True)
record.signal('record-changed')
record.set_modified(self.name)
elif force_change:
self.sig_changed(record)
record.validate(softvalidation=True)
record.signal('record-changed')
record.set_modified()
def set_default(self, record, value):
self.set(record, value, _default=True)
@@ -1040,11 +1006,9 @@ class BinaryField(Field):
with open(filename, 'wb') as fp:
fp.write(data)
self.set(record, _FileCache(filename))
record.modified_fields.setdefault(self.name)
record.signal('record-modified')
self.sig_changed(record)
record.validate(softvalidation=True)
record.signal('record-changed')
record.set_modified(self.name)
def get_size(self, record):
result = record.value.get(self.name) or 0
+39 -52
View File
@@ -5,13 +5,12 @@ import operator
from tryton import rpc
from tryton.common import MODELACCESS, RPCException, RPCExecute
from tryton.common.domain_inversion import is_leaf
from tryton.signal_event import SignalEvent
from .field import Field, M2OField, ReferenceField
from .record import Record
class Group(SignalEvent, list):
class Group(list):
def __init__(self, model_name, fields, ids=None, parent=None,
parent_name='', child_name='', context=None, domain=None,
@@ -22,6 +21,7 @@ class Group(SignalEvent, list):
self.__domain = domain
self.__domain4inversion = None
self.lock_signal = False
self.screens = []
self.parent = parent
self.parent_name = parent_name or ''
self.children = []
@@ -104,7 +104,7 @@ class Group(SignalEvent, list):
super(Group, self).insert(pos, record)
self.__id2record[record.id] = record
if not self.lock_signal:
self.signal('group-list-changed', ('record-added', record, pos))
self._group_list_changed('record-added', record, pos)
def append(self, record):
assert record.group is self
@@ -114,8 +114,8 @@ class Group(SignalEvent, list):
super(Group, self).append(record)
self.__id2record[record.id] = record
if not self.lock_signal:
self.signal('group-list-changed', (
'record-added', record, self.__len__() - 1))
self._group_list_changed(
'record-added', record, self.__len__() - 1)
def _remove(self, record):
idx = self.index(record)
@@ -125,7 +125,7 @@ class Group(SignalEvent, list):
self.__getitem__(idx + 1)
else:
self.__getitem__(idx - 1).next[id(self)] = None
self.signal('group-list-changed', ('record-removed', record, idx))
self._group_list_changed('record-removed', record, idx)
super(Group, self).remove(record)
del self.__id2record[record.id]
@@ -137,8 +137,7 @@ class Group(SignalEvent, list):
# Destroy record before propagating the signal to recursively
# destroy also the underlying records
record.destroy()
self.signal(
'group-list-changed', ('record-removed', record, length - 1))
self._group_list_changed('record-removed', record, length - 1)
self.pop()
length -= 1
self.__id2record = {}
@@ -155,11 +154,6 @@ class Group(SignalEvent, list):
self._remove(record)
self.append(record)
def __setitem__(self, i, value):
super(Group, self).__setitem__(i, value)
if not self.lock_signal:
self.signal('group-list-changed', ('record-changed', i))
def __repr__(self):
return '<Group %s at %s>' % (self.model_name, id(self))
@@ -262,10 +256,6 @@ class Group(SignalEvent, list):
else:
self.insert(position, new_record)
position += 1
new_record.signal_connect(self, 'record-changed',
self._record_changed)
new_record.signal_connect(self, 'record-modified',
self._record_modified)
new_records.append(new_record)
# Remove previously removed or deleted records
@@ -278,13 +268,12 @@ class Group(SignalEvent, list):
if self.lock_signal:
self.lock_signal = False
self.signal('group-cleared')
self._group_list_changed('group-cleared')
if new_records and modified:
for record in new_records:
record.modified_fields.setdefault('id')
new_records[0].signal('record-modified')
new_records[0].signal('record-changed')
self.record_modified()
self.current_idx = 0
return True
@@ -321,11 +310,7 @@ class Group(SignalEvent, list):
def add(self, record, position=-1, signal=True):
if record.group is not self:
record.signal_unconnect(record.group)
record.group = self
record.signal_connect(self, 'record-changed', self._record_changed)
record.signal_connect(self, 'record-modified',
self._record_modified)
if record not in self:
if position == -1:
self.append(record)
@@ -338,10 +323,8 @@ class Group(SignalEvent, list):
if record_del.id == record.id:
self.record_deleted.remove(record_del)
self.current_idx = position
record.modified_fields.setdefault('id')
record.signal('record-modified')
record.set_modified('id')
if signal:
self.signal('group-changed', record)
# Set parent field to trigger on_change
if self.parent and self.parent_name in self.fields:
field = self.fields[self.parent_name]
@@ -389,23 +372,16 @@ class Group(SignalEvent, list):
if index is None:
index = 0
index += 1
record.signal_unconnect(self, 'record-changed')
try:
record[field].set_client(record, index)
finally:
record.signal_connect(self, 'record-changed',
self._record_changed)
record[field].set_client(record, index)
changed = record
prev = record
if changed:
self.signal('group-changed', changed)
self.record_modified()
def new(self, default=True, obj_id=None, rec_name=None):
record = Record(self.model_name, obj_id, group=self)
if default:
record.default_get(rec_name=rec_name)
record.signal_connect(self, 'record-changed', self._record_changed)
record.signal_connect(self, 'record-modified', self._record_modified)
return record
def unremove(self, record, signal=True):
@@ -414,7 +390,7 @@ class Group(SignalEvent, list):
if record in self.record_deleted:
self.record_deleted.remove(record)
if signal:
record.signal('record-changed', record.parent)
self.record_modified()
def remove(self, record, remove=False, modified=True, signal=True,
force_remove=False):
@@ -431,11 +407,9 @@ class Group(SignalEvent, list):
if record not in self.record_deleted:
self.record_deleted.append(record)
if record.parent:
record.parent.modified_fields.setdefault('id')
record.parent.signal('record-modified')
record.parent.set_modified('id')
if modified:
record.modified_fields.setdefault('id')
record.signal('record-modified')
record.set_modified('id')
if record.id < 0 or force_remove:
self._remove(record)
@@ -445,13 +419,7 @@ class Group(SignalEvent, list):
self.current_idx = None
if signal:
record.signal('record-changed', record.parent)
def _record_changed(self, record, signal_data):
self.signal('group-changed', record)
def _record_modified(self, record, signal_data):
self.signal('record-modified', record)
self.record_modified()
def prev(self):
if len(self) and self.current_idx is not None:
@@ -497,7 +465,7 @@ class Group(SignalEvent, list):
for record in new:
record.set_default(values, signal=False)
# Trigger signal only once with the last record
record.signal('record-changed')
self.record_modified()
def get(self, id):
'Return record with the id'
@@ -518,9 +486,8 @@ class Group(SignalEvent, list):
# One2Many connect the group to itself to send signals to the parent
# but as we are destroying the group, we do not need to notify the
# parent otherwise it will trigger unnecessary display.
self.signal_unconnect(self)
self.clear()
super(Group, self).destroy()
self.screens.clear()
self.parent = None
def get_by_path(self, path):
'return record by path'
@@ -537,3 +504,23 @@ class Group(SignalEvent, list):
if not isinstance(group, Group):
return None
return record
def _group_list_changed(self, action, *args):
group = self
while group.parent:
if group.model_name != group.parent.model_name:
break
else:
group = group.parent.group
for screen in group.screens:
screen.group_list_changed(group, action, *args)
def record_modified(self):
if not self.parent:
for screen in self.screens:
screen.record_modified()
else:
self.parent.modified_fields.setdefault(self.child_name)
self.parent.group.fields[self.child_name].sig_changed(self.parent)
self.parent.validate(softvalidation=True)
self.parent.group.record_modified()
+9 -10
View File
@@ -6,14 +6,13 @@ import tryton.common as common
from tryton.common import RPCException, RPCExecute
from tryton.config import CONFIG
from tryton.pyson import PYSONDecoder
from tryton.signal_event import SignalEvent
from . import field as fields
logger = logging.getLogger(__name__)
class Record(SignalEvent):
class Record:
id = -1
@@ -183,10 +182,6 @@ class Record(SignalEvent):
parent = parent.parent
return i
def set_modified(self, value):
if value:
self.signal('record-modified')
def children_group(self, field_name):
if not field_name:
return []
@@ -448,7 +443,7 @@ class Record(SignalEvent):
if validate:
self.validate(softvalidation=True)
if signal:
self.signal('record-changed')
self.set_modified()
def set(self, val, signal=True, validate=True):
later = {}
@@ -482,7 +477,7 @@ class Record(SignalEvent):
if validate:
self.validate(fieldnames, softvalidation=True)
if signal:
self.signal('record-changed')
self.set_modified()
def set_on_change(self, values):
for fieldname, value in list(values.items()):
@@ -513,7 +508,7 @@ class Record(SignalEvent):
self.parent.on_change([self.group.child_name])
self.parent.on_change_with([self.group.child_name])
self.signal('record-changed')
self.set_modified()
def expr_eval(self, expr):
if not isinstance(expr, str):
@@ -675,9 +670,13 @@ class Record(SignalEvent):
return
return clicks
def set_modified(self, field=None):
if field:
self.modified_fields.setdefault(field)
self.group.record_modified()
def destroy(self):
for v in self.value.values():
if hasattr(v, 'destroy'):
v.destroy()
super(Record, self).destroy()
self.destroyed = True
+44 -35
View File
@@ -27,13 +27,12 @@ from tryton.gui.window.view_form.view.screen_container import ScreenContainer
from tryton.jsonrpc import JSONEncoder
from tryton.pyson import PYSONDecoder
from tryton.rpc import clear_cache
from tryton.signal_event import SignalEvent
_ = gettext.gettext
logger = logging.getLogger(__name__)
class Screen(SignalEvent):
class Screen:
"Screen"
# Width of tree columns per model
@@ -44,7 +43,7 @@ class Screen(SignalEvent):
context = attributes.get('context', {})
self.limit = attributes.get('limit', CONFIG['client.limit'])
self.offset = 0
super(Screen, self).__init__()
self.windows = []
self.readonly = attributes.get('readonly', False)
if not (MODELACCESS[model_name]['write']
@@ -401,12 +400,15 @@ class Screen(SignalEvent):
fields = {}
fields_views = {}
if self.group is not None:
self.group.signal_unconnect(self)
for name, field in self.group.fields.items():
fields[name] = field.attrs
fields_views[name] = field.views
if self in self.group.screens:
self.group.screens.remove(self)
group.on_write.update(self.group.on_write)
self.tree_states_done.clear()
self.__group = group
self.group.screens.append(self)
self.parent = group.parent
self.parent_name = group.parent_name
if self.parent:
@@ -416,12 +418,6 @@ class Screen(SignalEvent):
self.current_record = group[0]
else:
self.current_record = None
self.__group.signal_connect(self, 'group-cleared', self._group_cleared)
self.__group.signal_connect(self, 'group-list-changed',
self._group_list_changed)
self.__group.signal_connect(self, 'record-modified',
self._record_modified)
self.__group.signal_connect(self, 'group-changed', self._group_changed)
self.__group.add_fields(fields)
for name, views in fields_views.items():
self.__group.fields[name].views.update(views)
@@ -434,23 +430,35 @@ class Screen(SignalEvent):
self.group = Group(self.model_name, {}, domain=self.domain,
context=context, readonly=self.__readonly)
def _group_cleared(self, group, signal):
for view in self.views:
if view.view_type == 'tree':
view.display(force=True)
def _group_list_changed(self, group, signal):
def group_list_changed(self, group, action, *args):
for view in self.views:
if hasattr(view, 'group_list_changed'):
view.group_list_changed(group, signal)
view.group_list_changed(group, action, *args)
def _record_modified(self, group, signal):
self.signal('record-modified', signal)
def _group_changed(self, group, record):
if not self.parent:
def record_modified(self, display=True):
for window in self.windows:
if hasattr(window, 'record_modified'):
window.record_modified()
if display:
self.display()
self.signal('group-changed', record)
def record_message(self, position, size, max_size, record_id):
for window in self.windows:
if hasattr(window, 'record_message'):
window.record_message(position, size, max_size, record_id)
def record_saved(self):
for window in self.windows:
if hasattr(window, 'record_saved'):
window.record_saved()
def update_resources(self, resources):
for window in self.windows:
if hasattr(window, 'update_resources'):
window.update_resources(resources)
def has_update_resources(self):
return any(hasattr(w, 'update_resources') for w in self.windows)
def __get_current_record(self):
if (self.__current_record is not None
@@ -468,9 +476,10 @@ class Screen(SignalEvent):
pos = record.get_index_path()
else:
pos = 0
self.signal('record-message', (pos, len(self.group) + self.offset,
self.search_count, record and record.id))
self.signal('resources', record.resources if record else None)
self.record_message(
pos, len(self.group) + self.offset,
self.search_count, record and record.id)
self.update_resources(record.resources if record else None)
# update resources after 1 second
GLib.timeout_add(1000, self._update_resources, record)
return True
@@ -480,16 +489,15 @@ class Screen(SignalEvent):
def _update_resources(self, record):
if (record
and record == self.current_record
and self.signal_connected('resources')):
self.signal('resources', record.get_resources())
and self.has_update_resources()):
self.update_resources(record.get_resources())
return False
def destroy(self):
self.windows.clear()
for view in self.views:
view.destroy()
del self.views[:]
super(Screen, self).destroy()
self.group.signal_unconnect(self)
self.group.destroy()
def default_row_activate(self):
@@ -695,7 +703,7 @@ class Screen(SignalEvent):
path = path[:-1] + ((path[-1][0], record_id),)
self.current_record = self.group.get_by_path(path)
self.display()
self.signal('record-saved')
self.record_saved()
return saved
def __get_current_view(self):
@@ -772,8 +780,8 @@ class Screen(SignalEvent):
self.current_record = None
record.group.remove(record, remove=remove, signal=False,
force_remove=force_remove)
# send record-changed only once
record.signal('record-changed')
# call only once
record.set_modified()
if delete:
for record in records:
@@ -881,6 +889,7 @@ class Screen(SignalEvent):
self.tree_states[parent][view.children_field] = (
[], [[path]])
elif view.view_type == 'tree':
view.save_width()
paths = view.get_expanded_paths()
selected_paths = view.get_selected_paths()
self.tree_states[parent][view.children_field] = (
@@ -951,7 +960,7 @@ class Screen(SignalEvent):
if set_cursor:
self.set_cursor(reset_view=False)
self.set_tree_state()
# Force record-message signal
# Force record_message signal
self.current_record = self.current_record
def display_next(self):
@@ -1211,7 +1220,7 @@ class Screen(SignalEvent):
except RPCException:
return
record.set_on_change(changes)
record.signal('record-changed')
record.set_modified()
def _button_class(self, button):
ids = [r.id for r in self.selected_records]
@@ -94,7 +94,7 @@ class Many2Many(Widget):
row_activate=self._on_activate,
readonly=True,
limit=None)
self.screen.signal_connect(self, 'record-message', self._sig_label)
self.screen.windows.append(self)
vbox.pack_start(self.screen.widget, expand=True, fill=True, padding=0)
@@ -270,8 +270,8 @@ class Many2Many(Widget):
not self._readonly
and self._position))
def _sig_label(self, screen, signal_data):
self._position = signal_data[0]
def record_message(self, position, *args):
self._position = position
self._set_button_sensitive()
def display(self):
@@ -170,7 +170,7 @@ class One2Many(Widget):
limit=None,
breadcrumb=breadcrumb)
self.screen.pre_validate = bool(int(attrs.get('pre_validate', 0)))
self.screen.signal_connect(self, 'record-message', self._sig_label)
self.screen.windows.append(self)
vbox.pack_start(self.screen.widget, expand=True, fill=True, padding=0)
@@ -507,9 +507,9 @@ class One2Many(Widget):
win.screen.search_filter(quote(text))
win.show()
def _sig_label(self, screen, signal_data):
self._position = signal_data[0]
self._length = signal_data[1]
def record_message(self, position, size, *args):
self._position = position
self._length = size
if self._position:
name = str(self._position)
else:
@@ -555,8 +555,7 @@ class One2Many(Widget):
def set_value(self):
self.screen.current_view.set_value()
if self.screen.modified(): # TODO check if required
self.record.modified_fields.setdefault(self.field.name)
self.record.signal('record-modified')
self.view.screen.record_modified(display=False)
return True
def _completion_match_selected(self, completion, model, iter_):
@@ -78,7 +78,7 @@ class Widget(object):
if not self.widget.props.window:
return
if self.record and self.get_value() == value:
self.record.signal('record-modified')
self.view.screen.record_modified(display=False)
def get_value():
if not self.widget.props.window:
@@ -125,6 +125,9 @@ class Widget(object):
self.invisible_set(self.attrs.get(
'invisible', states.get('invisible', False)))
def get_value(self):
pass
def set_value(self):
pass
+8 -6
View File
@@ -917,14 +917,16 @@ class ViewTree(View):
return True
return False
def group_list_changed(self, group, signal):
def group_list_changed(self, group, action, *args):
model = self.treeview.get_model()
if model is not None:
if signal[0] == 'record-added':
model.added(group, signal[1])
elif signal[0] == 'record-removed':
model.removed(group, signal[1])
self.display()
if action == 'record-added':
record, pos = args
model.added(group, record)
elif action == 'record-removed':
record, pos = args
model.removed(group, record)
self.display(force=action == 'group-cleared')
def __str__(self):
return 'ViewList (%d)' % id(self)
@@ -114,14 +114,13 @@ class ViewListForm(View):
selected_rows = self.listbox.get_selected_rows()
return [self.group[r.get_index()] for r in selected_rows]
def group_list_changed(self, group, signal):
action = signal[0]
def group_list_changed(self, group, action, *args):
if action == 'record-added':
position = signal[2]
record, position = args
self._model.emit('items-changed', position, 0, 1)
self._view_forms.insert(position, self._view_forms.pop())
elif action == 'record-removed':
position = signal[2]
record, position = args
self._model.emit('items-changed', position, 1, 0)
self._view_forms.pop(position)
+21 -20
View File
@@ -75,6 +75,7 @@ class WinForm(NoModal, InfoBar):
self.but_new = None
self._initial_value = None
self.view_type = view_type
if view_type == 'form':
if new:
label, icon = _("Delete"), 'tryton-delete'
@@ -277,17 +278,11 @@ class WinForm(NoModal, InfoBar):
self.win.vbox.pack_start(
self.info_bar, expand=False, fill=True, padding=0)
self.screen.windows.append(self)
if view_type == 'tree':
self.screen.signal_connect(self, 'record-message', self._sig_label)
self.screen.screen_container.alternate_viewport.connect(
'key-press-event', self.on_keypress)
if self.save_current and not new:
self.screen.signal_connect(self, 'record-message',
self.activate_save)
self.screen.signal_connect(self, 'record-modified',
self.activate_save)
self.register()
self.show()
@@ -350,22 +345,25 @@ class WinForm(NoModal, InfoBar):
win.screen.search_filter(quote(value))
win.show()
def _sig_label(self, screen, signal_data):
def record_message(self, position, size, *args):
self.activate_save()
if self.view_type != 'tree':
return
name = '_'
access = common.MODELACCESS[screen.model_name]
access = common.MODELACCESS[self.screen.model_name]
deletable = True
if screen.current_record:
deletable = screen.current_record.deletable
readonly = screen.group.readonly
if signal_data[0] >= 1:
name = str(signal_data[0])
if self.screen.current_record:
deletable = self.screen.current_record.deletable
readonly = self.screen.group.readonly
if position >= 1:
name = str(position)
if self.domain is not None:
self.but_remove.set_sensitive(True)
if signal_data[0] < signal_data[1]:
if position < size:
self.but_next.set_sensitive(True)
else:
self.but_next.set_sensitive(False)
if signal_data[0] > 1:
if position > 1:
self.but_pre.set_sensitive(True)
else:
self.but_pre.set_sensitive(False)
@@ -379,10 +377,13 @@ class WinForm(NoModal, InfoBar):
self.but_pre.set_sensitive(False)
if self.domain is not None:
self.but_remove.set_sensitive(False)
line = '(%s/%s)' % (name, signal_data[1])
line = '(%s/%s)' % (name, position)
self.label.set_text(line)
def activate_save(self, *args):
def record_modified(self, *args):
self.activate_save()
def activate_save(self):
modified = self.screen.modified()
# Keep sensible as change could have been trigger by a Many2One edition
sensitive = modified or self.but_ok.props.sensitive
@@ -441,7 +442,7 @@ class WinForm(NoModal, InfoBar):
elif record.modified:
record.cancel()
record.reload()
record.signal('record-changed')
record.set_modified()
if added:
record.modified_fields.setdefault('id')
result = False
@@ -461,12 +462,12 @@ class WinForm(NoModal, InfoBar):
self.win.set_default_response(Gtk.ResponseType.OK)
def destroy(self):
self.screen.windows.remove(self)
self.screen.screen_container.alternate_view = False
viewport = self.screen.screen_container.alternate_viewport
if viewport and viewport.get_parent():
viewport.get_parent().remove(viewport)
self.screen.switch_view(view_type=self.prev_view.view_type)
self.screen.signal_unconnect(self)
if getattr(self, 'win', None):
self.win.destroy()
NoModal.destroy(self)
+10 -8
View File
@@ -14,7 +14,6 @@ from tryton.exceptions import TrytonServerError
from tryton.gui import Main
from tryton.gui.window.nomodal import NoModal
from tryton.gui.window.view_form.screen import Screen
from tryton.signal_event import SignalEvent
from .infobar import InfoBar
from .tabcontent import TabContent
@@ -109,7 +108,7 @@ class Wizard(InfoBar):
self.screen.new(default=False)
self.screen.current_record.set_default(view['defaults'])
self.update_buttons(self.screen.current_record)
self.update_buttons()
self.screen.set_cursor()
self.screen_state = view['state']
@@ -187,10 +186,11 @@ class Wizard(InfoBar):
button.show()
return button
def _record_changed(self, screen, record):
self.update_buttons(record)
def record_modified(self):
self.update_buttons()
def update_buttons(self, record):
def update_buttons(self):
record = self.screen.current_record
for button in self.states.values():
button.state_set(record)
@@ -199,12 +199,14 @@ class Wizard(InfoBar):
for button in buttons:
self._get_button(button)
if self.screen:
self.screen.windows.remove(self)
self.screen = Screen(view['model'], mode=[], context=self.context)
self.screen.add_view(view)
self.screen.switch_view()
self.screen.widget.show()
self.screen.signal_connect(self, 'group-changed',
self._record_changed)
self.screen.windows.append(self)
title = Gtk.Label(
label=common.ellipsize(self.name, 80),
@@ -245,7 +247,7 @@ class Wizard(InfoBar):
self.info_bar, expand=False, fill=True, padding=0)
class WizardForm(Wizard, TabContent, SignalEvent):
class WizardForm(Wizard, TabContent):
"Wizard"
def __init__(self, name=''):
-42
View File
@@ -1,42 +0,0 @@
# This file is part of Tryton. The COPYRIGHT file at the top level of
# this repository contains the full copyright notices and license terms.
"Signal event"
class SignalEvent(object):
"Signal event"
def __init__(self, *args, **kwargs):
super(SignalEvent, self).__init__(*args, **kwargs)
self.__connects = {}
def signal(self, signal, signal_data=None):
for fnct, data, key in self.__connects.get(signal, []):
fnct(self, signal_data, *data)
return True
def signal_connected(self, signal):
return bool(self.__connects.get(signal))
def signal_connect(self, key, signal, fnct, *data):
self.__connects.setdefault(signal, [])
if (fnct, data, key) not in self.__connects[signal]:
self.__connects[signal].append((fnct, data, key))
return True
def signal_unconnect(self, key, signal=None):
if signal is None:
signal = list(self.__connects.keys())
else:
signal = [signal]
for sig in signal:
i = 0
while i < len(self.__connects[sig]):
if self.__connects[sig][i][2] is key:
del self.__connects[sig][i]
else:
i += 1
return True
def destroy(self):
self.__connects = {}