diff --git a/CHANGELOG b/CHANGELOG
index 74a5486766..c44613e54e 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,3 +1,5 @@
+* Added additional gtk.Entry for filename on BinaryField
+* Display deleted lines in One2Many and Many2Many
* Handle URL
* Add communication between boards
* Added domain inversion feature
diff --git a/share/pixmaps/tryton/tryton-undo.svg b/share/pixmaps/tryton/tryton-undo.svg
new file mode 100644
index 0000000000..d3cce96f1b
--- /dev/null
+++ b/share/pixmaps/tryton/tryton-undo.svg
@@ -0,0 +1,230 @@
+
+
+
diff --git a/tryton/common/cellrenderercombo.py b/tryton/common/cellrenderercombo.py
index ab5544ef1a..374ade5bd2 100644
--- a/tryton/common/cellrenderercombo.py
+++ b/tryton/common/cellrenderercombo.py
@@ -29,6 +29,8 @@ class CellRendererCombo(gtk.GenericCellRenderer):
gobject.PARAM_READWRITE),
'text-column': (gobject.TYPE_INT, 'Text Column',
'Text Column', 0, 10, 0, gobject.PARAM_READWRITE),
+ 'strikethrough': (gobject.TYPE_BOOLEAN, 'Strikethrough',
+ 'Strikethrough', False, gobject.PARAM_WRITABLE),
}
def __init__(self):
@@ -40,6 +42,11 @@ class CellRendererCombo(gtk.GenericCellRenderer):
self.editable = self._renderer.get_property('editable')
self.visible = True
+ def set_sensitive(self, value):
+ if hasattr(self._renderer, 'set_sensitive'):
+ return self._renderer.set_sensitive(value)
+ return self._renderer.set_property('sensitive', value)
+
def do_set_property(self, pspec, value):
setattr(self, pspec.name, value)
if pspec.name == 'visible':
diff --git a/tryton/common/cellrendererdate.py b/tryton/common/cellrendererdate.py
index f2b4279027..d7e199f4bc 100644
--- a/tryton/common/cellrendererdate.py
+++ b/tryton/common/cellrendererdate.py
@@ -22,6 +22,8 @@ class CellRendererDate(gtk.GenericCellRenderer):
'Editable', 0, 10, 0, gobject.PARAM_READWRITE),
'visible': (gobject.TYPE_INT, 'Visible',
'Visible', 0, 10, 0, gobject.PARAM_READWRITE),
+ 'strikethrough': (gobject.TYPE_BOOLEAN, 'Strikethrough',
+ 'Strikethrough', False, gobject.PARAM_WRITABLE),
}
def __init__(self, format):
@@ -36,6 +38,11 @@ class CellRendererDate(gtk.GenericCellRenderer):
self.editable = self._renderer.get_property('editable')
self.visible = True
+ def set_sensitive(self, value):
+ if hasattr(self._renderer, 'set_sensitive'):
+ return self._renderer.set_sensitive(value)
+ return self._renderer.set_property('sensitive', value)
+
def do_set_property(self, pspec, value):
setattr(self, pspec.name, value)
if pspec.name == 'visible':
diff --git a/tryton/common/cellrenderertext.py b/tryton/common/cellrenderertext.py
index f11cf478a1..4beded4d23 100644
--- a/tryton/common/cellrenderertext.py
+++ b/tryton/common/cellrenderertext.py
@@ -23,6 +23,8 @@ class CellRendererText(gtk.GenericCellRenderer):
'XAlign', 0, 1, 0, gobject.PARAM_READWRITE),
'visible': (gobject.TYPE_INT, 'Visible',
'Visible', 0, 10, 0, gobject.PARAM_READWRITE),
+ 'strikethrough': (gobject.TYPE_BOOLEAN, 'Strikethrough',
+ 'Strikethrough', False, gobject.PARAM_WRITABLE),
}
def __init__(self):
@@ -34,6 +36,11 @@ class CellRendererText(gtk.GenericCellRenderer):
self.editable = self._renderer.get_property('editable')
self.visible = True
+ def set_sensitive(self, value):
+ if hasattr(self._renderer, 'set_sensitive'):
+ return self._renderer.set_sensitive(value)
+ return self._renderer.set_property('sensitive', value)
+
def do_set_property(self, pspec, value):
setattr(self, pspec.name, value)
if pspec.name == 'visible':
diff --git a/tryton/common/cellrenderertoggle.py b/tryton/common/cellrenderertoggle.py
index 52d2f3313c..2f4f4592dd 100644
--- a/tryton/common/cellrenderertoggle.py
+++ b/tryton/common/cellrenderertoggle.py
@@ -27,6 +27,11 @@ class CellRendererToggle(gtk.GenericCellRenderer):
self.activatable = self._renderer.get_property('activatable')
self.visible = True
+ def set_sensitive(self, value):
+ if hasattr(self._renderer, 'set_sensitive'):
+ return self._renderer.set_sensitive(value)
+ return self._renderer.set_property('sensitive', value)
+
def do_set_property(self, pspec, value):
setattr(self, pspec.name, value)
if pspec.name == 'visible':
diff --git a/tryton/gui/window/shortcuts.py b/tryton/gui/window/shortcuts.py
index cfcf779f2b..bdbb00f1c6 100644
--- a/tryton/gui/window/shortcuts.py
+++ b/tryton/gui/window/shortcuts.py
@@ -24,17 +24,22 @@ class Shortcuts(object):
self.dialog.vbox.pack_start(notebook)
shortcuts = [
- (_('Text Entries Shortcuts'),),
- (' + X', _('Cut selected text')),
- (' + C', _('Copy selected text')),
- (' + V', _('Paste copied text')),
- ('', _('Next widget')),
- (' + ', _('Previous widget')),
- (_('Relation Entries Shortcuts'),),
- ('', _('Create new relation')),
- ('', _('Open/Search relation')),
- (_('Date/Datetime Entries Shortcuts'),),
- (_('''You can use special operators:
+ (_('Text Entries Shortcuts'),),
+ (' + X', _('Cut selected text')),
+ (' + C', _('Copy selected text')),
+ (' + V', _('Paste copied text')),
+ ('', _('Next widget')),
+ (' + ', _('Previous widget')),
+ (_('Relation Entries Shortcuts'),),
+ ('', _('Create new relation')),
+ ('', _('Open/Search relation')),
+ (_('List Entries Shortcuts'),),
+ ('', _('Create new line')),
+ ('', _('Open relation')),
+ ('', _('Mark line for deletion')),
+ ('', _('Unmark line for deletion')),
+ (_('Date/Datetime Entries Shortcuts'),),
+ (_('''You can use special operators:
* + to increase the date
* - to decrease the date or clear
* = to set the date or the current date
@@ -49,8 +54,8 @@ y for years
Examples:
"+21d" increase of 21 days the date
"=11m" set the date to the 11th month of the year
-"-2w" decrease of 2 weeks the date'''),)
- ]
+"-2w" decrease of 2 weeks the date'''),),
+ ]
notebook.append_page(self._fill_table(shortcuts),
gtk.Label(_('Edition Widgets')))
diff --git a/tryton/gui/window/view_form/model/field.py b/tryton/gui/window/view_form/model/field.py
index e8b8ad7853..9d24c5f782 100644
--- a/tryton/gui/window/view_form/model/field.py
+++ b/tryton/gui/window/view_form/model/field.py
@@ -179,7 +179,7 @@ class CharField(object):
def get_state_attrs(self, record):
if self.name not in record.state_attrs:
record.state_attrs[self.name] = self.attrs.copy()
- if record.group.readonly:
+ if record.group.readonly or record.readonly:
record.state_attrs[self.name]['readonly'] = True
return record.state_attrs[self.name]
@@ -449,10 +449,10 @@ class O2MField(CharField):
record2.get(check_load=check_load, get_readonly=readonly)))
if record.value[self.name].record_removed:
result.append(('unlink', [x.id for x in \
- record.value[self.name].record_removed]))
+ record.value[self.name].record_removed]))
if record.value[self.name].record_deleted:
result.append(('delete', [x.id for x in \
- record.value[self.name].record_deleted]))
+ record.value[self.name].record_deleted]))
return result
def get_timestamp(self, record):
@@ -473,7 +473,8 @@ class O2MField(CharField):
if record.value.get(self.name) is None:
return []
for record2 in record.value[self.name]:
- result.append(record2.get_eval(check_load=check_load))
+ if not (record2.deleted or record2.removed):
+ result.append(record2.get_eval(check_load=check_load))
return result
def set(self, record, value, modified=False):
@@ -531,7 +532,7 @@ class O2MField(CharField):
parent_datetime_field=self.attrs.get('datetime_field'))
if record.value.get(self.name):
group.record_deleted.extend(x for x in record.value[self.name]
- if x.id > 0)
+ if x.id > 0)
group.record_deleted.extend(record.value[self.name].record_deleted)
group.record_removed.extend(record.value[self.name].record_removed)
record.value[self.name] = group
@@ -698,6 +699,9 @@ class ReferenceField(CharField):
if not value:
record.value[self.name] = False
return
+ if isinstance(value, basestring):
+ model, ref_id = value.split(',')
+ value = model, (ref_id, record.value.get(self.name + '.rec_name'))
ref_model, (ref_id, ref_str) = value
if ref_model:
ref_id = int(ref_id)
diff --git a/tryton/gui/window/view_form/model/group.py b/tryton/gui/window/view_form/model/group.py
index 82671bdfc5..5454e608cf 100644
--- a/tryton/gui/window/view_form/model/group.py
+++ b/tryton/gui/window/view_form/model/group.py
@@ -27,8 +27,7 @@ class Group(SignalEvent, list):
self.load_fields(fields)
self.current_idx = None
self.load(ids)
- self.record_removed = []
- self.record_deleted = []
+ self.record_deleted, self.record_removed = [], []
self.on_write = set()
self.readonly = readonly
if self._context.get('_datetime'):
@@ -87,8 +86,7 @@ class Group(SignalEvent, list):
if not self.lock_signal:
self.signal('group-list-changed', ('group-cleared',))
self.__id2record = {}
- self.record_removed = []
- self.record_deleted = []
+ self.record_removed, self.record_deleted = [], []
def move(self, record, pos):
self.lock_signal = True
@@ -159,9 +157,16 @@ class Group(SignalEvent, list):
def load(self, ids, display=True, modified=False):
if not ids:
return True
+ # Work with sets to compute intersection and set difference
+ set_records = set(self.get(x) for x in ids)
+ for record in set_records & set(self.record_removed):
+ self.record_removed.remove(record)
+ for record in set_records & set(self.record_deleted):
+ self.record_deleted.remove(record)
- old_ids = [x.id for x in self]
- ids = [x for x in ids if x not in old_ids]
+ set_records -= set(x for x in self)
+ # return on the list form in order to preserver ordering
+ ids = [x for x in ids if self.get(x) in set_records]
if not ids:
return True
@@ -177,12 +182,6 @@ class Group(SignalEvent, list):
self._record_changed)
new_record.signal_connect(self, 'record-modified',
self._record_modified)
- for record in self.record_removed[:]:
- if record.id in ids:
- self.record_removed.remove(record)
- for record in self.record_deleted[:]:
- if record.id in ids:
- self.record_deleted.remove(record)
if self.lock_signal:
self.lock_signal = False
self.signal('group-cleared')
@@ -253,18 +252,31 @@ class Group(SignalEvent, list):
self.signal('group-changed', record)
return record
+ def unremove(self, record, signal=True):
+ if record in self.record_removed:
+ self.record_removed.remove(record)
+ if record in self.record_deleted:
+ self.record_deleted.remove(record)
+ if signal:
+ record.signal('record-changed', record.parent)
+
def remove(self, record, remove=False, modified=True, signal=True):
idx = self.index(record)
if self[idx].id > 0:
if remove:
+ if self[idx] in self.record_deleted:
+ self.record_deleted.remove(self[idx])
self.record_removed.append(self[idx])
else:
+ if self[idx] in self.record_removed:
+ self.record_removed.remove(self[idx])
self.record_deleted.append(self[idx])
if record.parent:
record.parent.modified = True
if modified:
record.modified = True
- self._remove(self[idx])
+ if not record.parent or self[idx].id <= 0:
+ self._remove(self[idx])
if len(self):
self.current_idx = min(idx, len(self) - 1)
@@ -351,8 +363,7 @@ class Group(SignalEvent, list):
for field in self.fields.itervalues():
field.destroy()
self.fields = {}
- self.record_removed = None
- self.record_deleted = None
+ self.record_deleted, self.record_removed = [], []
self.__id2record = None
for record in self:
record.destroy()
diff --git a/tryton/gui/window/view_form/model/record.py b/tryton/gui/window/view_form/model/record.py
index b5c6df3a48..2ce4109f85 100644
--- a/tryton/gui/window/view_form/model/record.py
+++ b/tryton/gui/window/view_form/model/record.py
@@ -106,6 +106,25 @@ class Record(SignalEvent):
modified = property(get_modified, set_modified)
+ def get_removed(self):
+ if self.group is not None:
+ return self in self.group.record_removed
+ return False
+
+ removed = property(get_removed)
+
+ def get_deleted(self):
+ if self.group is not None:
+ return self in self.group.record_deleted
+ return False
+
+ deleted = property(get_deleted)
+
+ def get_readonly(self):
+ return self.deleted or self.removed
+
+ readonly = property(get_readonly)
+
def is_modified(self):
return self.modified
diff --git a/tryton/gui/window/view_form/screen/screen.py b/tryton/gui/window/view_form/screen/screen.py
index bbef413001..a9889be6f8 100644
--- a/tryton/gui/window/view_form/screen/screen.py
+++ b/tryton/gui/window/view_form/screen/screen.py
@@ -504,6 +504,10 @@ class Screen(SignalEvent):
self.display()
self.request_set()
+ def unremove(self):
+ if self.current_record in self.group:
+ self.group.unremove(self.current_record)
+
def remove(self, delete=False, remove=False):
res = False
reload_ids = []
diff --git a/tryton/gui/window/view_form/view/form_gtk/binary.py b/tryton/gui/window/view_form/view/form_gtk/binary.py
index ad69d0a1b4..db9ca59a5f 100644
--- a/tryton/gui/window/view_form/view/form_gtk/binary.py
+++ b/tryton/gui/window/view_form/view/form_gtk/binary.py
@@ -9,6 +9,12 @@ from interface import WidgetInterface
_ = gettext.gettext
+def humanize(size):
+ for x in ('bytes', 'KB', 'MB', 'GB', 'TB', 'PB'):
+ if size < 1000:
+ return '%3.1f%s' % (size, x)
+ size /= 1000.0
+
class Binary(WidgetInterface):
"Binary"
@@ -17,12 +23,26 @@ class Binary(WidgetInterface):
super(Binary, self).__init__(field_name, model_name, window,
attrs=attrs)
+ self.filename = attrs.get('filename')
+ self.filename_visible = attrs.get('filename_visible')
+
self.tooltips = Tooltips()
self.widget = gtk.HBox(spacing=0)
- self.wid_text = gtk.Entry()
- self.wid_text.set_property('activates_default', True)
- self.widget.pack_start(self.wid_text, expand=True, fill=True)
+ if self.filename and self.filename_visible:
+ self.wid_text = gtk.Entry()
+ self.wid_text.set_property('activates_default', True)
+ self.wid_text.connect('focus-in-event', lambda x, y: self._focus_in())
+ self.wid_text.connect('focus-out-event', lambda x, y: self._focus_out())
+ self.wid_text.connect_after('key_press_event', self.sig_key_press)
+ self.wid_size = gtk.Entry()
+ self.wid_size.set_width_chars(11)
+ self.wid_size.props.sensitive = False
+ self.widget.pack_start(self.wid_text, expand=True, fill=True)
+ else:
+ self.wid_text = None
+ self.widget.pack_start(self.wid_size, expand=not self.filename,
+ fill=True)
self.but_new = gtk.Button()
img_new = gtk.Image()
@@ -35,7 +55,8 @@ class Binary(WidgetInterface):
self.but_save_as = gtk.Button()
img_save_as = gtk.Image()
- img_save_as.set_from_stock('tryton-save-as', gtk.ICON_SIZE_SMALL_TOOLBAR)
+ img_save_as.set_from_stock('tryton-save-as',
+ gtk.ICON_SIZE_SMALL_TOOLBAR)
self.but_save_as.set_image(img_save_as)
self.but_save_as.set_relief(gtk.RELIEF_NONE)
self.but_save_as.connect('clicked', self.sig_save_as)
@@ -61,11 +82,17 @@ class Binary(WidgetInterface):
else:
self.but_new.show()
self.but_remove.show()
- self.widget.set_focus_chain([self.but_new, self.but_save_as,
- self.but_remove])
+ if self.wid_text:
+ focus_chain = [self.wid_text]
+ else:
+ focus_chain = [self.but_new, self.but_save_as, self.but_remove]
+ self.widget.set_focus_chain(focus_chain)
def grab_focus(self):
- return self.wid_text.grab_focus()
+ if self.wid_text:
+ return self.wid_text.grab_focus()
+ else:
+ return self.wid_size.grab_focus()
def sig_new(self, widget=None):
try:
@@ -74,9 +101,9 @@ class Binary(WidgetInterface):
if filename and self.field:
self.field.set_client(self.record,
base64.encodestring(open(filename, 'rb').read()))
- fname = self.attrs.get('fname_widget', False)
- if fname:
- self.parent.value = {fname:os.path.basename(filename)}
+ if self.filename and self.filename_visible and self.record:
+ name_wid = self.record.group.fields[self.filename]
+ name_wid.set_client(self.record, os.path.basename(filename))
self.display(self.record, self.field)
except Exception, exception:
warning(_('Error reading the file.\nError message:\n%s') \
@@ -98,29 +125,47 @@ class Binary(WidgetInterface):
def sig_remove(self, widget=None):
if self.field:
self.field.set_client(self.record, False)
- fname = self.attrs.get('fname_widget', False)
- if fname:
- self.parent.value = {fname:False}
self.display(self.record, self.field)
+ def sig_key_press(self, widget, event, *args):
+ editable = self.wid_text and self.wid_text.get_editable()
+ if event.keyval == gtk.keysyms.F3 and editable:
+ self.sig_new(widget)
+ return True
+ elif event.keyval == gtk.keysyms.F2:
+ self.sig_save_as(widget)
+ return True
+ return False
+
def display(self, record, field):
super(Binary, self).display(record, field)
if not field:
- self.wid_text.set_text('')
+ if self.wid_text:
+ self.wid_text.set_text('')
+ self.wid_size.set_text('')
self.but_save_as.set_sensitive(False)
return False
- self.wid_text.set_text(self._size_get(field.get(record)))
+ if self.wid_text:
+ name_wid = record.group.fields[self.filename]
+ self.wid_text.set_text(name_wid.get(record) or '')
+ self.wid_size.set_text(humanize(len(field.get(record) or [])))
self.but_save_as.set_sensitive(bool(field.get(record)))
return True
def display_value(self):
- return self.wid_text.get_text()
-
- def _size_get(self, value):
- return value and ('%d ' + _('bytes')) % len(value) or ''
+ if self.wid_text:
+ return self.wid_text.get_text()
+ else:
+ return ''
def set_value(self, record, field):
+ if self.wid_text:
+ name_wid = self.record.group.fields[self.filename]
+ name_wid.set_client(self.record, self.wid_text.get_text() or False)
return
def _color_widget(self):
- return self.wid_text
+ if self.wid_text:
+ return self.wid_text
+ else:
+ return self.wid_size
diff --git a/tryton/gui/window/view_form/view/form_gtk/image.py b/tryton/gui/window/view_form/view/form_gtk/image.py
index b0e3f989fe..36c722b8f0 100644
--- a/tryton/gui/window/view_form/view/form_gtk/image.py
+++ b/tryton/gui/window/view_form/view/form_gtk/image.py
@@ -20,6 +20,7 @@ class Image(WidgetInterface):
super(Image, self).__init__(field_name, model_name, window,
attrs=attrs)
+ self.filename = attrs.get('filename')
self.height = int(attrs.get('img_height', 100))
self.width = int(attrs.get('img_width', 300))
@@ -102,6 +103,9 @@ class Image(WidgetInterface):
if filename:
self.field.set_client(self.record,
encodestring(open(filename, 'rb').read()))
+ if self.filename and self.record:
+ name_wid = self.record.group.fields[self.filename]
+ name_wid.set_client(self.record, os.path.basename(filename))
self.update_img()
def sig_save_as(self, widget):
diff --git a/tryton/gui/window/view_form/view/form_gtk/interface.py b/tryton/gui/window/view_form/view/form_gtk/interface.py
index 08d6db1f1b..8d72d4ceb4 100644
--- a/tryton/gui/window/view_form/view/form_gtk/interface.py
+++ b/tryton/gui/window/view_form/view/form_gtk/interface.py
@@ -167,6 +167,7 @@ class WidgetInterface(object):
'fg_color_normal': style.fg[gtk.STATE_NORMAL],
'fg_color_insensitive': style.fg[gtk.STATE_INSENSITIVE],
'text_color_normal': style.text[gtk.STATE_NORMAL],
+ 'text_color_insensitive': style.text[gtk.STATE_INSENSITIVE],
}
if COLORS.get(name):
diff --git a/tryton/gui/window/view_form/view/form_gtk/many2many.py b/tryton/gui/window/view_form/view/form_gtk/many2many.py
index 12298ae648..058c2692c5 100644
--- a/tryton/gui/window/view_form/view/form_gtk/many2many.py
+++ b/tryton/gui/window/view_form/view/form_gtk/many2many.py
@@ -96,6 +96,15 @@ class Many2Many(WidgetInterface):
self.widget.destroy()
del self.widget
+ def color_set(self, name):
+ super(Many2Many, self).color_set(name)
+ widget = self._color_widget()
+ # if the style to apply is different from readonly then insensitive
+ # cellrenderers should use the default insensitive color
+ if name != 'readonly':
+ widget.modify_text(gtk.STATE_INSENSITIVE,
+ self.colors['text_color_insensitive'])
+
def _sig_add(self, *args):
domain = self.field.domain_get(self.record)
context = self.field.context_get(self.record)
diff --git a/tryton/gui/window/view_form/view/form_gtk/one2many.py b/tryton/gui/window/view_form/view/form_gtk/one2many.py
index 1233258257..db1958e6cd 100644
--- a/tryton/gui/window/view_form/view/form_gtk/one2many.py
+++ b/tryton/gui/window/view_form/view/form_gtk/one2many.py
@@ -104,7 +104,7 @@ class One2Many(WidgetInterface):
self.but_del = gtk.Button()
tooltips.set_tip(self.but_del, _('Delete selected record'))
- self.but_del.connect('clicked', self._sig_remove)
+ self.but_del.connect('clicked', self._sig_remove, False)
img_del = gtk.Image()
img_del.set_from_stock('tryton-delete', gtk.ICON_SIZE_SMALL_TOOLBAR)
img_del.set_alignment(0.5, 0.5)
@@ -112,6 +112,16 @@ class One2Many(WidgetInterface):
self.but_del.set_relief(gtk.RELIEF_NONE)
hbox.pack_start(self.but_del, expand=False, fill=False)
+ self.but_undel = gtk.Button()
+ tooltips.set_tip(self.but_undel, _('Undelete selected record'))
+ self.but_undel.connect('clicked', self._sig_undelete)
+ img_undel = gtk.Image()
+ img_undel.set_from_stock('tryton-undo', gtk.ICON_SIZE_SMALL_TOOLBAR)
+ img_undel.set_alignment(0.5, 0.5)
+ self.but_undel.add(img_undel)
+ self.but_undel.set_relief(gtk.RELIEF_NONE)
+ hbox.pack_start(self.but_undel, expand=False, fill=False)
+
hbox.pack_start(gtk.VSeparator(), expand=False, fill=True)
self.but_pre = gtk.Button()
@@ -195,6 +205,9 @@ class One2Many(WidgetInterface):
and widget == self.screen.widget:
self._sig_remove(widget)
return False
+ if event.keyval == gtk.keysyms.Insert and widget == self.screen.widget:
+ self._sig_undelete(widget)
+ return False
def destroy(self):
self.screen.destroy()
@@ -206,6 +219,15 @@ class One2Many(WidgetInterface):
self.screen.switch_view()
self.color_set(self.color_name)
+ def color_set(self, name):
+ super(One2Many, self).color_set(name)
+ widget = self._color_widget()
+ # if the style to apply is different from readonly then insensitive
+ # cellrenderers should use the default insensitive color
+ if name != 'readonly':
+ widget.modify_text(gtk.STATE_INSENSITIVE,
+ self.colors['text_color_insensitive'])
+
def _readonly_set(self, value):
self._readonly = value
self.but_new.set_sensitive(not value)
@@ -231,12 +253,6 @@ class One2Many(WidgetInterface):
self.screen.new(context=ctx)
self.screen.current_view.widget.set_sensitive(True)
else:
- readonly = False
- domain = []
- if self.field and self.record:
- readonly = self.field.get_state_attrs(self.record
- ).get('readonly', False)
- domain = self.field.domain_get(self.record)
win = WinForm(self.screen, self.window, new=True,
context=ctx)
while True:
@@ -250,8 +266,9 @@ class One2Many(WidgetInterface):
def _sig_edit(self, widget=None):
self.view.set_value()
- if self.screen.current_record:
- if not self.screen.current_record.validate():
+ record = self.screen.current_record
+ if record:
+ if not record.validate():
self.screen.display()
return
win = WinForm(self.screen, self.window)
@@ -277,6 +294,9 @@ class One2Many(WidgetInterface):
def _sig_remove(self, widget, remove=False):
self.screen.remove(remove=remove)
+ def _sig_undelete(self, button):
+ self.screen.unremove()
+
def _sig_activate(self, *args):
self._sig_add()
self.wid_text.grab_focus()
@@ -333,9 +353,12 @@ class One2Many(WidgetInterface):
self.but_pre.set_sensitive(True)
else:
self.but_pre.set_sensitive(False)
+ self.but_del.set_sensitive(True)
+ self.but_undel.set_sensitive(True)
else:
self.but_open.set_sensitive(False)
self.but_del.set_sensitive(False)
+ self.but_undel.set_sensitive(False)
self.but_next.set_sensitive(False)
self.but_pre.set_sensitive(False)
if self.attrs.get('add_remove'):
diff --git a/tryton/gui/window/view_form/view/form_gtk/parser.py b/tryton/gui/window/view_form/view/form_gtk/parser.py
index 0026ef582c..630b48d8e1 100644
--- a/tryton/gui/window/view_form/view/form_gtk/parser.py
+++ b/tryton/gui/window/view_form/view/form_gtk/parser.py
@@ -518,7 +518,7 @@ class ParserForm(ParserInterface):
continue
for attr_name in ('relation', 'domain', 'selection',
'relation_field', 'string', 'views', 'invisible',
- 'add_remove', 'sort', 'context', 'size'):
+ 'add_remove', 'sort', 'context', 'size', 'filename'):
if attr_name in fields[name].attrs and \
not attr_name in attrs:
attrs[attr_name] = fields[name].attrs[attr_name]
diff --git a/tryton/gui/window/view_form/view/list_gtk/parser.py b/tryton/gui/window/view_form/view/list_gtk/parser.py
index d5b9377225..41f3bac2dd 100644
--- a/tryton/gui/window/view_form/view/list_gtk/parser.py
+++ b/tryton/gui/window/view_form/view/list_gtk/parser.py
@@ -250,6 +250,10 @@ class Char(object):
if isinstance(cell, CellRendererToggle):
cell.set_active(bool(text))
else:
+ cell.set_sensitive(not (record.deleted or record.removed))
+ if isinstance(cell,
+ (CellRendererText, CellRendererDate, CellRendererCombo)):
+ cell.set_property('strikethrough', record.deleted)
cell.set_property('text', text)
fg_color = self.get_color(record)
cell.set_property('foreground', fg_color)
@@ -293,7 +297,8 @@ class Char(object):
cell.set_property('background-set', False)
else:
cell.set_property('background-set', True)
- cell.set_property('foreground-set', True)
+ cell.set_property('foreground-set',
+ not (record.deleted or record.removed))
if isinstance(cell, CellRendererToggle):
cell.set_property('activatable', not readonly)