Refactoring

- Better naming in model
- Group extends list
- Add an index to Group
- New common windows for dialog of many2one, one2many and many2many
- one2many and many2many dialog use the same screen than the widget
- Reduce the number of option in Screen
- Remove RPCProxy to handle logout exception on every server call
- Better naming of event signals
- Fix on_change detection for many2many for issue1400
This commit is contained in:
Cédric Krier committed 2010-02-12 11:07:09 +01:00
1 parent 00d12fd71c
commit 999f2737a0
43 files changed
+2468 -2766

No files matched your search

+10
View File
@@ -1,3 +1,13 @@
* Refactoring:
* Better naming in model
* Group extends list
* Add an index to Group
* New common windows for dialog of many2one, one2many and many2many
* one2many and many2many dialog use the same screen than the widget
* Reduce the number of option in Screen
* Remove RPCProxy to handle logout exception on every server call
* Better naming of event signals
* Fix on_change detection for many2many for issue1400
* Add PySON to replace python string evaluation
* Don't show "Spell Checking" option if gtkspell is not present
* Use the same internal model for many2many and one2many fields
+19 -18
View File
@@ -52,8 +52,7 @@ class Form(SignalEvent):
self.screen = Screen(self.model, self.window, view_type=view_type,
context=self.context, view_ids=view_ids, domain=domain,
hastoolbar=CONFIG['form.toolbar'], show_search=True,
limit=limit, readonly=bool(auto_refresh), form=self,
limit=limit, readonly=bool(auto_refresh),
search_value=search_value)
self.screen.signal_connect(self, 'record-message', self._record_message)
self.screen.signal_connect(self, 'record-modified', self._record_modified)
@@ -227,9 +226,9 @@ class Form(SignalEvent):
return True
def update_attachment_count(self, reload=False):
value = self.screen.current_model
if value:
attachment_count = value.get_attachment_count(reload=reload)
record = self.screen.current_record
if record:
attachment_count = record.get_attachment_count(reload=reload)
else:
attachment_count = 0
self.signal('attachment-count', attachment_count)
@@ -296,19 +295,21 @@ class Form(SignalEvent):
self.message_info(_('Records removed!'), 'green')
def sig_import(self, widget=None):
fields = []
while(self.screen.view_to_load):
self.screen.load_view_to_load()
win = WinImport(self.model, self.screen.fields, fields,
parent=self.window)
fields = {}
for name, field in self.screen.group.fields.iteritems():
fields[name] = field.attrs
win = WinImport(self.model, fields, parent=self.window)
win.run()
def sig_save_as(self, widget=None):
fields = []
while(self.screen.view_to_load):
while self.screen.view_to_load:
self.screen.load_view_to_load()
win = WinExport(self.model, self.ids_get(),
self.screen.fields, fields, parent=self.window,
fields = {}
for name, field in self.screen.group.fields.iteritems():
fields[name] = field.attrs
win = WinExport(self.model, self.ids_get(), fields, parent=self.window,
context=self.context)
win.run()
@@ -373,9 +374,9 @@ class Form(SignalEvent):
else:
obj_id = self.id_get()
self.screen.search_filter()
for model in self.screen.models:
if model.id == obj_id:
self.screen.current_model = model
for record in self.screen.group:
if record.id == obj_id:
self.screen.current_record = record
self.screen.display(set_cursor=True)
break
self.message_info('')
@@ -383,8 +384,8 @@ class Form(SignalEvent):
def sig_action(self, keyword='form_action'):
ids = self.ids_get()
if self.screen.current_model:
obj_id = self.screen.current_model.id
if self.screen.current_record:
obj_id = self.screen.current_record.id
else:
obj_id = False
if self.screen.current_view.view_type == 'form':
@@ -403,7 +404,7 @@ class Form(SignalEvent):
if 'active_id' in ctx:
del ctx['active_id']
res = Action.exec_keyword(keyword, self.window, {
'model': self.screen.resource,
'model': self.screen.model_name,
'id': obj_id or False,
'ids': ids,
}, context=ctx, alwaysask=True)
+20 -23
View File
@@ -3,7 +3,6 @@
"Preference"
import gettext
import gtk
from tryton.rpc import RPCProxy
import tryton.rpc as rpc
import copy
from tryton.gui.window.view_form.screen import Screen
@@ -35,19 +34,13 @@ class Preference(object):
self.win.set_default_response(gtk.RESPONSE_OK)
user = RPCProxy('res.user')
args = ('model', 'res.user', 'get_preferences_fields_view',
rpc.CONTEXT)
try:
res = user.get_preferences_fields_view(rpc.CONTEXT)
res = rpc.execute(*args)
except Exception, exception:
if not common.process_exception(exception, parent):
self.win.destroy()
self.win = None
return
try:
res = user.get_preferences_fields_view(rpc.CONTEXT)
except Exception, exception:
common.process_exception(exception, parent)
res = common.process_exception(exception, parent, *args)
if not res:
self.win.destroy()
self.win = None
return
@@ -59,15 +52,17 @@ class Preference(object):
fields = res['fields']
self.screen = Screen('res.user', self.win, view_type=[])
self.screen.new(default=False)
self.screen.add_view_custom(arch, fields, display=True)
self.screen.add_view(arch, fields, display=True)
args = ('model', 'res.user', 'get_preferences', False, rpc.CONTEXT)
try:
preferences = user.get_preferences(False, rpc.CONTEXT)
preferences = rpc.execute(*args)
except Exception, exception:
common.process_exception(exception, parent)
self.win.destroy()
raise
self.screen.current_model.set(preferences)
preferences = common.process_exception(exception, parent, *args)
if not preferences:
self.win.destroy()
raise
self.screen.current_record.set(preferences)
width, height = self.screen.screen_container.size_get()
parent_width, parent_height = parent.get_size()
@@ -85,7 +80,7 @@ class Preference(object):
res = False
while True:
if self.win.run() == gtk.RESPONSE_OK:
if self.screen.current_model.validate():
if self.screen.current_record.validate():
vals = copy.copy(self.screen.get(get_modifiedonly=True))
if 'password' in vals:
password = common.ask(_('Current Password:'),
@@ -94,12 +89,14 @@ class Preference(object):
break
else:
password = False
user = RPCProxy('res.user')
args = ('model', 'res.user', 'set_preferences', vals,
password, rpc.CONTEXT)
try:
user.set_preferences(vals, password, rpc.CONTEXT)
rpc.execute(*args)
except Exception, exception:
common.process_exception(exception, self.win)
continue
if not common.process_exception(exception, self.win,
*args):
continue
res = True
break
else:
+2 -3
View File
@@ -402,9 +402,8 @@ class Tree(SignalEvent):
return res
def sig_save_as(self, widget=None):
win = WinExport(self.model, self.ids_get(),
self.tree_res.fields, [], parent=self.window,
context=self.context)
win = WinExport(self.model, self.ids_get(), self.tree_res.fields,
parent=self.window, context=self.context)
win.run()
def sig_close(self):
+3 -1
View File
@@ -146,7 +146,9 @@ class Action(object):
self.screen = Screen(self.action['res_model'], self._window,
view_type=self.action['view_mode'], context=self.context,
view_ids=view_ids, domain=self.domain, readonly=True)
alignment.add(self.screen.widget)
self.screen.screen_container.alternate_view = True
self.screen.switch_view(view_type=self.action['view_mode'])
alignment.add(self.screen.screen_container.alternate_viewport)
name = self.screen.current_view.title
self.screen.signal_connect(self, 'record-message', self._sig_label)
elif self.action['view_type'] == 'tree':
+360 -347
View File
@@ -1,8 +1,8 @@
#This file is part of Tryton. The COPYRIGHT file at the top level of
#this repository contains the full copyright notices and license terms.
from tryton.rpc import RPCProxy
import tryton.rpc as rpc
from tryton.common import DT_FORMAT, DHM_FORMAT, HM_FORMAT, datetime_strftime
import tryton.common as common
from tryton.pyson import PYSONDecoder
import time
import datetime
@@ -10,7 +10,7 @@ from decimal import Decimal
import logging
class ModelField(object):
class Field(object):
'''
get: return the values to write to the server
get_client: return the value for the client widget (form_gtk)
@@ -32,128 +32,128 @@ class CharField(object):
self.internal = False
self.default_attrs = {}
def sig_changed(self, model):
if self.get_state_attrs(model).get('readonly', False):
def sig_changed(self, record):
if self.get_state_attrs(record).get('readonly', False):
return
if self.attrs.get('on_change', False):
model.on_change(self.name, self.attrs['on_change'])
record.on_change(self.name, self.attrs['on_change'])
if self.attrs.get('change_default', False):
model.cond_default(self.attrs['name'], self.get(model))
model.on_change_with(self.name)
record.cond_default(self.attrs['name'], self.get(record))
record.on_change_with(self.name)
def domain_get(self, model):
return model.expr_eval(self.attrs.get('domain', []))
def domain_get(self, record):
return record.expr_eval(self.attrs.get('domain', []))
def context_get(self, model, check_load=True, eval_context=True):
def context_get(self, record, check_load=True, eval_context=True):
context = {}
context.update(self.parent.context)
if eval_context:
context.update(model.expr_eval(self.attrs.get('context', {}),
context.update(record.expr_eval(self.attrs.get('context', {}),
check_load=check_load))
return context
def validate(self, model):
def validate(self, record):
res = True
if bool(int(self.get_state_attrs(model).get('required') or 0)):
if not self.get(model) \
and not bool(int(self.get_state_attrs(model
if bool(int(self.get_state_attrs(record).get('required') or 0)):
if not self.get(record) \
and not bool(int(self.get_state_attrs(record
).get('readonly') or 0)):
res = False
self.get_state_attrs(model)['valid'] = res
self.get_state_attrs(record)['valid'] = res
return res
def set(self, model, value, modified=False):
model.value[self.name] = value
def set(self, record, value, modified=False):
record.value[self.name] = value
if modified:
model.modified = True
model.modified_fields.setdefault(self.name)
record.modified = True
record.modified_fields.setdefault(self.name)
return True
def get(self, model, check_load=True, readonly=True, modified=False):
return model.value.get(self.name, False) or False
def get(self, record, check_load=True, readonly=True, modified=False):
return record.value.get(self.name, False) or False
def get_eval(self, model, check_load=True):
return self.get(model, check_load=check_load, readonly=True,
def get_eval(self, record, check_load=True):
return self.get(record, check_load=check_load, readonly=True,
modified=False)
def set_client(self, model, value, force_change=False):
internal = model.value.get(self.name, False)
prev_modified = model.modified
self.set(model, value)
if (internal or False) != (model.value.get(self.name, False) or False):
model.modified = True
model.modified_fields.setdefault(self.name)
def set_client(self, record, value, force_change=False):
internal = record.value.get(self.name, False)
prev_modified = record.modified
self.set(record, value)
if (internal or False) != (record.value.get(self.name, False) or False):
record.modified = True
record.modified_fields.setdefault(self.name)
try:
self.sig_changed(model)
self.sig_changed(record)
except:
model.value[self.name] = internal
model.modified = prev_modified
record.value[self.name] = internal
record.modified = prev_modified
return
model.signal('record-changed', model)
record.signal('record-changed')
def get_client(self, model):
return model.value[self.name] or False
def get_client(self, record):
return record.value.get(self.name) or False
def set_default(self, model, value, modified=False):
res = self.set(model, value, modified=modified)
def set_default(self, record, value, modified=False):
res = self.set(record, value, modified=modified)
return res
def set_on_change(self, model, value):
return self.set(model, value, modified=True)
def set_on_change(self, record, value):
return self.set(record, value, modified=True)
def get_default(self, model):
return self.get(model)
def get_default(self, record):
return self.get(record)
def create(self, model):
def create(self, record):
return False
def state_set(self, model, states=('readonly', 'required', 'invisible')):
state_changes = model.expr_eval(self.attrs.get('states', {}),
def state_set(self, record, states=('readonly', 'required', 'invisible')):
state_changes = record.expr_eval(self.attrs.get('states', {}),
check_load=False)
for key in states:
if key == 'readonly' and self.attrs.get(key, False):
continue
if key in state_changes:
self.get_state_attrs(model)[key] = state_changes[key]
self.get_state_attrs(record)[key] = state_changes[key]
elif key in self.attrs:
self.get_state_attrs(model)[key] = self.attrs[key]
if model.mgroup.readonly:
self.get_state_attrs(model)['readonly'] = True
self.get_state_attrs(record)[key] = self.attrs[key]
if record.group.readonly:
self.get_state_attrs(record)['readonly'] = True
if 'value' in state_changes:
value = state_changes['value']
if value:
self.set(model, value, modified=True)
self.set(record, value, modified=True)
def get_state_attrs(self, model):
if self.name not in model.state_attrs:
model.state_attrs[self.name] = self.attrs.copy()
if model.mgroup.readonly:
model.state_attrs[self.name]['readonly'] = True
return model.state_attrs[self.name]
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:
record.state_attrs[self.name]['readonly'] = True
return record.state_attrs[self.name]
def get_timestamp(self, model):
def get_timestamp(self, record):
return {}
class SelectionField(CharField):
def set(self, model, value, modified=False):
def set(self, record, value, modified=False):
if isinstance(value, (list, tuple)):
value = value[0]
return super(SelectionField, self).set(model, value,
return super(SelectionField, self).set(record, value,
modified=modified)
class DateTimeField(CharField):
def set_client(self, model, value, force_change=False):
def set_client(self, record, value, force_change=False):
if value:
value = datetime.datetime(*time.strptime(value, DHM_FORMAT)[:6])
return super(DateTimeField, self).set_client(model, value,
return super(DateTimeField, self).set_client(record, value,
force_change=force_change)
def get_client(self, model):
value = super(DateTimeField, self).get_client(model)
def get_client(self, record):
value = super(DateTimeField, self).get_client(record)
if not value:
return False
return datetime_strftime(value, DHM_FORMAT)
@@ -161,14 +161,14 @@ class DateTimeField(CharField):
class DateField(CharField):
def set_client(self, model, value, force_change=False):
def set_client(self, record, value, force_change=False):
if value:
value = datetime.date(*time.strptime(value, DT_FORMAT)[:3])
return super(DateField, self).set_client(model, value,
return super(DateField, self).set_client(record, value,
force_change=force_change)
def get_client(self, model):
value = super(DateField, self).get_client(model)
def get_client(self, record):
value = super(DateField, self).get_client(record)
if not value:
return False
return datetime_strftime(value, DT_FORMAT)
@@ -176,77 +176,78 @@ class DateField(CharField):
class FloatField(CharField):
def set_client(self, model, value, force_change=False):
internal = model.value[self.name]
prev_modified = model.modified
self.set(model, value)
digits = model.expr_eval(self.attrs.get('digits', (12, 2)))
if abs(float(internal or 0.0) - float(model.value[self.name] or 0.0)) \
def set_client(self, record, value, force_change=False):
internal = record.value.get(self.name)
prev_modified = record.modified
self.set(record, value)
digits = record.expr_eval(self.attrs.get('digits', (12, 2)))
if abs(float(internal or 0.0) - float(record.value[self.name] or 0.0)) \
>= (10.0**(-int(digits[1]))):
if not self.get_state_attrs(model).get('readonly', False):
model.modified = True
model.modified_fields.setdefault(self.name)
if not self.get_state_attrs(record).get('readonly', False):
record.modified = True
record.modified_fields.setdefault(self.name)
try:
self.sig_changed(model)
self.sig_changed(record)
except:
model.value[self.name] = internal
model.modified = prev_modified
model.signal('record-changed', model)
record.value[self.name] = internal
record.modified = prev_modified
record.signal('record-changed')
class NumericField(CharField):
def set_client(self, model, value, force_change=False):
def set_client(self, record, value, force_change=False):
value = Decimal(str(value))
internal = model.value[self.name]
prev_modified = model.modified
self.set(model, value)
digits = model.expr_eval(self.attrs.get('digits', (12, 2)))
if abs((internal or Decimal('0.0')) - (model.value[self.name] or Decimal('0.0'))) \
internal = record.value.get(self.name)
prev_modified = record.modified
self.set(record, value)
digits = record.expr_eval(self.attrs.get('digits', (12, 2)))
if abs((internal or Decimal('0.0')) - \
(record.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)
if not self.get_state_attrs(record).get('readonly', False):
record.modified = True
record.modified_fields.setdefault(self.name)
try:
self.sig_changed(model)
self.sig_changed(record)
except:
model.value[self.name] = internal
model.modified = prev_modified
record.value[self.name] = internal
record.modified = prev_modified
return
model.signal('record-changed', model)
record.signal('record-changed')
class IntegerField(CharField):
def get(self, model, check_load=True, readonly=True, modified=False):
return model.value.get(self.name, 0) or 0
def get(self, record, check_load=True, readonly=True, modified=False):
return record.value.get(self.name) or 0
def get_client(self, model):
return model.value[self.name] or 0
def get_client(self, record):
return record.value.get(self.name) or 0
class BooleanField(CharField):
def set_client(self, model, value, force_change=False):
def set_client(self, record, value, force_change=False):
value = bool(value)
internal = bool(model.value.get(self.name, False))
prev_modified = model.modified
self.set(model, value)
if internal != bool(model.value.get(self.name, False)):
model.modified = True
model.modified_fields.setdefault(self.name)
internal = bool(record.value.get(self.name, False))
prev_modified = record.modified
self.set(record, value)
if internal != bool(record.value.get(self.name, False)):
record.modified = True
record.modified_fields.setdefault(self.name)
try:
self.sig_changed(model)
self.sig_changed(record)
except:
model.value[self.name] = internal
model.modified = prev_modified
record.value[self.name] = internal
record.modified = prev_modified
return
model.signal('record-changed', model)
record.signal('record-changed')
def get(self, model, check_load=True, readonly=True, modified=False):
return bool(model.value.get(self.name, False))
def get(self, record, check_load=True, readonly=True, modified=False):
return bool(record.value.get(self.name, False))
def get_client(self, model):
return bool(model.value[self.name])
def get_client(self, record):
return bool(record.value.get(self.name))
class M2OField(CharField):
@@ -254,350 +255,358 @@ class M2OField(CharField):
internal = (id, name)
'''
def create(self, model):
def create(self, record):
return (False, '')
def get(self, model, check_load=True, readonly=True, modified=False):
if model.value[self.name]:
if isinstance(model.value[self.name], (int, basestring, long)):
self.set(model, model.value[self.name])
if isinstance(model.value[self.name], (int, basestring, long)):
return model.value[self.name]
return model.value[self.name][0] or False
def get(self, record, check_load=True, readonly=True, modified=False):
if record.value.get(self.name):
if isinstance(record.value[self.name], (int, basestring, long)):
self.set(record, record.value[self.name])
if isinstance(record.value[self.name], (int, basestring, long)):
return record.value[self.name]
return record.value[self.name][0] or False
return False
def get_client(self, model):
#model._check_load()
if model.value[self.name]:
if isinstance(model.value[self.name], (int, basestring, long)):
self.set(model, model.value[self.name])
if isinstance(model.value[self.name], (int, basestring, long)):
return model.value[self.name]
return model.value[self.name][1]
def get_client(self, record):
if record.value.get(self.name):
if isinstance(record.value[self.name], (int, basestring, long)):
self.set(record, record.value[self.name])
if isinstance(record.value[self.name], (int, basestring, long)):
return record.value[self.name]
return record.value[self.name][1]
return False
def set(self, model, value, modified=False):
def set(self, record, value, modified=False):
if value and isinstance(value, (int, long)):
rpc2 = RPCProxy(self.attrs['relation'])
args = ('model', self.attrs['relation'], 'read', value,
['rec_name'], rpc.CONTEXT)
try:
result = rpc2.read(value, ['rec_name'], rpc.CONTEXT)
except:
return
result = rpc.execute(*args)
except Exception, exception:
result = common.process_exception(exception, record.window,
*args)
if not result:
return
value = value, result['rec_name']
if value and len(value) != 2:
value = (False, '')
model.value[self.name + '.rec_name'] = ''
record.value[self.name + '.rec_name'] = ''
else:
if value:
model.value[self.name + '.rec_name'] = value[1]
record.value[self.name + '.rec_name'] = value[1]
else:
model.value[self.name + '.rec_name'] = ''
model.value[self.name] = value or (False, '')
record.value[self.name + '.rec_name'] = ''
record.value[self.name] = value or (False, '')
if modified:
model.modified = True
model.modified_fields.setdefault(self.name)
record.modified = True
record.modified_fields.setdefault(self.name)
def set_client(self, model, value, force_change=False):
internal = model.value[self.name]
prev_modified = model.modified
self.set(model, value)
if (internal[0] or False) != (model.value[self.name][0] or False):
model.modified = True
model.modified_fields.setdefault(self.name)
def set_client(self, record, value, force_change=False):
internal = record.value.get(self.name)
prev_modified = record.modified
self.set(record, value)
if (internal[0] or False) != (record.value[self.name][0] or False):
record.modified = True
record.modified_fields.setdefault(self.name)
try:
self.sig_changed(model)
self.sig_changed(record)
except:
model.value[self.name] = internal
model.modified = prev_modified
record.value[self.name] = internal
record.modified = prev_modified
return
model.signal('record-changed', model)
record.signal('record-changed')
elif force_change:
try:
self.sig_changed(model)
self.sig_changed(record)
except:
model.value[self.name] = internal
record.value[self.name] = internal
return
model.signal('record-changed', model)
record.signal('record-changed')
def context_get(self, model, check_load=True, eval_context=True):
context = super(M2OField, self).context_get(model,
def context_get(self, record, check_load=True, eval_context=True):
context = super(M2OField, self).context_get(record,
check_load=check_load, eval_context=eval_context)
if eval_context and self.attrs.get('datetime_field'):
context['_datetime'] = model.get_eval(
context['_datetime'] = record.get_eval(
check_load=check_load)[self.attrs.get('datetime_field')]
return context
class O2MField(CharField):
'''
internal = ModelRecordGroup of the related objects
internal = Group of the related objects
'''
def __init__(self, parent, attrs):
super(O2MField, self).__init__(parent, attrs)
self.context = {}
def create(self, model):
from group import ModelRecordGroup
mod = ModelRecordGroup(self.attrs['relation'], {}, model.window,
parent=model, parent_name=self.attrs.get('relation_field', ''),
def create(self, record):
from group import Group
group = Group(self.attrs['relation'], {}, record.window,
parent=record, parent_name=self.attrs.get('relation_field', ''),
context=self.context,
parent_datetime_field=self.attrs.get('datetime_field'))
mod.signal_connect(mod, 'model-changed', self._model_changed)
return mod
group.signal_connect(group, 'group-changed', self._group_changed)
return group
def _model_changed(self, group, model):
if model.modified:
model.parent.modified = True
model.parent.modified_fields.setdefault(self.name)
self.sig_changed(model.parent)
model.parent.signal('record-changed', model.parent)
def _group_changed(self, group, record):
record.parent.modified = True
record.parent.modified_fields.setdefault(self.name)
self.sig_changed(record.parent)
record.parent.signal('record-changed')
def get_client(self, model):
return model.value[self.name]
def get_client(self, record):
return record.value.get(self.name)
def get(self, model, check_load=True, readonly=True, modified=False):
if not model.value[self.name]:
def get(self, record, check_load=True, readonly=True, modified=False):
if record.value.get(self.name) is None:
return []
result = [('add', [])]
for model2 in model.value[self.name].models:
if model2.id > 0:
values = model2.get(check_load=check_load, get_readonly=readonly,
for record2 in record.value[self.name]:
if record2.id > 0:
values = record2.get(check_load=check_load, get_readonly=readonly,
get_modifiedonly=modified)
if model2.is_modified() and values:
result.append(('write', model2.id, values))
if record2.is_modified() and values:
result.append(('write', record2.id, values))
else:
result[0][1].append(model2.id)
result[0][1].append(record2.id)
else:
result.append(('create',
model2.get(check_load=check_load, get_readonly=readonly)))
if model.value[self.name].model_removed:
record2.get(check_load=check_load, get_readonly=readonly)))
if record.value[self.name].record_removed:
result.append(('unlink', [x.id for x in \
model.value[self.name].model_removed]))
if model.value[self.name].model_deleted:
record.value[self.name].record_removed]))
if record.value[self.name].record_deleted:
result.append(('delete', [x.id for x in \
model.value[self.name].model_deleted]))
record.value[self.name].record_deleted]))
return result
def get_timestamp(self, model):
if not model.value[self.name]:
def get_timestamp(self, record):
if record.value.get(self.name) is None:
return {}
result = {}
for model2 in (model.value[self.name].models \
+ model.value[self.name].model_removed \
+ model.value[self.name].model_deleted):
result.update(model2.get_timestamp())
for record2 in (record.value[self.name] \
+ record.value[self.name].record_removed \
+ record.value[self.name].record_deleted):
result.update(record2.get_timestamp())
return result
def get_eval(self, model, check_load=True):
def get_eval(self, record, check_load=True):
result = []
if not model.value[self.name]:
if record.value.get(self.name) is None:
return []
for model2 in model.value[self.name].models:
result.append(model2.get_eval(check_load=check_load))
for record2 in record.value[self.name]:
result.append(record2.get_eval(check_load=check_load))
return result
def set(self, model, value, modified=False):
from group import ModelRecordGroup
mod = ModelRecordGroup(self.attrs['relation'], {}, model.window,
parent=model, parent_name=self.attrs.get('relation_field', ''),
def set(self, record, value, modified=False):
from group import Group
group = record.value.get(self.name)
if group is not None:
group.signal_unconnect(group)
group = Group(self.attrs['relation'], {}, record.window,
parent=record, parent_name=self.attrs.get('relation_field', ''),
context=self.context,
parent_datetime_field=self.attrs.get('datetime_field'))
mod.signal_connect(mod, 'model-changed', self._model_changed)
mod.model_deleted.extend(x for x in model.value[self.name].models
if x.id > 0)
mod.model_deleted.extend(model.value[self.name].model_deleted)
mod.model_removed.extend(model.value[self.name].model_removed)
model.value[self.name] = mod
model.value[self.name].load(value, display=False)
record.value[self.name] = group
record.value[self.name].load(value, display=False)
group.signal_connect(group, 'group-changed', self._group_changed)
if modified:
model.modified = True
model.modified_fields.setdefault(self.name)
record.modified = True
record.modified_fields.setdefault(self.name)
def set_client(self, model, value, force_change=False):
self.set(model, value)
model.signal('record-changed', model)
def set_client(self, record, value, force_change=False):
pass
def set_default(self, model, value, modified=False):
from group import ModelRecordGroup
def set_default(self, record, value, modified=False):
from group import Group
if value and len(value) and isinstance(value[0], (int, long)):
return self.set(model, value, modified=modified)
return self.set(record, value, modified=modified)
fields = {}
if value and len(value):
context = self.context_get(model)
rpc2 = RPCProxy(self.attrs['relation'])
context = self.context_get(record)
field_names = []
for val in value:
for fieldname in val.keys():
if fieldname not in field_names:
field_names.append(fieldname)
args = ('model', self.attrs['relation'], 'fields_get',
field_names, context)
try:
fields_name = []
for val in value:
for fieldname in val.keys():
if fieldname not in fields_name:
fields_name.append(fieldname)
fields = rpc2.fields_get(fields_name, context)
except:
return False
fields = rpc.execute(*args)
except Exception, exception:
fields = common.process_exception(exception, record.window,
*args)
if not fields:
return False
mod = ModelRecordGroup(
self.attrs['relation'], fields, model.window, parent=model,
group = record.value.get(self.name)
if group is not None:
group.signal_unconnect(group)
group = Group(
self.attrs['relation'], fields, record.window, parent=record,
parent_name=self.attrs.get('relation_field', ''),
context=self.context,
parent_datetime_field=self.attrs.get('datetime_field'))
mod.signal_connect(model.value[self.name],
'model-changed', self._model_changed)
mod.model_deleted.extend(x for x in model.value[self.name].models
group.signal_connect(group,
'group-changed', self._group_changed)
group.record_deleted.extend(x for x in record.value[self.name]
if x.id > 0)
mod.model_deleted.extend(model.value[self.name].model_deleted)
mod.model_removed.extend(model.value[self.name].model_removed)
model.value[self.name] = mod
mod = None
for record in (value or []):
mod = model.value[self.name].model_new(default=False)
mod.set_default(record, modified=modified)
model.value[self.name].model_add(mod)
model.value[self.name].current_model = mod
#mod.signal('record-changed')
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
for vals in (value or []):
new_record = record.value[self.name].new(default=False)
new_record.set_default(vals, modified=modified)
group.add(new_record)
return True
def set_on_change(self, model, value):
def set_on_change(self, record, value):
if isinstance(value, (list, tuple)):
return self.set(model, value, modified=True)
return self.set(record, value, modified=True)
if value and (value.get('add') or value.get('update')):
context = self.context_get(model)
rpc2 = RPCProxy(self.attrs['relation'])
context = self.context_get(record)
field_names = []
for val in (value.get('add', []) + value.get('update', [])):
for fieldname in val.keys():
if fieldname not in field_names:
field_names.append(fieldname)
args = ('model', self.attrs['relation'], 'fields_get',
field_names, context)
try:
fields_name = []
for val in (value.get('add', []) + value.get('update', [])):
for fieldname in val.keys():
if fieldname not in fields_name:
fields_name.append(fieldname)
fields = rpc2.fields_get(fields_name, context)
except:
return False
fields = rpc.execute(*args)
except Exception, exception:
fields = common.process_exception(exception, record.window,
*args)
if not fields:
return False
to_remove = []
for mod in model.value[self.name]:
if not mod.id:
to_remove.append(mod)
for record2 in record.value[self.name]:
if not record2.id:
to_remove.append(record2)
if value and value.get('remove'):
for model_id in value['remove']:
mod = model.value[self.name].get_by_id(model_id)
if mod:
to_remove.append(mod)
for mod in to_remove:
model.value[self.name].remove(mod, signal=False)
for record_id in value['remove']:
record2 = record.value[self.name].get(record_id)
if record2 is not None:
to_remove.append(record2)
for record2 in to_remove:
record.value[self.name].remove(record2, signal=False)
mod = None
if value and value.get('add') or value.get('update', []):
model.value[self.name].add_fields(fields, model.value[self.name],
signal=False)
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=False)
record.value[self.name].add_fields(fields, signal=False)
for vals in value.get('add', []):
new_record = record.value[self.name].new(default=False,
signal=False)
record.value[self.name].add(new_record)
new_record.set(vals, modified=True, signal=False)
for record in value.get('update', []):
if 'id' not in record:
for vals in value.get('update', []):
if 'id' not in vals:
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
record2 = record.value[self.name].get(vals['id'])
if record2 is not None:
record2.set(vals, modified=True, signal=False)
return True
def get_default(self, model):
res = [x.get_default() for x in model.value[self.name].models or []]
def get_default(self, record):
res = [x.get_default() for x in record.value.get(self.name) or []]
return res
def validate(self, model):
def validate(self, record):
res = True
for model2 in model.value[self.name].models:
if not model2.loaded:
for record2 in record.value[self.name]:
if not record2.loaded:
continue
if not model2.validate():
if not model2.is_modified():
model.value[self.name].models.remove(model2)
if not record2.validate():
if not record2.is_modified():
record.value[self.name].remove(record2)
else:
res = False
if not super(O2MField, self).validate(model):
if not super(O2MField, self).validate(record):
res = False
self.get_state_attrs(model)['valid'] = res
self.get_state_attrs(record)['valid'] = res
return res
def state_set(self, model, states=('readonly', 'required', 'invisible')):
super(O2MField, self).state_set(model, states=states)
if self.get_state_attrs(model).get('readonly', False):
model.value[self.name].readonly = True
def state_set(self, record, states=('readonly', 'required', 'invisible')):
super(O2MField, self).state_set(record, states=states)
if self.get_state_attrs(record).get('readonly', False):
record.value[self.name].readonly = True
else:
model.value[self.name].readonly = False
record.value[self.name].readonly = False
def get_removed_ids(self, model):
return [x.id for x in model.value[self.name].model_removed]
def get_removed_ids(self, record):
return [x.id for x in record.value[self.name].record_removed]
class M2MField(O2MField):
def get_default(self, model):
return [x.id for x in model.value[self.name].models
if x.id > 0]
def get_default(self, record):
return [x.id for x in record.value.get(self.name) or [] if x.id > 0]
def get_eval(self, model, check_load=True):
return [x.id for x in model.value[self.name].models]
def get_eval(self, record, check_load=True):
return [x.id for x in record.value.get(self.name) or []]
def set(self, model, value, modified=False):
from group import ModelRecordGroup
mod = ModelRecordGroup(self.attrs['relation'], {}, model.window,
parent=model, parent_name=self.attrs.get('relation_field', ''),
def set(self, record, value, modified=False):
from group import Group
group = record.value.get(self.name)
if group is not None:
group.signal_unconnect(group)
group = Group(self.attrs['relation'], {}, record.window,
parent=record, parent_name=self.attrs.get('relation_field', ''),
context=self.context,
parent_datetime_field=self.attrs.get('datetime_field'))
mod.signal_connect(mod, 'model-changed', self._model_changed)
mod.model_removed.extend(model.value[self.name].models)
mod.model_deleted.extend(model.value[self.name].model_deleted)
mod.model_removed.extend(model.value[self.name].model_removed)
model.value[self.name] = mod
model.value[self.name].load(value, display=False)
if record.value.get(self.name):
group.record_removed.extend(record.value[self.name])
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
record.value[self.name].load(value, display=False)
group.signal_connect(group, 'group-changed', self._group_changed)
if modified:
model.modified = True
model.modified_fields.setdefault(self.name)
record.modified = True
record.modified_fields.setdefault(self.name)
class ReferenceField(CharField):
def get_client(self, model):
if model.value[self.name]:
return model.value[self.name]
def get_client(self, record):
if record.value.get(self.name):
return record.value[self.name]
return False
def get(self, model, check_load=True, readonly=True, modified=False):
if model.value[self.name]:
if isinstance(model.value[self.name][1], (list, tuple)):
return '%s,%s' % (model.value[self.name][0],
str(model.value[self.name][1][0]))
def get(self, record, check_load=True, readonly=True, modified=False):
if record.value.get(self.name):
if isinstance(record.value[self.name][1], (list, tuple)):
return '%s,%s' % (record.value[self.name][0],
str(record.value[self.name][1][0]))
else:
return '%s,%s' % (model.value[self.name][0],
str(model.value[self.name][1]))
return '%s,%s' % (record.value[self.name][0],
str(record.value[self.name][1]))
return False
def set_client(self, model, value, force_change=False):
internal = model.value[self.name]
prev_modified = model.modified
#model.value[self.name] = value
self.set(model, value)
if (internal or False) != (model.value[self.name] or False):
model.modified = True
model.modified_fields.setdefault(self.name)
def set_client(self, record, value, force_change=False):
internal = record.value.get(self.name)
prev_modified = record.modified
self.set(record, value)
if (internal or False) != (record.value[self.name] or False):
record.modified = True
record.modified_fields.setdefault(self.name)
try:
self.sig_changed(model)
self.sig_changed(record)
except:
model.value[self.name] = internal
model.modified = prev_modified
record.value[self.name] = internal
record.modified = prev_modified
return
model.signal('record-changed', model)
record.signal('record-changed')
def set(self, model, value, modified=False):
def set(self, record, value, modified=False):
if not value:
model.value[self.name] = False
record.value[self.name] = False
return
ref_model, (ref_id, ref_str) = value
if ref_model:
@@ -605,28 +614,32 @@ class ReferenceField(CharField):
if not ref_id:
ref_str = ''
if not ref_str and ref_id:
rpc2 = RPCProxy(ref_model)
args = ('model', ref_model, 'read', ref_id,
['rec_name'], rpc.CONTEXT)
try:
result = rpc2.read(ref_id, ['rec_name'],
rpc.CONTEXT)['rec_name']
except:
return
result = rpc.execute(*args)
except Exception, exception:
result = common.process_exception(exception, record.window,
*args)
if not result:
return
result = result['rec_name']
if result:
model.value[self.name] = ref_model, (ref_id, result)
model.value[self.name + '.rec_name'] = result
record.value[self.name] = ref_model, (ref_id, result)
record.value[self.name + '.rec_name'] = result
else:
model.value[self.name] = ref_model, (0, '')
model.value[self.name + '.rec_name'] = ''
record.value[self.name] = ref_model, (0, '')
record.value[self.name + '.rec_name'] = ''
else:
model.value[self.name] = ref_model, (ref_id, ref_str)
model.value[self.name + '.rec_name'] = ref_str
record.value[self.name] = ref_model, (ref_id, ref_str)
record.value[self.name + '.rec_name'] = ref_str
else:
model.value[self.name] = ref_model, (ref_id, ref_id)
if self.name + '.rec_name' in model.value:
del model.value[self.name + '.rec_name']
record.value[self.name] = ref_model, (ref_id, ref_id)
if self.name + '.rec_name' in record.value:
del record.value[self.name + '.rec_name']
if modified:
model.modified = True
model.modified_fields.setdefault(self.name)
record.modified = True
record.modified_fields.setdefault(self.name)
TYPES = {
'char': CharField,
+211 -281
View File
@@ -1,120 +1,114 @@
#This file is part of Tryton. The COPYRIGHT file at the top level of
#this repository contains the full copyright notices and license terms.
from tryton.rpc import RPCProxy
import tryton.rpc as rpc
from record import ModelRecord
import field
from record import Record
from field import Field, O2MField
from tryton.signal_event import SignalEvent
import tryton.common as common
class ModelList(list):
def __init__(self, screen):
super(ModelList, self).__init__()
self.lock_signal = False
self.__screen = screen
class Group(SignalEvent, list):
def insert(self, pos, obj):
if pos >= 1:
self.__getitem__(pos - 1).next[id(self)] = obj
if pos < self.__len__():
obj.next[id(self)] = self.__getitem__(pos)
else:
obj.next[id(self)] = None
super(ModelList, self).insert(pos, obj)
if not self.lock_signal:
self.__screen.signal('record-changed', ('record-added', pos))
def append(self, obj):
if self.__len__() >= 1:
self.__getitem__(self.__len__() - 1).next[id(self)] = obj
obj.next[id(self)] = None
super(ModelList, self).append(obj)
if not self.lock_signal:
self.__screen.signal('record-changed', ('record-added', -1))
def remove(self, obj):
idx = self.index(obj)
if idx >= 1:
if idx + 1 < self.__len__():
self.__getitem__(idx - 1).next[id(self)] = self.__getitem__(idx + 1)
else:
self.__getitem__(idx - 1).next[id(self)] = None
super(ModelList, self).remove(obj)
if not self.lock_signal:
self.__screen.signal('record-changed', ('record-removed', idx))
def clear(self):
while self:
self.pop()
if not self.lock_signal:
self.__screen.signal('record-changed',
('record-removed', len(self)))
def move(self, obj, pos):
self.lock_signal = True
if self.__len__() > pos:
idx = self.index(obj)
self.remove(obj)
if pos > idx:
pos -= 1
self.insert(pos, obj)
else:
self.remove(obj)
self.append(obj)
self.lock_signal = False
def __setitem__(self, key, value):
super(ModelList, self).__setitem__(key, value)
if not self.lock_signal:
self.__screen.signal('record-changed', ('record-changed', key))
class ModelRecordGroup(SignalEvent):
def __init__(self, resource, fields, window, ids=None, parent=None,
def __init__(self, model_name, fields, window, ids=None, parent=None,
parent_name='', context=None, readonly=False,
parent_datetime_field=None):
super(ModelRecordGroup, self).__init__()
super(Group, self).__init__()
self.lock_signal = False
self.window = window
self.parent = parent
self.parent_name = parent_name
self.parent_datetime_field = parent_datetime_field
self._context = context or {}
self.resource = resource
self.rpc = RPCProxy(resource)
self.fields = fields
self.mfields = {}
ModelRecordGroup.mfields_load(fields.keys(), self)
self.models = ModelList(self)
self.model_name = model_name
self.fields = {}
self.load_fields(fields)
self.current_idx = None
self.load(ids)
self.model_removed = []
self.model_deleted = []
self.record_removed = []
self.record_deleted = []
self.on_write = set()
self.readonly = readonly
if self._context.get('_datetime'):
self.readonly = True
self.__id2record = {}
def insert(self, pos, record):
if pos >= 1:
self.__getitem__(pos - 1).next[id(self)] = record
if pos < self.__len__():
record.next[id(self)] = self.__getitem__(pos)
else:
record.next[id(self)] = None
super(Group, self).insert(pos, record)
self.__id2record[record.id] = record
if not self.lock_signal:
self.signal('group-list-changed', ('record-added', pos))
def append(self, record):
if self.__len__() >= 1:
self.__getitem__(self.__len__() - 1).next[id(self)] = record
record.next[id(self)] = None
super(Group, self).append(record)
self.__id2record[record.id] = record
if not self.lock_signal:
self.signal('group-list-changed', ('record-added', -1))
def _remove(self, record):
idx = self.index(record)
if idx >= 1:
if idx + 1 < self.__len__():
self.__getitem__(idx - 1).next[id(self)] = \
self.__getitem__(idx + 1)
else:
self.__getitem__(idx - 1).next[id(self)] = None
super(Group, self).remove(record)
del self.__id2record[record.id]
if not self.lock_signal:
self.signal('group-list-changed', ('record-removed', idx))
def clear(self):
while len(self):
self.pop()
if not self.lock_signal:
self.signal('group-list-changed', ('record-removed', len(self)))
self.record_removed = []
self.record_deleted = []
def move(self, record, pos):
self.lock_signal = True
if self.__len__() > pos:
idx = self.index(record)
self._remove(record)
if pos > idx:
pos -= 1
self.insert(pos, record)
else:
self._remove(record)
self.append(record)
self.lock_signal = False
def __setitem__(self, i, value):
super(Group, self).__setitem__(i, value)
if not self.lock_signal:
self.signal('group-list-changed', ('record-changed', key))
def __repr__(self):
return '<ModelRecordGroup %s at %s>' % (self.resource, id(self))
return '<Group %s at %s>' % (self.model_name, id(self))
@staticmethod
def mfields_load(fkeys, models):
for fname in fkeys:
fvalue = models.fields[fname]
modelfield = field.ModelField(fvalue['type'])
fvalue['name'] = fname
models.mfields[fname] = modelfield(models, fvalue)
if isinstance(models.mfields[fname], field.O2MField) \
and '_datetime' in models._context:
models.mfields[fname].context.update({
'_datetime': models._context['_datetime'],
def load_fields(self, fields):
for name, attr in fields.iteritems():
field = Field(attr['type'])
attr['name'] = name
self.fields[name] = field(self, attr)
if isinstance(self.fields[name], O2MField) \
and '_datetime' in self._context:
self.fields[name].context.update({
'_datetime': self._context['_datetime'],
})
def save(self):
for model in self.models:
saved = model.save()
for record in self:
saved = record.save()
self.writen(saved)
def writen(self, ids):
@@ -127,97 +121,63 @@ class ModelRecordGroup(SignalEvent):
return ids
def reload(self, ids):
for model in self.models:
if model.id in ids and not model.modified:
model._loaded.clear()
for record in self:
if record.id in ids and not record.modified:
record._loaded.clear()
def on_write_ids(self, ids):
if not self.on_write:
return False
res = []
for fnct in self.on_write:
args = ('model', self.model_name, fnct, ids, self.context)
try:
res += getattr(self.rpc, fnct)(ids, self.context)
res += rpc.execute(*args)
except Exception, exception:
common.process_exception(exception, self.window)
return False
res2 = common.process_exception(exception, self.window, *args)
if not res2:
return False
res += res2
return list({}.fromkeys(res))
def _load_for(self, values):
if len(values)>10:
self.models.lock_signal = True
id2values = dict((value['id'], value) for value in values)
for model in self.models:
if model.id in id2values:
model.set(id2values[model.id])
if len(values)>10:
self.models.lock_signal = False
self.signal('record-cleared')
def load(self, ids, display=True, modified=False):
if not ids:
return True
old_ids = [x.id for x in self.models]
old_ids = [x.id for x in self]
ids = [x for x in ids if x not in old_ids]
if not ids:
return True
if len(ids) > 10:
self.models.lock_signal = True
newmod = None
newmods = []
if len(ids) > 1:
self.lock_signal = True
new_records = []
for id in ids:
newmod = ModelRecord(self.resource, id, self.window,
new_record = Record(self.model_name, id, self.window,
parent=self.parent, parent_name=self.parent_name, group=self)
self.models.append(newmod)
newmods.append(newmod)
newmod.signal_connect(self, 'record-changed', self._record_changed)
newmod.signal_connect(self, 'record-modified', self._record_modified)
for model in self.model_removed[:]:
if model.id in ids:
self.model_removed.remove(model)
for model in self.model_deleted[:]:
if model.id in ids:
self.model_deleted.remove(model)
if len(ids) > 10:
self.models.lock_signal = False
self.signal('record-cleared')
self.append(new_record)
new_records.append(new_record)
new_record.signal_connect(self, 'record-changed', 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')
ctx = rpc.CONTEXT.copy()
ctx.update(self.context)
if self.fields:
try:
values = self.rpc.read(ids[:80], self.fields.keys() + \
[x + '.rec_name' for x in self.fields
if self.fields[x]['type'] in \
('many2one', 'reference')] + \
['_timestamp'], ctx)
except Exception, exception:
common.process_exception(exception, self.window)
return False
if not values:
return False
self._load_for(values)
if new_records and display:
self.signal('group-changed', new_records[0])
if newmod and display:
self.signal('model-changed', newmod)
if modified and newmods:
for newmod in newmods:
newmod.modified = True
# send record-changed only once
if newmod.parent:
newmod.signal('record-changed', newmod.parent)
if new_records and modified:
new_records[0].signal('record-changed')
self.current_idx = 0
return True
def clear(self):
self.models.clear()
self.model_removed = []
self.model_deleted = []
def _get_context(self):
ctx = rpc.CONTEXT.copy()
ctx.update(self._context)
@@ -225,176 +185,146 @@ class ModelRecordGroup(SignalEvent):
ctx['_datetime'] = self.parent.get_eval(check_load=False)\
[self.parent_datetime_field]
return ctx
context = property(_get_context)
def model_add(self, model, position=-1, modified=True):
#TODO To be checked
if not model.mgroup is self:
def add(self, record, position=-1, modified=True):
if not record.group is self:
fields = {}
for i in model.mgroup.fields:
fields[model.mgroup.fields[i]['name']] = \
model.mgroup.fields[i]
self.add_fields(fields, self)
self.add_fields(self.fields, model.mgroup)
model.mgroup = self
for i in record.group.fields:
fields[record.group.fields[i].attrs['name']] = \
record.group.fields[i].attrs
self.add_fields(fields)
record.group = self
if position == -1:
self.models.append(model)
self.append(record)
else:
self.models.insert(position, model)
self.insert(position, record)
self.current_idx = position
model.parent = self.parent
model.parent_name = self.parent_name
model.window = self.window
record.parent = self.parent
record.parent_name = self.parent_name
record.window = self.window
if modified:
model.modified = True
model.signal_connect(self, 'record-changed', self._record_changed)
model.signal_connect(self, 'record-modified', self._record_modified)
return model
def model_move(self, model, position=0):
self.models.move(model, position)
record.modified = True
record.signal_connect(self, 'record-changed', self._record_changed)
record.signal_connect(self, 'record-modified', self._record_modified)
return record
def set_sequence(self, field='sequence'):
index = 0
for model in self.models:
if model[field]:
if index >= model[field].get(model):
for record in self:
if record[field]:
if index >= record[field].get(record):
index += 1
model[field].set(model, index, modified=True)
record[field].set(record, index, modified=True)
else:
index = model[field].get(model)
index = record[field].get(record)
def model_new(self, default=True, domain=None, context=None):
newmod = ModelRecord(self.resource, None, self.window, group=self,
def new(self, default=True, domain=None, context=None, signal=True):
record = Record(self.model_name, None, self.window, group=self,
parent=self.parent, parent_name=self.parent_name, new=True)
newmod.signal_connect(self, 'record-changed', self._record_changed)
newmod.signal_connect(self, 'record-modified', self._record_modified)
record.signal_connect(self, 'record-changed', self._record_changed)
record.signal_connect(self, 'record-modified', self._record_modified)
if default:
ctx = {}
ctx.update(context or {})
ctx.update(self.context)
newmod.default_get(domain, ctx)
self.signal('model-changed', newmod)
return newmod
record.default_get(domain, ctx)
if signal:
self.signal('group-changed', record)
return record
def model_remove(self, model):
idx = self.models.index(model)
self.models.remove(model)
if model.parent:
model.parent.modified = True
if self.models:
self.current_idx = min(idx, len(self.models)-1)
def remove(self, record, remove=False, modified=True, signal=True):
idx = self.index(record)
if self[idx].id > 0:
if remove:
self.record_removed.append(self[idx])
else:
self.record_deleted.append(self[idx])
if record.parent:
record.parent.modified = True
if modified:
record.modified = True
self._remove(self[idx])
if len(self):
self.current_idx = min(idx, len(self) - 1)
else:
self.current_idx = None
def _record_changed(self, model, signal_data):
self.signal('model-changed', model)
if signal:
record.signal('record-changed', record.parent)
def _record_modified(self, model, signal_data):
self.signal('record-modified', model)
def _record_changed(self, record, signal_data):
self.signal('group-changed', record)
def _record_modified(self, record, signal_data):
self.signal('record-modified', record)
def prev(self):
if self.models and self.current_idx is not None:
self.current_idx = (self.current_idx - 1) % len(self.models)
elif self.models:
if len(self) and self.current_idx is not None:
self.current_idx = (self.current_idx - 1) % len(self)
elif len(self):
self.current_idx = 0
else:
return None
return self.models[self.current_idx]
return self[self.current_idx]
def next(self):
if self.models and self.current_idx is not None:
self.current_idx = (self.current_idx + 1) % len(self.models)
elif self.models:
if len(self) and self.current_idx is not None:
self.current_idx = (self.current_idx + 1) % len(self)
elif len(self):
self.current_idx = 0
else:
return None
return self.models[self.current_idx]
return self[self.current_idx]
def remove(self, model, remove=False, modified=True, signal=True):
idx = self.models.index(model)
if self.models[idx].id > 0:
if remove:
self.model_removed.append(self.models[idx])
else:
self.model_deleted.append(self.models[idx])
if model.parent:
model.parent.modified = True
if modified:
model.modified = True
self.models.remove(self.models[idx])
if signal:
model.signal('record-changed', model.parent)
def add_fields_custom(self, fields, models):
to_add = []
for field_add in fields.iterkeys():
if not field_add in models.fields:
models.fields[field_add] = fields[field_add]
models.fields[field_add]['name'] = field_add
to_add.append(field_add)
else:
models.fields[field_add].update(fields[field_add])
ModelRecordGroup.mfields_load(to_add, models)
for fname in to_add:
for model in models.models:
model.value[fname] = self.mfields[fname].create(model)
return to_add
def add_fields(self, fields, models, context=None, signal=True):
def add_fields(self, fields, context=None, signal=True):
if context is None:
context = {}
to_add = self.add_fields_custom(fields, models)
models = models.models
if not len(models):
to_add = {}
for name, attr in fields.iteritems():
if name not in self.fields:
to_add[name] = attr
else:
self.fields[name].attrs.update(attr)
self.load_fields(to_add)
for name in to_add:
for record in self:
record.value[name] = self.fields[name].create(record)
if not len(self):
return True
old = []
new = []
for model in models:
if model.id > 0:
if model.is_modified():
old.append(model.id)
else:
new.append(model)
for record in self:
if record.id <= 0:
new.append(record)
ctx = context.copy()
if len(old) and len(to_add):
ctx.update(rpc.CONTEXT)
ctx.update(self.context)
try:
values = self.rpc.read(old, to_add + \
[x + '.rec_name' for x in to_add
if self.fields[x]['type'] \
in ('many2one', 'reference')], ctx)
except Exception, exception:
common.process_exception(exception, self.window)
return False
if values:
for value in values:
value_id = value['id']
if 'id' not in to_add:
del value['id']
self[value_id].set(value, signal=False)
if len(new) and len(to_add):
ctx.update(self.context)
args = ('model', self.model_name, 'default_get', to_add.keys(), ctx)
try:
values = self.rpc.default_get(to_add, ctx)
values = rpc.execute(*args)
except Exception, exception:
common.process_exception(exception, self.window)
return False
for field_to_add in to_add:
if field_to_add not in values:
values[field_to_add] = False
for mod in new:
mod.set_default(values, signal=signal)
values = common.process_exception(exception, self.window, *args)
if not values:
return False
for name in to_add:
if name not in values:
values[name] = False
for record in new:
record.set_default(values, signal=signal)
def __iter__(self):
return iter(self.models)
def get(self, id):
'Return record with the id'
return self.__id2record.get(id)
def get_by_id(self, m_id):
for model in self.models:
if model.id == m_id:
return model
__getitem__ = get_by_id
def id_changed(self, old_id):
'Update index for old id'
record = self.__id2record[old_id]
self.__id2record[record.id] = record
del self.__id2record[old_id]
+149 -145
View File
@@ -1,15 +1,13 @@
#This file is part of Tryton. The COPYRIGHT file at the top level of
#this repository contains the full copyright notices and license terms.
import re
import time
from tryton.rpc import RPCProxy
import tryton.rpc as rpc
from tryton.signal_event import SignalEvent
import tryton.common as common
from tryton.pyson import PYSONDecoder
import field
import datetime
import tryton.common as common
import logging
import time
class EvalEnvironment(dict):
@@ -43,96 +41,91 @@ class EvalEnvironment(dict):
__repr__ = __str__
def __contains__(self, item):
return item in self.parent.mgroup.mfields
return item in self.parent.group.fields
class ModelRecord(SignalEvent):
class Record(SignalEvent):
id = -1
def __init__(self, resource, obj_id, window, group=None, parent=None,
def __init__(self, model_name, obj_id, window, group=None, parent=None,
parent_name='', new=False):
global ID_COUNT
super(ModelRecord, self).__init__()
super(Record, self).__init__()
self.window = window
self.resource = resource
self.rpc = RPCProxy(self.resource)
self.id = obj_id or ModelRecord.id
self.model_name = model_name
self.id = obj_id or Record.id
if self.id < 0:
ModelRecord.id -= 1
Record.id -= 1
self._loaded = set()
self.parent = parent
self.parent_name = parent_name
self.mgroup = group
self.group = group
if group is not None:
assert model_name == group.model_name
self.value = {}
self.state_attrs = {}
self.__modified = False
self.modified_fields = {}
self._timestamp = None
self.attachment_count = -1
self.next = {}
for key, val in self.mgroup.mfields.items():
self.next = {} # Used in Group list
for key, val in self.group.fields.items():
self.value[key] = val.create(self)
if (new and val.attrs['type']=='one2many') \
and (val.attrs.get('mode','tree,form').startswith('form')):
mod = self.value[key].model_new()
self.value[key].model_add(mod)
record = self.value[key].new()
self.value[key].add(record)
def __getitem__(self, name):
if name not in self._loaded and self.id > 0:
ids = [self.id]
if self in self.mgroup.models:
idx = self.mgroup.models.index(self)
length = len(self.mgroup.models)
if self in self.group:
idx = self.group.index(self)
length = len(self.group)
n = 1
while len(ids) < 80 and (idx - n >= 0 or \
idx + n < length) and n < 100:
if idx - n >= 0:
model = self.mgroup.models[idx - n]
if name not in model._loaded and model.id > 0:
ids.append(model.id)
record = self.group[idx - n]
if name not in record._loaded and record.id > 0:
ids.append(record.id)
if idx + n < length:
model = self.mgroup.models[idx + n]
if name not in model._loaded and model.id > 0:
ids.append(model.id)
record = self.group[idx + n]
if name not in record._loaded and record.id > 0:
ids.append(record.id)
n += 1
ctx = rpc.CONTEXT.copy()
ctx.update(self.context_get())
args = (ids, self.mgroup.mfields.keys() + \
[x + '.rec_name' for x in self.mgroup.mfields.keys()
if self.mgroup.fields[x]['type'] \
args = ('model', self.model_name, 'read',
ids, self.group.fields.keys() + \
[x + '.rec_name' for x in self.group.fields.keys()
if self.group.fields[x].attrs['type'] \
in ('many2one', 'reference')] + \
['_timestamp'], ctx)
try:
values = self.rpc.read(*args)
values = rpc.execute(*args)
except Exception, exception:
common.process_exception(exception, self.window)
try:
values = self.rpc.read(args)
except:
values = common.process_exception(exception, self.window, *args)
if not values:
log = logging.getLogger('record')
log.error('%s' % exception.args[-1])
values = [{'id': x} for x in ids]
model_set = None
id2value = dict((value['id'], value) for value in values)
if ids != [self.id]:
for model in self.mgroup.models:
value = id2value.get(model.id)
if value:
model.set(value, signal=False)
model_set = model
for id in ids:
record = self.group.get(id)
value = id2value.get(id)
if record and value:
record.set(value, signal=False)
else:
value = id2value.get(self.id)
if value:
self.set(value, signal=False)
model_set = self
if model_set:
model_set.signal('record-changed')
return self.mgroup.mfields.get(name, False)
return self.group.fields.get(name, False)
def __repr__(self):
return '<ModelRecord %s@%s>' % (self.id, self.resource)
return '<Record %s@%s>' % (self.id, self.model_name)
def get_modified(self):
return self.__modified
@@ -148,7 +141,7 @@ class ModelRecord(SignalEvent):
return self.modified
def fields_get(self):
return self.mgroup.mfields
return self.group.fields
def _check_load(self):
if not self.loaded:
@@ -157,7 +150,7 @@ class ModelRecord(SignalEvent):
return False
def get_loaded(self):
return set(self.mgroup.mfields.keys()) == self._loaded
return set(self.group.fields.keys()) == self._loaded
loaded = property(get_loaded)
@@ -166,12 +159,12 @@ class ModelRecord(SignalEvent):
if check_load:
self._check_load()
value = []
for name, mfield in self.mgroup.mfields.items():
for name, field in self.group.fields.iteritems():
if (get_readonly or \
not mfield.get_state_attrs(self).get('readonly', False)) \
not field.get_state_attrs(self).get('readonly', False)) \
and (not get_modifiedonly \
or mfield.name in self.modified_fields):
value.append((name, mfield.get(self, check_load=check_load,
or field.name in self.modified_fields):
value.append((name, field.get(self, check_load=check_load,
readonly=get_readonly, modified=get_modifiedonly)))
value = dict(value)
if includeid:
@@ -182,8 +175,8 @@ class ModelRecord(SignalEvent):
if check_load:
self._check_load()
value = {}
for name, mfield in self.mgroup.mfields.items():
value[name] = mfield.get_eval(self, check_load=check_load)
for name, field in self.group.fields.iteritems():
value[name] = field.get_eval(self, check_load=check_load)
value['id'] = self.id
return value
@@ -192,23 +185,25 @@ class ModelRecord(SignalEvent):
self.reload()
def get_timestamp(self):
result = {self.resource + ',' + str(self.id): self._timestamp}
for name, mfield in self.mgroup.mfields.items():
result.update(mfield.get_timestamp(self))
result = {self.model_name + ',' + str(self.id): self._timestamp}
for name, field in self.group.fields.iteritems():
result.update(field.get_timestamp(self))
return result
def save(self, force_reload=True):
self._check_load()
if self.id < 0:
value = self.get(get_readonly=True)
args = ('model', self.resource, 'create', value, self.context_get())
args = ('model', self.model_name, 'create', value, self.context_get())
try:
self.id = rpc.execute(*args)
res = rpc.execute(*args)
except Exception, exception:
res = common.process_exception(exception, self.window, *args)
if not res:
return False
self.id = res
old_id = self.id
self.id = res
self.group.id_changed(old_id)
else:
if not self.is_modified():
return self.id
@@ -216,7 +211,7 @@ class ModelRecord(SignalEvent):
context = self.context_get()
context = context.copy()
context['_timestamp'] = self.get_timestamp()
args = ('model', self.resource, 'write', [self.id], value, context)
args = ('model', self.model_name, 'write', [self.id], value, context)
try:
if not rpc.execute(*args):
return False
@@ -226,35 +221,41 @@ class ModelRecord(SignalEvent):
self._loaded.clear()
if force_reload:
self.reload()
if self.mgroup:
self.mgroup.writen(self.id)
if self.group:
self.group.writen(self.id)
return self.id
def default_get(self, domain=None, context=None):
if len(self.mgroup.fields):
if len(self.group.fields):
args = ('model', self.model_name, 'default_get',
self.group.fields.keys(), context)
try:
val = self.rpc.default_get(self.mgroup.fields.keys(), context)
vals = rpc.execute(*args)
except Exception, exception:
common.process_exception(exception, self.window)
val = self.rpc.default_get(self.mgroup.fields.keys(), context)
self.set_default(val)
vals = common.process_exception(exception, self.window, *args)
if not vals:
return
self.set_default(vals)
def rec_name(self):
ctx = rpc.CONTEXT.copy()
ctx.update(self.context_get())
args = ('model', self.model_name, 'read', self.id, ['rec_name'], ctx)
try:
name = self.rpc.read(self.id, ['rec_name'], ctx)['rec_name']
res = rpc.execute(*args)
except Exception, exception:
common.process_exception(exception, self.window)
name = self.rpc.read(self.id, ['rec_name'], ctx)['rec_name']
return name
res = common.process_exception(exception, self.window, *args)
if not res:
return ''
return res['rec_name']
def validate_set(self):
change = self._check_load()
for mfield in self.mgroup.mfields.itervalues():
self._check_load()
change = False
for field in self.group.fields.itervalues():
change = change or \
not mfield.get_state_attrs(self).get('valid', True)
mfield.get_state_attrs(self)['valid'] = True
not field.get_state_attrs(self).get('valid', True)
field.get_state_attrs(self)['valid'] = True
if change:
self.signal('record-changed')
return change
@@ -262,43 +263,44 @@ class ModelRecord(SignalEvent):
def validate(self):
self._check_load()
res = True
for mfield in self.mgroup.mfields.itervalues():
if not mfield.validate(self):
for field in self.group.fields.itervalues():
if not field.validate(self):
res = False
return res
def _get_invalid_fields(self):
res = []
for fname, mfield in self.mgroup.mfields.items():
if not mfield.get_state_attrs(self).get('valid', True):
res.append((fname, mfield.attrs['string']))
for fname, field in self.group.fields.iteritems():
if not field.get_state_attrs(self).get('valid', True):
res.append((fname, field.attrs['string']))
return dict(res)
invalid_fields = property(_get_invalid_fields)
def context_get(self):
return self.mgroup.context
return self.group.context
def get_default(self):
self._check_load()
value = dict([(name, mfield.get_default(self))
for name, mfield in self.mgroup.mfields.items()])
value = dict([(name, field.get_default(self))
for name, field in self.group.fields.iteritems()])
return value
def set_default(self, val, signal=True, modified=False):
for fieldname, value in val.items():
if fieldname not in self.mgroup.mfields:
if fieldname not in self.group.fields:
continue
if isinstance(self.mgroup.mfields[fieldname], field.M2OField):
if isinstance(self.group.fields[fieldname], field.M2OField):
if fieldname + '.rec_name' in val:
value = (value, val[fieldname + '.rec_name'])
elif isinstance(self.mgroup.mfields[fieldname], field.ReferenceField):
elif isinstance(self.group.fields[fieldname], field.ReferenceField):
if value:
ref_model, ref_id = value.split(',', 1)
if fieldname + '.rec_name' in val:
value = ref_model, (ref_id, val[fieldname + '.rec_name'])
else:
value = ref_model, (ref_id, ref_id)
self.mgroup.mfields[fieldname].set_default(self, value,
self.group.fields[fieldname].set_default(self, value,
modified=modified)
self._loaded.add(fieldname)
if signal:
@@ -310,25 +312,25 @@ class ModelRecord(SignalEvent):
if fieldname == '_timestamp':
self._timestamp = value
continue
if fieldname not in self.mgroup.mfields:
if fieldname not in self.group.fields:
continue
if isinstance(self.mgroup.mfields[fieldname], field.O2MField):
if isinstance(self.group.fields[fieldname], field.O2MField):
later[fieldname] = value
continue
if isinstance(self.mgroup.mfields[fieldname], field.M2OField):
if isinstance(self.group.fields[fieldname], field.M2OField):
if fieldname + '.rec_name' in val:
value = (value, val[fieldname + '.rec_name'])
elif isinstance(self.mgroup.mfields[fieldname], field.ReferenceField):
elif isinstance(self.group.fields[fieldname], field.ReferenceField):
if value:
ref_model, ref_id = value.split(',', 1)
if fieldname + '.rec_name' in val:
value = ref_model, (ref_id, val[fieldname + '.rec_name'])
else:
value = ref_model, (ref_id, ref_id)
self.mgroup.mfields[fieldname].set(self, value, modified=modified)
self.group.fields[fieldname].set(self, value, modified=modified)
self._loaded.add(fieldname)
for fieldname, value in later.iteritems():
self.mgroup.mfields[fieldname].set(self, value, modified=modified)
self.group.fields[fieldname].set(self, value, modified=modified)
self._loaded.add(fieldname)
self.modified = modified
if not self.modified:
@@ -348,8 +350,8 @@ class ModelRecord(SignalEvent):
if check_load:
self._check_load()
ctx = rpc.CONTEXT.copy()
for name, mfield in self.mgroup.mfields.items():
ctx[name] = mfield.get_eval(self, check_load=check_load)
for name, field in self.group.fields.items():
ctx[name] = field.get_eval(self, check_load=check_load)
ctx['context'] = self.context_get()
ctx['active_id'] = self.id
@@ -363,8 +365,8 @@ class ModelRecord(SignalEvent):
def _get_on_change_args(self, args):
res = {}
values = {}
for name, mfield in self.mgroup.mfields.iteritems():
values[name] = mfield.get_eval(self, check_load=False)
for name, field in self.group.fields.iteritems():
values[name] = field.get_eval(self, check_load=False)
if self.parent and self.parent_name:
values['_parent_' + self.parent_name] = EvalEnvironment(self.parent,
False)
@@ -385,41 +387,41 @@ class ModelRecord(SignalEvent):
ids = [self.id]
ctx = rpc.CONTEXT.copy()
ctx.update(self.context_get())
args = ('model', self.model_name, 'on_change_' + fieldname,
ids, args, ctx)
try:
res = getattr(self.rpc, 'on_change_' + fieldname)(ids, args,
ctx)
res = rpc.execute(*args)
except Exception, exception:
common.process_exception(exception, self.window)
res = getattr(self.rpc, 'on_change_' + fieldname)(ids, args,
ctx)
if res:
later = {}
for fieldname, value in res.items():
if fieldname not in self.mgroup.mfields:
continue
if isinstance(self.mgroup.mfields[fieldname], field.O2MField):
later[fieldname] = value
continue
if isinstance(self.mgroup.mfields[fieldname], field.M2OField):
res = common.process_exception(exception, self.window, *args)
if not res:
return
later = {}
for fieldname, value in res.items():
if fieldname not in self.group.fields:
continue
if isinstance(self.group.fields[fieldname], field.O2MField):
later[fieldname] = value
continue
if isinstance(self.group.fields[fieldname], field.M2OField):
if fieldname + '.rec_name' in res:
value = (value, res[fieldname + '.rec_name'])
elif isinstance(self.group.fields[fieldname],
field.ReferenceField):
if value:
ref_mode, ref_id = value.split(',', 1)
if fieldname + '.rec_name' in res:
value = (value, res[fieldname + '.rec_name'])
elif isinstance(self.mgroup.mfields[fieldname],
field.ReferenceField):
if value:
ref_mode, ref_id = value.split(',', 1)
if fieldname + '.rec_name' in res:
value = ref_model, (ref_id,
res[fieldname + '.rec_name'])
else:
value = ref_model, (ref_id, ref_id)
self.mgroup.mfields[fieldname].set_on_change(self, value)
for fieldname, value in later.items():
self.mgroup.mfields[fieldname].set_on_change(self, value)
self.signal('record-changed')
value = ref_model, (ref_id,
res[fieldname + '.rec_name'])
else:
value = ref_model, (ref_id, ref_id)
self.group.fields[fieldname].set_on_change(self, value)
for fieldname, value in later.items():
self.group.fields[fieldname].set_on_change(self, value)
self.signal('record-changed')
def on_change_with(self, field_name):
for fieldname in self.mgroup.mfields:
on_change_with = self.mgroup.mfields[fieldname].attrs.get(
for fieldname in self.group.fields:
on_change_with = self.group.fields[fieldname].attrs.get(
'on_change_with')
if not on_change_with:
continue
@@ -431,37 +433,39 @@ class ModelRecord(SignalEvent):
ids = [self.id]
ctx = rpc.CONTEXT.copy()
ctx.update(self.context_get())
args = ('model', self.model_name, 'on_change_with_' + fieldname,
ids, args, ctx)
try:
res = getattr(self.rpc, 'on_change_with_' + fieldname)(ids,
args, ctx)
res = rpc.execute(*args)
except Exception, exception:
common.process_exception(exception, self.window)
res = getattr(self.rpc, 'on_change_with_' + fieldname)(ids,
args, ctx)
self.mgroup.mfields[fieldname].set_on_change(self, res)
res = common.process_exception(exception, self.window, *args)
if not res:
return
self.group.fields[fieldname].set_on_change(self, res)
def cond_default(self, field_name, value):
ir_default = RPCProxy('ir.default')
ctx = rpc.CONTEXT.copy()
ctx.update(self.context_get())
args = ('model', 'ir.default', 'get_default', self.model_name,
field_name + '=' + str(value), ctx)
try:
self.set_default(ir_default.get_default(self.resource,
field_name + '=' + str(value), ctx))
res = rpc.execute(*args)
except Exception, exception:
common.process_exception(exception, self.window)
self.set_default(ir_default.get_default(self.resource,
field_name + '=' + str(value), ctx))
res = common.process_exception(exception, self.window, *args)
if not res:
return
self.set_default(res)
def get_attachment_count(self, reload=False):
if self.id < 0:
return 0
if self.attachment_count < 0 or reload:
ir_attachment = RPCProxy('ir.attachment')
args = ('model', 'ir.attachment', 'search_count', [
('res_model', '=', self.model_name),
('res_id', '=', self.id),
])
try:
self.attachment_count = ir_attachment.search_count([
('res_model', '=', self.resource),
('res_id', '=', self.id),
])
self.attachment_count = rpc.execute(*args)
except:
return 0
return self.attachment_count
+222 -226
View File
@@ -1,27 +1,25 @@
#This file is part of Tryton. The COPYRIGHT file at the top level of
#this repository contains the full copyright notices and license terms.
"Screen"
import xml.dom.minidom
from tryton.rpc import RPCProxy
import tryton.rpc as rpc
from tryton.gui.window.view_form.model.group import ModelRecordGroup
from tryton.gui.window.view_form.model.group import Group
from tryton.gui.window.view_form.view.screen_container import ScreenContainer
from tryton.gui.window.view_form.widget_search import Form
from tryton.signal_event import SignalEvent
from tryton.common import node_attributes
import gobject
from tryton.config import CONFIG
import tryton.common as common
import gobject
import copy
import xml.dom.minidom
class Screen(SignalEvent):
"Screen"
def __init__(self, model_name, window, view_ids=None, view_type=None,
parent=None, parent_name='', context=None, views_preload=None,
tree_saves=True, domain=None, create_new=False, row_activate=None,
hastoolbar=False, default_get=None, show_search=False, limit=None,
readonly=False, form=None, exclude_field=None, sort=None,
context=None, views_preload=None, domain=None, row_activate=None,
limit=None, readonly=False, exclude_field=None, sort=None,
search_value=None):
if view_ids is None:
view_ids = []
@@ -33,48 +31,35 @@ class Screen(SignalEvent):
views_preload = {}
if domain is None:
domain = []
if default_get is None:
default_get = {}
super(Screen, self).__init__()
self.__current_model = None
self.show_search = show_search
self.search_count = 0
self.hastoolbar = hastoolbar
self.default_get = default_get
if not row_activate:
# TODO change for a function that switch to form view
self.row_activate = self.switch_view
else:
self.row_activate = row_activate
self.create_new = create_new
self.name = model_name
self.domain = domain
self.views_preload = views_preload
self.resource = model_name
self.rpc = RPCProxy(model_name)
self.model_name = model_name
self.context = context
self.views = []
self.fields = {}
self.view_ids = view_ids
self.models = None
self.parent = parent
self.parent_name = parent_name
self.parent = None
self.parent_name = None
self.window = window
models = ModelRecordGroup(model_name, self.fields, self.window,
parent=self.parent, parent_name=parent_name, context=self.context,
self.__group = None
self.group = Group(model_name, {}, self.window, context=self.context,
readonly=readonly)
self.models_set(models)
self.current_model = None
self.__current_record = None
self.current_record = None
self.screen_container = ScreenContainer()
self.filter_widget = None
self.widget = self.screen_container.widget_get()
self.__current_view = 0
self.tree_saves = tree_saves
self.limit = limit
self.search_value = search_value
self.form = form
self.fields_view_tree = None
self.exclude_field = exclude_field
self.sort = sort
@@ -89,8 +74,11 @@ class Screen(SignalEvent):
self.screen_container.set(view.widget)
self.display()
def __repr__(self):
return '<Screen %s at %s>' % (self.model_name, id(self))
def search_active(self, active=True):
if active and self.show_search:
if active and not self.parent:
if not self.filter_widget:
if not self.fields_view_tree:
ctx = {}
@@ -98,13 +86,14 @@ class Screen(SignalEvent):
ctx.update(self.context)
try:
self.fields_view_tree = rpc.execute('model',
self.name, 'fields_view_get', False,
self.model_name, 'fields_view_get', False,
'tree', ctx)
except:
return
self.filter_widget = Form(self.fields_view_tree['arch'],
self.fields_view_tree['fields'], self.name, self.window,
self.domain, (self, self.search_filter), self.context)
self.fields_view_tree['fields'], self.model_name,
self.window, self.domain, (self, self.search_filter),
self.context)
self.screen_container.add_filter(self.filter_widget.widget,
self.search_filter, self.search_clear)
self.filter_widget.set_limit(self.limit)
@@ -126,7 +115,7 @@ class Screen(SignalEvent):
offset = self.filter_widget.get_offset()
values = self.filter_widget.value
else:
values = [('id', 'in', [x.id for x in self.models])]
values = [('id', 'in', [x.id for x in self.group])]
ctx = {}
ctx.update(rpc.CONTEXT)
ctx.update(self.context)
@@ -137,21 +126,21 @@ class Screen(SignalEvent):
values = self.domain
try:
try:
ids = rpc.execute('model', self.name, 'search', values,
ids = rpc.execute('model', self.model_name, 'search', values,
offset, limit, self.sort, ctx)
except Exception, exception:
common.process_exception(exception, self.window)
ids = rpc.execute('model', self.name, 'search', values,
ids = rpc.execute('model', self.model_name, 'search', values,
offset, limit, self.sort, ctx)
if not only_ids:
if len(ids) == limit:
try:
self.search_count = rpc.execute('model', self.name,
'search_count', values, ctx)
self.search_count = rpc.execute('model',
self.model_name, 'search_count', values, ctx)
except Exception, exception:
common.process_exception(exception, self.window)
self.search_count = rpc.execute('model', self.name,
'search_count', values, ctx)
self.search_count = rpc.execute('model',
self.model_name, 'search_count', values, ctx)
else:
self.search_count = len(ids)
except:
@@ -160,76 +149,79 @@ class Screen(SignalEvent):
return ids
self.clear()
self.load(ids)
return True
return bool(ids)
def models_set(self, models):
if self.models:
self.models.signal_unconnect(self)
self.models = models
self.parent = models.parent
self.parent_name = models.parent_name
if len(models.models):
self.current_model = models.models[0]
def __get_group(self):
return self.__group
def __set_group(self, group):
fields = {}
if self.group is not None:
self.group.signal_unconnect(self)
for name, field in self.group.fields.iteritems():
fields[name] = field.attrs
self.__group = group
self.parent = group.parent
self.parent_name = group.parent_name
if len(group):
self.current_record = group[0]
else:
self.current_model = None
self.models.signal_connect(self, 'record-cleared', self._record_cleared)
self.models.signal_connect(self, 'record-changed', self._record_changed)
self.models.signal_connect(self, 'record-modified', self._record_modified)
self.models.signal_connect(self, 'model-changed', self._model_changed)
models.add_fields(self.fields, models)
self.fields.update(models.fields)
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)
def _record_cleared(self, model_group, signal, *args):
group = property(__get_group, __set_group)
def _group_cleared(self, group, signal):
for view in self.views:
view.reload = True
if hasattr(view, 'reload'):
view.reload = True
def _record_changed(self, model_group, signal, *args):
def _group_list_changed(self, group, signal):
for view in self.views:
view.signal_record_changed(signal[0], model_group.models,
signal[1], *args)
if hasattr(view, 'group_list_changed'):
view.group_list_changed(group, signal)
def _record_modified(self, model_group, signal, *args):
def _record_modified(self, group, signal, *args):
self.signal('record-modified')
def _model_changed(self, model_group, model):
if self.parent:
self.parent.signal('record-changed', self.parent)
def _group_changed(self, group, record):
self.display()
def _get_current_model(self):
return self.__current_model
def __get_current_record(self):
return self.__current_record
#
# Check more or less fields than in the screen !
#
def _set_current_model(self, value):
self.__current_model = value
def __set_current_record(self, record):
self.__current_record = record
try:
offset = int(self.filter_widget.get_offset())
except:
offset = 0
try:
pos = self.models.models.index(value)
pos = self.group.index(record)
except:
pos = -1
self.signal('record-message', (pos + offset,
len(self.models.models or []) + offset,
self.search_count,
value and value.id))
self.signal('record-message', (pos + offset, len(self.group) + offset,
self.search_count, record and record.id))
attachment_count = 0
if value and value.attachment_count > 0:
attachment_count = value.attachment_count
if record and record.attachment_count > 0:
attachment_count = record.attachment_count
self.signal('attachment-count', attachment_count)
# update attachment-count after 1 second
gobject.timeout_add(1000, self.update_attachment, value)
gobject.timeout_add(1000, self.update_attachment, record)
return True
current_model = property(_get_current_model, _set_current_model)
def update_attachment(self, model):
if model != self.__current_model:
current_record = property(__get_current_record, __set_current_record)
def update_attachment(self, record):
if record != self.current_record:
return False
if model and self.signal_connected('attachment-count'):
attachment_count = model.get_attachment_count()
if record and self.signal_connected('attachment-count'):
attachment_count = record.get_attachment_count()
self.signal('attachment-count', attachment_count)
return False
@@ -237,30 +229,32 @@ class Screen(SignalEvent):
for view in self.views:
view.destroy()
del view
#del self.current_model
self.models.signal_unconnect(self)
del self.models
self.group.signal_unconnect(self)
del self.views
def switch_view(self):
def switch_view(self, view_type=None):
self.current_view.set_value()
if self.current_model and self.current_model not in self.models.models:
self.current_model = None
if len(self.view_to_load):
self.load_view_to_load()
self.__current_view = len(self.views) - 1
else:
self.__current_view = (self.__current_view + 1) % len(self.views)
if self.current_record and self.current_record not in self.group:
self.current_record = None
for i in xrange(len(self.views) + len(self.view_to_load)):
if len(self.view_to_load):
self.load_view_to_load()
self.__current_view = len(self.views) - 1
else:
self.__current_view = (self.__current_view + 1) % len(self.views)
if not view_type:
break
elif self.current_view.view_type == view_type:
break
self.screen_container.set(self.current_view.widget)
if self.current_model:
self.current_model.validate_set()
if self.current_record:
self.current_record.validate_set()
else:
if self.current_view.view_type == 'form':
self.new()
self.current_view.set_cursor()
self.current_view.cancel()
self.display()
# TODO: set True or False accoring to the type
def load_view_to_load(self):
if len(self.view_to_load):
@@ -272,9 +266,6 @@ class Screen(SignalEvent):
view_type = self.view_to_load.pop(0)
self.add_view_id(view_id, view_type)
def add_view_custom(self, arch, fields, display=False, toolbar=None):
return self.add_view(arch, fields, display, True, toolbar=toolbar)
def add_view_id(self, view_id, view_type, display=False, context=None):
if view_type in self.views_preload:
return self.add_view(self.views_preload[view_type]['arch'],
@@ -285,13 +276,15 @@ class Screen(SignalEvent):
ctx = {}
ctx.update(rpc.CONTEXT)
ctx.update(self.context)
args = ('model', self.model_name, 'fields_view_get',
view_id, view_type, ctx,
self.parent and False or CONFIG['form.toolbar'])
try:
view = self.rpc.fields_view_get(view_id, view_type, ctx,
self.hastoolbar)
view = rpc.execute(*args)
except Exception, exception:
common.process_exception(exception, self.window)
view = self.rpc.fields_view_get(view_id, view_type, ctx,
self.hastoolbar)
view = common.process_exception(exception, self.window, *args)
if not view:
return
if self.exclude_field:
if self.exclude_field in view['fields']:
view['fields'][self.exclude_field]['states'] = {'invisible': True}
@@ -302,8 +295,7 @@ class Screen(SignalEvent):
return self.add_view(view['arch'], view['fields'], display,
toolbar=view.get('toolbar', False), context=context)
def add_view(self, arch, fields, display=False, custom=False, toolbar=None,
context=None):
def add_view(self, arch, fields, display=False, toolbar=None, context=None):
if toolbar is None:
toolbar = {}
def _parse_fields(node, fields):
@@ -347,25 +339,26 @@ class Screen(SignalEvent):
self.fields_view_tree = {'arch': arch, 'fields': fields}
from tryton.gui.window.view_form.view.widget_parse import WidgetParse
models = self.models.models
if self.current_model and (self.current_model not in models):
models = models + [self.current_model]
if custom:
self.models.add_fields_custom(fields, self.models)
else:
self.models.add_fields(fields, self.models, context=context)
self.fields = self.models.fields
if self.current_record and (self.current_record not in self.group):
self.group.append(self.current_record)
self.group.add_fields(fields, context=context)
parser = WidgetParse(parent=self.parent, window=self.window)
view = parser.parse(self, xml_dom, self.fields, toolbar=toolbar)
view = parser.parse(self, xml_dom, self.group.fields, toolbar=toolbar)
self.views.append(view)
if display:
self.__current_view = len(self.views) - 1
self.current_view.display()
self.screen_container.set(view.widget)
self.screen_container.set(self.current_view.widget)
if self.current_record:
self.current_record.validate_set()
else:
if self.current_view.view_type == 'form':
self.new()
self.current_view.set_cursor()
self.current_view.cancel()
self.display()
return view
def editable_get(self):
@@ -375,11 +368,12 @@ class Screen(SignalEvent):
return False
def new(self, default=True, context=None):
if self.models.readonly:
if self.group.readonly:
return
if context is None:
context = {}
if self.current_view and ((self.current_view.view_type == 'tree' \
if self.current_view and \
((self.current_view.view_type == 'tree' \
and not (hasattr(self.current_view.widget_tree, 'editable') \
and self.current_view.widget_tree.editable)) \
or self.current_view.view_type == 'graph'):
@@ -393,18 +387,15 @@ class Screen(SignalEvent):
ctx.update(rpc.CONTEXT)
ctx.update(self.context)
ctx.update(context)
model = self.models.model_new(default, self.domain, ctx)
if (not self.current_view) \
or self.current_view.model_add_new \
or self.create_new:
self.models.model_add(model, self.new_model_position())
self.current_model = model
self.current_model.validate_set()
record = self.group.new(default, self.domain, ctx)
self.group.add(record, self.new_model_position())
self.current_record = record
self.current_record.validate_set()
self.display()
if self.current_view:
self.current_view.set_cursor(new=True)
self.request_set()
return self.current_model
return self.current_record
def new_model_position(self):
position = -1
@@ -416,78 +407,77 @@ class Screen(SignalEvent):
def set_on_write(self, func_name):
if func_name:
self.models.on_write.add(func_name)
self.group.on_write.add(func_name)
def cancel_current(self):
if self.current_model:
self.current_model.cancel()
if self.current_model.id < 0:
if self.current_record:
self.current_record.cancel()
if self.current_record.id < 0:
self.remove()
if self.current_view:
self.current_view.cancel()
def save_current(self):
if not self.current_model:
if not self.current_record:
return False
self.current_view.set_value()
obj_id = False
if self.current_model.validate():
obj_id = self.current_model.save(force_reload=True)
if self.current_record.validate():
obj_id = self.current_record.save(force_reload=True)
else:
self.current_view.set_cursor()
self.current_view.display()
return False
if self.current_view.view_type == 'tree':
for model in self.models.models:
if model.is_modified():
if model.validate():
obj_id = model.save(force_reload=True)
for record in self.group:
if record.is_modified():
if record.validate():
obj_id = record.save(force_reload=True)
else:
self.current_view.set_cursor()
self.current_model = model
self.current_record = record
self.current_view.set_cursor()
self.display()
return False
self.current_view.set_cursor()
self.display()
if self.current_model not in self.models:
self.models.model_add(self.current_model, modified=False)
self.display()
if self.current_record not in self.group:
self.group.add(self.current_record, modified=False)
self.request_set()
return obj_id
def _get_current_view(self):
def __get_current_view(self):
if not len(self.views):
return None
return self.views[self.__current_view]
current_view = property(_get_current_view)
current_view = property(__get_current_view)
def get(self, get_readonly=True, includeid=False, check_load=True,
get_modifiedonly=False):
if not self.current_model:
if not self.current_record:
return None
self.current_view.set_value()
return self.current_model.get(get_readonly=get_readonly,
return self.current_record.get(get_readonly=get_readonly,
includeid=includeid, check_load=check_load,
get_modifiedonly=get_modifiedonly)
def is_modified(self):
if not self.current_model:
return False
self.current_view.set_value()
res = False
if self.current_view.view_type != 'tree':
res = self.current_model.is_modified()
res = self.current_record and self.current_record.is_modified()
else:
for model in self.models.models:
if model.is_modified():
for record in self.group:
if record.is_modified():
res = True
return res
def reload(self, writen=False):
ids = self.sel_ids_get()
self.models.reload(ids)
self.group.reload(ids)
if writen:
self.models.writen(ids)
self.group.writen(ids)
if self.parent:
self.parent.reload()
self.display()
@@ -496,33 +486,36 @@ class Screen(SignalEvent):
def remove(self, delete=False, remove=False):
res = False
reload_ids = []
if self.current_view.view_type == 'form' and self.current_model:
obj_id = self.current_model.id
if delete and obj_id > 0:
if self.current_view.view_type == 'form' and self.current_record:
record_id = self.current_record.id
if delete and record_id > 0:
context = {}
context.update(rpc.CONTEXT)
context.update(self.context)
context['_timestamp'] = self.current_model.get_timestamp()
context['_timestamp'] = self.current_record.get_timestamp()
reload_ids = self.group.on_write_ids(record_id)
if reload_ids and record_id in reload_ids:
reload_ids.remove(record_id)
args = ('model', self.model_name, 'delete', [record_id],
context)
try:
reload_ids = self.models.on_write_ids(obj_id)
if reload_ids and obj_id in reload_ids:
reload_ids.remove(obj_id)
if not self.rpc.delete([obj_id], context):
return False
res = rpc.execute(*args)
except Exception, exception:
common.process_exception(exception, self.window)
res = common.process_exception(exception, self.window,
*args)
if not res:
return False
self.current_view.set_cursor()
if self.current_model in self.models.models:
idx = self.models.models.index(self.current_model)
self.models.remove(self.current_model, remove=remove)
if self.models.models:
idx = min(idx, len(self.models.models)-1)
self.current_model = self.models.models[idx]
if self.current_record in self.group:
idx = self.group.index(self.current_record)
self.group.remove(self.current_record, remove=remove)
if self.group:
idx = min(idx, len(self.group) - 1)
self.current_record = self.group[idx]
else:
self.current_model = None
self.current_record = None
if reload_ids:
self.models.reload(reload_ids)
self.group.reload(reload_ids)
self.display()
res = True
if self.current_view.view_type == 'tree':
@@ -532,38 +525,41 @@ class Screen(SignalEvent):
context.update(rpc.CONTEXT)
context.update(self.context)
context['_timestamp'] = {}
for obj_id in ids:
model = self.models.get_by_id(obj_id)
context['_timestamp'].update(model.get_timestamp())
for record_id in ids:
record = self.group.get(record_id)
context['_timestamp'].update(record.get_timestamp())
reload_ids = self.group.on_write_ids(ids)
if reload_ids:
for record_id in ids:
if record_id in reload_ids:
reload_ids.remove(record_id)
args = ('model', self.model_name, 'delete', ids,
context)
try:
reload_ids = self.models.on_write_ids(ids)
if reload_ids:
for obj_id in ids:
if obj_id in reload_ids:
reload_ids.remove(obj_id)
if not self.rpc.delete(ids, context):
return False
res = rpc.execute(*args)
except Exception, exception:
common.process_exception(exception, self.window)
res = common.process_exception(exception, self.window,
*args)
if not res:
return False
sel_models = self.current_view.sel_models_get()
if not sel_models:
sel_records = self.current_view.selected_records()
if not sel_records:
return True
idx = self.models.models.index(sel_models[0])
for model in sel_models:
idx = self.group.index(sel_records[0])
for record in sel_records:
# set current model to None to prevent __select_changed
# to save the previous_model as it can be already deleted.
self.current_model = None
self.models.remove(model, remove=remove, signal=False)
self.current_record = None
self.group.remove(record, remove=remove, signal=False)
# send record-changed only once
model.signal('record-changed', model.parent)
if self.models.models:
idx = min(idx, len(self.models.models)-1)
self.current_model = self.models.models[idx]
record.signal('record-changed')
if self.group:
idx = min(idx, len(self.group) - 1)
self.current_record = self.group[idx]
else:
self.current_model = None
self.current_record = None
if reload_ids:
self.models.reload(reload_ids)
self.group.reload(reload_ids)
self.current_view.set_cursor()
self.display()
res = True
@@ -571,12 +567,12 @@ class Screen(SignalEvent):
return res
def load(self, ids, set_cursor=True, modified=False):
self.models.load(ids, display=False, modified=modified)
self.group.load(ids, display=False, modified=modified)
self.current_view.reset()
if ids:
self.display(ids[0])
else:
self.current_model = None
self.current_record = None
self.display()
if set_cursor:
self.current_view.set_cursor()
@@ -584,7 +580,7 @@ class Screen(SignalEvent):
def display(self, res_id=None, set_cursor=False):
if res_id:
self.current_model = self.models[res_id]
self.current_record = self.group.get(res_id)
if self.views:
#XXX To remove when calendar will be implemented
if self.current_view.view_type == 'calendar' and \
@@ -592,9 +588,9 @@ class Screen(SignalEvent):
self.switch_view()
self.current_view.display()
self.current_view.widget.set_sensitive(
bool(self.models.models \
bool(self.group \
or (self.current_view.view_type != 'form') \
or self.current_model))
or self.current_record))
self.search_active(self.current_view.view_type \
in ('tree', 'graph', 'calendar'))
if set_cursor:
@@ -603,32 +599,32 @@ class Screen(SignalEvent):
def display_next(self):
self.current_view.set_value()
self.current_view.set_cursor(reset_view=False)
if self.current_model in self.models.models:
idx = self.models.models.index(self.current_model)
if self.current_record in self.group:
idx = self.group.index(self.current_record)
inc = 1
if self.current_view.view_type == 'tree':
start, end = self.current_view.widget_tree.get_visible_range()
inc += end[0] - start[0]
if inc >= 4 and (end[0] + 1) < len(self.models.models):
if inc >= 4 and (end[0] + 1) < len(self.group):
inc -= 3
vadjustment = self.current_view.widget_tree.get_vadjustment()
vadjustment.value = vadjustment.value + vadjustment.page_increment
idx = idx + inc
if idx >= len(self.models.models):
idx = len(self.models.models) - 1
self.current_model = self.models.models[idx]
if idx >= len(self.group):
idx = len(self.group) - 1
self.current_record = self.group[idx]
else:
self.current_model = len(self.models.models) \
and self.models.models[0]
self.current_record = len(self.group) \
and self.group[0]
self.current_view.set_cursor(reset_view=False)
if self.current_model:
self.current_model.validate_set()
if self.current_record:
self.current_record.validate_set()
self.display()
def display_prev(self):
self.current_view.set_value()
self.current_view.set_cursor(reset_view=False)
if self.current_model in self.models.models:
if self.current_record in self.group:
inc = 1
if self.current_view.view_type == 'tree':
range = self.current_view.widget_tree.get_visible_range()
@@ -642,38 +638,38 @@ class Screen(SignalEvent):
if vadjustment.value:
vadjustment.value = vadjustment.value - \
vadjustment.page_increment
idx = self.models.models.index(self.current_model) - inc
idx = self.group.index(self.current_record) - inc
if idx < 0:
idx = 0
self.current_model = self.models.models[idx]
self.current_record = self.group[idx]
else:
self.current_model = len(self.models.models) \
and self.models.models[-1]
self.current_record = len(self.group) \
and self.group[-1]
self.current_view.set_cursor(reset_view=False)
if self.current_model:
self.current_model.validate_set()
if self.current_record:
self.current_record.validate_set()
self.display()
def sel_ids_get(self):
return self.current_view.sel_ids_get()
def id_get(self):
if not self.current_model:
if not self.current_record:
return False
return self.current_model.id
return self.current_record.id
def ids_get(self):
return [x.id for x in self.models if x.id]
return [x.id for x in self.group if x.id]
def clear(self):
self.models.clear()
self.current_model = None
self.group.clear()
self.current_record = None
def on_change(self, fieldname, attr):
self.current_model.on_change(fieldname, attr)
self.current_record.on_change(fieldname, attr)
self.display()
def request_set(self):
if self.name == 'res.request':
if self.model_name == 'res.request':
from tryton.gui.main import Main
Main.get_main().request_set()
+59 -91
View File
@@ -12,49 +12,6 @@ from tryton.pyson import PYSONEncoder
_ = gettext.gettext
class ViewWidget(object):
def __init__(self, parent, widget, widget_name):
self.view_form = parent
self.widget = widget
self.widget._view = self
self.widget_name = widget_name
def display(self, model):
if not model:
self.widget.display(model, False)
return False
modelfield = model.mgroup.mfields.get(self.widget_name, None)
if modelfield:
modelfield.state_set(model)
self.widget.display(model, modelfield)
elif isinstance(self.widget, Action):
self.widget.display(model, False)
def reset(self, model):
modelfield = None
if model:
modelfield = model.mgroup.mfields.get(self.widget_name, None)
if modelfield and 'valid' in modelfield.get_state_attrs(model):
modelfield.get_state_attrs(model)['valid'] = True
self.display(model)
def set_value(self, model):
if self.widget_name in model.mgroup.mfields:
self.widget.set_value(model, model.mgroup.mfields[self.widget_name])
def _get_model(self):
return self.view_form.screen.current_model
model = property(_get_model)
def _get_modelfield(self):
if self.model:
return self.model.mgroup.mfields[self.widget_name]
modelfield = property(_get_modelfield)
class ViewForm(ParserView):
def __init__(self, window, screen, widget, children=None,
@@ -62,14 +19,14 @@ class ViewForm(ParserView):
super(ViewForm, self).__init__(window, screen, widget, children,
buttons, toolbar, notebooks, cursor_widget)
self.view_type = 'form'
self.model_add_new = False
for button in self.buttons:
button.form = self
self.widgets = dict((name, [ViewWidget(self, widget, name)
for widget in widgets])
for name, widgets in children.iteritems())
self.widgets = children
for widgets in self.widgets.itervalues():
for widget in widgets:
widget.view = self
vbox = gtk.VBox()
vp = gtk.Viewport()
@@ -145,8 +102,8 @@ class ViewForm(ParserView):
act = action.copy()
if atype in ('print', 'action'):
self.screen.save_current()
obj_id = self.screen.current_model \
and self.screen.current_model.id
obj_id = self.screen.current_record \
and self.screen.current_record.id
if obj_id < 0:
if atype in ('print'):
message(_('You must save this record ' \
@@ -157,15 +114,15 @@ class ViewForm(ParserView):
return False
email = {}
if 'email' in action:
email = self.screen.current_model.expr_eval(action['email'])
email = self.screen.current_record.expr_eval(action['email'])
if not email:
email = {}
email['subject'] = action['name'].replace('_', '')
act['email'] = email
self.screen.display()
if atype == 'relate':
obj_id = self.screen.current_model \
and self.screen.current_model.id
obj_id = self.screen.current_record \
and self.screen.current_record.id
if not obj_id:
message(_('You must select a record ' \
'to be able to use the relate button !'), self.window)
@@ -173,14 +130,14 @@ class ViewForm(ParserView):
encoder = PYSONEncoder()
if 'pyson_domain' in act:
act['pyson_domain'] = encoder.encode(
self.screen.current_model.expr_eval(
self.screen.current_record.expr_eval(
act['pyson_domain'], check_load=False))
if 'pyson_context' in act:
act['pyson_context'] = encoder.encode(
self.screen.current_model.expr_eval(
self.screen.current_record.expr_eval(
act['pyson_context'], check_load=False))
data = {
'model': self.screen.name,
'model': self.screen.model_name,
'id': obj_id,
'ids': [obj_id],
}
@@ -206,49 +163,60 @@ class ViewForm(ParserView):
def cancel(self):
for widgets in self.widgets.itervalues():
for widget in widgets:
widget.widget.cancel()
widget.cancel()
def set_value(self):
model = self.screen.current_model
if model:
for widgets in self.widgets.itervalues():
for widget in widgets:
widget.set_value(model)
record = self.screen.current_record
if record:
for name, widgets in self.widgets.iteritems():
if name in record.group.fields:
field = record.group.fields[name]
for widget in widgets:
widget.set_value(record, field)
def sel_ids_get(self):
if self.screen.current_model:
return [self.screen.current_model.id]
if self.screen.current_record:
return [self.screen.current_record.id]
return []
def sel_models_get(self):
if self.screen.current_model:
return [self.screen.current_model]
def selected_records(self):
if self.screen.current_record:
return [self.screen.current_record]
return []
def reset(self):
model = self.screen.current_model
for name, widgets in self.widgets.iteritems():
for widget in widgets:
widget.reset(model)
record = self.screen.current_record
if record:
for name, widgets in self.widgets.iteritems():
field = record.group.fields.get(name)
if field and 'valid' in field.get_state_attrs(record):
for widget in widgets:
field.get_state_attrs(record)['valid'] = True
widget.display(record, field)
def signal_record_changed(self, *args):
for widgets in self.widgets.itervalues():
for widget in widgets:
if hasattr(widget.widget, 'screen'):
for view in widget.widget.screen.views:
if hasattr(widget, 'screen'):
for view in widget.screen.views:
view.signal_record_changed(*args)
def display(self):
model = self.screen.current_model
if model:
# Force to set mfields in model
for field in model.mgroup.fields:
model[field].get(model, check_load=False)
for widgets in self.widgets.itervalues():
record = self.screen.current_record
if record:
# Force to set fields in record
for field in record.group.fields:
record[field].get(record, check_load=False)
for name, widgets in self.widgets.iteritems():
field = None
if record:
field = record.group.fields.get(name)
if field:
field.state_set(record)
for widget in widgets:
widget.display(model)
widget.display(record, field)
for button in self.buttons:
button.state_set(model)
button.state_set(record)
return True
def set_cursor(self, new=False, reset_view=True):
@@ -256,25 +224,25 @@ class ViewForm(ParserView):
for notebook in self.notebooks:
notebook.set_current_page(0)
if self.cursor_widget in self.widgets:
self.widgets[self.cursor_widget][0].widget.grab_focus()
model = self.screen.current_model
self.widgets[self.cursor_widget][0].grab_focus()
record = self.screen.current_record
position = reduce(lambda x, y: x + len(y), self.widgets, 0)
focus_widget = None
if model:
for widgets in self.widgets.itervalues():
if record:
for name, widgets in self.widgets.iteritems():
for widget in widgets:
modelfield = model.mgroup.mfields.get(widget.widget_name, None)
if not modelfield:
field = record.group.fields.get(name)
if not field:
continue
if not modelfield.get_state_attrs(model).get('valid', True):
if widget.widget.position > position:
if not field.get_state_attrs(record).get('valid', True):
if widget.position > position:
continue
position = widget.widget.position
position = widget.position
focus_widget = widget
if focus_widget:
for notebook in self.notebooks:
for i in range(notebook.get_n_pages()):
child = notebook.get_nth_page(i)
if focus_widget.widget.widget.is_ancestor(child):
if focus_widget.widget.is_ancestor(child):
notebook.set_current_page(i)
focus_widget.widget.grab_focus()
focus_widget.grab_focus()
@@ -13,8 +13,9 @@ _ = gettext.gettext
class Binary(WidgetInterface):
"Binary"
def __init__(self, window, parent, model, attrs=None):
super(Binary, self).__init__(window, parent, model, attrs)
def __init__(self, field_name, model_name, window, attrs=None):
super(Binary, self).__init__(field_name, model_name, window,
attrs=attrs)
self.tooltips = Tooltips()
@@ -52,8 +53,6 @@ class Binary(WidgetInterface):
self.tooltips.enable()
self.model_field = None
def _readonly_set(self, value):
if value:
self.but_new.hide()
@@ -71,48 +70,47 @@ class Binary(WidgetInterface):
def sig_new(self, widget=None):
try:
filename = file_selection(_('Open...'),
parent=self._window)
if filename and self.model_field:
self.model_field.set_client(self._view.model,
parent=self.window)
if filename and self.field:
self.field.set_client(self.record,
base64.encodestring(file(filename, 'rb').read()))
fname = self.attrs.get('fname_widget', False)
if fname:
self.parent.value = {fname:os.path.basename(filename)}
self.display(self._view.model, self.model_field)
self.display(self.record, self.field)
except Exception, exception:
warning(_('Error reading the file.\nError message:\n%s') \
% str(exception), self._window, _('Error'))
% str(exception), self.window, _('Error'))
def sig_save_as(self, widget=None):
try:
filename = file_selection(_('Save As...'),
parent=self._window, action=gtk.FILE_CHOOSER_ACTION_SAVE)
if filename and self.model_field:
parent=self.window, action=gtk.FILE_CHOOSER_ACTION_SAVE)
if filename and self.field:
file_p = file(filename,'wb+')
file_p.write(base64.decodestring(
self.model_field.get(self._view.model)))
self.field.get(self.record)))
file_p.close()
except Exception, exception:
warning(_('Error writing the file.\nError message:\n%s') \
% str(exception), self._window, _('Error'))
% str(exception), self.window, _('Error'))
def sig_remove(self, widget=None):
if self.model_field:
self.model_field.set_client(self._view.model, False)
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._view.model, self.model_field)
self.display(self.record, self.field)
def display(self, model, model_field):
super(Binary, self).display(model, model_field)
if not model_field:
def display(self, record, field):
super(Binary, self).display(record, field)
if not field:
self.wid_text.set_text('')
self.but_save_as.set_sensitive(False)
return False
self.model_field = model_field
self.wid_text.set_text(self._size_get(model_field.get(model)))
self.but_save_as.set_sensitive(bool(model_field.get(model)))
self.wid_text.set_text(self._size_get(field.get(record)))
self.but_save_as.set_sensitive(bool(field.get(record)))
return True
def display_value(self):
@@ -121,7 +119,7 @@ class Binary(WidgetInterface):
def _size_get(self, value):
return value and ('%d ' + _('bytes')) % len(value) or ''
def set_value(self, model, model_field):
def set_value(self, record, field):
return
def _color_widget(self):
@@ -18,8 +18,9 @@ _ = gettext.gettext
class Calendar(WidgetInterface):
"Calendar"
def __init__(self, window, parent=None, model=None, attrs=None):
super(Calendar, self).__init__(window, parent, model=model, attrs=attrs)
def __init__(self, field_name, model_name, window, attrs=None):
super(Calendar, self).__init__(field_name, model_name, window,
attrs=attrs)
self.format = date_format()
self.widget = date_widget.ComplexEntry(self.format, spacing=0)
@@ -66,7 +67,7 @@ class Calendar(WidgetInterface):
def grab_focus(self):
return self.entry.grab_focus()
def get_value(self, model):
def get_value(self, record):
value = self.entry.get_text()
if value == '':
return False
@@ -76,16 +77,16 @@ class Calendar(WidgetInterface):
return False
return datetime_strftime(date, DT_FORMAT)
def set_value(self, model, model_field):
model_field.set_client(model, self.get_value(model))
def set_value(self, record, field):
field.set_client(record, self.get_value(record))
return True
def display(self, model, model_field):
if not model_field:
def display(self, record, field):
if not field:
self.entry.clear()
return False
super(Calendar, self).display(model, model_field)
value = model_field.get_client(model)
super(Calendar, self).display(record, field)
value = field.get_client(record)
if not value:
self.entry.clear()
else:
@@ -109,7 +110,7 @@ class Calendar(WidgetInterface):
return self.entry.get_text()
def cal_open(self, widget):
win = gtk.Dialog(_('Date Selection'), self._window,
win = gtk.Dialog(_('Date Selection'), self.window,
gtk.DIALOG_MODAL|gtk.DIALOG_DESTROY_WITH_PARENT,
(gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL,
gtk.STOCK_OK, gtk.RESPONSE_OK))
@@ -127,7 +128,7 @@ class Calendar(WidgetInterface):
win.show_all()
try:
val = self.get_value(self.model)
val = self.get_value(self.record)
if val:
cal.select_month(int(val[5:7])-1, int(val[0:4]))
cal.select_day(int(val[8:10]))
@@ -147,15 +148,16 @@ class Calendar(WidgetInterface):
format = format.replace('%Y', '0%Y')
self.entry.set_text(datetime_strftime(date, format))
self._focus_out()
self._window.present()
self.window.present()
win.destroy()
class DateTime(WidgetInterface):
"DateTime"
def __init__(self, window, parent, model, attrs=None):
super(DateTime, self).__init__(window, parent, model, attrs=attrs)
def __init__(self, field_name, model_name, window, attrs=None):
super(DateTime, self).__init__(field_name, model_name, window,
attrs=attrs)
self.format = date_format() + ' ' + HM_FORMAT
self.widget = date_widget.ComplexEntry(self.format, spacing=0)
@@ -201,7 +203,7 @@ class DateTime(WidgetInterface):
def grab_focus(self):
return self.entry.grab_focus()
def get_value(self, model, timezone=True):
def get_value(self, record, timezone=True):
value = self.entry.get_text()
if value == '':
return False
@@ -221,15 +223,15 @@ class DateTime(WidgetInterface):
pass
return datetime_strftime(date, DHM_FORMAT)
def set_value(self, model, model_field):
model_field.set_client(model, self.get_value(model))
def set_value(self, record, field):
field.set_client(record, self.get_value(record))
return True
def display(self, model, model_field):
super(DateTime, self).display(model, model_field)
if not model_field:
def display(self, record, field):
super(DateTime, self).display(record, field)
if not field:
return self.show(False)
self.show(model_field.get_client(model))
self.show(field.get_client(record))
def show(self, dt_val, timezone=True):
if not dt_val:
@@ -263,7 +265,7 @@ class DateTime(WidgetInterface):
return self.entry.get_text()
def cal_open(self, widget):
win = gtk.Dialog(_('Date Time Selection'), self._window,
win = gtk.Dialog(_('Date Time Selection'), self.window,
gtk.DIALOG_MODAL|gtk.DIALOG_DESTROY_WITH_PARENT,
(gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL,
gtk.STOCK_OK, gtk.RESPONSE_OK))
@@ -292,7 +294,7 @@ class DateTime(WidgetInterface):
win.show_all()
try:
val = self.get_value(self.model, timezone=False)
val = self.get_value(self.record, timezone=False)
if val:
widget_hour.set_value(int(val[11:13]))
widget_minute.set_value(int(val[-5:-3]))
@@ -314,5 +316,5 @@ class DateTime(WidgetInterface):
value = datetime_strftime(date, DHM_FORMAT)
self.show(value, timezone=False)
self._focus_out()
self._window.present()
self.window.present()
win.destroy()
@@ -6,10 +6,8 @@ from interface import WidgetInterface
class Char(WidgetInterface):
"Char"
def __init__(self, window, parent, model, attrs=None):
if attrs is None:
attrs = {}
super(Char, self).__init__(window, parent, model=model, attrs=attrs)
def __init__(self, field_name, model_name, window, attrs=None):
super(Char, self).__init__(field_name, model_name, window, attrs=attrs)
self.widget = gtk.HBox()
self.entry = gtk.Entry()
@@ -29,15 +27,15 @@ class Char(WidgetInterface):
def grab_focus(self):
return self.entry.grab_focus()
def set_value(self, model, model_field):
return model_field.set_client(model, self.entry.get_text() or False)
def set_value(self, record, field):
return field.set_client(record, self.entry.get_text() or False)
def display(self, model, model_field):
super(Char, self).display(model, model_field)
if not model_field:
def display(self, record, field):
super(Char, self).display(record, field)
if not field:
self.entry.set_text('')
return False
self.entry.set_text(model_field.get(model) or '')
self.entry.set_text(field.get(record) or '')
def _readonly_set(self, value):
super(Char, self)._readonly_set(value)
@@ -50,6 +48,6 @@ class Char(WidgetInterface):
class Sha(Char):
def __init__(self, window, parent, model, attrs=None):
super(Sha, self).__init__(window, parent, model=model, attrs=attrs)
def __init__(self, field_name, model_name, window, attrs=None):
super(Sha, self).__init__(field_name, model_name, window, attrs=attrs)
self.entry.set_visibility(False)
@@ -8,8 +8,9 @@ _ = gettext.gettext
class CheckBox(WidgetInterface):
def __init__(self, window, parent, model, attrs=None):
super(CheckBox, self).__init__(window, parent, model, attrs)
def __init__(self, field_name, model_name, window, attrs=None):
super(CheckBox, self).__init__(field_name, model_name, window,
attrs=attrs)
self.widget = gtk.CheckButton()
self.widget.connect('focus-in-event', lambda x, y: self._focus_in())
self.widget.connect('focus-out-event', lambda x, y: self._focus_out())
@@ -20,15 +21,15 @@ class CheckBox(WidgetInterface):
super(CheckBox, self)._readonly_set(value)
self.widget.set_sensitive(not value)
def set_value(self, model, model_field):
model_field.set_client(model, int(self.widget.get_active()))
def set_value(self, record, field):
field.set_client(record, self.widget.get_active())
def display(self, model, model_field):
super(CheckBox, self).display(model, model_field)
if not model_field:
def display(self, record, field):
super(CheckBox, self).display(record, field)
if not field:
self.widget.set_active(False)
return False
self.widget.set_active(bool(model_field.get(model)))
self.widget.set_active(bool(field.get(record)))
def display_value(self):
if self.widget.get_active():
@@ -1,6 +1,5 @@
#This file is part of Tryton. The COPYRIGHT file at the top level of
#this repository contains the full copyright notices and license terms.
from char import Char
from integer import Integer
import locale
@@ -8,28 +7,29 @@ import locale
class Float(Integer):
"Float"
def __init__(self, window, parent, model, attrs=None):
super(Float, self).__init__(window, parent, model=model, attrs=attrs)
def __init__(self, field_name, model_name, window, attrs=None):
super(Float, self).__init__(field_name, model_name, window,
attrs=attrs)
self.digits = attrs.get('digits', (16, 2))
def set_value(self, model, model_field):
def set_value(self, record, field):
try:
value = locale.atof(self.entry.get_text())
except:
value = 0.0
return model_field.set_client(model, value)
return field.set_client(record, value)
def display(self, model, model_field):
super(Char, self).display(model, model_field)
if not model_field:
def display(self, record, field):
super(Float, self).display(record, field)
if not field:
self.entry.set_text('')
return False
if isinstance(self.digits, str):
digits = self._view.model.expr_eval(self.digits)
digits = record.expr_eval(self.digits)
else:
digits = self.digits
self.entry.set_text(locale.format('%.' + str(digits[1]) + 'f',
model_field.get(model) or 0.0, True))
field.get(record) or 0.0, True))
def sig_insert_text(self, entry, new_text, new_text_length, position):
value = entry.get_text()
@@ -42,7 +42,7 @@ class Float(Integer):
return
if isinstance(self.digits, str):
digits = self._view.model.expr_eval(self.digits)
digits = self.record.expr_eval(self.digits)
else:
digits = self.digits
@@ -8,8 +8,8 @@ import tryton.rpc as rpc
class FloatTime(WidgetInterface):
def __init__(self, window, parent, model, attrs=None):
super(FloatTime, self).__init__(window, parent, model=model,
def __init__(self, field_name, model_name, window, attrs=None):
super(FloatTime, self).__init__(field_name, model_name, window,
attrs=attrs)
self.widget = gtk.HBox()
@@ -33,19 +33,19 @@ class FloatTime(WidgetInterface):
def grab_focus(self):
return self.entry.grab_focus()
def set_value(self, model, model_field):
def set_value(self, record, field):
value = self.entry.get_text()
if not value:
return model_field.set_client(model, 0.0)
return model_field.set_client(model,
return field.set_client(record, 0.0)
return field.set_client(record,
common.text_to_float_time(value, self.conv))
def display(self, model, model_field):
super(FloatTime, self).display(model, model_field)
if not model_field:
def display(self, record, field):
super(FloatTime, self).display(record, field)
if not field:
self.entry.set_text('00:00')
return False
val = model_field.get(model)
val = field.get(record)
self.entry.set_text(common.float_time_to_text(val, self.conv))
@@ -16,8 +16,9 @@ NOIMAGE = file(os.path.join(PIXMAPS_DIR, 'tryton-noimage.png'), 'rb').read()
class Image(WidgetInterface):
def __init__(self, window, parent, model, attrs=None):
super(Image, self).__init__(window, parent, model, attrs=attrs)
def __init__(self, field_name, model_name, window, attrs=None):
super(Image, self).__init__(field_name, model_name, window,
attrs=attrs)
self.height = int(attrs.get('img_height', 100))
self.width = int(attrs.get('img_width', 300))
@@ -96,22 +97,22 @@ class Image(WidgetInterface):
for pat in ("*.png", "*.jpg", "*.gif", "*.tif", "*.xpm"):
filter_image.add_pattern(pat)
filename = file_selection(_('Open...'), parent=self._window,
filename = file_selection(_('Open...'), parent=self.window,
preview=True, filters=[filter_image, filter_all])
if filename:
self._view.modelfield.set_client(self._view.model,
self.field.set_client(self.record,
encodestring(file(filename, 'rb').read()))
self.update_img()
def sig_save_as(self, widget):
filename = file_selection(_('Save As...'), parent=self._window,
filename = file_selection(_('Save As...'), parent=self.window,
action=gtk.FILE_CHOOSER_ACTION_SAVE)
if filename:
file(filename, 'wb').write(decodestring(
self._view.modelfield.get_client(self._view.model)))
self.field.get_client(self.record)))
def sig_remove(self, widget):
self._view.modelfield.set_client(self._view.model, False)
self.field.set_client(self.record, False)
self.update_img()
def drag_motion(self, widget, context, x, y, timestamp):
@@ -127,26 +128,26 @@ class Image(WidgetInterface):
if info == 0:
uri = selection.get_text().split('\n')[0]
if uri:
self._view.modelfield.set_client(self._view.model,
self.field.set_client(self.record,
encodestring(urllib.urlopen(uri).read()))
self.update_img()
elif info == 1:
uri = selection.data.split('\r\n')[0]
if uri:
self._view.modelfield.set_client(self._view.model,
self.field.set_client(self.record,
encodestring(urllib.urlopen(uri).read()))
self.update_img()
elif info == 2:
data = selection.get_pixbuf()
if data:
self._view.modelfield.set_client(self._view.model,
self.field.set_client(self.record,
encodestring(data))
self.update_img()
def update_img(self):
value = None
if self._view:
value = self._view.modelfield.get_client(self._view.model)
if self.field:
value = self.field.get_client(self.record)
if not value:
data = NOIMAGE
else:
@@ -190,8 +191,8 @@ class Image(WidgetInterface):
gtk.gdk.INTERP_BILINEAR)
self.image.set_from_pixbuf(scaled)
def display(self, model, model_field):
if not model_field:
def display(self, record, field):
if not field:
return False
super(Image, self).display(model, model_field)
super(Image, self).display(record, field)
self.update_img()
@@ -7,26 +7,28 @@ import locale
class Integer(Char):
"Integer"
def __init__(self, window, parent, model, attrs=None):
super(Integer, self).__init__(window, parent, model=model, attrs=attrs)
def __init__(self, field_name, model_name, window, attrs=None):
super(Integer, self).__init__(field_name, model_name, window,
attrs=attrs)
self.entry.set_max_length(0)
self.entry.set_alignment(1.0)
self.entry.connect('insert_text', self.sig_insert_text)
def set_value(self, model, model_field):
def set_value(self, record, field):
try:
value = locale.atoi(self.entry.get_text())
except:
value = 0
return model_field.set_client(model, value)
return field.set_client(record, value)
def display(self, model, model_field):
super(Char, self).display(model, model_field)
if not model_field:
def display(self, record, field):
# skip Char call because set_text doesn't work with int
super(Char, self).display(record, field)
if not field:
self.entry.set_text('')
return False
self.entry.set_text(locale.format('%d',
model_field.get(model) or 0, True))
field.get(record) or 0, True))
def display_value(self):
return self.entry.get_text()
@@ -1,7 +1,6 @@
#This file is part of Tryton. The COPYRIGHT file at the top level of
#this repository contains the full copyright notices and license terms.
import gtk
from tryton.rpc import RPCProxy
import tryton.rpc as rpc
from tryton.common import COLORS, process_exception, message
from tryton.config import TRYTON_ICON
@@ -16,7 +15,7 @@ _ATTRS_BOOLEAN = {
'readonly': False
}
def field_pref_set(field, name, model, value, client_value, dependance,
def field_pref_set(field, name, model_name, value, client_value, dependance,
window, reset=False):
dialog = WidgetFieldPreference(window, reset=reset)
if dependance is None:
@@ -60,7 +59,7 @@ def field_pref_set(field, name, model, value, client_value, dependance,
method = 'reset_default'
else:
method = 'set_default'
args = ('model', 'ir.default', method, model, field, clause,
args = ('model', 'ir.default', method, model_name, field, clause,
value, user, rpc.CONTEXT)
try:
rpc.execute(*args)
@@ -72,14 +71,12 @@ def field_pref_set(field, name, model, value, client_value, dependance,
class WidgetInterface(object):
def __init__(self, window, parent=None, model=None, attrs=None):
if attrs is None:
attrs = {}
self.parent = parent
self.model = model
self._window = window
self._view = None
self.attrs = attrs
def __init__(self, field_name, model_name, window, attrs=None):
self.field_name = field_name
self.model_name = model_name
self.window = window
self.view = None # Filled by ViewForm
self.attrs = attrs or {}
for key, val in _ATTRS_BOOLEAN.iteritems():
self.attrs[key] = attrs.get(key, False) not in ('False', '0', False)
self.default_readonly = self.attrs.get('readonly', False)
@@ -96,41 +93,51 @@ class WidgetInterface(object):
self.colors = {}
self.visible = True
def __get_record(self):
return self.view.screen.current_record
record = property(__get_record)
def __get_field(self):
if self.record:
return self.record.group.fields[self.field_name]
field = property(__get_field)
def destroy(self):
pass
def _menu_sig_default_get(self):
if self._view.modelfield.get_state_attrs(self._view.model)\
.get('readonly', False):
if self.field.get_state_attrs(self.record).get('readonly', False):
return False
model = self._view.modelfield.parent.resource
args = ('model', model, 'default_get', [self.attrs['name']])
model_name = self.field.parent.model_name
args = ('model', model_name, 'default_get', [self.attrs['name']])
try:
res = rpc.execute(*args)
except Exception, exception:
process_exception(exception, self._window, *args)
self._view.modelfield.set_default(self._view.model,
process_exception(exception, self.window, *args)
self.field.set_default(self.record,
res.get(self.attrs['name'], False), modified=True)
self.display(self._view.model, self._view.modelfield)
self.display(self.record, self.field)
def _menu_sig_default_set(self, reset=False):
deps = []
for wname, wviews in self._view.view_form.widgets.iteritems():
for wname, wviews in self.view.widgets.iteritems():
for wview in wviews:
if wview.modelfield.attrs.get('change_default', False):
wvalue = wview.modelfield.get(self._view.model)
wvalue = wview.modelfield.get(self.record)
name = wview.modelfield.attrs.get('string', wname)
value = wview.modelfield.get_client(self._view.model)
value = wview.modelfield.get_client(self.record)
deps.append((wname, name, wvalue, value))
if not self._view.modelfield.validate(self._view.model):
message(_('Invalid field!'), parent=self._window)
if not self.field.validate(self.record):
message(_('Invalid field!'), parent=self.window)
return
value = self._view.modelfield.get_default(self._view.model)
value = self.field.get_default(self.record)
client_value = self.display_value()
model = self._view.modelfield.parent.resource
field_pref_set(self._view.widget_name,
self.attrs.get('string', self._view.widget_name), model,
value, client_value, deps, self._window, reset=reset)
model_name = self.field.parent.model_name
field_pref_set(self.field_name,
self.attrs.get('string', self.field_name), model_name,
value, client_value, deps, self.window, reset=reset)
def sig_activate(self, widget=None):
# emulate a focus_out so that the onchange is called if needed
@@ -205,7 +212,7 @@ class WidgetInterface(object):
widget.show()
def display_value(self):
return self._view.modelfield.get_client(self._view.model)
return self.field.get_client(self.record)
def _menu_open(self, obj, event):
if event.button == 3:
@@ -243,30 +250,30 @@ class WidgetInterface(object):
pass
def _focus_out(self):
if not self._view.modelfield:
if not self.field:
return False
if not self.visible:
return False
self.set_value(self._view.model, self._view.modelfield)
self.set_value(self.record, self.field)
def display(self, model, modelfield):
if not modelfield:
def display(self, record, field):
if not field:
self._readonly_set(self.attrs.get('readonly', False))
return
self._readonly_set(modelfield.get_state_attrs(model).\
self._readonly_set(field.get_state_attrs(record).\
get('readonly', False))
if modelfield.get_state_attrs(model).get('readonly', False):
if field.get_state_attrs(record).get('readonly', False):
self.color_set('readonly')
elif not modelfield.get_state_attrs(model).get('valid', True):
elif not field.get_state_attrs(record).get('valid', True):
self.color_set('invalid')
elif modelfield.get_state_attrs(model).get('required', False):
elif field.get_state_attrs(record).get('required', False):
self.color_set('required')
else:
self.color_set('normal')
self.invisible_set(modelfield.get_state_attrs(model).\
self.invisible_set(field.get_state_attrs(record).\
get('invisible', False))
def set_value(self, model, model_field):
def set_value(self, record, field):
pass
def cancel(self):
@@ -3,9 +3,9 @@
import gtk
from tryton.gui.window.view_form.screen import Screen
from interface import WidgetInterface
from one2many import Dialog
import tryton.rpc as rpc
from tryton.gui.window.win_search import WinSearch
from tryton.gui.window.win_form import WinForm
from tryton.gui.window.view_form.widget_search.form import _LIMIT
import tryton.common as common
import gettext
@@ -15,8 +15,9 @@ _ = gettext.gettext
class Many2Many(WidgetInterface):
def __init__(self, window, parent, model, attrs=None):
super(Many2Many, self).__init__(window, parent, model, attrs)
def __init__(self, field_name, model_name, window, attrs=None):
super(Many2Many, self).__init__(field_name, model_name, window,
attrs=attrs)
self.widget = gtk.VBox(homogeneous=False, spacing=5)
@@ -59,7 +60,7 @@ class Many2Many(WidgetInterface):
hbox.set_focus_chain([self.wid_text])
self.screen = Screen(attrs['relation'], self._window,
self.screen = Screen(attrs['relation'], self.window,
view_type=['tree'], views_preload=attrs.get('views', {}),
row_activate=self._on_activate)
@@ -89,8 +90,8 @@ class Many2Many(WidgetInterface):
del self.widget
def _sig_add(self, *args):
domain = self._view.modelfield.domain_get(self._view.model)
context = self._view.modelfield.context_get(self._view.model)
domain = self.field.domain_get(self.record)
context = self.field.context_get(self.record)
value = self.wid_text.get_text()
try:
@@ -101,11 +102,11 @@ class Many2Many(WidgetInterface):
ids = rpc.execute('model', self.attrs['relation'], 'search',
dom , 0, _LIMIT, None, context)
except Exception, exception:
common.process_exception(exception, self._window)
common.process_exception(exception, self.window)
return False
if len(ids) != 1 or not value:
win = WinSearch(self.attrs['relation'], sel_multi=True, ids=ids,
context=context, domain=domain, parent=self._window,
context=context, domain=domain, parent=self.window,
views_preload=self.attrs.get('views', {}))
ids = win.run()
@@ -129,22 +130,11 @@ class Many2Many(WidgetInterface):
self._sig_edit()
def _sig_edit(self):
if self.screen.current_model:
readonly = False
domain = []
if self._view.modelfield and self._view.model:
modelfield = self._view.modelfield
model = self._view.model
readonly = modelfield.get_state_attrs(model
).get('readonly', False)
domain = modelfield.domain_get(self._view.model)
dia = Dialog(self.attrs['relation'], parent=self._view.model,
model=self.screen.current_model, attrs=self.attrs,
window=self._window, readonly=readonly, domain=domain)
res, record = dia.run()
if res:
record.save()
dia.destroy()
if self.screen.current_record:
win = WinForm(self.screen, self.window)
if win.run():
self.screen.current_record.save()
win.destroy()
def _readonly_set(self, value):
super(Many2Many, self)._readonly_set(value)
@@ -153,20 +143,20 @@ class Many2Many(WidgetInterface):
self.wid_but_remove.set_sensitive(not value)
self.wid_but_add.set_sensitive(not value)
def display(self, model, model_field):
if not model_field:
self.screen.current_model = None
def display(self, record, field):
if field is None:
self.screen.current_record = None
self.screen.display()
return False
super(Many2Many, self).display(model, model_field)
new_models = model_field.get_client(model)
if self.screen.models != new_models:
self.screen.models_set(new_models)
super(Many2Many, self).display(record, field)
new_group = field.get_client(record)
if id(self.screen.group) != id(new_group):
self.screen.group = new_group
self.screen.display()
return True
def display_value(self):
ids = self._view.modelfield.get_default(self._view.model)
ids = self.field.get_default(self.record)
try:
result = rpc.execute('model', self.attrs['relation'], 'read',
ids, ['rec_name'], rpc.CONTEXT)
@@ -174,6 +164,6 @@ class Many2Many(WidgetInterface):
return str(ids)
return ', '.join(x['rec_name'] for x in result)
def set_value(self, model, model_field):
def set_value(self, record, field):
self.screen.current_view.set_value()
return True
@@ -8,7 +8,7 @@ from tryton.common import TRYTON_ICON, COLOR_SCHEMES
import tryton.common as common
from tryton.gui.window.view_form.screen import Screen
from tryton.gui.window.win_search import WinSearch
from tryton.rpc import RPCProxy
from tryton.gui.window.win_form import WinForm
import tryton.rpc as rpc
from tryton.action import Action
from tryton.gui.window.view_form.widget_search.form import _LIMIT
@@ -18,151 +18,11 @@ import pango
_ = gettext.gettext
class Dialog(object):
def __init__(self, model, obj_id=None, attrs=None, domain=None,
context=None, window=None):
if attrs is None:
attrs = {}
self.dia = gtk.Dialog(_('Link'), window,
gtk.DIALOG_MODAL|gtk.DIALOG_DESTROY_WITH_PARENT)
self.window = window
if ('string' in attrs) and attrs['string']:
self.dia.set_title(attrs['string'])
self.dia.set_property('default-width', 760)
self.dia.set_property('default-height', 500)
self.dia.set_position(gtk.WIN_POS_CENTER_ON_PARENT)
self.dia.set_icon(TRYTON_ICON)
self.dia.set_has_separator(False)
self.accel_group = gtk.AccelGroup()
self.dia.add_accel_group(self.accel_group)
icon_cancel = gtk.STOCK_CLOSE
if not obj_id:
icon_cancel = gtk.STOCK_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,
gtk.keysyms.Return, gtk.gdk.CONTROL_MASK, gtk.ACCEL_VISIBLE)
self.dia.set_default_response(gtk.RESPONSE_OK)
self.dia.show()
self.screen = Screen(model, self.dia, domain=domain, context=context,
view_type=['form'], views_preload=attrs.get('views', {}))
if obj_id:
self.screen.load([obj_id])
else:
self.screen.new()
name = attrs.get('string', '')
if name:
name += ' - '
name += self.screen.current_view.title
self.dia.set_title(name)
title = gtk.Label()
title.set_use_markup(True)
title.modify_font(pango.FontDescription("12"))
title.set_label('<b>' + name + '</b>')
title.set_padding(20, 3)
title.set_alignment(0.0, 0.5)
title.modify_fg(gtk.STATE_NORMAL, gtk.gdk.color_parse("#000000"))
title.show()
self.info_label = gtk.Label()
self.info_label.set_padding(3, 3)
self.info_label.set_alignment(1.0, 0.5)
self.eb_info = gtk.EventBox()
self.eb_info.add(self.info_label)
self.eb_info.connect('button-release-event',
lambda *a: self.message_info(''))
vbox = gtk.VBox()
vbox.pack_start(self.eb_info, expand=True, fill=True, padding=5)
vbox.show()
hbox = gtk.HBox()
hbox.pack_start(title, expand=True, fill=True)
hbox.pack_start(vbox, expand=False, fill=True, padding=20)
hbox.show()
frame = gtk.Frame()
frame.set_shadow_type(gtk.SHADOW_ETCHED_IN)
frame.add(hbox)
frame.show()
eb = gtk.EventBox()
eb.add(frame)
eb.modify_bg(gtk.STATE_NORMAL, gtk.gdk.color_parse("#ffffff"))
eb.show()
self.dia.vbox.pack_start(eb, expand=False, fill=True, padding=3)
scroll = gtk.ScrolledWindow()
scroll.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
scroll.set_placement(gtk.CORNER_TOP_LEFT)
scroll.set_shadow_type(gtk.SHADOW_NONE)
scroll.show()
self.dia.vbox.pack_start(scroll, expand=True, fill=True)
viewport = gtk.Viewport()
viewport.set_shadow_type(gtk.SHADOW_NONE)
viewport.show()
scroll.add(viewport)
self.screen.widget.show()
viewport.add(self.screen.widget)
i, j = self.screen.screen_container.size_get()
viewport.set_size_request(i, j + 30)
self.dia.show()
self.screen.current_view.set_cursor()
self.screen.display()
def message_info(self, message, color='red'):
if message:
self.info_label.set_label(message)
self.eb_info.modify_bg(gtk.STATE_NORMAL, gtk.gdk.color_parse(
COLOR_SCHEMES.get(color, 'white')))
self.eb_info.show_all()
else:
self.info_label.set_label('')
self.eb_info.hide()
def run(self):
while True:
res = self.dia.run()
if res == gtk.RESPONSE_OK:
obj_id = None
try:
obj_id = self.screen.save_current()
except Exception, exception:
common.process_exception(exception, self.dia)
if obj_id:
return (True, (self.screen.current_model.id,
self.screen.current_model.rec_name()))
else:
self.screen.display()
else:
break
return (False, False)
def destroy(self):
self.window.present()
self.screen.destroy()
self.dia.destroy()
class Many2One(WidgetInterface):
def __init__(self, window, parent, model, attrs=None):
if attrs is None:
attrs = {}
WidgetInterface.__init__(self, window, parent, model, attrs)
def __init__(self, field_name, model_name, window, attrs=None):
super(Many2One, self).__init__(field_name, model_name, window,
attrs=attrs)
self.widget = gtk.HBox(spacing=0)
self.widget.set_property('sensitive', True)
@@ -208,7 +68,6 @@ class Many2One(WidgetInterface):
self.tooltips.enable()
self._readonly = False
self.model_type = attrs['relation']
self.completion = gtk.EntryCompletion()
self.liststore = gtk.ListStore(gobject.TYPE_STRING, gobject.TYPE_STRING)
@@ -219,7 +78,7 @@ class Many2One(WidgetInterface):
['rec_name'])
names = [(x['id'], x['rec_name']) for x in result]
except Exception, exception:
common.process_exception(exception, self._window)
common.process_exception(exception, self.window)
names = []
if names:
self.load_completion(names)
@@ -227,12 +86,6 @@ class Many2One(WidgetInterface):
def grab_focus(self):
return self.wid_text.grab_focus()
def _focus_out(self):
return WidgetInterface._focus_out(self)
def _focus_in(self):
return WidgetInterface._focus_in(self)
def load_completion(self, names):
self.completion.set_match_func(self.match_func, None)
self.completion.connect("match-selected", self.on_completion_match)
@@ -248,8 +101,8 @@ class Many2One(WidgetInterface):
return modelstr.startswith(key_string)
def on_completion_match(self, completion, model, iter):
self._view.modelfield.set_client(self._view.model, int(model[iter][0]))
self.display(self._view.model, self._view.modelfield)
self.field.set_client(self.record, int(model[iter][0]))
self.display(self.record, self.field)
return True
def _readonly_set(self, value):
@@ -267,19 +120,19 @@ class Many2One(WidgetInterface):
def sig_activate(self, widget, event=None, key_press=False):
if not self.focus_out:
return
if not self._view.modelfield:
if not self.field:
return
self.changed = False
value = self._view.modelfield.get(self._view.model)
value = self.field.get(self.record)
self.focus_out = False
if not value:
if not self._readonly and (self.wid_text.get_text() or \
(self._view.modelfield.get_state_attrs(
self._view.model)['required']) and key_press):
domain = self._view.modelfield.domain_get(self._view.model)
(self.field.get_state_attrs(
self.record)['required']) and key_press):
domain = self.field.domain_get(self.record)
context = rpc.CONTEXT.copy()
context.update(self._view.modelfield.context_get(self._view.model))
context.update(self.field.context_get(self.record))
self.wid_text.grab_focus()
try:
@@ -293,70 +146,80 @@ class Many2One(WidgetInterface):
'search', dom, 0, _LIMIT, None, context)
except Exception, exception:
self.focus_out = True
common.process_exception(exception, self._window)
common.process_exception(exception, self.window)
self.changed = True
return False
if len(ids)==1:
self._view.modelfield.set_client(self._view.model, ids[0],
self.field.set_client(self.record, ids[0],
force_change=True)
self.focus_out = True
self.display(self._view.model, self._view.modelfield)
self.display(self.record, self.field)
return True
win = WinSearch(self.attrs['relation'], sel_multi=False,
ids=ids, context=context, domain=domain,
parent=self._window,
parent=self.window,
views_preload=self.attrs.get('views', {}))
ids = win.run()
if ids:
self._view.modelfield.set_client(self._view.model, ids[0],
self.field.set_client(self.record, ids[0],
force_change=True)
self.focus_out = True
self.display(self._view.model, self._view.modelfield)
self.display(self.record, self.field)
return True
else:
self.focus_out = True
self.display(self._view.model, self._view.modelfield)
self.display(self.record, self.field)
return False
self.focus_out = True
self.display(self._view.model, self._view.modelfield)
self.display(self.record, self.field)
self.changed = True
return True
def get_screen(self):
domain = self.field.domain_get(self.record)
context = self.field.context_get(self.record)
return Screen(self.attrs['relation'], self.window, domain=domain,
context=context, view_type=['form'],
views_preload=self.attrs.get('views', {}))
def sig_new(self, *args):
self.focus_out = False
domain = self._view.modelfield.domain_get(self._view.model)
context = self._view.modelfield.context_get(self._view.model)
dia = Dialog(self.attrs['relation'], attrs=self.attrs,
window=self._window, domain=domain, context=context)
res, value = dia.run()
if res:
self._view.modelfield.set_client(self._view.model, value)
self.display(self._view.model, self._view.modelfield)
dia.destroy()
screen = self.get_screen()
win = WinForm(screen, self.window, new=True)
while win.run():
if screen.save_current():
value = (screen.current_record.id,
screen.current_record.rec_name())
self.field.set_client(self.record, value)
break
else:
screen.display()
win.destroy()
self.focus_out = True
def sig_edit(self, widget):
self.changed = False
value = self._view.modelfield.get(self._view.model)
value = self.field.get(self.record)
self.focus_out = False
if value:
domain = self._view.modelfield.domain_get(self._view.model)
context = self._view.modelfield.context_get(self._view.model)
dia = Dialog(self.attrs['relation'],
self._view.modelfield.get(self._view.model),
attrs=self.attrs, window=self._window, domain=domain,
context=context)
res, value = dia.run()
if res:
self._view.modelfield.set_client(self._view.model, value,
force_change=True)
dia.destroy()
screen = self.get_screen()
screen.load([self.field.get(self.record)])
win = WinForm(screen, self.window)
while win.run():
if screen.save_current():
value = (screen.current_record.id,
screen.current_record.rec_name())
self.field.set_client(self.record, value, force_change=True)
break
else:
screen.display()
win.destroy()
else:
if not self._readonly:
domain = self._view.modelfield.domain_get(self._view.model)
domain = self.field.domain_get(self.record)
context = rpc.CONTEXT.copy()
context.update(self._view.modelfield.context_get(self._view.model))
context.update(self.field.context_get(self.record))
self.wid_text.grab_focus()
try:
@@ -370,26 +233,26 @@ class Many2One(WidgetInterface):
'search', dom, 0, _LIMIT, None, context)
except Exception, exception:
self.focus_out = True
common.process_exception(exception, self._window)
common.process_exception(exception, self.window)
self.changed = True
return False
if ids and len(ids)==1:
self._view.modelfield.set_client(self._view.model, ids[0],
self.field.set_client(self.record, ids[0],
force_change=True)
self.focus_out = True
self.display(self._view.model, self._view.modelfield)
self.display(self.record, self.field)
return True
win = WinSearch(self.attrs['relation'], sel_multi=False,
ids=ids, context=context,
domain=domain, parent=self._window,
domain=domain, parent=self.window,
views_preload=self.attrs.get('views', {}))
ids = win.run()
if ids:
self._view.modelfield.set_client(self._view.model, ids[0],
self.field.set_client(self.record, ids[0],
force_change=True)
self.focus_out = True
self.display(self._view.model, self._view.modelfield)
self.display(self.record, self.field)
self.changed = True
def sig_key_press(self, widget, event, *args):
@@ -407,22 +270,22 @@ class Many2One(WidgetInterface):
def sig_changed(self, *args):
if not self.changed:
return False
if self._view.modelfield.get(self._view.model):
self._view.modelfield.set_client(self._view.model, False)
self.display(self._view.model, self._view.modelfield)
if self.field.get(self.record):
self.field.set_client(self.record, False)
self.display(self.record, self.field)
return False
def set_value(self, model, model_field):
def set_value(self, record, field):
pass # No update of the model, the model is updated in real time !
def display(self, model, model_field):
def display(self, record, field):
self.changed = False
if not model_field:
if not field:
self.wid_text.set_text('')
self.changed = True
return False
WidgetInterface.display(self, model, model_field)
res = model_field.get_client(model)
super(Many2One, self).display(record, field)
res = field.get_client(record)
self.wid_text.set_text((res and str(res)) or '')
img = gtk.Image()
if res:
@@ -436,10 +299,15 @@ class Many2One(WidgetInterface):
self.changed = True
def _populate_popup(self, widget, menu):
value = self._view.modelfield.get(self._view.model)
ir_action_keyword = RPCProxy('ir.action.keyword')
relates = ir_action_keyword.get_keyword('form_relate',
(self.model_type, 0), rpc.CONTEXT)
value = self.field.get(self.record)
args = ('model', 'ir.action.keyword', 'get_keyword',
'form_relate', (self.attrs['relation'], 0), rpc.CONTEXT)
try:
relates = rpc.execute(*args)
except Exception, exception:
relates = common.process_exception(exception, self.window)
if not relates:
return False
menu_entries = []
menu_entries.append((None, None, None))
menu_entries += self._menu_entries
@@ -471,27 +339,27 @@ class Many2One(WidgetInterface):
data = {}
context = {}
act = action.copy()
obj_id = self._view.modelfield.get(self._view.model)
obj_id = self.field.get(self.record)
if not obj_id:
common.message(_('You must select a record to use the relation!'),
self._window)
self.window)
return False
screen = Screen(self.attrs['relation'], self._window)
screen = Screen(self.attrs['relation'], self.window)
screen.load([obj_id])
encoder = PYSONEncoder()
act['domain'] = encoder.encode(screen.current_model.expr_eval(
act['domain'] = encoder.encode(screen.current_record.expr_eval(
act.get('domain', []), check_load=False))
act['context'] = encoder.encode(screen.current_model.expr_eval(
act['context'] = encoder.encode(screen.current_record.expr_eval(
act.get('context', {}), check_load=False))
data['model'] = self.model_type
data['model'] = self.attrs['relation']
data['id'] = obj_id
data['ids'] = [obj_id]
return Action._exec_action(act, self._window, data, context)
return Action._exec_action(act, self.window, data, context)
def click_and_action(self, atype):
obj_id = self._view.modelfield.get(self._view.model)
return Action.exec_keyword(atype, self._window, {
'model': self.model_type,
obj_id = self.field.get(self.record)
return Action.exec_keyword(atype, self.window, {
'model': self.attrs['relation'],
'id': obj_id or False,
'ids': [obj_id],
}, alwaysask=True)
@@ -5,8 +5,9 @@ import gettext
from tryton.common import TRYTON_ICON, COLOR_SCHEMES
from interface import WidgetInterface
from tryton.gui.window.view_form.screen import Screen
from tryton.gui.window.view_form.model.group import ModelRecordGroup
from tryton.gui.window.view_form.model.group import Group
from tryton.gui.window.win_search import WinSearch
from tryton.gui.window.win_form import WinForm
from tryton.gui.window.view_form.widget_search.form import _LIMIT
import tryton.common as common
import tryton.rpc as rpc
@@ -14,462 +15,153 @@ import pango
_ = gettext.gettext
def _create_menu(self, attrs):
hbox = gtk.HBox(homogeneous=False, spacing=0)
menubar = gtk.MenuBar()
if hasattr(menubar, 'set_pack_direction') and \
hasattr(menubar, 'set_child_pack_direction'):
menubar.set_pack_direction(gtk.PACK_DIRECTION_LTR)
menubar.set_child_pack_direction(gtk.PACK_DIRECTION_LTR)
menuitem_title = gtk.ImageMenuItem(stock_id='tryton-preferences')
menu_title = gtk.Menu()
menuitem_set_to_default = gtk.MenuItem(_('Set to default value'), True)
menuitem_set_to_default.connect('activate',
lambda *x: self._menu_sig_default_get())
menu_title.add(menuitem_set_to_default)
menuitem_set_default = gtk.MenuItem(_('Set as default'), True)
menuitem_set_default.connect('activate',
lambda *x: self._menu_sig_default_set())
menu_title.add(menuitem_set_default)
menuitem_reset_default = gtk.MenuItem(_('Reset default'), True)
menuitem_reset_default.connect('activate',
lambda *x: self._menu_sig_default_set(reset=True))
menu_title.add(menuitem_reset_default)
menuitem_title.set_submenu(menu_title)
menubar.add(menuitem_title)
hbox.pack_start(menubar, expand=True, fill=True)
tooltips = common.Tooltips()
if attrs.get('add_remove'):
self.wid_text = gtk.Entry()
self.wid_text.set_property('width_chars', 13)
self.wid_text.connect('activate', self._sig_activate)
hbox.pack_start(self.wid_text, expand=True, fill=True)
self.but_add = gtk.Button()
tooltips.set_tip(self.but_add, _('Add'))
self.but_add.connect('clicked', self._sig_add)
img_add = gtk.Image()
img_add.set_from_stock('tryton-list-add', gtk.ICON_SIZE_SMALL_TOOLBAR)
img_add.set_alignment(0.5, 0.5)
self.but_add.add(img_add)
self.but_add.set_relief(gtk.RELIEF_NONE)
hbox.pack_start(self.but_add, expand=False, fill=False)
self.but_remove = gtk.Button()
tooltips.set_tip(self.but_remove, _('Remove'))
self.but_remove.connect('clicked', self._sig_remove, True)
img_remove = gtk.Image()
img_remove.set_from_stock('tryton-list-remove', gtk.ICON_SIZE_SMALL_TOOLBAR)
img_remove.set_alignment(0.5, 0.5)
self.but_remove.add(img_remove)
self.but_remove.set_relief(gtk.RELIEF_NONE)
hbox.pack_start(self.but_remove, expand=False, fill=False)
hbox.pack_start(gtk.VSeparator(), expand=False, fill=True)
self.but_new = gtk.Button()
tooltips.set_tip(self.but_new, _('Create a new record'))
self.but_new.connect('clicked', self._sig_new)
img_new = gtk.Image()
img_new.set_from_stock('tryton-new', gtk.ICON_SIZE_SMALL_TOOLBAR)
img_new.set_alignment(0.5, 0.5)
self.but_new.add(img_new)
self.but_new.set_relief(gtk.RELIEF_NONE)
hbox.pack_start(self.but_new, expand=False, fill=False)
self.but_open = gtk.Button()
tooltips.set_tip(self.but_open, _('Edit selected record'))
self.but_open.connect('clicked', self._sig_edit)
img_open = gtk.Image()
img_open.set_from_stock('tryton-open', gtk.ICON_SIZE_SMALL_TOOLBAR)
img_open.set_alignment(0.5, 0.5)
self.but_open.add(img_open)
self.but_open.set_relief(gtk.RELIEF_NONE)
hbox.pack_start(self.but_open, expand=False, fill=False)
self.but_del = gtk.Button()
tooltips.set_tip(self.but_del, _('Delete selected record'))
self.but_del.connect('clicked', self._sig_remove)
img_del = gtk.Image()
img_del.set_from_stock('tryton-delete', gtk.ICON_SIZE_SMALL_TOOLBAR)
img_del.set_alignment(0.5, 0.5)
self.but_del.add(img_del)
self.but_del.set_relief(gtk.RELIEF_NONE)
hbox.pack_start(self.but_del, expand=False, fill=False)
hbox.pack_start(gtk.VSeparator(), expand=False, fill=True)
but_pre = gtk.Button()
tooltips.set_tip(but_pre, _('Previous'))
but_pre.connect('clicked', self._sig_previous)
img_pre = gtk.Image()
img_pre.set_from_stock('tryton-go-previous', gtk.ICON_SIZE_SMALL_TOOLBAR)
img_pre.set_alignment(0.5, 0.5)
but_pre.add(img_pre)
but_pre.set_relief(gtk.RELIEF_NONE)
hbox.pack_start(but_pre, expand=False, fill=False)
self.label = gtk.Label('(0,0)')
hbox.pack_start(self.label, expand=False, fill=False)
but_next = gtk.Button()
tooltips.set_tip(but_next, _('Next'))
but_next.connect('clicked', self._sig_next)
img_next = gtk.Image()
img_next.set_from_stock('tryton-go-next', gtk.ICON_SIZE_SMALL_TOOLBAR)
img_next.set_alignment(0.5, 0.5)
but_next.add(img_next)
but_next.set_relief(gtk.RELIEF_NONE)
hbox.pack_start(but_next, expand=False, fill=False)
hbox.pack_start(gtk.VSeparator(), expand=False, fill=True)
but_switch = gtk.Button()
tooltips.set_tip(but_switch, _('Switch'))
but_switch.connect('clicked', self.switch_view)
img_switch = gtk.Image()
img_switch.set_from_stock('tryton-fullscreen', gtk.ICON_SIZE_SMALL_TOOLBAR)
img_switch.set_alignment(0.5, 0.5)
but_switch.add(img_switch)
but_switch.set_relief(gtk.RELIEF_NONE)
hbox.pack_start(but_switch, expand=False, fill=False)
if attrs.get('add_remove'):
hbox.set_focus_chain([self.wid_text])
else:
hbox.set_focus_chain([])
tooltips.enable()
return hbox, menuitem_title
class Dialog(object):
def __init__(self, model_name, parent, model=None, attrs=None,
model_ctx=None, window=None, default_get_ctx=None, readonly=False,
domain=None):
if attrs is None:
attrs = {}
if model_ctx is None:
model_ctx = {}
if default_get_ctx is None:
default_get_ctx = {}
self.attrs = attrs
self.model_name = model_name
self.parent=parent
self.model_ctx = model_ctx
self.default_get_ctx = default_get_ctx
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)
self.dia.set_position(gtk.WIN_POS_CENTER_ON_PARENT)
self.dia.set_icon(TRYTON_ICON)
self.dia.set_has_separator(False)
self.accel_group = gtk.AccelGroup()
self.dia.add_accel_group(self.accel_group)
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_ok = self.dia.add_button(gtk.STOCK_OK, gtk.RESPONSE_OK)
self.but_ok.add_accelerator('clicked', self.accel_group,
gtk.keysyms.Return, gtk.gdk.CONTROL_MASK, gtk.ACCEL_VISIBLE)
self.dia.set_default_response(gtk.RESPONSE_OK)
self.default_get_ctx = default_get_ctx
menuitem_title = None
if isinstance(model, ModelRecordGroup):
hbox, menuitem_title = _create_menu(self, attrs)
self.dia.vbox.pack_start(hbox, expand=False, fill=True)
self.dia.show()
self.screen = Screen(model_name, self.dia, view_type=[], parent=parent,
parent_name=attrs.get('relation_field', ''),
exclude_field=attrs.get('relation_field', None), readonly=readonly,
domain=domain)
self.screen.models._context.update(model_ctx)
modified = False
if not model:
model = self.screen.new(context=default_get_ctx)
modified = True
if isinstance(model, ModelRecordGroup):
self.screen.tree_saves = False
self.screen.add_view_id(False, 'tree', display=True,
context=default_get_ctx)
self.screen.add_view_id(False, 'form', display=False,
context=default_get_ctx)
self.screen.signal_connect(self, 'record-message', self._sig_label)
self.screen.widget.connect('key_press_event', self.on_keypress)
self.screen.models_set(model)
else:
self.screen.models.model_add(model, modified=modified)
self.screen.current_model = model
if ('views' in attrs) and ('form' in attrs['views']):
arch = attrs['views']['form']['arch']
fields = attrs['views']['form']['fields']
if attrs.get('relation_field', False) \
and attrs['relation_field'] in fields:
del fields[attrs['relation_field']]
self.screen.add_view(arch, fields, display=True,
context=default_get_ctx)
else:
self.screen.add_view_id(False, 'form', display=True,
context=default_get_ctx)
name = self.screen.current_view.title
self.dia.set_title(name)
if menuitem_title:
menuitem_title.get_child().set_text(name)
title = gtk.Label()
title.set_use_markup(True)
title.modify_font(pango.FontDescription("12"))
title.set_label('<b>' + name + '</b>')
title.set_padding(20, 3)
title.set_alignment(0.0, 0.5)
title.modify_fg(gtk.STATE_NORMAL, gtk.gdk.color_parse("#000000"))
title.show()
self.info_label = gtk.Label()
self.info_label.set_padding(3, 3)
self.info_label.set_alignment(1.0, 0.5)
self.eb_info = gtk.EventBox()
self.eb_info.add(self.info_label)
self.eb_info.connect('button-release-event',
lambda *a: self.message_info(''))
vbox = gtk.VBox()
vbox.pack_start(self.eb_info, expand=True, fill=True, padding=5)
vbox.show()
hbox = gtk.HBox()
hbox.pack_start(title, expand=True, fill=True)
hbox.pack_start(vbox, expand=False, fill=True, padding=20)
hbox.show()
frame = gtk.Frame()
frame.set_shadow_type(gtk.SHADOW_ETCHED_IN)
frame.add(hbox)
frame.show()
eb = gtk.EventBox()
eb.add(frame)
eb.modify_bg(gtk.STATE_NORMAL, gtk.gdk.color_parse("#ffffff"))
eb.show()
self.dia.vbox.pack_start(eb, expand=False, fill=True, padding=3)
scroll = gtk.ScrolledWindow()
scroll.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
scroll.set_placement(gtk.CORNER_TOP_LEFT)
scroll.set_shadow_type(gtk.SHADOW_NONE)
scroll.show()
self.dia.vbox.pack_start(scroll, expand=True, fill=True)
viewport = gtk.Viewport()
viewport.set_shadow_type(gtk.SHADOW_NONE)
viewport.show()
scroll.add(viewport)
self.screen.widget.show()
viewport.add(self.screen.widget)
width, height = self.screen.screen_container.size_get()
viewport.set_size_request(width, height + 30)
self.screen.display()
self.screen.current_view.set_cursor()
def message_info(self, message, color='red'):
if message:
self.info_label.set_label(message)
self.eb_info.modify_bg(gtk.STATE_NORMAL, gtk.gdk.color_parse(
COLOR_SCHEMES.get(color, 'white')))
self.eb_info.show_all()
else:
self.info_label.set_label('')
self.eb_info.hide()
def on_keypress(self, widget, event):
if (event.keyval == gtk.keysyms.F3) \
and self.but_new.get_property('sensitive'):
self._sig_new(widget)
return False
if event.keyval == gtk.keysyms.F2 \
and widget == self.screen.widget:
self._sig_edit(widget)
return False
if event.keyval in (gtk.keysyms.Delete, gtk.keysyms.KP_Delete) \
and widget == self.screen.widget:
self._sig_remove(widget)
return False
def switch_view(self, widget):
self.screen.switch_view()
def _sig_new(self, widget):
if (self.screen.current_view.view_type == 'form') \
or self.screen.editable_get():
self.screen.new(context=self.default_get_ctx)
self.screen.current_view.widget.set_sensitive(True)
else:
dia = Dialog(self.model_name, parent=self.parent,
attrs=self.attrs, model_ctx=self.model_ctx,
default_get_ctx=self.default_get_ctx,
window=self.window)
res = True
while res:
res, value = dia.run()
if res:
self.screen.models.model_add(value)
value.signal('record-changed', value.parent)
self.screen.display()
dia.new()
dia.destroy()
def _sig_edit(self, widget=None):
if self.screen.current_model:
dia = Dialog(self.model_name, parent=self.parent,
model=self.screen.current_model, attrs=self.attrs,
window=self.window)
res, value = dia.run()
dia.destroy()
def _sig_next(self, widget):
self.screen.display_next()
def _sig_previous(self, widget):
self.screen.display_prev()
def _sig_remove(self, widget, remove=False):
self.screen.remove(remove=remove)
def _sig_activate(self, *args):
self._sig_add()
self.wid_text.grab_focus()
def _sig_add(self, *args):
domain = []
context = rpc.CONTEXT.copy()
try:
if self.wid_text.get_text():
dom = [('rec_name', 'ilike',
'%' + self.wid_text.get_text() + '%'), domain]
else:
dom = domain
ids = rpc.execute('model', self.attrs['relation'],
'search', dom, 0, _LIMIT, None, context)
except Exception, exception:
common.process_exception(exception, self._window)
return False
if len(ids) != 1:
win = WinSearch(self.attrs['relation'], sel_multi=True, ids=ids,
context=context, domain=domain, parent=self._window,
views_preload=self.attrs.get('views', {}))
ids = win.run()
res_id = None
if ids:
res_id = ids[0]
self.screen.load(ids, modified=True)
self.screen.display(res_id=res_id)
if self.screen.current_view:
self.screen.current_view.set_cursor()
self.wid_text.set_text('')
def _sig_label(self, screen, signal_data):
name = '_'
if signal_data[0] >= 0:
name = str(signal_data[0] + 1)
line = '(%s/%s)' % (name, signal_data[1])
self.label.set_text(line)
def _menu_sig_default_get(self):
pass
def _menu_sig_default_set(self, reset=False):
pass
def new(self):
model = self.screen.new(context=self.default_get_ctx)
self.screen.models.model_add(model)
return True
def run(self):
end = False
while not end:
res = self.dia.run()
self.screen.current_view.set_value()
end = (res != gtk.RESPONSE_OK) \
or (not self.screen.current_model \
or self.screen.current_model.validate())
if not end:
self.screen.current_view.set_cursor()
self.screen.display()
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):
if self.screen.current_view:
self.screen.current_view.set_value()
if not self.but_cancel \
and self.screen.current_model \
and not self.screen.current_model.validate():
if self.screen.current_view:
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()
self.dia.destroy()
self.screen.destroy()
class One2Many(WidgetInterface):
def __init__(self, window, parent, model, attrs=None):
super(One2Many, self).__init__(window, parent, model, attrs)
def __init__(self, field_name, model_name, window, attrs=None):
super(One2Many, self).__init__(field_name, model_name, window,
attrs=attrs)
self.widget = gtk.VBox(homogeneous=False, spacing=5)
hbox, menuitem_title = _create_menu(self, attrs)
hbox = gtk.HBox(homogeneous=False, spacing=0)
menubar = gtk.MenuBar()
if hasattr(menubar, 'set_pack_direction') and \
hasattr(menubar, 'set_child_pack_direction'):
menubar.set_pack_direction(gtk.PACK_DIRECTION_LTR)
menubar.set_child_pack_direction(gtk.PACK_DIRECTION_LTR)
menuitem_title = gtk.ImageMenuItem(stock_id='tryton-preferences')
menu_title = gtk.Menu()
menuitem_set_to_default = gtk.MenuItem(_('Set to default value'), True)
menuitem_set_to_default.connect('activate',
lambda *x: self._menu_sig_default_get())
menu_title.add(menuitem_set_to_default)
menuitem_set_default = gtk.MenuItem(_('Set as default'), True)
menuitem_set_default.connect('activate',
lambda *x: self._menu_sig_default_set())
menu_title.add(menuitem_set_default)
menuitem_reset_default = gtk.MenuItem(_('Reset default'), True)
menuitem_reset_default.connect('activate',
lambda *x: self._menu_sig_default_set(reset=True))
menu_title.add(menuitem_reset_default)
menuitem_title.set_submenu(menu_title)
menubar.add(menuitem_title)
hbox.pack_start(menubar, expand=True, fill=True)
tooltips = common.Tooltips()
if attrs.get('add_remove'):
self.wid_text = gtk.Entry()
self.wid_text.set_property('width_chars', 13)
self.wid_text.connect('activate', self._sig_activate)
hbox.pack_start(self.wid_text, expand=True, fill=True)
self.but_add = gtk.Button()
tooltips.set_tip(self.but_add, _('Add'))
self.but_add.connect('clicked', self._sig_add)
img_add = gtk.Image()
img_add.set_from_stock('tryton-list-add', gtk.ICON_SIZE_SMALL_TOOLBAR)
img_add.set_alignment(0.5, 0.5)
self.but_add.add(img_add)
self.but_add.set_relief(gtk.RELIEF_NONE)
hbox.pack_start(self.but_add, expand=False, fill=False)
self.but_remove = gtk.Button()
tooltips.set_tip(self.but_remove, _('Remove'))
self.but_remove.connect('clicked', self._sig_remove, True)
img_remove = gtk.Image()
img_remove.set_from_stock('tryton-list-remove', gtk.ICON_SIZE_SMALL_TOOLBAR)
img_remove.set_alignment(0.5, 0.5)
self.but_remove.add(img_remove)
self.but_remove.set_relief(gtk.RELIEF_NONE)
hbox.pack_start(self.but_remove, expand=False, fill=False)
hbox.pack_start(gtk.VSeparator(), expand=False, fill=True)
self.but_new = gtk.Button()
tooltips.set_tip(self.but_new, _('Create a new record'))
self.but_new.connect('clicked', self._sig_new)
img_new = gtk.Image()
img_new.set_from_stock('tryton-new', gtk.ICON_SIZE_SMALL_TOOLBAR)
img_new.set_alignment(0.5, 0.5)
self.but_new.add(img_new)
self.but_new.set_relief(gtk.RELIEF_NONE)
hbox.pack_start(self.but_new, expand=False, fill=False)
self.but_open = gtk.Button()
tooltips.set_tip(self.but_open, _('Edit selected record'))
self.but_open.connect('clicked', self._sig_edit)
img_open = gtk.Image()
img_open.set_from_stock('tryton-open', gtk.ICON_SIZE_SMALL_TOOLBAR)
img_open.set_alignment(0.5, 0.5)
self.but_open.add(img_open)
self.but_open.set_relief(gtk.RELIEF_NONE)
hbox.pack_start(self.but_open, expand=False, fill=False)
self.but_del = gtk.Button()
tooltips.set_tip(self.but_del, _('Delete selected record'))
self.but_del.connect('clicked', self._sig_remove)
img_del = gtk.Image()
img_del.set_from_stock('tryton-delete', gtk.ICON_SIZE_SMALL_TOOLBAR)
img_del.set_alignment(0.5, 0.5)
self.but_del.add(img_del)
self.but_del.set_relief(gtk.RELIEF_NONE)
hbox.pack_start(self.but_del, expand=False, fill=False)
hbox.pack_start(gtk.VSeparator(), expand=False, fill=True)
but_pre = gtk.Button()
tooltips.set_tip(but_pre, _('Previous'))
but_pre.connect('clicked', self._sig_previous)
img_pre = gtk.Image()
img_pre.set_from_stock('tryton-go-previous', gtk.ICON_SIZE_SMALL_TOOLBAR)
img_pre.set_alignment(0.5, 0.5)
but_pre.add(img_pre)
but_pre.set_relief(gtk.RELIEF_NONE)
hbox.pack_start(but_pre, expand=False, fill=False)
self.label = gtk.Label('(0,0)')
hbox.pack_start(self.label, expand=False, fill=False)
but_next = gtk.Button()
tooltips.set_tip(but_next, _('Next'))
but_next.connect('clicked', self._sig_next)
img_next = gtk.Image()
img_next.set_from_stock('tryton-go-next', gtk.ICON_SIZE_SMALL_TOOLBAR)
img_next.set_alignment(0.5, 0.5)
but_next.add(img_next)
but_next.set_relief(gtk.RELIEF_NONE)
hbox.pack_start(but_next, expand=False, fill=False)
hbox.pack_start(gtk.VSeparator(), expand=False, fill=True)
but_switch = gtk.Button()
tooltips.set_tip(but_switch, _('Switch'))
but_switch.connect('clicked', self.switch_view)
img_switch = gtk.Image()
img_switch.set_from_stock('tryton-fullscreen', gtk.ICON_SIZE_SMALL_TOOLBAR)
img_switch.set_alignment(0.5, 0.5)
but_switch.add(img_switch)
but_switch.set_relief(gtk.RELIEF_NONE)
hbox.pack_start(but_switch, expand=False, fill=False)
if attrs.get('add_remove'):
hbox.set_focus_chain([self.wid_text])
else:
hbox.set_focus_chain([])
tooltips.enable()
self.widget.pack_start(hbox, expand=False, fill=True)
self.screen = Screen(attrs['relation'], self._window,
view_type=attrs.get('mode','tree,form').split(','),
parent=self.parent, parent_name=attrs.get('relation_field', ''),
self.screen = Screen(attrs['relation'], self.window,
view_type=attrs.get('mode', 'tree,form').split(','),
views_preload=attrs.get('views', {}),
tree_saves=attrs.get('saves', False), create_new=True,
row_activate=self._on_activate,
default_get=attrs.get('default_get', {}),
exclude_field=attrs.get('relation_field', None))
self.screen.signal_connect(self, 'record-message', self._sig_label)
menuitem_title.get_child().set_text(attrs.get('string', ''))
@@ -515,17 +207,12 @@ class One2Many(WidgetInterface):
self.but_remove.set_sensitive(not value)
def _sig_new(self, widget):
self._view.view_form.set_value()
ctx = self._view.model.expr_eval(self.screen.default_get)
ctx.update(self._view.model.expr_eval(self.attrs.get('context', {})))
self.view.set_value()
ctx = {}
ctx.update(self.record.expr_eval(self.attrs.get('context', {})))
sequence = None
idx = -1
if self.screen.current_view.view_type == 'tree':
sequence = self.screen.current_view.widget_tree.sequence
select_ids = self.screen.sel_ids_get()
if select_ids:
model = self.screen.models.get_by_id(select_ids[0])
idx = self.screen.models.models.index(model)
if (self.screen.current_view.view_type == 'form') \
or self.screen.editable_get():
self.screen.new(context=ctx)
@@ -533,48 +220,27 @@ class One2Many(WidgetInterface):
else:
readonly = False
domain = []
if self._view.modelfield and self._view.model:
modelfield = self._view.modelfield
model = self._view.model
readonly = modelfield.get_state_attrs(model
if self.field and self.record:
readonly = self.field.get_state_attrs(self.record
).get('readonly', False)
domain = modelfield.domain_get(self._view.model)
dia = Dialog(self.attrs['relation'], parent=self._view.model,
attrs=self.attrs,
model_ctx=self.screen.models._context,
default_get_ctx=ctx, window=self._window,
readonly=readonly, domain=domain)
res = True
while res:
res, value = dia.run()
if res:
if idx >= 0:
idx += 1
self.screen.models.model_add(value, position=idx)
value.signal('record-changed', value.parent)
self.screen.display_next()
dia.new()
dia.destroy()
domain = self.field.domain_get(self.record)
win = WinForm(self.screen, self.window, new=True,
context=ctx)
while True:
if win.run():
win.new()
else:
break
win.destroy()
if sequence:
self.screen.models.set_sequence(field=sequence)
self.screen.group.set_sequence(field=sequence)
def _sig_edit(self, widget=None):
self._view.view_form.set_value()
if self.screen.current_model:
readonly = False
domain = []
if self._view.modelfield and self._view.model:
modelfield = self._view.modelfield
model = self._view.model
readonly = modelfield.get_state_attrs(model
).get('readonly', False)
domain = modelfield.domain_get(self._view.model)
dia = Dialog(self.attrs['relation'], parent=self._view.model,
model=self.screen.current_model, attrs=self.attrs,
window=self._window, readonly=readonly, domain=domain,
model_ctx=self.screen.models.context)
res, value = dia.run()
dia.destroy()
self.view.set_value()
if self.screen.current_record:
win = WinForm(self.screen, self.window)
win.run()
win.destroy()
def _sig_next(self, widget):
self.screen.display_next()
@@ -590,14 +256,14 @@ class One2Many(WidgetInterface):
self.wid_text.grab_focus()
def _sig_add(self, *args):
self._view.view_form.set_value()
domain = self._view.modelfield.domain_get(self._view.model)
self.view.set_value()
domain = self.field.domain_get(self.record)
context = rpc.CONTEXT.copy()
context.update(self._view.modelfield.context_get(self._view.model))
context.update(self.field.context_get(self.record))
domain = domain[:]
domain.extend(self._view.model.expr_eval(self.attrs.get('add_remove'),
domain.extend(self.record.expr_eval(self.attrs.get('add_remove'),
context))
removed_ids = self._view.modelfield.get_removed_ids(self._view.model)
removed_ids = self.field.get_removed_ids(self.record)
try:
if self.wid_text.get_text():
@@ -608,11 +274,11 @@ class One2Many(WidgetInterface):
ids = rpc.execute('model', self.attrs['relation'],
'search', dom, 0, _LIMIT, None, context)
except Exception, exception:
common.process_exception(exception, self._window)
common.process_exception(exception, self.window)
return False
if len(ids) != 1:
win = WinSearch(self.attrs['relation'], sel_multi=True, ids=ids,
context=context, domain=domain, parent=self._window,
context=context, domain=domain, parent=self.window,
views_preload=self.attrs.get('views', {}))
ids = win.run()
@@ -632,38 +298,35 @@ class One2Many(WidgetInterface):
line = '(%s/%s)' % (name, signal_data[1])
self.label.set_text(line)
def display(self, model, model_field):
if not model_field:
self.screen.current_model = None
def display(self, record, field):
if field is None:
self.screen.current_record = None
self.screen.display()
return False
super(One2Many, self).display(model, model_field)
new_models = model_field.get_client(model)
if self.screen.models != new_models:
self.screen.models_set(new_models)
super(One2Many, self).display(record, field)
new_group = field.get_client(record)
if id(self.screen.group) != id(new_group):
self.screen.group = new_group
if (self.screen.current_view.view_type == 'tree') \
and self.screen.editable_get():
self.screen.current_model = None
self.screen.current_record = None
readonly = False
domain = []
if self._view.modelfield and self._view.model:
modelfield = self._view.modelfield
model = self._view.model
readonly = modelfield.get_state_attrs(model
).get('readonly', False)
domain = modelfield.domain_get(self._view.model)
if record:
readonly = field.get_state_attrs(record).get('readonly', False)
domain = field.domain_get(record)
if self.screen.domain != domain:
self.screen.domain = domain
self.screen.models.readonly = readonly
self.screen.group.readonly = readonly
self.screen.display()
return True
def display_value(self):
return '<' + self.attrs.get('string', '') + '>'
def set_value(self, model, model_field):
def set_value(self, record, field):
self.screen.current_view.set_value()
if self.screen.is_modified():
model.modified = True
model.modified_fields.setdefault(model_field.name)
record.modified = True
record.modified_fields.setdefault(field.name)
return True
@@ -40,16 +40,16 @@ class Button(object):
def button_clicked(self, widget):
if not self.form:
return
model = self.form.screen.current_model
record = self.form.screen.current_record
obj_id = self.form.screen.save_current()
if obj_id:
if not self.attrs.get('confirm', False) or \
common.sur(self.attrs['confirm'], self.form.window):
button_type = self.attrs.get('type', 'workflow')
ctx = rpc.CONTEXT.copy()
ctx.update(model.context_get())
ctx.update(record.context_get())
if button_type == 'workflow':
args = ('model', self.form.screen.name,
args = ('model', self.form.screen.model_name,
'workflow_trigger_validate', obj_id,
self.attrs['name'], ctx)
try:
@@ -58,7 +58,7 @@ class Button(object):
common.process_exception(exception, self.form.window,
*args)
elif button_type == 'object':
args = ('model', self.form.screen.name, self.attrs['name'],
args = ('model', self.form.screen.model_name, self.attrs['name'],
[obj_id], ctx)
try:
rpc.execute(*args)
@@ -76,7 +76,7 @@ class Button(object):
*args)
if action_id:
Action.execute(action_id, {
'model': self.form.screen.name,
'model': self.form.screen.model_name,
'id': obj_id,
'ids': [obj_id],
}, self.form.window, context=ctx)
@@ -84,14 +84,11 @@ class Button(object):
raise Exception('Unallowed button type')
self.form.screen.reload(writen=True)
else:
if self.form.screen.form:
self.form.screen.form.message_info(
_('Invalid Form, correct red fields!'))
self.form.screen.display()
def state_set(self, model):
if model:
state_changes = model.expr_eval(self.attrs.get('states', {}),
def state_set(self, record):
if record:
state_changes = record.expr_eval(self.attrs.get('states', {}),
check_load=False)
else:
state_changes = {}
@@ -120,9 +117,9 @@ class Label(gtk.Label):
super(Label, self).__init__(str=str)
self.attrs = attrs or {}
def state_set(self, model):
if model:
state_changes = model.expr_eval(self.attrs.get('states', {}),
def state_set(self, record):
if record:
state_changes = record.expr_eval(self.attrs.get('states', {}),
check_load=False)
else:
state_changes = {}
@@ -138,9 +135,9 @@ class VBox(gtk.VBox):
super(VBox, self).__init__(homogeneous, spacing)
self.attrs = attrs or {}
def state_set(self, model):
if model:
state_changes = model.expr_eval(self.attrs.get('states', {}),
def state_set(self, record):
if record:
state_changes = record.expr_eval(self.attrs.get('states', {}),
check_load=False)
else:
state_changes = {}
@@ -156,9 +153,9 @@ class Image(gtk.Image):
super(Image, self).__init__()
self.attrs = attrs or {}
def state_set(self, model):
if model:
state_changes = model.expr_eval(self.attrs.get('states', {}),
def state_set(self, record):
if record:
state_changes = record.expr_eval(self.attrs.get('states', {}),
check_load=False)
else:
state_changes = {}
@@ -180,9 +177,9 @@ class Frame(gtk.Frame):
self.set_shadow_type(gtk.SHADOW_NONE)
self.set_border_width(0)
def state_set(self, model):
if model:
state_changes = model.expr_eval(self.attrs.get('states', {}),
def state_set(self, record):
if record:
state_changes = record.expr_eval(self.attrs.get('states', {}),
check_load=False)
else:
state_changes = {}
@@ -199,9 +196,9 @@ class ScrolledWindow(gtk.ScrolledWindow):
vadjustment=vadjustment)
self.attrs = attrs or {}
def state_set(self, model):
if model:
state_changes = model.expr_eval(self.attrs.get('states', {}),
def state_set(self, record):
if record:
state_changes = record.expr_eval(self.attrs.get('states', {}),
check_load=False)
else:
state_changes = {}
@@ -298,7 +295,7 @@ class ParserForm(ParserInterface):
screen=screen)
self.widget_id = 0
def parse(self, model, root_node, fields, notebook=None, paned=None,
def parse(self, model_name, root_node, fields, notebook=None, paned=None,
tooltips=None):
dict_widget = {}
button_list = []
@@ -323,7 +320,7 @@ class ParserForm(ParserInterface):
attrs = common.node_attributes(node)
if not cursor_widget:
if attrs.get('name') and fields.get(attrs['name']) \
and not fields[attrs['name']].get('exclude_field',
and not fields[attrs['name']].attrs.get('exclude_field',
False):
cursor_widget = attrs.get('name')
if node.localName == 'image':
@@ -339,10 +336,10 @@ class ParserForm(ParserInterface):
if 'string' in attrs or 'name' in attrs:
if not text:
if 'name' in attrs and attrs['name'] in fields:
if 'states' in fields[attrs['name']]:
if 'states' in fields[attrs['name']].attrs:
attrs['states'] = \
fields[attrs['name']]['states']
text = fields[attrs['name']]['string']
fields[attrs['name']].attrs['states']
text = fields[attrs['name']].attrs['string']
vbox = VBox(attrs=attrs)
button_list.append(vbox)
if text:
@@ -359,13 +356,16 @@ class ParserForm(ParserInterface):
text = attrs.get('string', '')
if 'name' in attrs and attrs['name'] in fields:
if 'states' not in attrs \
and 'states' in fields[attrs['name']]:
attrs['states'] = fields[attrs['name']]['states']
and 'states' in fields[attrs['name']].attrs:
attrs['states'] = fields[attrs['name']].attrs['states']
if not text:
if gtk.widget_get_default_direction() == gtk.TEXT_DIR_RTL:
text = _(':') + fields[attrs['name']]['string']
if gtk.widget_get_default_direction() == \
gtk.TEXT_DIR_RTL:
text = _(':') + \
fields[attrs['name']].attrs['string']
else:
text = fields[attrs['name']]['string'] + _(':')
text = fields[attrs['name']].attrs['string'] + \
_(':')
if 'align' not in attrs:
attrs['align'] = 1.0
elif not text:
@@ -436,7 +436,7 @@ class ParserForm(ParserInterface):
container.wid_add(notebook, colspan=attrs.get('colspan', 4),
expand=True, fill=True)
widget, widgets, buttons, spam, notebook_list2, cursor_widget2 = \
self.parse(model, node, fields, notebook,
self.parse(model_name, node, fields, notebook,
tooltips=tooltips)
max_width, max_height = -1, -1
window_width, window_height = Main.get_main().window.get_size()
@@ -465,11 +465,11 @@ class ParserForm(ParserInterface):
angle = 0
text = attrs.get('string', '')
if 'name' in attrs and attrs['name'] in fields:
if 'states' in fields[attrs['name']]:
if 'states' in fields[attrs['name']].attrs:
attrs['states'] = \
fields[attrs['name']]['states']
fields[attrs['name']].attrs['states']
if not text:
text = fields[attrs['name']]['string']
text = fields[attrs['name']].attrs['string']
if not text:
text = _('No String Attr.')
if '_' not in text:
@@ -478,7 +478,7 @@ class ParserForm(ParserInterface):
label.set_angle(angle)
label.set_use_underline(True)
widget, widgets, buttons, spam, notebook_list2, cursor_widget2 = \
self.parse(model, node, fields, notebook,
self.parse(model_name, node, fields, notebook,
tooltips=tooltips)
if not cursor_widget:
cursor_widget = cursor_widget2
@@ -509,18 +509,18 @@ class ParserForm(ParserInterface):
log = logging.getLogger('view')
log.error('Unknown field "%s"' % str(name))
continue
ftype = attrs.get('widget', fields[name]['type'])
fields[name].update(attrs)
fields[name]['model'] = model
ftype = attrs.get('widget', fields[name].attrs['type'])
fields[name].attrs.update(attrs)
fields[name].attrs['model'] = model_name
if not ftype in WIDGETS_TYPE:
container.empty_add(int(attrs.get('colspan', 1)))
continue
fields[name]['name'] = name
fields[name].attrs['name'] = name
if 'saves' in attrs:
fields[name]['saves'] = attrs['saves']
widget_act = WIDGETS_TYPE[ftype][0](self.window, self.parent,
model, fields[name])
fields[name].attrs['saves'] = attrs['saves']
widget_act = WIDGETS_TYPE[ftype][0](name, model_name,
self.window, fields[name].attrs)
self.widget_id += 1
widget_act.position = self.widget_id
dict_widget.setdefault(name, [])
@@ -538,21 +538,22 @@ class ParserForm(ParserInterface):
xfill = True
if 'xfill' in attrs:
xfill = bool(common.safe_eval(attrs['xfill']))
hlp = fields[name].get('help', attrs.get('help', False))
hlp = fields[name].attrs.get('help', attrs.get('help', False))
if attrs.get('height', False) or attrs.get('width', False):
widget_act.widget.set_size_request(
int(attrs.get('width', -1)),
int(attrs.get('height', -1)))
translate = False
if ftype in ('char', 'text'):
translate = fields[name].get('translate', False)
container.wid_add(widget_act.widget, fields[name]['string'],
expand, translate=translate, colspan=size, fname=name,
translate = fields[name].attrs.get('translate', False)
container.wid_add(widget_act.widget,
fields[name].attrs['string'], expand,
translate=translate, colspan=size, fname=name,
help_tip=hlp, fill=fill, xexpand=xexpand, xfill=xfill)
elif node.localName == 'group':
widget, widgets, buttons, spam, notebook_list2, cursor_widget2 = \
self.parse(model, node, fields, tooltips=tooltips)
self.parse(model_name, node, fields, tooltips=tooltips)
if not cursor_widget:
cursor_widget = cursor_widget2
notebook_list.extend(notebook_list2)
@@ -562,9 +563,9 @@ class ParserForm(ParserInterface):
button_list += buttons
text = ''
if 'name' in attrs and attrs['name'] in fields:
if 'states' in fields[attrs['name']]:
attrs['states'] = fields[attrs['name']]['states']
text = fields[attrs['name']]['string']
if 'states' in fields[attrs['name']].attrs:
attrs['states'] = fields[attrs['name']].attrs['states']
text = fields[attrs['name']].attrs['string']
if attrs.get('string'):
text = attrs['string']
@@ -580,7 +581,7 @@ class ParserForm(ParserInterface):
container.wid_add(hpaned, colspan=int(attrs.get('colspan', 4)),
expand=True, fill=True)
widget, widgets, buttons, spam, notebook_list2, cursor_widget2 = \
self.parse(model, node, fields, paned=hpaned,
self.parse(model_name, node, fields, paned=hpaned,
tooltips=tooltips)
if not cursor_widget:
cursor_widget = cursor_widget2
@@ -596,7 +597,7 @@ class ParserForm(ParserInterface):
container.wid_add(vpaned, colspan=int(attrs.get('colspan', 4)),
expand=True, fill=True)
widget, widgets, buttons, spam, notebook_list, cursor_widget2 = \
self.parse(model, node, fields, paned=vpaned,
self.parse(model_name, node, fields, paned=vpaned,
tooltips=tooltips)
if not cursor_widget:
cursor_widget = cursor_widget2
@@ -609,7 +610,7 @@ class ParserForm(ParserInterface):
vpaned.set_position(int(attrs['position']))
elif node.localName == 'child1':
widget, widgets, buttons, spam, notebook_list2, cursor_widget2 = \
self.parse(model, node, fields, paned=paned,
self.parse(model_name, node, fields, paned=paned,
tooltips=tooltips)
if not cursor_widget:
cursor_widget = cursor_widget2
@@ -621,7 +622,7 @@ class ParserForm(ParserInterface):
paned.pack1(widget, resize=True, shrink=True)
elif node.localName == 'child2':
widget, widgets, buttons, spam, notebook_list, cursor_widget2 = \
self.parse(model, node, fields, paned=paned,
self.parse(model_name, node, fields, paned=paned,
tooltips=tooltips)
if not cursor_widget:
cursor_widget = cursor_widget2
@@ -632,20 +633,20 @@ class ParserForm(ParserInterface):
dict_widget[widget_name].extend(widgets)
paned.pack2(widget, resize=True, shrink=True)
for (button, src, name, widget) in container.trans_box:
button.connect('clicked', self.translate, model, name,
button.connect('clicked', self.translate, model_name, name,
src, widget)
return container.pop(), dict_widget, button_list, on_write, \
notebook_list, cursor_widget
def translate(self, widget, model, name, src, widget_entry):
obj_id = self.screen.current_model.id
def translate(self, widget, model_name, name, src, widget_entry):
obj_id = self.screen.current_record.id
if obj_id < 0:
common.message(
_('You need to save the record before adding translations!'),
parent=self.window)
return False
obj_id = self.screen.current_model.save(force_reload=False)
obj_id = self.screen.current_record.save(force_reload=False)
try:
lang_ids = rpc.execute('model', 'ir.lang',
'search', [('translatable', '=', '1')])
@@ -744,7 +745,7 @@ class ParserForm(ParserInterface):
context = copy.copy(rpc.CONTEXT)
context['language'] = lang['code']
try:
val = rpc.execute('model', model,
val = rpc.execute('model', model_name,
'read', [obj_id], [name], context)
except Exception, exception:
common.process_exception(exception, self.window)
@@ -795,7 +796,7 @@ class ParserForm(ParserInterface):
value_set(widget_entry, new_val['value'])
context = copy.copy(rpc.CONTEXT)
context['language'] = new_val['code']
args = ('model', model, 'write', [obj_id],
args = ('model', model_name, 'write', [obj_id],
{str(name): new_val['value']}, context)
try:
rpc.execute(*args)
@@ -805,7 +806,7 @@ class ParserForm(ParserInterface):
self.window.present()
win.destroy()
return
self.screen.current_model.reload()
self.screen.current_record.reload()
self.window.present()
win.destroy()
return True
@@ -14,8 +14,9 @@ class ProgressBar(WidgetInterface):
'top_to_bottom': gtk.PROGRESS_TOP_TO_BOTTOM,
}
def __init__(self, window, parent, model, attrs=None):
super(ProgressBar, self).__init__(window, parent, model=model, attrs=attrs)
def __init__(self, field_name, model_name, window, attrs=None):
super(ProgressBar, self).__init__(field_name, model_name, window,
parent, attrs=attrs)
self.digits = attrs.get('digits', (16, 2))
self.widget = gtk.ProgressBar()
orientation = self.orientations.get(attrs.get('orientation',
@@ -30,7 +31,7 @@ class ProgressBar(WidgetInterface):
return False
value = float(model_field.get(model) or 0.0)
if isinstance(self.digits, str):
digits = self._view.model.expr_eval(self.digits)
digits = self.record.expr_eval(self.digits)
else:
digits = self.digits
self.widget.set_text(locale.format('%.' + str(digits[1]) + 'f',
@@ -4,10 +4,10 @@ import gtk
import gobject
import gettext
from interface import WidgetInterface
from many2one import Dialog
from tryton.gui.window.win_search import WinSearch
from tryton.gui.window.win_form import WinForm
from tryton.gui.window.view_form.screen import Screen
import tryton.rpc as rpc
from tryton.rpc import RPCProxy
import tryton.common as common
from tryton.gui.window.view_form.widget_search.form import _LIMIT
@@ -16,10 +16,9 @@ _ = gettext.gettext
class Reference(WidgetInterface):
def __init__(self, window, parent, model, attrs=None):
if attrs is None:
attrs = {}
super(Reference, self).__init__(window, parent, model, attrs)
def __init__(self, field_name, model_name, window, attrs=None):
super(Reference, self).__init__(field_name, model_name, window,
attrs=attrs)
self.widget = gtk.HBox(spacing=0)
@@ -81,9 +80,9 @@ class Reference(WidgetInterface):
if not isinstance(selection, (list, tuple)):
try:
selection = rpc.execute('model',
self.model, selection, rpc.CONTEXT)
self.model_name, selection, rpc.CONTEXT)
except Exception, exception:
common.process_exception(exception, self._window)
common.process_exception(exception, self.window)
selection = []
selection.sort(lambda x, y: cmp(x[1], y[1]))
self.set_popdown(selection)
@@ -131,7 +130,7 @@ class Reference(WidgetInterface):
def _color_widget(self):
return self.wid_text
def set_value(self, model, model_field):
def set_value(self, record, field):
return
def sig_activate(self, widget=None):
@@ -142,7 +141,7 @@ class Reference(WidgetInterface):
return
child = self.widget_combo.get_child()
self.changed = False
value = self._view.modelfield.get_client(self._view.model)
value = self.field.get_client(self.record)
self.focus_out = False
if not value:
@@ -155,17 +154,23 @@ class Reference(WidgetInterface):
return False
if model and obj_id:
if not leave:
dia = Dialog(model, obj_id, attrs=self.attrs,
window=self._window)
res, value = dia.run()
if res:
self._view.modelfield.set_client(self._view.model,
(model, value), force_change=True)
dia.destroy()
screen = Screen(model, self.window, view_type=['form'])
screen.load([obj_id])
win = WinForm(screen, self.window)
while win.run():
if screen.save_current():
value = (screen.current_record.id,
screen.current_record.rec_name())
self.field(self.record, (model, value),
force_change=True)
break
else:
screen.display()
win.destroy()
elif model:
if not self._readonly and ( self.wid_text.get_text() or not leave):
domain = self._view.modelfield.domain_get(self._view.model)
context = self._view.modelfield.context_get(self._view.model)
domain = self.field.domain_get(self.record)
context = self.field.context_get(self.record)
try:
if self.wid_text.get_text():
@@ -179,40 +184,41 @@ class Reference(WidgetInterface):
except Exception, exception:
self.focus_out = True
self.changed = True
common.process_exception(exception, self._window)
common.process_exception(exception, self.window)
return False
if ids and len(ids) == 1:
self._view.modelfield.set_client(self._view.model,
(model, (ids[0], '')))
self.display(self._view.model, self._view.modelfield)
self.field.set_client(self.record, (model, (ids[0], '')))
self.display(self.record, self.field)
self.focus_out = True
self.changed = True
return True
win = WinSearch(model, sel_multi=False, ids=ids, context=context,
domain=domain, parent=self._window)
domain=domain, parent=self.window)
ids = win.run()
if ids:
self._view.modelfield.set_client(self._view.model,
(model, (ids[0], '')))
self.field.set_client(self.record, (model, (ids[0], '')))
else:
self._view.modelfield.set_client(self._view.model,
('', (name, name)))
self.field.set_client(self.record, ('', (name, name)))
self.focus_out = True
self.changed = True
self.display(self._view.model, self._view.modelfield)
self.display(self.record, self.field)
def sig_new(self, *args):
model = self.get_model()
if not model:
return
dia = Dialog(model, window=self._window)
res, value = dia.run()
if res:
self._view.modelfield.set_client(self._view.model,
(model, value))
self.display(self._view.model, self._view.modelfield)
dia.destroy()
screen = Screen(model, self.window, view_type=['form'])
win = WinForm(screen, self.window, new=True)
while win.run():
if screen.save_current():
value = (screen.current_record.id,
screen.current_record.rec_name())
self.field.set_client(self.record, (model, value))
break
else:
screen.display()
win.destroy()
def sig_key_press(self, widget, event):
editable = self.wid_text.get_editable()
@@ -223,7 +229,7 @@ class Reference(WidgetInterface):
self.sig_focus_out(widget, event)
return True
elif event.keyval in (gtk.keysyms.Tab, gtk.keysyms.Return) and editable:
if self._view.modelfield.get(self._view.model) or \
if self.field.get(self.record) or \
not self.wid_text.get_text():
return False
self.sig_focus_out(widget, event, leave=True)
@@ -234,32 +240,30 @@ class Reference(WidgetInterface):
if not self.changed:
return
self.wid_text.set_text('')
self._view.modelfield.set_client(self._view.model,
(self.get_model(), (0, '')))
self.field.set_client(self.record, (self.get_model(), (0, '')))
def sig_changed(self, *args):
if not self.changed:
return False
val = self._view.modelfield.get_client(self._view.model)
val = self.field.get_client(self.record)
if not val:
model, (obj_id, name) = '', (0, '')
else:
model, (obj_id, name) = val
if self.get_model() and obj_id:
self._view.modelfield.set_client(self._view.model,
(self.get_model(), (0, '')))
self.display(self._view.model, self._view.modelfield)
self.field.set_client(self.record, (self.get_model(), (0, '')))
self.display(self.record, self.field)
return False
def display(self, model, model_field):
def display(self, record, field):
child = self.widget_combo.get_child()
self.changed = False
if not model_field:
if not field:
child.set_text('')
self.changed =True
return False
super(Reference, self).display(model, model_field)
value = model_field.get_client(model)
super(Reference, self).display(record, field)
value = field.get_client(record)
img = gtk.Image()
if not value:
model, (obj_id, name) = '', (0, '')
@@ -268,12 +272,15 @@ class Reference(WidgetInterface):
if model:
child.set_text(self._selection2[model])
if not name and obj_id:
args = ('model', model, 'read', obj_id, ['rec_name'],
rpc.CONTEXT)
try:
name = RPCProxy(model).read(obj_id, ['rec_name'],
rpc.CONTEXT)['rec_name']
name = rpc.execute(*args)
except Exception, exception:
common.process_exception(exception, self._window)
name = '???'
name = common.process_exception(exception, self.window,
*args)
if not name:
name = '???'
self.wid_text.set_text(name)
if obj_id:
img.set_from_stock('tryton-open', gtk.ICON_SIZE_SMALL_TOOLBAR)
@@ -9,8 +9,9 @@ import tryton.common as common
class Selection(WidgetInterface):
def __init__(self, window, parent, model, attrs=None):
super(Selection, self).__init__(window, parent, model, attrs)
def __init__(self, field_name, model_name, window, attrs=None):
super(Selection, self).__init__(field_name, model_name, window,
attrs=attrs)
self.widget = gtk.HBox(spacing=3)
self.entry = gtk.ComboBoxEntry()
@@ -40,16 +41,16 @@ class Selection(WidgetInterface):
['rec_name'])
selection = [(x['id'], x['rec_name']) for x in result]
except Exception, exception:
common.process_exception(exception, self._window)
common.process_exception(exception, self.window)
selection = []
self.selection = selection[:]
else:
if not isinstance(selection, (list, tuple)):
try:
selection = rpc.execute('model',
self.model, selection, rpc.CONTEXT)
self.model_name, selection, rpc.CONTEXT)
except Exception, exception:
common.process_exception(exception, self._window)
common.process_exception(exception, self.window)
selection = []
self.selection = selection[:]
@@ -123,24 +124,24 @@ class Selection(WidgetInterface):
value = val
if len(txt) == len(text):
break
self._view.modelfield.set_client(self._view.model, value, force_change=True)
self.display(self._view.model, self._view.modelfield)
self.field.set_client(self.record, value, force_change=True)
self.display(self.record, self.field)
def set_value(self, model, model_field):
model_field.set_client(model, self.value_get())
def set_value(self, record, field):
field.set_client(record, self.value_get())
def _menu_sig_default_set(self, reset=False):
self.set_value(self._view.model, self._view.modelfield)
self.set_value(self.record, self.field)
super(Selection, self)._menu_sig_default_set(reset=reset)
def display(self, model, model_field):
def display(self, record, field):
child = self.entry.get_child()
self.changed = False
if not model_field:
if not field:
child.set_text('')
return False
super(Selection, self).display(model, model_field)
value = model_field.get(model)
super(Selection, self).display(record, field)
value = field.get(record)
if isinstance(value, (list, tuple)):
value = value[0]
if not value:
@@ -13,8 +13,9 @@ except:
class TextBox(WidgetInterface):
def __init__(self, window, parent, model, attrs=None):
super(TextBox, self).__init__(window, parent, model, attrs)
def __init__(self, field_name, model_name, window, attrs=None):
super(TextBox, self).__init__(field_name, model_name, window,
attrs=attrs)
self.widget = gtk.HBox()
self.scrolledwindow = gtk.ScrolledWindow()
@@ -55,8 +56,8 @@ class TextBox(WidgetInterface):
if not value and self.attrs.get('spell') \
and CONFIG['client.spellcheck'] \
and self._view and self._view.model:
language = self._view.model.expr_eval(self.attrs['spell'])
and self.record:
language = self.record.expr_eval(self.attrs['spell'])
try:
if not spell:
spell = gtkspell.Spell(self.textview)
@@ -76,16 +77,16 @@ class TextBox(WidgetInterface):
def _color_widget(self):
return self.textview
def set_value(self, model, model_field):
def set_value(self, record, field):
buf = self.textview.get_buffer()
iter_start = buf.get_start_iter()
iter_end = buf.get_end_iter()
current_text = buf.get_text(iter_start, iter_end, False)
model_field.set_client(model, current_text or False)
field.set_client(record, current_text or False)
def display(self, model, model_field):
super(TextBox, self).display(model, model_field)
value = model_field and model_field.get(model)
def display(self, record, field):
super(TextBox, self).display(record, field)
value = field and field.get(record)
if not value:
value = ''
buf = self.textview.get_buffer()
@@ -101,8 +102,8 @@ class TextBox(WidgetInterface):
pass
if self.attrs.get('spell') and CONFIG['client.spellcheck'] \
and self._view and self._view.model:
language = self._view.model.expr_eval(self.attrs['spell'])
and self.record:
language = self.record.expr_eval(self.attrs['spell'])
try:
if not spell:
spell = gtkspell.Spell(self.textview)
@@ -120,7 +121,7 @@ class TextBox(WidgetInterface):
del spell
def display_value(self):
lines = (self._view.modelfield.get_client(self._view.model) or '').split('\n')
lines = (self.field.get_client(self.record) or '').split('\n')
if len(lines) > 1:
return lines[0] + '...'
else:
@@ -10,10 +10,8 @@ import tryton.common as common
class URL(Char):
"url"
def __init__(self, window, parent, model, attrs=None):
if attrs is None:
attrs = {}
super(URL, self).__init__(window, parent, model, attrs=attrs)
def __init__(self, field_name, model_name, window, attrs=None):
super(URL, self).__init__(field_name, model_name, window, attrs=attrs)
self.tooltips = common.Tooltips()
self.button = gtk.Button()
@@ -26,8 +24,8 @@ class URL(Char):
self.widget.pack_start(self.button, expand=False, fill=False)
self.widget.set_focus_chain([self.entry])
def display(self, model, model_field):
super(URL, self).display(model, model_field)
def display(self, record, field):
super(URL, self).display(record, field)
self.set_tooltips()
def set_tooltips(self):
@@ -10,7 +10,6 @@ class ViewGraph(ParserView):
super(ViewGraph, self).__init__(window, screen, widget, children,
buttons, toolbar, notebooks, cursor_widget)
self.view_type = 'graph'
self.model_add_new = False
self.widgets = children
def __getitem__(self, name):
@@ -37,9 +36,6 @@ class ViewGraph(ParserView):
def reset(self):
pass
def signal_record_changed(self, *args):
self.display()
def display(self):
for widget in self.widgets.itervalues():
widget.display(self.screen.models)
@@ -354,7 +354,7 @@ class Graph(gtk.DrawingArea):
if yfield.get('domain'):
values = rpc.CONTEXT.copy()
values['state'] = 'draft'
for field in model.mgroup.fields:
for field in model.group.fields:
values[field] = model[field].get(model, check_load=False)
if not PYSONDecoder(values).decode(yfield['domain']):
continue
+97 -95
View File
@@ -2,7 +2,6 @@
#this repository contains the full copyright notices and license terms.
import gobject
import gtk
from tryton.rpc import RPCProxy
import tryton.rpc as rpc
import locale
from interface import ParserView
@@ -13,6 +12,7 @@ import tryton.common as common
from tryton.config import CONFIG
from tryton.common.cellrendererbutton import CellRendererButton
from tryton.common.cellrenderertoggle import CellRendererToggle
from tryton.pyson import PYSONEncoder
import os
_ = gettext.gettext
@@ -20,17 +20,16 @@ _ = gettext.gettext
class AdaptModelGroup(gtk.GenericTreeModel):
def __init__(self, model_group):
def __init__(self, group):
super(AdaptModelGroup, self).__init__()
self.model_group = model_group
self.models = model_group.models
self.group = group
self.last_sort = None
self.sort_asc = True
self.set_property('leak_references', False)
def added(self, modellist, position):
if modellist is self.models:
model = self.models[position]
if modellist is self.group:
model = self.group[position]
self.row_inserted(self.on_get_path(model),
self.get_iter(self.on_get_path(model)))
@@ -42,26 +41,26 @@ class AdaptModelGroup(gtk.GenericTreeModel):
self.invalidate_iters()
def append(self, model):
self.model_group.model_add(model)
self.group.add(model)
def prepend(self, model):
self.model_group.model_add(model, 0)
self.group.add(model, 0)
def remove(self, iter):
idx = self.get_path(iter)[0]
self.model_group.model_remove(self.models[idx])
self.group.remove(self.group[idx])
self.invalidate_iters()
def move(self, path, position):
idx = path[0]
self.model_group.model_move(self.models[idx], position)
self.group.move(self.group[idx], position)
def sort(self, ids):
ids2pos = {}
pos = 0
new_order = []
for model in self.models:
ids2pos[model.id] = pos
for record in self.group:
ids2pos[record.id] = pos
new_order.append(pos)
pos += 1
pos = 0
@@ -73,19 +72,19 @@ class AdaptModelGroup(gtk.GenericTreeModel):
pos += 1
except:
continue
self.models.sort(lambda x, y: \
self.group.sort(lambda x, y: \
cmp(new_order[ids2pos[x.id]], new_order[ids2pos[y.id]]))
prev = None
for model in self.models:
for record in self.group:
if prev:
prev.next[id(self.models)] = model
prev = model
prev.next[id(self.group)] = record
prev = record
if prev:
prev.next[id(self.models)] = None
prev.next[id(self.group)] = None
self.rows_reordered(None, None, new_order)
def __len__(self):
return len(self.models)
return len(self.group)
def on_get_flags(self):
return gtk.TREE_MODEL_LIST_ONLY
@@ -97,17 +96,17 @@ class AdaptModelGroup(gtk.GenericTreeModel):
return gobject.TYPE_PYOBJECT
def on_get_path(self, iter):
if iter in self.models:
return self.models.index(iter)
if iter in self.group:
return self.group.index(iter)
else:
return 0
def on_get_iter(self, path):
if isinstance(path, tuple):
path = path[0]
if self.models:
if path < len(self.models):
return self.models[path]
if self.group is not None:
if path < len(self.group):
return self.group[path]
else:
return None
else:
@@ -119,7 +118,7 @@ class AdaptModelGroup(gtk.GenericTreeModel):
def on_iter_next(self, node):
try:
return node.next[id(self.models)]
return node.next[id(self.group)]
except IndexError:
return None
@@ -131,11 +130,11 @@ class AdaptModelGroup(gtk.GenericTreeModel):
def on_iter_n_children(self, node):
if node is None:
return len(self.models)
return len(self.group)
return 0
def on_iter_nth_child(self, node, nth):
if node is None and self.models:
if node is None and self.group is not None:
return self.on_get_iter(0)
return None
@@ -151,7 +150,6 @@ class ViewList(ParserView):
buttons, toolbar, notebooks, cursor_widget)
self.store = None
self.view_type = 'tree'
self.model_add_new = True
self.widget = gtk.VBox()
self.widget_tree = widget
scroll = gtk.ScrolledWindow()
@@ -272,13 +270,13 @@ class ViewList(ParserView):
return False
email = {}
if action.get('email'):
email = self.screen.current_model.expr_eval(action['email'])
email = self.screen.current_record.expr_eval(action['email'])
if not email:
email = {}
email['subject'] = action['name'].replace('_', '')
act['email'] = email
data = {
'model': self.screen.name,
'model': self.screen.model_name,
'id': obj_id,
'ids': obj_ids,
}
@@ -327,13 +325,13 @@ class ViewList(ParserView):
self.copy_clear_func, selection)
def copy_foreach(self, treemodel, path,iter, data):
model = treemodel.get_value(iter, 0)
record = treemodel.get_value(iter, 0)
values = []
for col in self.widget_tree.get_columns():
if not col.get_visible() or not col.name:
continue
cell = self.widget_tree.cells[col.name]
values.append('"' + str(cell.get_textual_value(model)) + '"')
values.append('"' + str(cell.get_textual_value(record)) + '"')
data.append('\t'.join(values))
return
@@ -370,9 +368,9 @@ class ViewList(ParserView):
info, etime):
treeview.emit_stop_by_name('drag-data-received')
if treeview.sequence:
for model in self.screen.models.models:
if model[treeview.sequence].get_state_attrs(
model).get('readonly', False):
for record in self.screen.group:
if record[treeview.sequence].get_state_attrs(
record).get('readonly', False):
return
if not selection.data:
return
@@ -389,7 +387,7 @@ class ViewList(ParserView):
model.move(data, idx + 1)
context.drop_finish(False, etime)
if treeview.sequence:
self.screen.models.set_sequence(field=treeview.sequence)
self.screen.group.set_sequence(field=treeview.sequence)
def drag_data_delete(self, treeview, context):
treeview.emit_stop_by_name('drag-data-delete')
@@ -404,18 +402,21 @@ class ViewList(ParserView):
model = selection.get_selected_rows()[0]
if (not path) or not path[0]:
return False
model = model.models[path[0][0]]
record = model.group[path[0][0]]
if hasattr(path[1], '_type') and path[1]._type == 'many2one':
value = model[path[1].name].get(model)
ir_action_keyword = RPCProxy('ir.action.keyword')
value = record[path[1].name].get(record)
args = ('model', 'ir.action.keyword', 'get_keyword',
'form_relate',
(self.screen.fields[path[1].name]['relation'], 0),
rpc.CONTEXT)
try:
relates = ir_action_keyword.get_keyword('form_relate',
(self.screen.fields[path[1].name]['relation'], 0),
rpc.CONTEXT)
relates = rpc.execute(*args)
except Exception, exception:
common.process_exception(exception, self.window)
return False
relates = common.process_exception(exception, self.window,
*args)
if not relates:
return False
menu_entries = []
menu_entries.append((None, None, None))
menu_entries.append((_('Actions'),
@@ -457,11 +458,12 @@ class ViewList(ParserView):
screen = Screen(self.screen.fields[path[1].name]['relation'],
self.window)
screen.load([value])
act['domain'] = str(screen.current_model.expr_eval(act.get('domain', []),
check_load=False))
act['context'] = str(screen.current_model.expr_eval(act.get('context', {}),
check_load=False))
data['model'] = self.screen.name
encoder = PYSONEncoder()
act['domain'] = encoder.encode(screen.current_record.expr_eval(
act.get('domain', []), check_load=False))
act['context'] = encoder.encode(screen.current_record.expr_eval(
act.get('context', {}), check_load=False))
data['model'] = self.screen.model_name
data['id'] = value
data['ids'] = [value]
return Action._exec_action(act, self.window, data, context)
@@ -473,19 +475,19 @@ class ViewList(ParserView):
'ids': [value],
}, alwaysask=True)
def signal_record_changed(self, signal, *args):
if self.store:
if signal == 'record-added':
self.store.added(*args)
elif signal == 'record-removed':
self.store.removed(*args)
def group_list_changed(self, group, signal):
if self.store is not None:
if signal[0] == 'record-added':
self.store.added(group, signal[1])
elif signal[0] == 'record-removed':
self.store.removed(group, signal[1])
self.update_children()
def cancel(self):
pass
def __str__(self):
return 'ViewList (%s)' % self.screen.resource
return 'ViewList (%s)' % self.screen.model_name
def __getitem__(self, name):
return None
@@ -523,26 +525,26 @@ class ViewList(ParserView):
self.screen.row_activate()
def __select_changed(self, tree_sel):
previous_model = self.screen.current_model
previous_record = self.screen.current_record
if tree_sel.get_mode() == gtk.SELECTION_SINGLE:
model, iter = tree_sel.get_selected()
if iter:
path = model.get_path(iter)[0]
self.screen.current_model = model.models[path]
self.screen.current_record = model.group[path]
elif tree_sel.get_mode() == gtk.SELECTION_MULTIPLE:
model, paths = tree_sel.get_selected_rows()
if paths:
self.screen.current_model = model.models[paths[0][0]]
self.screen.current_record = model.group[paths[0][0]]
if hasattr(self.widget_tree, 'editable') \
and self.widget_tree.editable \
and self.screen.tree_saves \
and previous_model != self.screen.current_model:
if previous_model and \
not (previous_model.validate() and previous_model.save()):
self.screen.current_model = previous_model
and not self.screen.parent \
and previous_record != self.screen.current_record:
if previous_record and \
not (previous_record.validate() and previous_record.save()):
self.screen.current_record = previous_record
self.set_cursor()
return True
self.update_children()
@@ -561,12 +563,12 @@ class ViewList(ParserView):
def display(self):
if self.reload \
or (not self.widget_tree.get_model()) \
or self.screen.models != \
self.widget_tree.get_model().model_group:
self.store = AdaptModelGroup(self.screen.models)
or self.screen.group != \
self.widget_tree.get_model().group:
self.store = AdaptModelGroup(self.screen.group)
self.widget_tree.set_model(self.store)
self.reload = False
if not self.screen.current_model:
if not self.screen.current_record:
# Should find a simpler solution to do something like
#self.widget.set_cursor(None,None,False)
if self.store:
@@ -578,12 +580,12 @@ class ViewList(ParserView):
self.update_children()
def set_state(self):
model = self.screen.current_model
if model:
for field in model.mgroup.fields:
modelfield = model.mgroup.mfields.get(field, None)
if modelfield:
modelfield.state_set(model)
record = self.screen.current_record
if record:
for field in record.group.fields:
field = record.group.fields.get(field, None)
if field:
field.state_set(record)
def update_children(self):
ids = self.sel_ids_get()
@@ -591,23 +593,23 @@ class ViewList(ParserView):
value = 0.0
value_selected = 0.0
loaded = True
for model in self.screen.models.models:
if not model.loaded:
for record in self.screen.group:
if not record.loaded:
loaded = False
break
if model.id in ids or not ids:
if record.id in ids or not ids:
if not value_selected:
value_selected = model.fields_get()[self.children[child][0]]\
.get(model, check_load=False)
value_selected = record.fields_get()[self.children[child][0]]\
.get(record, check_load=False)
else:
value_selected += model.fields_get()[self.children[child][0]]\
.get(model, check_load=False)
value_selected += record.fields_get()[self.children[child][0]]\
.get(record, check_load=False)
if not value:
value = model.fields_get()[self.children[child][0]]\
.get(model, check_load=False)
value = record.fields_get()[self.children[child][0]]\
.get(record, check_load=False)
else:
value += model.fields_get()[self.children[child][0]]\
.get(model, check_load=False)
value += record.fields_get()[self.children[child][0]]\
.get(record, check_load=False)
if loaded:
label_str = locale.format('%.' + str(self.children[child][3]) + 'f',
@@ -624,8 +626,8 @@ class ViewList(ParserView):
def set_cursor(self, new=False, reset_view=True):
self.widget_tree.grab_focus()
if self.screen.current_model:
path = self.store.on_get_path(self.screen.current_model)
if self.screen.current_record:
path = self.store.on_get_path(self.screen.current_record)
focus_column = None
for column in self.widget_tree.get_columns():
renderers = column.get_cell_renderers()
@@ -647,21 +649,21 @@ class ViewList(ParserView):
def sel_ids_get(self):
def _func_sel_get(store, path, iter, ids):
model = store.on_get_iter(path)
if model and model.id > 0:
ids.append(model.id)
record = store.on_get_iter(path)
if record and record.id > 0:
ids.append(record.id)
ids = []
sel = self.widget_tree.get_selection()
sel.selected_foreach(_func_sel_get, ids)
return ids
def sel_models_get(self):
def _func_sel_get(store, path, iter, models):
models.append(store.on_get_iter(path))
models = []
def selected_records(self):
def _func_sel_get(store, path, iter, records):
records.append(store.on_get_iter(path))
records = []
sel = self.widget_tree.get_selection()
sel.selected_foreach(_func_sel_get, models)
return models
sel.selected_foreach(_func_sel_get, records)
return records
def unset_editable(self):
self.widget_tree.editable = False
@@ -10,9 +10,9 @@ _ = gettext.gettext
class EditableTreeView(gtk.TreeView):
leaving_model_events = (gtk.keysyms.Up, gtk.keysyms.Down,
leaving_record_events = (gtk.keysyms.Up, gtk.keysyms.Down,
gtk.keysyms.Return)
leaving_events = leaving_model_events + (gtk.keysyms.Tab,
leaving_events = leaving_record_events + (gtk.keysyms.Tab,
gtk.keysyms.ISO_Left_Tab, gtk.keysyms.KP_Enter)
def __init__(self, position):
@@ -20,38 +20,38 @@ class EditableTreeView(gtk.TreeView):
self.editable = position
self.cells = {}
def on_quit_cell(self, current_model, fieldname, value):
modelfield = current_model[fieldname]
if hasattr(modelfield, 'editabletree_entry'):
del modelfield.editabletree_entry
def on_quit_cell(self, current_record, fieldname, value):
field = current_record[fieldname]
if hasattr(field, 'editabletree_entry'):
del field.editabletree_entry
cell = self.cells[fieldname]
# The value has not changed and is valid ... do nothing.
if value == cell.get_textual_value(current_model) \
and modelfield.validate(current_model):
if value == cell.get_textual_value(current_record) \
and field.validate(current_record):
return
try:
real_value = cell.value_from_text(current_model, value)
modelfield.set_client(current_model, real_value)
real_value = cell.value_from_text(current_record, value)
field.set_client(current_record, real_value)
except parser.UnsettableColumn:
return
def on_open_remote(self, current_model, fieldname, create, value):
modelfield = current_model[fieldname]
def on_open_remote(self, current_record, fieldname, create, value):
field = current_record[fieldname]
cell = self.cells[fieldname]
if value != cell.get_textual_value(current_model) or not value:
if value != cell.get_textual_value(current_record) or not value:
changed = True
else:
changed = False
try:
valid, value = cell.open_remote(current_model, create,
valid, value = cell.open_remote(current_record, create,
changed, value)
if valid:
modelfield.set_client(current_model, value)
field.set_client(current_record, value)
except NotImplementedError:
pass
return cell.get_textual_value(current_model)
return cell.get_textual_value(current_record)
def on_create_line(self):
model = self.get_model()
@@ -60,12 +60,9 @@ class EditableTreeView(gtk.TreeView):
else:
method = model.append
ctx = self.screen.context.copy()
if self.screen.current_model and self.screen.current_model.parent:
ctx.update(self.screen.current_model.parent.expr_eval(
self.screen.default_get))
new_model = model.model_group.model_new(domain=self.screen.domain,
new_record = model.group.new(domain=self.screen.domain,
context=ctx)
res = method(new_model)
res = method(new_record)
return res
def __next_column(self, col):
@@ -115,24 +112,24 @@ class EditableTreeView(gtk.TreeView):
def set_value(self):
path, column = self.get_cursor()
store = self.get_model()
model = self.get_model()
if not path or not column:
return True
model = store.get_value(store.get_iter(path), 0)
modelfield = model[column.name]
if hasattr(modelfield, 'editabletree_entry'):
entry = modelfield.editabletree_entry
record = model.get_value(model.get_iter(path), 0)
field = record[column.name]
if hasattr(field, 'editabletree_entry'):
entry = field.editabletree_entry
if isinstance(entry, gtk.Entry):
txt = entry.get_text()
else:
txt = entry.get_active_text()
self.on_quit_cell(model, column.name, txt)
self.on_quit_cell(record, column.name, txt)
return True
def on_keypressed(self, entry, event):
path, column = self.get_cursor()
store = self.get_model()
model = store.get_value(store.get_iter(path), 0)
model = self.get_model()
record = model.get_value(model.get_iter(path), 0)
leaving = False
if event.keyval == gtk.keysyms.Right:
@@ -157,24 +154,20 @@ class EditableTreeView(gtk.TreeView):
else:
txt = entry.get_active_text()
entry.disconnect(entry.editing_done_id)
self.on_quit_cell(model, column.name, txt)
self.on_quit_cell(record, column.name, txt)
entry.editing_done_id = entry.connect('editing_done',
self.on_editing_done)
if event.keyval in self.leaving_model_events:
if not model.validate():
invalid_fields = model.invalid_fields
if event.keyval in self.leaving_record_events:
if not record.validate():
invalid_fields = record.invalid_fields
col = None
for col in self.get_columns():
if col.name in invalid_fields:
break
self.set_cursor(path, col, True)
if self.screen.form:
self.screen.form.message_info(
_('Warning; field "%s" is required!') % \
invalid_fields[col.name])
return True
if self.screen.tree_saves:
obj_id = model.save()
if not self.screen.parent:
obj_id = record.save()
if not obj_id:
return True
if event.keyval in (gtk.keysyms.Tab, gtk.keysyms.KP_Enter) \
@@ -187,12 +180,12 @@ class EditableTreeView(gtk.TreeView):
self.set_cursor(path, new_col, True)
elif event.keyval == gtk.keysyms.Up:
entry.disconnect(entry.editing_done_id)
self._key_up(path, store, column)
self._key_up(path, model, column)
entry.editing_done_id = entry.connect('editing_done',
self.on_editing_done)
elif event.keyval == gtk.keysyms.Down:
entry.disconnect(entry.editing_done_id)
self._key_down(path, store, column)
self._key_down(path, model, column)
entry.editing_done_id = entry.connect('editing_done',
self.on_editing_done)
elif event.keyval in (gtk.keysyms.Return,):
@@ -211,22 +204,22 @@ class EditableTreeView(gtk.TreeView):
break
entry.disconnect(entry.editing_done_id)
if self.editable == 'top':
new_path = self._key_up(path, store, col)
new_path = self._key_up(path, model, col)
else:
new_path = self._key_down(path, store, column)
new_path = self._key_down(path, model, column)
entry.editing_done_id = entry.connect('editing_done',
self.on_editing_done)
elif event.keyval == gtk.keysyms.Escape:
if model.id < 0:
store.remove(store.get_iter(path))
self.screen.current_model = False
if record.id < 0:
model.remove(model.get_iter(path))
self.screen.current_record = False
if not path[0]:
self.screen.current_model = False
if path[0] == len(self.screen.models.models) \
self.screen.current_record = False
if path[0] == len(self.screen.group) \
and path[0]:
path = (path[0] - 1,)
self.screen.display()
if len(self.screen.models.models):
if len(self.screen.group):
self.set_cursor(path, column, False)
elif event.keyval in (gtk.keysyms.F3, gtk.keysyms.F2):
if isinstance(entry, gtk.Entry):
@@ -234,9 +227,8 @@ class EditableTreeView(gtk.TreeView):
else:
value = entry.get_active_text()
entry.disconnect(entry.editing_done_id)
newval = self.on_open_remote(model, column.name,
create=(event.keyval==gtk.keysyms.F3),
value=value)
newval = self.on_open_remote(record, column.name,
create=(event.keyval==gtk.keysyms.F3), value=value)
if isinstance(entry, gtk.Entry):
entry.set_text(newval)
else:
@@ -245,31 +237,31 @@ class EditableTreeView(gtk.TreeView):
self.on_editing_done)
self.set_cursor(path, column, True)
else:
modelfield = model[column.name]
field = record[column.name]
if isinstance(entry, gtk.Entry):
entry.set_max_length(int(modelfield.attrs.get('size', 0)))
# store in the model the entry widget to get the value in set_value
modelfield.editabletree_entry = entry
model.modified = True
model.modified_fields.setdefault(column.name)
entry.set_max_length(int(field.attrs.get('size', 0)))
# store in the record the entry widget to get the value in set_value
field.editabletree_entry = entry
record.modified = True
record.modified_fields.setdefault(column.name)
return False
return True
def _key_down(self, path, store, column):
if path[0] == len(store) - 1 and self.editable == 'bottom':
def _key_down(self, path, model, column):
if path[0] == len(model) - 1 and self.editable == 'bottom':
self.on_create_line()
new_path = (path[0] + 1) % len(store)
new_path = (path[0] + 1) % len(model)
self.set_cursor(new_path, column, True)
self.scroll_to_cell(new_path)
return new_path
def _key_up(self, path, store, column):
def _key_up(self, path, model, column):
if path[0] == 0 and self.editable == 'top':
self.on_create_line()
new_path = 0
else:
new_path = (path[0] - 1) % len(store)
new_path = (path[0] - 1) % len(model)
self.set_cursor(new_path, column, True)
self.scroll_to_cell(new_path)
return new_path
@@ -278,9 +270,9 @@ class EditableTreeView(gtk.TreeView):
path, column = self.get_cursor()
if not path:
return True
store = self.get_model()
model = store.get_value(store.get_iter(path), 0)
model = self.get_model()
record = model.get_value(model.get_iter(path), 0)
if isinstance(entry, gtk.Entry):
self.on_quit_cell(model, column.name, entry.get_text())
self.on_quit_cell(record, column.name, entry.get_text())
elif isinstance(entry, gtk.ComboBoxEntry):
self.on_quit_cell(model, column.name, entry.get_active_text())
self.on_quit_cell(record, column.name, entry.get_active_text())
@@ -1,23 +1,13 @@
#This file is part of Tryton. The COPYRIGHT file at the top level of
#this repository contains the full copyright notices and license terms.
import locale
import gtk
from tryton.rpc import RPCProxy
from editabletree import EditableTreeView
from tryton.gui.window.view_form.view.interface import ParserInterface
import time
from tryton.gui.window.view_form.view.form_gtk.many2one import Dialog \
as M2ODialog
from tryton.gui.window.view_form.view.form_gtk.one2many import Dialog \
as O2MDialog
from tryton.gui.window.win_search import WinSearch
from tryton.gui.window.win_form import WinForm
from tryton.gui.window.view_form.screen import Screen
from tryton.gui.window.view_form.widget_search.form import _LIMIT
import tryton.rpc as rpc
import datetime
from tryton.common import DT_FORMAT, DHM_FORMAT, COLORS, node_attributes, \
TRYTON_ICON, HM_FORMAT
import tryton.common as common
@@ -31,6 +21,10 @@ from tryton.common.cellrendererfloat import CellRendererFloat
from tryton.action import Action
from tryton.translate import date_format
from tryton.pyson import PYSONDecoder
import gtk
import locale
import datetime
import time
import gettext
_ = gettext.gettext
@@ -60,10 +54,10 @@ def sort_model(column, treeview, screen):
else:
column.arrow_show = False
column.arrow.hide()
model = treeview.get_model()
if screen.search_count == len(model):
store = treeview.get_model()
if screen.search_count == len(store):
ids = screen.search_filter(only_ids=True)
model.sort(ids)
store.sort(ids)
else:
screen.search_filter()
@@ -73,7 +67,7 @@ class ParserTree(ParserInterface):
super(ParserTree, self).__init__(window, parent, attrs, screen)
self.treeview = None
def parse(self, model, root_node, fields):
def parse(self, model_name, root_node, fields):
dict_widget = {}
button_list = []
attrs = node_attributes(root_node)
@@ -102,11 +96,11 @@ class ParserTree(ParserInterface):
bool(int(node_attrs[boolean_fields]))
if fname not in fields:
continue
fields[fname].update(node_attrs)
node_attrs.update(fields[fname])
fields[fname].attrs.update(node_attrs)
node_attrs.update(fields[fname].attrs)
cell = CELLTYPES.get(node_attrs.get('widget',
fields[fname]['type']))(fname, model,
treeview, node_attrs, self.window)
fields[fname].attrs['type']))(fname, model_name,
treeview, self.window, node_attrs)
treeview.cells[fname] = cell
renderer = cell.renderer
@@ -122,15 +116,15 @@ class ParserTree(ParserInterface):
renderer.connect_after('editing-started', send_keys,
treeview)
col = gtk.TreeViewColumn(fields[fname]['string'], renderer)
col = gtk.TreeViewColumn(fields[fname].attrs['string'], renderer)
col.name = fname
hbox = gtk.HBox(False, 2)
label = gtk.Label(fields[fname]['string'])
label = gtk.Label(fields[fname].attrs['string'])
label.show()
help = fields[fname]['string']
if fields[fname].get('help'):
help += '\n' + fields[fname]['help']
help = fields[fname].attrs['string']
if fields[fname].attrs.get('help'):
help += '\n' + fields[fname].attrs['help']
tooltips.set_tip(label, help)
tooltips.enable()
arrow = gtk.Arrow(gtk.ARROW_DOWN, gtk.SHADOW_IN)
@@ -141,7 +135,7 @@ class ParserTree(ParserInterface):
hbox.show()
col.set_widget(hbox)
col._type = fields[fname]['type']
col._type = fields[fname].attrs['type']
col.set_cell_data_func(renderer, cell.setter)
col.set_clickable(True)
twidth = {
@@ -158,10 +152,10 @@ class ParserTree(ParserInterface):
'many2many': 50,
'boolean': 20,
}
if 'width' in fields[fname]:
width = int(fields[fname]['width'])
if 'width' in fields[fname].attrs:
width = int(fields[fname].attrs['width'])
else:
width = twidth.get(fields[fname]['type'], 100)
width = twidth.get(fields[fname].attrs['type'], 100)
col.width = width
if width > 0:
col.set_fixed_width(width)
@@ -171,30 +165,30 @@ class ParserTree(ParserInterface):
col.connect('clicked', sort_model, treeview, self.screen)
col.set_resizable(True)
col.set_sizing(gtk.TREE_VIEW_COLUMN_FIXED)
col.set_visible(not fields[fname].get('tree_invisible', False))
col.set_visible(not fields[fname].attrs.get('tree_invisible', False))
i = treeview.append_column(col)
if 'sum' in fields[fname] and fields[fname]['type'] \
if 'sum' in fields[fname].attrs and fields[fname].attrs['type'] \
in ('integer', 'biginteger', 'float', 'numeric',
'float_time'):
label = gtk.Label()
label.set_use_markup(True)
label_str = fields[fname]['sum'] + ': '
label_bold = bool(int(fields[fname].get('sum_bold', 0)))
label_str = fields[fname].attrs['sum'] + ': '
label_bold = bool(int(fields[fname].attrs.get('sum_bold', 0)))
if label_bold:
label.set_markup('<b>%s</b>' % label_str)
else:
label.set_markup(label_str)
label_sum = gtk.Label()
label_sum.set_use_markup(True)
if isinstance(fields[fname].get('digits'), str):
if isinstance(fields[fname].attrs.get('digits'), str):
digits = 2
else:
digits = fields[fname].get('digits', (16, 2))[1]
digits = fields[fname].attrs.get('digits', (16, 2))[1]
dict_widget[i] = (fname, label, label_sum, digits,
label_bold)
elif node.localName == 'button':
#TODO add shortcut
cell = Button(treeview, node_attrs, self.window, self.screen)
cell = Button(treeview, self.window, self.screen, node_attrs)
button_list.append(cell)
renderer = cell.renderer
string = node_attrs.get('string', _('Unknown'))
@@ -239,24 +233,24 @@ class ParserTree(ParserInterface):
class Char(object):
def __init__(self, field_name, model, treeview=None, attrs=None,
window=None):
def __init__(self, field_name, model_name, treeview, window, attrs=None):
super(Char, self).__init__()
self.field_name = field_name
self.model = model
self.model_name = model_name
self.attrs = attrs or {}
self.renderer = CellRendererText()
self.treeview = treeview
self.window = window
def setter(self, column, cell, store, iter):
model = store.get_value(iter, 0)
text = self.get_textual_value(model)
record = store.get_value(iter, 0)
text = self.get_textual_value(record)
if isinstance(cell, CellRendererToggle):
cell.set_active(bool(text))
else:
cell.set_property('text', text)
fg_color = self.get_color(model)
fg_color = self.get_color(record)
cell.set_property('foreground', fg_color)
if fg_color == 'black':
cell.set_property('foreground-set', False)
@@ -274,22 +268,22 @@ class Char(object):
and self.treeview.editable:
states = ('readonly', 'required', 'invisible')
field = model[self.field_name]
field.state_set(model, states=states)
invisible = field.get_state_attrs(model).get('invisible', False)
field = record[self.field_name]
field.state_set(record, states=states)
invisible = field.get_state_attrs(record).get('invisible', False)
cell.set_property('visible', not invisible)
if hasattr(self.treeview, 'editable') \
and self.treeview.editable:
readonly = field.get_state_attrs(model).get('readonly', False)
readonly = field.get_state_attrs(record).get('readonly', False)
if invisible:
readonly = True
if not isinstance(cell, CellRendererToggle):
bg_color = 'white'
if not field.get_state_attrs(model).get('valid', True):
if not field.get_state_attrs(record).get('valid', True):
bg_color = COLORS.get('invalid', 'white')
elif bool(int(field.get_state_attrs(model).get('required', 0))):
elif bool(int(field.get_state_attrs(record).get('required', 0))):
bg_color = COLORS.get('required', 'white')
cell.set_property('background', bg_color)
if bg_color == 'white':
@@ -308,50 +302,50 @@ class Char(object):
cell.set_property('xalign', align)
def get_color(self, model):
return model.expr_eval(self.treeview.colors, check_load=False)
def get_color(self, record):
return record.expr_eval(self.treeview.colors, check_load=False)
def open_remote(self, model, create, changed=False, text=None):
def open_remote(self, record, create, changed=False, text=None):
raise NotImplementedError
def get_textual_value(self, model):
return model[self.field_name].get_client(model) or ''
def get_textual_value(self, record):
return record[self.field_name].get_client(record) or ''
def value_from_text(self, model, text):
def value_from_text(self, record, text):
return text
class Int(Char):
def __init__(self, field_name, model, treeview=None, attrs=None,
window=None):
super(Int, self).__init__(field_name, model, treeview=treeview,
attrs=attrs, window=window)
def __init__(self, field_name, model_name, treeview, window, attrs=None):
super(Int, self).__init__(field_name, model_name, treeview, window,
attrs=attrs)
self.renderer = CellRendererInteger()
def value_from_text(self, model, text):
def value_from_text(self, record, text):
return int(text)
def get_textual_value(self, model):
def get_textual_value(self, record):
return locale.format('%d',
model[self.field_name].get_client(model) or 0, True)
record[self.field_name].get_client(record) or 0, True)
class Boolean(Int):
def __init__(self, *args):
super(Boolean, self).__init__(*args)
def __init__(self, field_name, model_name, treeview, window, attrs=None):
super(Boolean, self).__init__(field_name, model_name, treeview, window,
attrs=attrs)
self.renderer = CellRendererToggle()
self.renderer.connect('toggled', self._sig_toggled)
def get_textual_value(self, model):
return model[self.field_name].get_client(model)
def get_textual_value(self, record):
return record[self.field_name].get_client(record)
def _sig_toggled(self, renderer, path):
store = self.treeview.get_model()
model = store.get_value(store.get_iter(path), 0)
field = model[self.field_name]
if not field.get_state_attrs(model).get('readonly', False):
value = model[self.field_name].get_client(model)
model[self.field_name].set_client(model, int(not value))
record = store.get_value(store.get_iter(path), 0)
field = record[self.field_name]
if not field.get_state_attrs(record).get('readonly', False):
value = record[self.field_name].get_client(record)
record[self.field_name].set_client(record, int(not value))
self.treeview.set_cursor(path)
return True
@@ -359,24 +353,20 @@ class Boolean(Int):
class Date(Char):
server_format = DT_FORMAT
def __init__(self, field_name, model, treeview=None, attrs=None,
window=None):
def __init__(self, field_name, model_name, treeview, window, attrs=None):
super(Date, self).__init__(field_name, model_name, treeview, window,
attrs=attrs)
self.display_format = date_format()
self.field_name = field_name
self.model = model
self.attrs = attrs or {}
self.renderer = CellRendererDate(self.display_format)
self.treeview = treeview
self.window = window
def get_textual_value(self, model):
value = model[self.field_name].get_client(model)
def get_textual_value(self, record):
value = record[self.field_name].get_client(record)
if not value:
return ''
date = datetime.date(*time.strptime(value, self.server_format)[:3])
return common.datetime_strftime(date, self.display_format)
def value_from_text(self, model, text):
def value_from_text(self, record, text):
if not text:
return False
try:
@@ -389,14 +379,13 @@ class Date(Char):
class Datetime(Date):
server_format = DHM_FORMAT
def __init__(self, field_name, model, treeview=None, attrs=None,
window=None):
super(Datetime, self).__init__(field_name, model,
treeview=treeview, attrs=attrs, window=window)
def __init__(self, field_name, model_name, treeview, window, attrs=None):
super(Datetime, self).__init__(field_name, model_name, treeview,
window, attrs=attrs)
self.display_format = date_format() + ' ' + HM_FORMAT
def get_textual_value(self, model):
value = model[self.field_name].get_client(model)
def get_textual_value(self, record):
value = record[self.field_name].get_client(record)
if not value:
return ''
date = datetime.datetime(*time.strptime(value,
@@ -413,7 +402,7 @@ class Datetime(Date):
pass
return common.datetime_strftime(date, self.display_format)
def value_from_text(self, model, text):
def value_from_text(self, record, text):
if not text:
return False
try:
@@ -436,30 +425,29 @@ class Datetime(Date):
class Float(Char):
def __init__(self, field_name, model, treeview=None, attrs=None,
window=None):
super(Float, self).__init__(field_name, model, treeview=treeview,
attrs=attrs, window=window)
def __init__(self, field_name, model_name, treeview, window, attrs=None):
super(Float, self).__init__(field_name, model_name, treeview, window,
attrs=attrs)
self.renderer = CellRendererFloat()
def setter(self, column, cell, store, iter):
super(Float, self).setter(column, cell, store, iter)
model = store.get_value(iter, 0)
record = store.get_value(iter, 0)
if isinstance(self.attrs.get('digits'), str):
digits = model.expr_eval(self.attrs['digits'])
digits = record.expr_eval(self.attrs['digits'])
else:
digits = self.attrs.get('digits', (16, 2))
cell.digits = digits
def get_textual_value(self, model):
def get_textual_value(self, record):
if isinstance(self.attrs.get('digits'), str):
digit = model.expr_eval(self.attrs['digits'])[1]
digit = record.expr_eval(self.attrs['digits'])[1]
else:
digit = self.attrs.get('digits', (16, 2))[1]
return locale.format('%.'+str(digit)+'f',
model[self.field_name].get_client(model) or 0.0, True)
record[self.field_name].get_client(record) or 0.0, True)
def value_from_text(self, model, text):
def value_from_text(self, record, text):
try:
return locale.atof(text)
except:
@@ -468,72 +456,71 @@ class Float(Char):
class FloatTime(Char):
def __init__(self, field_name, model, treeview=None, attrs=None,
window=None):
super(FloatTime, self).__init__(field_name, model, treeview=treeview,
attrs=attrs, window=window)
def __init__(self, field_name, model_name, treeview, window, attrs=None):
super(FloatTime, self).__init__(field_name, model_name, treeview,
window, attrs=attrs)
self.conv = None
if attrs and attrs.get('float_time'):
self.conv = rpc.CONTEXT.get(attrs['float_time'])
def get_textual_value(self, model):
val = model[self.field_name].get_client(model)
def get_textual_value(self, record):
val = record[self.field_name].get_client(record)
return common.float_time_to_text(val, self.conv)
def value_from_text(self, model, text):
def value_from_text(self, record, text):
return common.text_to_float_time(text, self.conv)
class M2O(Char):
def value_from_text(self, model, text):
modelfield = model.mgroup.mfields[self.field_name]
if not text and not modelfield.get_state_attrs(
model)['required']:
def value_from_text(self, record, text):
field = record.group.fields[self.field_name]
if not text and not field.get_state_attrs(
record)['required']:
return False
relation = model[self.field_name].attrs['relation']
rpc_relation = RPCProxy(relation)
domain = model[self.field_name].domain_get(model)
context = model[self.field_name].context_get(model)
relation = record[self.field_name].attrs['relation']
domain = record[self.field_name].domain_get(record)
context = record[self.field_name].context_get(record)
if text:
dom = [('rec_name', 'ilike', '%' + text + '%'),
domain]
else:
dom = domain
args = ('model', relation, 'search', dom, 0, None, None,
context)
try:
if text:
dom = [('rec_name', 'ilike', '%' + text + '%'),
domain]
else:
dom = domain
ids = rpc_relation.search(dom, 0, None, None, context)
ids = rpc.execute(*args)
except Exception, exception:
common.process_exception(exception, self.window)
return '???'
ids = common.process_exception(exception, self.window, *args)
if not ids:
return '???'
if len(ids) != 1:
return self.search_remote(relation, ids,
domain=domain, context=context)[0]
return ids[0]
def open_remote(self, model, create=True, changed=False, text=None):
modelfield = model.mgroup.mfields[self.field_name]
relation = modelfield.attrs['relation']
def open_remote(self, record, create=True, changed=False, text=None):
field = record.group.fields[self.field_name]
relation = field.attrs['relation']
domain = modelfield.domain_get(model)
context = modelfield.context_get(model)
domain = field.domain_get(record)
context = field.context_get(record)
if create:
obj_id = None
elif not changed:
obj_id = modelfield.get(model)
obj_id = field.get(record)
else:
rpc_relation = RPCProxy(relation)
if text:
dom = [('rec_name', 'ilike', '%' + text + '%'), domain]
else:
dom = domain
args = ('model', relation, 'search', dom, 0, None, None, context)
try:
if text:
dom = [('rec_name', 'ilike', '%' + text + '%'), domain]
else:
dom = domain
ids = rpc_relation.search(dom, 0, None, None, context)
ids = rpc.execute(*args)
except Exception, exception:
common.process_exception(exception, self.window)
return False, False
ids = common.process_exception(exception, self.window, *args)
if not ids:
return False, False
if len(ids) == 1:
return True, ids[0]
searched = self.search_remote(relation, ids, domain=domain,
@@ -541,29 +528,41 @@ class M2O(Char):
if searched[0]:
return True, searched
return False, False
dia = M2ODialog(relation, obj_id, domain=domain, context=context,
window=self.window)
res, value = dia.run()
dia.destroy()
if res:
screen = Screen(relation, self.window, domain=domain, context=context,
view_type=['form'])
if obj_id:
screen.load([obj_id])
win = WinForm(screen, self.window)
else:
win = WinForm(screen, self.window, new=True)
value = False
while win.run():
if screen.save_current():
value = (screen.current_record.id,
screen.current_record.rec_name())
break
else:
screen.display()
win.destroy()
if value:
return True, value
else:
return False, False
def search_remote(self, relation, ids=None, domain=None, context=None):
rpc_relation = RPCProxy(relation)
win = WinSearch(relation, sel_multi=False, ids=ids, context=context,
domain=domain, parent=self.window)
found = win.run()
if found:
arg = ('model', relation, 'read', found[0], ['rec_name'],
context)
try:
name = rpc_relation.read(found[0], ['rec_name'],
context)['rec_name']
return found[0], name
res = rpc.execute(*args)
except Exception, exception:
common.process_exception(exception, self.window)
return False, None
res = common.process_exception(exception, self.window, *args)
if not res:
return False, None
return found[0], res['rec_name']
else:
return False, None
@@ -579,24 +578,25 @@ class O2M(Char):
super(O2M, self).setter(column, cell, store, iter)
cell.set_property('xalign', 0.5)
def get_textual_value(self, model):
return '( ' + str(len(model[self.field_name].\
get_client(model).models)) + ' )'
def get_textual_value(self, record):
return '( ' + str(len(record[self.field_name].\
get_client(record))) + ' )'
def value_from_text(self, model, text):
def value_from_text(self, record, text):
pass
def open_remote(self, model, create=True, changed=False, text=None):
models = model.value[self.field_name]
modelfield = model.mgroup.mfields[self.field_name]
relation = modelfield.attrs['relation']
context = modelfield.context_get(model)
def open_remote(self, record, create=True, changed=False, text=None):
group = record.value[self.field_name]
field = record.group.fields[self.field_name]
relation = field.attrs['relation']
context = field.context_get(record)
dia = O2MDialog(relation, parent=model, model=models,
attrs=modelfield.attrs, default_get_ctx=context,
window=self.window)
res, value = dia.run()
dia.destroy()
screen = Screen(relation, self.window, view_type=['tree', 'form'],
exclude_field=field.attrs.get('relation_field'))
screen.group = group
win = WinForm(screen, self.window, view_type='tree', context=context)
win.run()
win.destroy()
return False, False
@@ -606,53 +606,55 @@ class M2M(Char):
super(M2M, self).setter(column, cell, store, iter)
cell.set_property('xalign', 0.5)
def get_textual_value(self, model):
return '( ' + str(len(model[self.field_name].\
get_client(model).models)) + ' )'
def get_textual_value(self, record):
return '( ' + str(len(record[self.field_name].\
get_client(record))) + ' )'
def value_from_text(self, model, text):
def value_from_text(self, record, text):
if not text:
return []
if not (text[0] != '('):
return model[self.field_name].get(model)
relation = model[self.field_name].attrs['relation']
rpc_relation = RPCProxy(relation)
domain = model[self.field_name].domain_get(model)
context = model[self.field_name].context_get(model)
return record[self.field_name].get(record)
field = record[self.field_name]
relation = field.attrs['relation']
domain = field.domain_get(record)
context = field.context_get(record)
if text:
dom = [('rec_name', 'ilike', '%' + text + '%'),
domain]
else:
dom = domain
args = ('model', relation, 'search', dom, 0, _LIMIT, None, context)
try:
if text:
dom = [('rec_name', 'ilike', '%' + text + '%'),
domain]
else:
dom = domain
ids = rpc_relation.search(dom, 0, _LIMIT, None, context)
ids = rpc.execute(*args)
except Exception, exception:
common.process_exception(exception, self.window)
return []
ids = common.process_exception(exception, self.window, *args)
if ids is False:
return []
win = WinSearch(relation, sel_multi=True, ids=ids, context=context,
domain=domain, parent=self.window)
found = win.run()
return found or []
def open_remote(self, model, create=True, changed=False, text=None):
modelfield = model[self.field_name]
relation = modelfield.attrs['relation']
rpc_relation = RPCProxy(relation)
context = model[self.field_name].context_get(model)
domain = model[self.field_name].domain_get(model)
def open_remote(self, record, create=True, changed=False, text=None):
field = record[self.field_name]
relation = field.attrs['relation']
context = field.context_get(record)
domain = field.domain_get(record)
if create:
if text and len(text) and text[0] != '(':
domain.append(('name', '=', text))
args = ('model', relation, 'search', domain)
try:
ids = rpc_relation.search(domain)
ids = rpc.execute(*args)
except Exception, exception:
common.process_exception(exception, self.window)
return False, None
ids = common.process_exception(exception, self.window, *args)
if ids is False:
return False, None
if ids and len(ids)==1:
return True, ids
else:
ids = [x.id for x in model[self.field_name].get_client(model)]
ids = [x.id for x in field.get_client(record)]
win = WinSearch(relation, sel_multi=True, ids=ids, context=context,
domain=domain, parent=self.window)
found = win.run()
@@ -670,21 +672,22 @@ class Selection(Char):
selection = self.attrs.get('selection', [])[:]
self.selection = selection[:]
if 'relation' in self.attrs:
args = ('model', self.attrs['relation'], 'search_read',
self.attrs.get('domain', []), 0, None, None, rpc.CONTEXT,
['rec_name'])
try:
result = rpc.execute('model',
self.attrs['relation'], 'search_read',
self.attrs.get('domain', []),
0, None, None, rpc.CONTEXT, ['rec_name'])
selection = [(x['id'], x['rec_name']) for x in result]
result = rpc.execute(*args)
except Exception, exception:
common.process_exception(exception, self.window)
selection = []
result = common.process_exception(exception, self.window, *args)
if not result:
result = []
selection = [(x['id'], x['rec_name']) for x in result]
self.selection = selection[:]
else:
if not isinstance(selection, (list, tuple)):
try:
selection = rpc.execute('model',
self.model, selection, rpc.CONTEXT)
self.model_name, selection, rpc.CONTEXT)
except Exception, exception:
common.process_exception(exception, self.window)
selection = []
@@ -710,13 +713,13 @@ class Selection(Char):
self.renderer.set_property('model', selection_data)
self.renderer.set_property('text-column', 1)
def get_textual_value(self, model):
value = model[self.field_name].get(model)
def get_textual_value(self, record):
value = record[self.field_name].get(record)
if isinstance(value, (list, tuple)):
value = value[0]
return dict(self.selection).get(value, '')
def value_from_text(self, model, text):
def value_from_text(self, record, text):
res = False
for val, txt in self._selection:
if txt[:len(text)].lower() == text.lower():
@@ -728,16 +731,15 @@ class Selection(Char):
class Reference(Char):
def __init__(self, field_name, model, treeview=None, attrs=None,
window=None):
super(Reference, self).__init__(field_name, model, treeview=treeview,
attrs=attrs, window=window)
def __init__(self, field_name, model_name, treeview, window, attrs=None):
super(Reference, self).__init__(field_name, model_name, treeview,
window, attrs=attrs)
self._selection = {}
selection = attrs.get('selection', [])
if not isinstance(selection, (list, tuple)):
try:
selection = rpc.execute('model',
model, selection, rpc.CONTEXT)
model_name, selection, rpc.CONTEXT)
except Exception, exception:
common.process_exception(exception, self.window)
selection = []
@@ -745,25 +747,30 @@ class Reference(Char):
for i, j in selection:
self._selection[i] = str(j)
def get_textual_value(self, model):
value = model[self.field_name].get_client(model)
def get_textual_value(self, record):
value = record[self.field_name].get_client(record)
if not value:
model, (obj_id, name) = '', (0, '')
else:
model, (obj_id, name) = value
if model:
if not name and obj_id:
args = ('model', model, 'read', obj_id, ['rec_name'],
rpc.CONTEXT)
try:
name = RPCProxy(model).read(obj_id, ['rec_name'],
rpc.CONTEXT)['rec_name']
res = rpc.execute(*args)
except Exception, exception:
common.process_exception(exception, self.window)
res = common.process_exception(exception, self.window,
*args)
if not res:
name = '???'
else:
name = res['rec_name']
return self._selection.get(model, model) + ',' + name
else:
return name
def value_from_text(self, model, text):
def value_from_text(self, record, text):
pass
@@ -775,9 +782,10 @@ class ProgressBar(object):
'top_to_bottom': gtk.PROGRESS_TOP_TO_BOTTOM,
}
def __init__(self, field_name, model, treeview=None, attrs=None, window=None):
def __init__(self, field_name, model_name, treeview, window, attrs=None):
super(ProgressBar, self).__init__()
self.field_name = field_name
self.model = model
self.model_name = model_name
self.attrs = attrs or {}
self.renderer = gtk.CellRendererProgress()
orientation = self.orientations.get(self.attrs.get('orientation',
@@ -787,29 +795,29 @@ class ProgressBar(object):
self.window = window
def setter(self, column, cell, store, iter):
model = store.get_value(iter, 0)
value = float(self.get_textual_value(model) or 0.0)
record = store.get_value(iter, 0)
value = float(self.get_textual_value(record) or 0.0)
cell.set_property('value', value)
if isinstance(self.attrs.get('digits'), str):
digit = model.expr_eval(self.attrs['digits'])[1]
digit = record.expr_eval(self.attrs['digits'])[1]
else:
digit = self.attrs.get('digits', (16, 2))[1]
text = locale.format('%.' + str(digit) + 'f', value, True)
cell.set_property('text', text + '%')
def open_remote(self, model, create, changed=False, text=None):
def open_remote(self, record, create, changed=False, text=None):
raise NotImplementedError
def get_textual_value(self, model):
return model[self.field_name].get_client(model) or ''
def get_textual_value(self, record):
return record[self.field_name].get_client(record) or ''
def value_from_text(self, model, text):
def value_from_text(self, record, text):
return float(text)
class Button(object):
def __init__(self, treeview=None, attrs=None, window=None, screen=None):
def __init__(self, treeview, windown, screen, attrs=None):
super(Button, self).__init__()
self.attrs = attrs or {}
self.renderer = CellRendererButton(attrs.get('string', _('Unknown')))
@@ -823,24 +831,24 @@ class Button(object):
if not path:
return True
store = self.treeview.get_model()
model = store.get_value(store.get_iter(path), 0)
record = store.get_value(store.get_iter(path), 0)
state_changes = PYSONDecoder().decode(model.expr_eval(
state_changes = PYSONDecoder().decode(record.expr_eval(
self.attrs.get('states', {}), check_load=False))
if state_changes.get('invisible') \
or state_changes.get('readonly'):
return True
self.screen.current_model = model
self.screen.current_record = record
obj_id = self.screen.save_current()
if obj_id:
if not self.attrs.get('confirm', False) or \
common.sur(self.attrs['confirm'], self.window):
button_type = self.attrs.get('type', 'workflow')
ctx = rpc.CONTEXT.copy()
ctx.update(model.context_get())
ctx.update(record.context_get())
if button_type == 'workflow':
args = ('model', self.screen.name,
args = ('model', self.screen.model_name,
'workflow_trigger_validate', obj_id,
self.attrs['name'], ctx)
try:
@@ -848,7 +856,7 @@ class Button(object):
except Exception, exception:
common.process_exception(exception, self.window, *args)
elif button_type == 'object':
args = ('model', self.screen.name,
args = ('model', self.screen.model_name,
self.attrs['name'], [obj_id], ctx)
try:
rpc.execute(*args)
@@ -865,7 +873,7 @@ class Button(object):
self.window, *args)
if action_id:
Action.execute(action_id, {
'model': self.screen.name,
'model': self.screen.model_name,
'id': obj_id,
'ids': [obj_id],
}, self.window, context=ctx)
@@ -873,9 +881,6 @@ class Button(object):
raise Exception('Unallowed button type')
self.screen.reload(writen=True)
else:
if self.screen.form:
self.screen.form.message_info(
_('Invalid Form, correct red fields!'))
self.screen.display()
CELLTYPES = {
@@ -15,6 +15,9 @@ class ScreenContainer(object):
self.vbox.pack_end(self.viewport)
self.filter_vbox = None
self.button = None
self.alternate_viewport = gtk.Viewport()
self.alternate_viewport.set_shadow_type(gtk.SHADOW_NONE)
self.alternate_view = False
def widget_get(self):
return self.vbox
@@ -70,6 +73,15 @@ class ScreenContainer(object):
self.filter_vbox.hide()
def set(self, widget):
if self.alternate_view:
if self.alternate_viewport.get_child():
self.alternate_viewport.remove(
self.alternate_viewport.get_child())
if widget == self.viewport.get_child():
self.viewport.remove(self.viewport.get_child())
self.alternate_viewport.add(widget)
self.alternate_viewport.show_all()
return
if self.viewport.get_child():
self.viewport.remove(self.viewport.get_child())
self.viewport.add(widget)
@@ -36,7 +36,7 @@ class WidgetParse(ParserInterface):
widget = PARSERS[node.localName](self.window, self.parent,
self.attrs, screen)
wid, child, buttons, on_write, notebooks, cursor_widget = \
widget.parse(screen.resource, node, fields)
widget.parse(screen.model_name, node, fields)
screen.set_on_write(on_write)
res = PARSERS2[node.localName](self.window, screen, wid, child,
buttons, toolbar, notebooks, cursor_widget)
+47 -35
View File
@@ -14,14 +14,10 @@ import os
_ = gettext.gettext
class WinExport(object):
"Window export"
def __init__(self, model, ids, fields, preload=None, parent=None,
context=None):
if preload is None:
preload = []
def __init__(self, model, ids, fields, parent=None, context=None):
self.dialog = gtk.Dialog(
title= _("Export to CSV"),
parent=parent,
@@ -187,9 +183,6 @@ class WinExport(object):
self.model1 = gtk.TreeStore(gobject.TYPE_STRING, gobject.TYPE_STRING)
self.model2 = gtk.ListStore(gobject.TYPE_STRING, gobject.TYPE_STRING)
for i in preload:
self.model2.set(self.model2.append(), 0, i[1], 1, i[0])
self.fields = {}
def model_populate(fields, prefix_node='', prefix=None,
@@ -278,45 +271,64 @@ class WinExport(object):
self.model2.clear()
def fill_predefwin(self):
ir_export = rpc.RPCProxy('ir.export')
ir_export_line = rpc.RPCProxy('ir.export.line')
args = ('model', 'ir.export', 'search',
[('resource', '=', self.model)], 0, None, None, rpc.CONTEXT)
try:
export_ids = ir_export.search([('resource', '=', self.model)])
export_ids = rpc.execute(*args)
except Exception, exception:
common.process_exception(exception, self.parent)
return
for export in ir_export.read(export_ids):
try:
fields = ir_export_line.read(export['export_fields'])
except Exception, exception:
common.process_exception(exception, self.parent)
continue
self.predef_model.append((
export['id'],
[f['name'] for f in fields],
export_ids = common.process_exception(exception, self.parent,
*args)
if not export_ids:
return
args = ('model', 'ir.export', 'read', export_ids, None, rpc.CONTEXT)
try:
exports = rpc.execute(*args)
except Exception, exception:
exports = common.process_exception(exception, self.parent, *args)
if not exports:
return
args = ('model', 'ir.export.line', 'read',
[x['export_fields'] for x in exports], None, rpc.CONTEXT)
try:
lines = rpc.execute(*args)
except Exception, exception:
lines = common.process_exception(exception, self.parent, *args)
if not lines:
return
id2lines = {}
for line in lines:
id2lines.setdefault(line['export'], []).append(line)
for export in exports:
self.predef_model.append((export['id'],
[x['name'] for x in id2lines[export['id']]],
export['name'],
', '.join(self.fields_data[f['name']]['string'] \
for f in fields),
))
','.join(self.fields_data[x['name']]['string']
for x in id2lines[export['id']])))
self.pref_export.set_model(self.predef_model)
def add_predef(self, widget):
name = common.ask('What is the name of this export?', self.parent)
name = common.ask(_('What is the name of this export?'), self.parent)
if not name:
return
ir_export = rpc.RPCProxy('ir.export')
iter = self.model2.get_iter_root()
fields = []
while iter:
field_name = self.model2.get_value(iter, 1)
fields.append(field_name)
iter = self.model2.iter_next(iter)
args = ('model', 'ir.export', 'create', {
'name': name,
'resource': self.model,
'export_fields': [('create', {
'name': x,
}) for x in fields],
}, rpc.CONTEXT)
try:
new_id = ir_export.create({'name' : name, 'resource' : self.model,
'export_fields' : [('create', {'name' : f}) for f in fields]})
new_id = rpc.execute(*args)
except Exception, exception:
common.process_exception(exception, self.dialog)
return
new_ids = common.process_exception(exception, self.dialog, *args)
if not new_id:
return
self.predef_model.append((
new_id,
fields,
@@ -331,13 +343,13 @@ class WinExport(object):
(model, i) = sel
if not i:
return None
ir_export = rpc.RPCProxy('ir.export')
export_id = model.get_value(i, 0)
args = ('model', 'ir.export', 'delete', export_id, rpc.CONTEXT)
try:
ir_export.delete(export_id)
rpc.execute(*args)
except Exception, exception:
common.process_exception(exception, self.dialog)
return
if not common.process_exception(exception, self.dialog, *args):
return
for i in range(len(self.predef_model)):
if self.predef_model[i][0] == export_id:
del self.predef_model[i]
+309
View File
@@ -0,0 +1,309 @@
#This file is part of Tryton. The COPYRIGHT file at the top level of
#this repository contains the full copyright notices and license terms.
from tryton.common import TRYTON_ICON
import tryton.common as common
import gtk
import pango
import gettext
_ = gettext.gettext
class WinForm(object):
"Form window"
def __init__(self, screen, parent, view_type='form', new=False,
context=None):
self.parent = parent
self.screen = screen
self.context = context
self.prev_view = self.screen.current_view
self.screen.screen_container.alternate_view = True
switch_new = False
if view_type == 'form' and not self.screen.current_record:
switch_new = True
if view_type not in (x.view_type for x in self.screen.views) and \
view_type not in self.screen.view_to_load:
self.screen.add_view_id(False, view_type, display=True)
else:
self.screen.switch_view(view_type=view_type)
if new and not switch_new:
self.screen.new(context=self.context)
self.win = gtk.Dialog(_('Link'), parent,
gtk.DIALOG_MODAL|gtk.DIALOG_DESTROY_WITH_PARENT)
self.win.connect('close', self._sig_close)
self.win.set_property('default-width', 760)
self.win.set_property('default-height', 500)
self.win.set_position(gtk.WIN_POS_CENTER_ON_PARENT)
self.win.set_icon(TRYTON_ICON)
self.win.set_has_separator(False)
self.accel_group = gtk.AccelGroup()
self.win.add_accel_group(self.accel_group)
self.but_cancel = None
if new:
icon_cancel = gtk.STOCK_CANCEL
self.but_cancel = self.win.add_button(icon_cancel,
gtk.RESPONSE_CANCEL)
self.but_ok = self.win.add_button(gtk.STOCK_OK, gtk.RESPONSE_OK)
self.but_ok.add_accelerator('clicked', self.accel_group,
gtk.keysyms.Return, gtk.gdk.CONTROL_MASK, gtk.ACCEL_VISIBLE)
self.win.set_default_response(gtk.RESPONSE_OK)
self.win.set_title(self.screen.current_view.title)
title = gtk.Label()
title.set_use_markup(True)
title.modify_font(pango.FontDescription("12"))
title.set_label('<b>' + self.screen.current_view.title + '</b>')
title.set_padding(20, 3)
title.set_alignment(0.0, 0.5)
title.modify_fg(gtk.STATE_NORMAL, gtk.gdk.color_parse("#000000"))
title.show()
self.info_label = gtk.Label()
self.info_label.set_padding(3, 3)
self.info_label.set_alignment(1.0, 0.5)
self.eb_info = gtk.EventBox()
self.eb_info.add(self.info_label)
self.eb_info.connect('button-release-event',
lambda *a: self.message_info(''))
vbox = gtk.VBox()
vbox.pack_start(self.eb_info, expand=True, fill=True, padding=5)
vbox.show()
hbox = gtk.HBox()
hbox.pack_start(title, expand=True, fill=True)
hbox.pack_start(vbox, expand=False, fill=True, padding=20)
hbox.show()
frame = gtk.Frame()
frame.set_shadow_type(gtk.SHADOW_ETCHED_IN)
frame.add(hbox)
frame.show()
eb = gtk.EventBox()
eb.add(frame)
eb.modify_bg(gtk.STATE_NORMAL, gtk.gdk.color_parse("#ffffff"))
eb.show()
self.win.vbox.pack_start(eb, expand=False, fill=True, padding=3)
if view_type == 'tree':
hbox = gtk.HBox(homogeneous=False, spacing=0)
tooltips = common.Tooltips()
self.but_new = gtk.Button()
tooltips.set_tip(self.but_new, _('Create a new record'))
self.but_new.connect('clicked', self._sig_new)
img_new = gtk.Image()
img_new.set_from_stock('tryton-new', gtk.ICON_SIZE_SMALL_TOOLBAR)
img_new.set_alignment(0.5, 0.5)
self.but_new.add(img_new)
self.but_new.set_relief(gtk.RELIEF_NONE)
hbox.pack_start(self.but_new, expand=False, fill=False)
self.but_del = gtk.Button()
tooltips.set_tip(self.but_del, _('Delete selected record'))
self.but_del.connect('clicked', self._sig_remove)
img_del = gtk.Image()
img_del.set_from_stock('tryton-delete', gtk.ICON_SIZE_SMALL_TOOLBAR)
img_del.set_alignment(0.5, 0.5)
self.but_del.add(img_del)
self.but_del.set_relief(gtk.RELIEF_NONE)
hbox.pack_start(self.but_del, expand=False, fill=False)
hbox.pack_start(gtk.VSeparator(), expand=False, fill=True)
but_pre = gtk.Button()
tooltips.set_tip(but_pre, _('Previous'))
but_pre.connect('clicked', self._sig_previous)
img_pre = gtk.Image()
img_pre.set_from_stock('tryton-go-previous', gtk.ICON_SIZE_SMALL_TOOLBAR)
img_pre.set_alignment(0.5, 0.5)
but_pre.add(img_pre)
but_pre.set_relief(gtk.RELIEF_NONE)
hbox.pack_start(but_pre, expand=False, fill=False)
self.label = gtk.Label('(0,0)')
hbox.pack_start(self.label, expand=False, fill=False)
but_next = gtk.Button()
tooltips.set_tip(but_next, _('Next'))
but_next.connect('clicked', self._sig_next)
img_next = gtk.Image()
img_next.set_from_stock('tryton-go-next', gtk.ICON_SIZE_SMALL_TOOLBAR)
img_next.set_alignment(0.5, 0.5)
but_next.add(img_next)
but_next.set_relief(gtk.RELIEF_NONE)
hbox.pack_start(but_next, expand=False, fill=False)
hbox.pack_start(gtk.VSeparator(), expand=False, fill=True)
but_switch = gtk.Button()
tooltips.set_tip(but_switch, _('Switch'))
but_switch.connect('clicked', self.switch_view)
img_switch = gtk.Image()
img_switch.set_from_stock('tryton-fullscreen', gtk.ICON_SIZE_SMALL_TOOLBAR)
img_switch.set_alignment(0.5, 0.5)
but_switch.add(img_switch)
but_switch.set_relief(gtk.RELIEF_NONE)
hbox.pack_start(but_switch, expand=False, fill=False)
tooltips.enable()
alignment = gtk.Alignment(1.0)
alignment.add(hbox)
alignment.show_all()
self.win.vbox.pack_start(alignment, expand=False, fill=True)
scroll = gtk.ScrolledWindow()
scroll.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
scroll.set_placement(gtk.CORNER_TOP_LEFT)
scroll.set_shadow_type(gtk.SHADOW_NONE)
scroll.show()
self.win.vbox.pack_start(scroll, expand=True, fill=True)
scroll.add(self.screen.screen_container.alternate_viewport)
width, height = self.screen.current_view.widget.size_request()
scroll.set_size_request(width, height + 30)
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)
self.screen.display()
self.screen.current_view.set_cursor()
def message_info(self, message, color='red'):
if message:
self.info_label.set_label(message)
self.eb_info.modify_bg(gtk.STATE_NORMAL, gtk.gdk.color_parse(
COLOR_SCHEMES.get(color, 'white')))
self.eb_info.show_all()
else:
self.info_label.set_label('')
self.eb_info.hide()
def on_keypress(self, widget, event):
if (event.keyval == gtk.keysyms.F3) \
and self.but_new.get_property('sensitive'):
self._sig_new(widget)
return False
if event.keyval in (gtk.keysyms.Delete, gtk.keysyms.KP_Delete) \
and widget == self.screen.screen_container.alternate_viewport:
self._sig_remove(widget)
return False
def switch_view(self, widget):
self.screen.switch_view()
def _sig_new(self, widget):
self.screen.new(context=self.context)
self.screen.current_view.widget.set_sensitive(True)
def _sig_next(self, widget):
self.screen.display_next()
def _sig_previous(self, widget):
self.screen.display_prev()
def _sig_remove(self, widget):
self.screen.remove(delete=True)
def _sig_activate(self, *args):
self._sig_add()
self.wid_text.grab_focus()
def _sig_add(self, *args):
domain = []
context = rpc.CONTEXT.copy()
try:
if self.wid_text.get_text():
dom = [('rec_name', 'ilike',
'%' + self.wid_text.get_text() + '%'), domain]
else:
dom = domain
ids = rpc.execute('model', self.attrs['relation'],
'search', dom, 0, _LIMIT, None, context)
except Exception, exception:
common.process_exception(exception, self.window)
return False
if len(ids) != 1:
win = WinSearch(self.attrs['relation'], sel_multi=True, ids=ids,
context=context, domain=domain, parent=self.window,
views_preload=self.attrs.get('views', {}))
ids = win.run()
res_id = None
if ids:
res_id = ids[0]
self.screen.load(ids, modified=True)
self.screen.display(res_id=res_id)
if self.screen.current_view:
self.screen.current_view.set_cursor()
self.wid_text.set_text('')
def _sig_label(self, screen, signal_data):
name = '_'
if signal_data[0] >= 0:
name = str(signal_data[0] + 1)
line = '(%s/%s)' % (name, signal_data[1])
self.label.set_text(line)
def _sig_close(self, widget):
if self.screen.current_view:
self.screen.current_view.set_value()
if self.but_cancel:
self.screen.remove(delete=True)
elif self.screen.current_record and \
not self.screen.current_record.validate():
if self.screen.current_view:
self.screen.current_view.set_cursor()
self.screen.current_view.display()
widget.emit_stop_by_name('close')
def run(self):
end = False
while not end:
res = self.win.run()
self.screen.current_view.set_value()
end = (res != gtk.RESPONSE_OK) \
or (not self.screen.current_record \
or self.screen.current_record.validate())
if not end:
self.screen.current_view.set_cursor()
self.screen.display()
if self.but_cancel:
self.but_cancel.set_label(gtk.STOCK_CLOSE)
if res == gtk.RESPONSE_OK:
return True
elif res == gtk.RESPONSE_CANCEL:
self.screen.remove(delete=True)
return False
def new(self):
self.screen.new(context=self.context)
self.screen.current_view.display()
self.screen.current_view.set_cursor(new=True)
def destroy(self):
self.screen.screen_container.alternate_view = False
viewport = self.screen.screen_container.alternate_viewport
if viewport.get_child():
viewport.remove(viewport.get_child())
self.screen.switch_view(view_type=self.prev_view.view_type)
self.screen.signal_unconnect(self)
self.win.destroy()
self.parent.present()
+13 -18
View File
@@ -14,7 +14,7 @@ _ = gettext.gettext
class WinImport(object):
"Window import"
def __init__(self, model, fields, preload=None, parent=None):
def __init__(self, model, fields, parent=None):
self.dialog = gtk.Dialog(
title=_("Import from CSV"), parent=parent,
flags=gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT
@@ -195,9 +195,6 @@ class WinImport(object):
gobject.TYPE_STRING)
self.model2 = gtk.ListStore(gobject.TYPE_STRING, gobject.TYPE_STRING)
for field in (preload or []):
self.model2.set(self.model2.append(), 0, field[1], 1, field[0])
self.fields = {}
self.fields_invert = {}
@@ -207,28 +204,26 @@ class WinImport(object):
fields_order.sort(lambda x, y: -cmp(fields[x].get('string', ''),
fields[y].get('string', '')))
for field in fields_order:
if (fields[field]['type'] not in ('reference',)) \
and (not fields[field].get('readonly', False) \
or not dict(fields[field].get('states', {}).get(
'draft', [('readonly', True)])).get('readonly',
True)):
self.fields_data[prefix_node+field] = fields[field]
st_name = prefix_value+fields[field]['string'] or field
if not fields[field].get('readonly', False):
self.fields_data[prefix_node + field] = fields[field]
st_name = prefix_value + fields[field]['string'] or field
node = self.model1.insert(prefix, 0, [st_name,
prefix_node+field,
(fields[field].get('required', False) and \
'#ddddff') or 'white'])
self.fields[prefix_node+field] = st_name
self.fields_invert[st_name] = prefix_node+field
self.fields_invert[st_name] = prefix_node + field
if fields[field]['type'] == 'one2many' and level > 0:
args = ('model', fields[field]['relation'],
'fields_get', None, rpc.CONTEXT)
try:
fields2 = rpc.execute('model',
fields[field]['relation'], 'fields_get',
None, rpc.CONTEXT)
fields2 = rpc.execute(*args)
except Exception, exception:
common.process_exception(exception, self.dialog)
continue
model_populate(fields2, prefix_node+field+'/', node,
fields2 = common.process_exception(exception,
self.dialog, *args)
if not fields2:
continue
model_populate(fields2, prefix_node + field + '/', node,
st_name+'/', level-1)
model_populate(fields)
+19 -78
View File
@@ -7,6 +7,7 @@ from tryton.gui.window.view_form.screen import Screen
import tryton.gui.window.view_form.widget_search as widget_search
from tryton.config import TRYTON_ICON
import tryton.common as common
from tryton.gui.window.win_form import WinForm
_ = gettext.gettext
@@ -47,7 +48,8 @@ class WinSearch(object):
self.win.vbox.pack_start(scrollwindow, expand=True, fill=True)
self.screen = Screen(model, self.win, view_type=['tree'],
context=context, views_preload=views_preload)
context=context, views_preload=views_preload,
row_activate=self.sig_activate)
self.view = self.screen.current_view
self.view.unset_editable()
sel = self.view.widget_tree.get_selection()
@@ -61,44 +63,12 @@ class WinSearch(object):
viewport.add(self.screen.widget)
scrollwindow.add(viewport)
scrollwindow.show_all()
self.view.widget_tree.connect('row_activated', self.sig_activate)
self.view.widget_tree.connect('button_press_event', self.sig_button)
self.model_name = model
if 'tree' in views_preload:
view_form = views_preload['tree']
else:
ctx = self.context.copy()
ctx.update(rpc.CONTEXT)
try:
args = ('model', self.model_name, 'fields_view_get',
False, 'tree', ctx)
view_form = rpc.execute(*args)
except Exception, exception:
view_form = common.process_exception(exception, self.parent, *args)
self.form = widget_search.Form(view_form['arch'], view_form['fields'],
model, parent=self.win, call=(self, self.find))
self.title = _('Search: %s') % self.form.name
self.title_results = _('Search: %s (%%d result(s))') % \
self.form.name.replace('%', '%%')
self.win.set_title(self.title)
hbox.pack_start(self.form.widget)
self.ids = ids
if self.ids:
self.reload()
self.old_search = None
self.old_offset = self.old_limit = None
if self.ids:
self.old_search = []
self.old_limit = self.form.get_limit()
self.old_offset = self.form.get_offset()
self.view.widget.show_all()
if self.form.focusable:
self.form.focusable.grab_focus()
if ids:
self.screen.load(ids)
self.win.set_size_request(700, 500)
@@ -113,37 +83,6 @@ class WinSearch(object):
self.win.response(gtk.RESPONSE_OK)
return False
def find(self, *args):
limit = self.form.get_limit()
offset = self.form.get_offset()
if (self.old_search == self.form.value) \
and (self.old_limit==limit) \
and (self.old_offset==offset):
self.win.response(gtk.RESPONSE_OK)
return False
self.old_offset = offset
self.old_limit = limit
value = self.form.value
value += self.domain
try:
self.ids = rpc.execute('model', self.model_name, 'search', value,
offset, limit, None, rpc.CONTEXT)
except Exception, exception:
common.process_exception(exception, self.win)
return False
self.reload()
self.old_search = self.form.value
self.win.set_title(self.title_results % len(self.ids))
return True
def reload(self):
self.screen.clear()
self.screen.load(self.ids)
sel = self.view.widget_tree.get_selection()
def sel_ids_get(self):
return self.screen.sel_ids_get()
def destroy(self):
self.parent.present()
self.screen.destroy()
@@ -154,22 +93,24 @@ class WinSearch(object):
while not end:
button = self.win.run()
if button == gtk.RESPONSE_OK:
res = self.sel_ids_get()
res = self.screen.sel_ids_get()
end = True
elif button == gtk.RESPONSE_APPLY:
end = not self.find()
end = not self.screen.search_filter()
if end:
res = self.sel_ids_get()
res = self.screen.sel_ids_get()
elif button == gtk.RESPONSE_ACCEPT:
from tryton.gui.window.view_form.view.form_gtk.many2one \
import Dialog
dia = Dialog(self.model_name, window=self.win,
domain=self.domain, context=self.context)
res, value = dia.run()
if res:
res = [value[0]]
else:
res = None
res = None
screen = Screen(self.model_name, self.win, domain=self.domain,
context=self.context, view_type=['form'])
win = WinForm(screen, self.win, new=True)
while win.run():
if screen.save_current():
res = [screen.current_record.id]
break
else:
screen.display()
win.destroy()
end = True
else:
res = None
+1 -1
View File
@@ -175,7 +175,7 @@ class Wizard(SignalEvent):
self.screen = Screen(obj_name, self.window, view_type=[],
context=context)
self.screen.add_view_custom(arch, fields, display=True)
self.screen.add_view(arch, fields, display=True)
self.screen.widget.show()
title = gtk.Label()
+1 -22
View File
@@ -168,9 +168,8 @@ def logout():
def context_reload():
global CONTEXT, TIMEZONE
user = RPCProxy('res.user')
try:
context = user.get_preferences(True, {})
context = execute('model', 'res.user', 'get_preferences', True, {})
except:
return
CONTEXT = {}
@@ -224,23 +223,3 @@ def execute(*args):
def execute_nonblocking(*args):
return _execute(False, *args)
class RPCProxy(object):
def __init__(self, name):
self.name = name
self.__attrs = {}
def __getattr__(self, attr):
if attr not in self.__attrs:
self.__attrs[attr] = RPCFunction(self.name, attr)
return self.__attrs[attr]
class RPCFunction(object):
def __init__(self, name, func_name):
self.name = name
self.func = func_name
def __call__(self, *args):
return execute('model', self.name, self.func, *args)
+1 -1
View File
@@ -24,7 +24,7 @@ class SignalEvent(object):
return True
def signal_unconnect(self, key, signal=None):
if not signal:
if signal is None:
signal = self.__connects.keys()
else:
signal = [signal]
+4 -4
View File
@@ -55,7 +55,7 @@ class Dialog(object):
val[i] = fields[i]['value']
self.screen = Screen(obj_name, self.dia, view_type=[], context=context)
self.screen.add_view_custom(arch, fields, display=True)
self.screen.add_view(arch, fields, display=True)
title = gtk.Label()
title.set_use_markup(True)
@@ -110,7 +110,7 @@ class Dialog(object):
self.dia.set_title(self.screen.current_view.title)
self.dia.show()
self.screen.new(default=False)
self.screen.current_model.set(val)
self.screen.current_record.set(val)
self.screen.current_view.set_cursor()
def run(self, datas=None):
@@ -119,7 +119,7 @@ class Dialog(object):
while True:
res = self.dia.run()
self.screen.current_view.set_value()
if self.screen.current_model.validate() \
if self.screen.current_record.validate() \
or (res<0) or (self.states[res]=='end'):
break
self.screen.display()
@@ -206,7 +206,7 @@ class Wizard(object):
dia = Dialog(res['arch'], res['fields'], res['state'],
res['object'], parent, action=action,
size=res['size'], context=ctx)
dia.screen.current_model.set(datas['form'])
dia.screen.current_record.set(datas['form'])
res2 = dia.run(datas['form'])
if not res2:
break