diff --git a/CHANGELOG b/CHANGELOG index e0eaf1ee52..433467797e 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,4 @@ +* Add factor on number widgets * Add calendar view * Add URL entry * Remove request diff --git a/tryton/gui/window/view_form/model/field.py b/tryton/gui/window/view_form/model/field.py index b555e8de99..5e4990fa3d 100644 --- a/tryton/gui/window/view_form/model/field.py +++ b/tryton/gui/window/view_form/model/field.py @@ -11,6 +11,7 @@ import time import datetime import decimal from decimal import Decimal +import math from tryton.translate import date_format from tryton.common import RPCExecute, RPCException @@ -263,8 +264,9 @@ class TimeField(CharField): return record.expr_eval(self.attrs['format']) -class NumberField(CharField): +class FloatField(CharField): _default = None + default_digits = (16, 2) def check_required(self, record): state_attrs = self.get_state_attrs(record) @@ -277,71 +279,62 @@ class NumberField(CharField): def get(self, record): return record.value.get(self.name, self._default) - def digits(self, record): - default = (16, 2) - return tuple(y if x is None else x for x, y in zip( - record.expr_eval(self.attrs.get('digits', default)), default)) + def digits(self, record, factor=1): + digits = tuple(y if x is None else x for x, y in zip( + record.expr_eval( + self.attrs.get('digits', self.default_digits)), + self.default_digits)) + shift = int(round(math.log(factor, 10))) + return (digits[0] + shift, digits[1] - shift) + def convert(self, value): + try: + return locale.atof + except ValueError: + return self._default -class FloatField(NumberField): - - def set_client(self, record, value, force_change=False): + def set_client(self, record, value, force_change=False, factor=1): if isinstance(value, basestring): - try: - value = locale.atof(value) - except ValueError: - value = self._default + value = self.convert(value) + if value is not None: + value /= factor super(FloatField, self).set_client(record, value, force_change=force_change) - def get_client(self, record): + def get_client(self, record, factor=1): value = record.value.get(self.name) if value is not None: - digits = self.digits(record) - return locale.format('%.*f', (digits[1], value), True) + digit = self.digits(record, factor=factor)[1] + return locale.format('%.*f', (digit, value * factor), True) else: return '' -class NumericField(NumberField): +class NumericField(FloatField): - def set_client(self, record, value, force_change=False): - if isinstance(value, basestring): - try: - value = locale.atof(value, Decimal) - except decimal.InvalidOperation: - value = self._default - super(NumericField, self).set_client(record, value, - force_change=force_change) + def convert(self, value): + try: + return locale.atof(value, Decimal) + except decimal.InvalidOperation: + return self._default - def get_client(self, record): - value = record.value.get(self.name) - if value is not None: - digits = self.digits(record) - return locale.format('%.*f', (digits[1], value), True) - else: - return '' + def set_client(self, record, value, force_change=False, factor=1): + return super(NumericField, self).set_client(record, value, + force_change=force_change, factor=Decimal(str(factor))) + + def get_client(self, record, factor=1): + return super(NumericField, self).get_client(record, + factor=Decimal(str(factor))) -class IntegerField(NumberField): +class IntegerField(FloatField): + default_digits = (16, 0) - def set_client(self, record, value): - if isinstance(value, basestring): - try: - value = locale.atoi(value) - except ValueError: - value = self._default - super(IntegerField, self).set_client(record, value) - - def get_client(self, record): - value = record.value.get(self.name) - if value is not None: - return locale.format('%d', value, True) - else: - return '' - - def digits(self, record): - return (16, 0) + def convert(self, value): + try: + return locale.atoi(value) + except ValueError: + return self._default class BooleanField(CharField): diff --git a/tryton/gui/window/view_form/view/form_gtk/float.py b/tryton/gui/window/view_form/view/form_gtk/float.py index 49dd901286..2ae2f77545 100644 --- a/tryton/gui/window/view_form/view/form_gtk/float.py +++ b/tryton/gui/window/view_form/view/form_gtk/float.py @@ -12,17 +12,11 @@ class Float(Integer): super(Float, self).__init__(field_name, model_name, attrs=attrs) self.entry.connect('key-press-event', self.key_press_event) - def set_value(self, record, field): - return field.set_client(record, self.entry.get_text()) - def display(self, record, field): super(Float, self).display(record, field) - if not field: - self.entry.set_text('') - return False - digits = field.digits(record) - self.entry.set_width_chars(sum(digits)) - self.entry.set_text(field.get_client(record)) + if field: + digits = field.digits(record, factor=self.factor) + self.entry.set_width_chars(sum(digits)) def key_press_event(self, widget, event): for name in ('KP_Decimal', 'KP_Separator'): @@ -43,7 +37,7 @@ class Float(Integer): if new_value in ('-', decimal_point): return - digits = self.field.digits(self.record) + digits = self.field.digits(self.record, factor=self.factor) try: locale.atof(new_value) diff --git a/tryton/gui/window/view_form/view/form_gtk/integer.py b/tryton/gui/window/view_form/view/form_gtk/integer.py index e47be89803..cc8ee4db22 100644 --- a/tryton/gui/window/view_form/view/form_gtk/integer.py +++ b/tryton/gui/window/view_form/view/form_gtk/integer.py @@ -17,9 +17,19 @@ class Integer(Char): self.entry.set_max_length(0) self.entry.set_alignment(1.0) self.entry.connect('insert_text', self.sig_insert_text) + self.factor = float(attrs.get('factor', 1)) + + @property + def modified(self): + if self.record and self.field: + entry = self.entry.get_child() if self.autocomplete else self.entry + value = entry.get_text() or '' + return self.field.get_client(self.record, self.factor) != value + return False def set_value(self, record, field): - return field.set_client(record, self.entry.get_text()) + return field.set_client(record, self.entry.get_text(), + factor=self.factor) def display(self, record, field): # skip Char call because set_text doesn't work with int @@ -27,7 +37,7 @@ class Integer(Char): if not field: self.entry.set_text('') return False - self.entry.set_text(field.get_client(record)) + self.entry.set_text(field.get_client(record, factor=self.factor)) def sig_insert_text(self, entry, new_text, new_text_length, position): value = entry.get_text() 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 eb6d60d0ce..3d19bed003 100644 --- a/tryton/gui/window/view_form/view/list_gtk/parser.py +++ b/tryton/gui/window/view_form/view/list_gtk/parser.py @@ -9,7 +9,7 @@ import locale import gettext import webbrowser -from functools import wraps +from functools import wraps, partial from editabletree import EditableTreeView, TreeView from tryton.gui.window.view_form.view.interface import ParserInterface @@ -360,12 +360,15 @@ class Affix(object): class Char(object): - def __init__(self, field_name, model_name, treeview, attrs=None): + def __init__(self, field_name, model_name, treeview, attrs=None, + renderer=None): super(Char, self).__init__() self.field_name = field_name self.model_name = model_name self.attrs = attrs or {} - self.renderer = CellRendererText() + if renderer is None: + renderer = CellRendererText + self.renderer = renderer() self.renderer.connect('editing-started', self.editing_started) self.treeview = treeview @@ -469,19 +472,34 @@ class Char(object): class Int(Char): - def __init__(self, field_name, model_name, treeview, attrs=None): + def __init__(self, field_name, model_name, treeview, attrs=None, + renderer=None): + if renderer is None: + renderer = CellRendererInteger super(Int, self).__init__(field_name, model_name, treeview, - attrs=attrs) - self.renderer = CellRendererInteger() - self.renderer.connect('editing-started', self.editing_started) + attrs=attrs, renderer=renderer) + self.factor = float(attrs.get('factor', 1)) + + def get_textual_value(self, record): + if not record: + return '' + return record[self.field_name].get_client(record, factor=self.factor) + + def value_from_text(self, record, text, callback=None): + field = record[self.field_name] + field.set_client(record, text, factor=self.factor) + if callback: + callback() -class Boolean(Int): +class Boolean(Char): - def __init__(self, field_name, model_name, treeview, attrs=None): + def __init__(self, field_name, model_name, treeview, attrs=None, + renderer=None): + if renderer is None: + renderer = CellRendererToggle super(Boolean, self).__init__(field_name, model_name, treeview, - attrs=attrs) - self.renderer = CellRendererToggle() + attrs=attrs, renderer=renderer) self.renderer.connect('toggled', self._sig_toggled) def _sig_toggled(self, renderer, path): @@ -510,19 +528,17 @@ class URL(Char): class Date(Char): - def __init__(self, field_name, model_name, treeview, attrs=None): + def __init__(self, field_name, model_name, treeview, attrs=None, + renderer=None): + if renderer is None: + renderer = partial(CellRendererDate, date_format()) super(Date, self).__init__(field_name, model_name, treeview, - attrs=attrs) - self.renderer = CellRendererDate(date_format()) + attrs=attrs, renderer=renderer) self.renderer.connect('editing-started', self.editing_started) class Datetime(Date): - def __init__(self, field_name, model_name, treeview, attrs=None): - super(Datetime, self).__init__(field_name, model_name, treeview, - attrs=attrs) - @realized def setter(self, column, cell, store, iter): super(Datetime, self).setter(column, cell, store, iter) @@ -534,10 +550,6 @@ class Datetime(Date): class Time(Date): - def __init__(self, field_name, model_name, treeview, attrs=None): - super(Time, self).__init__(field_name, model_name, treeview, - attrs=attrs) - @realized def setter(self, column, cell, store, iter): super(Time, self).setter(column, cell, store, iter) @@ -547,28 +559,30 @@ class Time(Date): self.renderer.format = time_format -class Float(Char): +class Float(Int): - def __init__(self, field_name, model_name, treeview, attrs=None): + def __init__(self, field_name, model_name, treeview, attrs=None, + renderer=None): + if renderer is None: + renderer = CellRendererFloat super(Float, self).__init__(field_name, model_name, treeview, - attrs=attrs) - self.renderer = CellRendererFloat() - self.renderer.connect('editing-started', self.editing_started) + attrs=attrs, renderer=renderer) @realized def setter(self, column, cell, store, iter): super(Float, self).setter(column, cell, store, iter) record = store.get_value(iter, 0) field = record[self.field_name] - digits = field.digits(record) + digits = field.digits(record, factor=self.factor) cell.digits = digits class FloatTime(Char): - def __init__(self, field_name, model_name, treeview, attrs=None): + def __init__(self, field_name, model_name, treeview, attrs=None, + renderer=None): super(FloatTime, self).__init__(field_name, model_name, treeview, - attrs=attrs) + attrs=attrs, renderer=renderer) self.conv = None if attrs and attrs.get('float_time'): self.conv = rpc.CONTEXT.get(attrs['float_time']) @@ -588,11 +602,13 @@ class FloatTime(Char): class Binary(Char): - def __init__(self, field_name, model_name, treeview, attrs=None): + def __init__(self, field_name, model_name, treeview, attrs=None, + renderer=None): + if renderer is None: + renderer = partial(CellRendererBinary, bool(self.filename)) super(Binary, self).__init__(field_name, model_name, treeview, attrs=attrs) self.filename = attrs.get('filename') - self.renderer = CellRendererBinary(bool(self.filename)) self.renderer.connect('new', self.new_binary) self.renderer.connect('open', self.open_binary) self.renderer.connect('save', self.save_binary) @@ -657,12 +673,12 @@ class Binary(Char): class M2O(Char): - def __init__(self, field_name, model_name, treeview, attrs=None): + def __init__(self, field_name, model_name, treeview, attrs=None, + renderer=None): + if renderer is None and int(attrs.get('completion', 1)): + renderer = partial(CellRendererTextCompletion, self.set_completion) super(M2O, self).__init__(field_name, model_name, treeview, - attrs=attrs) - if int(attrs.get('completion', 1)): - self.renderer = CellRendererTextCompletion(self.set_completion) - self.renderer.connect('editing-started', self.editing_started) + attrs=attrs, renderer=renderer) def value_from_text(self, record, text, callback=None): field = record.group.fields[self.field_name] @@ -937,9 +953,10 @@ class Selection(Char, SelectionMixin): class Reference(Char, SelectionMixin): - def __init__(self, field_name, model_name, treeview, attrs=None): + def __init__(self, field_name, model_name, treeview, attrs=None, + renderer=None): super(Reference, self).__init__(field_name, model_name, treeview, - attrs=attrs) + attrs=attrs, renderer=renderer) self.init_selection() self._selection = dict(self.selection)