From 8e4468795b75af50d81803c3525abdc0e8ad34c9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Mon, 4 Aug 2008 11:12:20 +0200 Subject: [PATCH 1/5] Use Decimal comparison of numeric fields --- tryton/gui/window/view_form/model/field.py | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/tryton/gui/window/view_form/model/field.py b/tryton/gui/window/view_form/model/field.py index cb39719467..5c0d7cf3d4 100644 --- a/tryton/gui/window/view_form/model/field.py +++ b/tryton/gui/window/view_form/model/field.py @@ -192,8 +192,19 @@ class NumericField(FloatField): def set_client(self, model, value, test_state=True, force_change=False): value = Decimal(str(value)) - return super(NumericField, self).set_client(model, value, - test_state=test_state, force_change=force_change) + internal = model.value[self.name] + self.set(model, value, test_state) + if isinstance(self.attrs.get('digits'), str): + digits = model.expr_eval(self.attrs['digits']) + else: + digits = self.attrs.get('digits', (12, 2)) + if abs((internal or Decimal('0.0')) - (model.value[self.name] or Decimal('0.0'))) \ + >= Decimal(str(10.0**(-int(digits[1])))): + if not self.get_state_attrs(model).get('readonly', False): + model.modified = True + model.modified_fields.setdefault(self.name) + self.sig_changed(model) + model.signal('record-changed', model) class IntegerField(CharField): From b5f8f3531260fc10022157077786141de0a6a061 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Mon, 4 Aug 2008 15:02:18 +0200 Subject: [PATCH 2/5] Fix on_change_with to be called only if the changed field is in the list --- tryton/gui/window/view_form/model/record.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tryton/gui/window/view_form/model/record.py b/tryton/gui/window/view_form/model/record.py index 4b6be183f7..96e869cbfc 100644 --- a/tryton/gui/window/view_form/model/record.py +++ b/tryton/gui/window/view_form/model/record.py @@ -320,12 +320,14 @@ class ModelRecord(SignalEvent): self.mgroup.mfields[fieldname].set_on_change(self, value) self.signal('record-changed') - def on_change_with(self, fieldname): + def on_change_with(self, field_name): for fieldname in self.mgroup.mfields: on_change_with = self.mgroup.mfields[fieldname].attrs.get( 'on_change_with') if not on_change_with: continue + if field_name not in on_change_with: + continue args = {} for arg in on_change_with: try: From ebae5d67c929126edfae9835bed17632ea345242 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Mon, 4 Aug 2008 15:12:36 +0200 Subject: [PATCH 3/5] Remove "Cancel" button on dialog of one2many when editing an existing model. Prevent to close the window with a invalid model. --- .../view_form/view/form_gtk/one2many.py | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) 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 473a7e673a..29ba1bc151 100644 --- a/tryton/gui/window/view_form/view/form_gtk/one2many.py +++ b/tryton/gui/window/view_form/view/form_gtk/one2many.py @@ -160,6 +160,7 @@ class Dialog(object): self.dia = gtk.Dialog(_('Link'), window, gtk.DIALOG_MODAL|gtk.DIALOG_DESTROY_WITH_PARENT) + self.dia.connect('close', self._sig_close) self.window = window self.dia.set_property('default-width', 760) self.dia.set_property('default-height', 500) @@ -169,11 +170,11 @@ class Dialog(object): self.accel_group = gtk.AccelGroup() self.dia.add_accel_group(self.accel_group) - icon_cancel = gtk.STOCK_CLOSE + self.but_cancel = None if not model: icon_cancel = gtk.STOCK_CANCEL - self.but_cancel = self.dia.add_button(icon_cancel, - gtk.RESPONSE_CANCEL) + self.but_cancel = self.dia.add_button(icon_cancel, + gtk.RESPONSE_CANCEL) self.but_ok = self.dia.add_button(gtk.STOCK_OK, gtk.RESPONSE_OK) self.but_ok.add_accelerator('clicked', self.accel_group, @@ -366,13 +367,23 @@ class Dialog(object): if not end: self.screen.current_view.set_cursor() self.screen.display() - self.but_cancel.set_label(gtk.STOCK_CLOSE) + if self.but_cancel: + self.but_cancel.set_label(gtk.STOCK_CLOSE) if res == gtk.RESPONSE_OK: model = self.screen.current_model return (True, model) return (False, None) + def _sig_close(self, widget): + self.screen.current_view.set_value() + if not self.but_cancel \ + and self.screen.current_model \ + and not self.screen.current_model.validate(): + self.screen.current_view.set_cursor() + self.screen.display() + widget.emit_stop_by_name('close') + def destroy(self): self.screen.signal_unconnect(self) self.window.present() From a6232c81e1685689b188cde418ea81a9a64994b6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Mon, 4 Aug 2008 19:13:39 +0200 Subject: [PATCH 4/5] Add temporary id to record with a negative value Allow to update one2many records with on_change --- tryton/gui/window/view_form/model/field.py | 21 ++++++++++++------- tryton/gui/window/view_form/model/group.py | 4 ++-- tryton/gui/window/view_form/model/record.py | 22 +++++++++++++------- tryton/gui/window/view_form/screen/screen.py | 2 +- 4 files changed, 30 insertions(+), 19 deletions(-) diff --git a/tryton/gui/window/view_form/model/field.py b/tryton/gui/window/view_form/model/field.py index 5c0d7cf3d4..18648430e9 100644 --- a/tryton/gui/window/view_form/model/field.py +++ b/tryton/gui/window/view_form/model/field.py @@ -352,7 +352,7 @@ class O2MField(CharField): for model2 in model.value[self.name].models: if (modified and not model2.is_modified()): continue - if model2.id: + if model2.id > 0: result.append(('write', model2.id, model2.get(check_load=check_load, get_readonly=readonly, get_modifiedonly=modified))) @@ -419,14 +419,12 @@ class O2MField(CharField): return True def set_on_change(self, model, value): - from group import ModelRecordGroup - - if value and value.get('add'): + if value and (value.get('add') or value.get('update')): context = self.context_get(model) rpc2 = RPCProxy(self.attrs['relation']) try: fields_name = [] - for val in value['add']: + for val in (value.get('add', []) + value.get('update', [])): for fieldname in val.keys(): if fieldname not in fields_name: fields_name.append(fieldname) @@ -447,12 +445,19 @@ class O2MField(CharField): model.value[self.name].remove(mod) mod = None - if value and value.get('add'): + if value and value.get('add') or value.get('update', []): model.value[self.name].add_fields(fields, model.value[self.name]) - for record in (value['add'] or []): + for record in value.get('add', []): mod = model.value[self.name].model_new(default=False) model.value[self.name].model_add(mod) - mod.set(record, modified=True, signal=True) + mod.set(record, modified=True, signal=False) + + for record in value.get('update', []): + if 'id' not in record: + continue + mod = model.value[self.name].get_by_id(record['id']) + if mod: + mod.set(record, modified=True, signal=False) model.value[self.name].current_model = mod return True diff --git a/tryton/gui/window/view_form/model/group.py b/tryton/gui/window/view_form/model/group.py index 02e46b4bf0..dcfbe25c58 100644 --- a/tryton/gui/window/view_form/model/group.py +++ b/tryton/gui/window/view_form/model/group.py @@ -287,7 +287,7 @@ class ModelRecordGroup(SignalEvent): def remove(self, model, remove=False, modified=True): idx = self.models.index(model) - if self.models[idx].id: + if self.models[idx].id > 0: if remove: self.model_removed.append(self.models[idx].id) else: @@ -325,7 +325,7 @@ class ModelRecordGroup(SignalEvent): old = [] new = [] for model in models: - if model.id: + if model.id > 0: if model.is_modified(): old.append(model.id) elif to_add: diff --git a/tryton/gui/window/view_form/model/record.py b/tryton/gui/window/view_form/model/record.py index 96e869cbfc..d37cd08fe0 100644 --- a/tryton/gui/window/view_form/model/record.py +++ b/tryton/gui/window/view_form/model/record.py @@ -23,12 +23,18 @@ class EvalEnvironment(object): class ModelRecord(SignalEvent): + id = -1 + + def __init__(self, resource, obj_id, window, group=None, parent=None, new=False ): + global ID_COUNT super(ModelRecord, self).__init__() self.window = window self.resource = resource self.rpc = RPCProxy(self.resource) - self.id = obj_id + self.id = obj_id or ModelRecord.id + if self.id < 0: + ModelRecord.id -= 1 self._loaded = False self.parent = parent self.mgroup = group @@ -47,7 +53,7 @@ class ModelRecord(SignalEvent): self.value[key].model_add(mod) def __getitem__(self, name): - if not self._loaded and self.id: + if not self._loaded and self.id > 0: ids = [self.id] idx = self.mgroup.models.index(self) length = len(self.mgroup.models) @@ -135,7 +141,7 @@ class ModelRecord(SignalEvent): def save(self, force_reload=True): self._check_load() - if not self.id: + if self.id < 0: value = self.get(get_readonly=True) try: self.id = self.rpc.create(value, self.context_get()) @@ -143,7 +149,7 @@ class ModelRecord(SignalEvent): self.id = common.process_exception(exception, self.window, 'object', 'execute', self.resource, 'create', value, self.context_get()) - if not self.id: + if not self.id or self.id < 0: return False else: if not self.is_modified(): @@ -256,7 +262,7 @@ class ModelRecord(SignalEvent): self.signal('record-changed') def reload(self): - if not self.id: + if self.id < 0: return ctx = rpc.CONTEXT.copy() ctx.update(self.context_get()) @@ -297,7 +303,7 @@ class ModelRecord(SignalEvent): args[arg] = self.expr_eval(arg) except: args[arg] = False - ids = self.id and [self.id] or [] + ids = [self.id] ctx = rpc.CONTEXT.copy() ctx.update(self.context_get()) try: @@ -334,7 +340,7 @@ class ModelRecord(SignalEvent): args[arg] = self.expr_eval(arg) except: args[arg] = False - ids = self.id and [self.id] or [] + ids = [self.id] ctx = rpc.CONTEXT.copy() ctx.update(self.context_get()) try: @@ -359,7 +365,7 @@ class ModelRecord(SignalEvent): field_name + '=' + str(value), ctx)) def get_attachment_count(self, reload=False): - if not self.id: + if self.id < 0: return 0 if self.attachment_count < 0 or reload: ir_attachment = RPCProxy('ir.attachment') diff --git a/tryton/gui/window/view_form/screen/screen.py b/tryton/gui/window/view_form/screen/screen.py index 1fda884001..4f8c59cec3 100644 --- a/tryton/gui/window/view_form/screen/screen.py +++ b/tryton/gui/window/view_form/screen/screen.py @@ -461,7 +461,7 @@ class Screen(SignalEvent): reload_ids = [] if self.current_view.view_type == 'form' and self.current_model: obj_id = self.current_model.id - if delete and obj_id: + if delete and obj_id > 0: try: reload_ids = self.models.on_write_ids(obj_id) if reload_ids and obj_id in reload_ids: From 30cda6ddb16abb32b197ece8069ca257bccc181d Mon Sep 17 00:00:00 2001 From: Bertrand Chenal Date: Mon, 4 Aug 2008 20:28:19 +0200 Subject: [PATCH 5/5] Use new icon --- share/pixmaps/tryton-icon.png | Bin 1794 -> 1280 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/share/pixmaps/tryton-icon.png b/share/pixmaps/tryton-icon.png index cacbcdbb9550f15f782c690c7d55735b67459c99..316a7c24b960376777bef9e982d1db31773bc9b4 100644 GIT binary patch delta 1271 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