From 6397fad1efb01234441352f5f1e7688ae63bf457 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicolas=20=C3=89vrard?= Date: Mon, 7 Feb 2011 18:14:58 +0100 Subject: [PATCH 1/4] Fix set_client for ReferenceField to support basestring values --- tryton/gui/window/view_form/model/field.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tryton/gui/window/view_form/model/field.py b/tryton/gui/window/view_form/model/field.py index 23f2e8fa85..32d2a464c4 100644 --- a/tryton/gui/window/view_form/model/field.py +++ b/tryton/gui/window/view_form/model/field.py @@ -695,6 +695,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) From 240d46be378cd927d8c027785ec80b0864c57df7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicolas=20=C3=89vrard?= Date: Wed, 16 Feb 2011 17:03:25 +0100 Subject: [PATCH 2/4] Display deleted lines in O2M and M2M --- CHANGELOG | 1 + share/pixmaps/tryton/tryton-undo.svg | 230 ++++++++++++++++++ tryton/common/cellrenderercombo.py | 5 + tryton/common/cellrendererdate.py | 5 + tryton/common/cellrenderertext.py | 5 + tryton/common/cellrenderertoggle.py | 3 + tryton/gui/window/shortcuts.py | 31 ++- tryton/gui/window/view_form/model/field.py | 11 +- tryton/gui/window/view_form/model/group.py | 41 ++-- tryton/gui/window/view_form/model/record.py | 19 ++ tryton/gui/window/view_form/screen/screen.py | 4 + .../view_form/view/form_gtk/interface.py | 1 + .../view_form/view/form_gtk/many2many.py | 9 + .../view_form/view/form_gtk/one2many.py | 41 +++- .../window/view_form/view/list_gtk/parser.py | 7 +- 15 files changed, 370 insertions(+), 43 deletions(-) create mode 100644 share/pixmaps/tryton/tryton-undo.svg diff --git a/CHANGELOG b/CHANGELOG index 74a5486766..0a4fecf592 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,4 @@ +* 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 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + Jakub Steiner + + + http://jimmac.musichall.cz + + Edit Undo + + + edit + undo + revert + + + + + + + + + + + + + + + + + diff --git a/tryton/common/cellrenderercombo.py b/tryton/common/cellrenderercombo.py index ab5544ef1a..d2116b2ef0 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,9 @@ class CellRendererCombo(gtk.GenericCellRenderer): self.editable = self._renderer.get_property('editable') self.visible = True + def set_sensitive(self, value): + return self._renderer.set_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..74109dcf61 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,9 @@ class CellRendererDate(gtk.GenericCellRenderer): self.editable = self._renderer.get_property('editable') self.visible = True + def set_sensitive(self, value): + return self._renderer.set_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..6f8d29f762 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,9 @@ class CellRendererText(gtk.GenericCellRenderer): self.editable = self._renderer.get_property('editable') self.visible = True + def set_sensitive(self, value): + return self._renderer.set_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..4904f8da2a 100644 --- a/tryton/common/cellrenderertoggle.py +++ b/tryton/common/cellrenderertoggle.py @@ -27,6 +27,9 @@ class CellRendererToggle(gtk.GenericCellRenderer): self.activatable = self._renderer.get_property('activatable') self.visible = True + def set_sensitive(self, value): + return self._renderer.set_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..4d31150afd 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 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/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/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) From a56d1106da7122beca539e7e6f76ae2d596e194b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicolas=20=C3=89vrard?= Date: Wed, 16 Feb 2011 17:41:21 +0100 Subject: [PATCH 3/4] Added additional gtk.Entry for filename on BinaryField --- CHANGELOG | 1 + .../window/view_form/view/form_gtk/binary.py | 85 ++++++++++++++----- .../window/view_form/view/form_gtk/image.py | 4 + .../window/view_form/view/form_gtk/parser.py | 2 +- 4 files changed, 71 insertions(+), 21 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index c93645bb21..d3c269f826 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,4 @@ +* Added additional gtk.Entry for filename on BinaryField * Add communication between boards * Added domain inversion feature * Handle loading attribute on fields 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/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] From 9495dd50a2a24162135859510f6f83a96040b69a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Wed, 16 Feb 2011 20:55:51 +0100 Subject: [PATCH 4/4] Add fallback to set_property when CellRenderer has not set_sensitive --- tryton/common/cellrenderercombo.py | 4 +++- tryton/common/cellrendererdate.py | 4 +++- tryton/common/cellrenderertext.py | 4 +++- tryton/common/cellrenderertoggle.py | 4 +++- 4 files changed, 12 insertions(+), 4 deletions(-) diff --git a/tryton/common/cellrenderercombo.py b/tryton/common/cellrenderercombo.py index d2116b2ef0..374ade5bd2 100644 --- a/tryton/common/cellrenderercombo.py +++ b/tryton/common/cellrenderercombo.py @@ -43,7 +43,9 @@ class CellRendererCombo(gtk.GenericCellRenderer): self.visible = True def set_sensitive(self, value): - return self._renderer.set_sensitive(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) diff --git a/tryton/common/cellrendererdate.py b/tryton/common/cellrendererdate.py index 74109dcf61..d7e199f4bc 100644 --- a/tryton/common/cellrendererdate.py +++ b/tryton/common/cellrendererdate.py @@ -39,7 +39,9 @@ class CellRendererDate(gtk.GenericCellRenderer): self.visible = True def set_sensitive(self, value): - return self._renderer.set_sensitive(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) diff --git a/tryton/common/cellrenderertext.py b/tryton/common/cellrenderertext.py index 6f8d29f762..4beded4d23 100644 --- a/tryton/common/cellrenderertext.py +++ b/tryton/common/cellrenderertext.py @@ -37,7 +37,9 @@ class CellRendererText(gtk.GenericCellRenderer): self.visible = True def set_sensitive(self, value): - return self._renderer.set_sensitive(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) diff --git a/tryton/common/cellrenderertoggle.py b/tryton/common/cellrenderertoggle.py index 4904f8da2a..2f4f4592dd 100644 --- a/tryton/common/cellrenderertoggle.py +++ b/tryton/common/cellrenderertoggle.py @@ -28,7 +28,9 @@ class CellRendererToggle(gtk.GenericCellRenderer): self.visible = True def set_sensitive(self, value): - return self._renderer.set_sensitive(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)