Allow to edit One2Many on editable list with list view
This commit is contained in:
1 parent
1e9be5bf49
commit
f209ec4d30
4 files changed
+217
-117
No files matched your search
@@ -74,6 +74,7 @@ class Screen(SignalEvent):
|
||||
self.fields_view_tree = None
|
||||
self.exclude_field = exclude_field
|
||||
self.sort = sort
|
||||
self.view_to_load = []
|
||||
|
||||
if view_type:
|
||||
self.view_to_load = view_type[1:]
|
||||
|
||||
@@ -3,9 +3,107 @@ import gettext
|
||||
from tryton.common import TRYTON_ICON
|
||||
from interface import WidgetInterface
|
||||
from tryton.gui.window.view_form.screen import Screen
|
||||
from tryton.gui.window.view_form.model.group import ModelRecordGroup
|
||||
|
||||
_ = gettext.gettext
|
||||
|
||||
def _create_menu(self):
|
||||
hbox = gtk.HBox(homogeneous=False, spacing=5)
|
||||
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='gtk-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 Default'), True)
|
||||
menuitem_set_default.connect('activate',
|
||||
lambda *x: self._menu_sig_default_set())
|
||||
menu_title.add(menuitem_set_default)
|
||||
menuitem_title.set_submenu(menu_title)
|
||||
|
||||
menubar.add(menuitem_title)
|
||||
hbox.pack_start(menubar, expand=True, fill=True)
|
||||
|
||||
tooltips = gtk.Tooltips()
|
||||
|
||||
self.eb_new = gtk.EventBox()
|
||||
tooltips.set_tip(self.eb_new, _('Create a new entry'))
|
||||
self.eb_new.set_events(gtk.gdk.BUTTON_PRESS)
|
||||
self.eb_new.connect('button_press_event', self._sig_new)
|
||||
img_new = gtk.Image()
|
||||
img_new.set_from_stock('gtk-new', gtk.ICON_SIZE_MENU)
|
||||
img_new.set_alignment(0.5, 0.5)
|
||||
self.eb_new.add(img_new)
|
||||
hbox.pack_start(self.eb_new, expand=False, fill=False)
|
||||
|
||||
self.eb_open = gtk.EventBox()
|
||||
tooltips.set_tip(self.eb_open, _('Edit this entry'))
|
||||
self.eb_open.set_events(gtk.gdk.BUTTON_PRESS)
|
||||
self.eb_open.connect('button_press_event', self._sig_edit)
|
||||
img_open = gtk.Image()
|
||||
img_open.set_from_stock('gtk-open', gtk.ICON_SIZE_MENU)
|
||||
img_open.set_alignment(0.5, 0.5)
|
||||
self.eb_open.add(img_open)
|
||||
hbox.pack_start(self.eb_open, expand=False, fill=False)
|
||||
|
||||
self.eb_del = gtk.EventBox()
|
||||
tooltips.set_tip(self.eb_del, _('Remove this entry'))
|
||||
self.eb_del.set_events(gtk.gdk.BUTTON_PRESS)
|
||||
self.eb_del.connect('button_press_event', self._sig_remove)
|
||||
img_del = gtk.Image()
|
||||
img_del.set_from_stock('gtk-delete', gtk.ICON_SIZE_MENU)
|
||||
img_del.set_alignment(0.5, 0.5)
|
||||
self.eb_del.add(img_del)
|
||||
hbox.pack_start(self.eb_del, expand=False, fill=False)
|
||||
|
||||
hbox.pack_start(gtk.VSeparator(), expand=False, fill=True)
|
||||
|
||||
eb_pre = gtk.EventBox()
|
||||
tooltips.set_tip(eb_pre, _('Previous'))
|
||||
eb_pre.set_events(gtk.gdk.BUTTON_PRESS)
|
||||
eb_pre.connect('button_press_event', self._sig_previous)
|
||||
img_pre = gtk.Image()
|
||||
img_pre.set_from_stock('gtk-go-back', gtk.ICON_SIZE_MENU)
|
||||
img_pre.set_alignment(0.5, 0.5)
|
||||
eb_pre.add(img_pre)
|
||||
hbox.pack_start(eb_pre, expand=False, fill=False)
|
||||
|
||||
self.label = gtk.Label('(0,0)')
|
||||
hbox.pack_start(self.label, expand=False, fill=False)
|
||||
|
||||
eb_next = gtk.EventBox()
|
||||
tooltips.set_tip(eb_next, _('Next'))
|
||||
eb_next.set_events(gtk.gdk.BUTTON_PRESS)
|
||||
eb_next.connect('button_press_event', self._sig_next)
|
||||
img_next = gtk.Image()
|
||||
img_next.set_from_stock('gtk-go-forward', gtk.ICON_SIZE_MENU)
|
||||
img_next.set_alignment(0.5, 0.5)
|
||||
eb_next.add(img_next)
|
||||
hbox.pack_start(eb_next, expand=False, fill=False)
|
||||
|
||||
hbox.pack_start(gtk.VSeparator(), expand=False, fill=True)
|
||||
|
||||
eb_switch = gtk.EventBox()
|
||||
tooltips.set_tip(eb_switch, _('Switch'))
|
||||
eb_switch.set_events(gtk.gdk.BUTTON_PRESS)
|
||||
eb_switch.connect('button_press_event', self.switch_view)
|
||||
img_switch = gtk.Image()
|
||||
img_switch.set_from_stock('gtk-justify-left', gtk.ICON_SIZE_MENU)
|
||||
img_switch.set_alignment(0.5, 0.5)
|
||||
eb_switch.add(img_switch)
|
||||
hbox.pack_start(eb_switch, expand=False, fill=False)
|
||||
|
||||
tooltips.enable()
|
||||
|
||||
return hbox, menuitem_title
|
||||
|
||||
|
||||
class Dialog(object):
|
||||
|
||||
@@ -19,6 +117,12 @@ class Dialog(object):
|
||||
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(_('Tryton - Link'), window,
|
||||
gtk.DIALOG_MODAL|gtk.DIALOG_DESTROY_WITH_PARENT)
|
||||
self.window = window
|
||||
@@ -44,6 +148,11 @@ class Dialog(object):
|
||||
|
||||
self.default_get_ctx = default_get_ctx
|
||||
|
||||
menuitem_title = None
|
||||
if isinstance(model, ModelRecordGroup):
|
||||
hbox, menuitem_title = _create_menu(self)
|
||||
self.dia.vbox.pack_start(hbox, expand=False, fill=True)
|
||||
|
||||
scroll = gtk.ScrolledWindow()
|
||||
scroll.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
|
||||
scroll.set_placement(gtk.CORNER_TOP_LEFT)
|
||||
@@ -60,25 +169,36 @@ class Dialog(object):
|
||||
self.screen.models._context.update(model_ctx)
|
||||
if not model:
|
||||
model = self.screen.new(context=default_get_ctx)
|
||||
self.screen.models.model_add(model)
|
||||
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,
|
||||
if isinstance(model, ModelRecordGroup):
|
||||
self.screen.models_set(model)
|
||||
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)
|
||||
else:
|
||||
self.screen.add_view_id(False, 'form', display=True,
|
||||
context=default_get_ctx)
|
||||
self.screen.models.model_add(model)
|
||||
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 = attrs.get('string', '')
|
||||
if name:
|
||||
name += ' - '
|
||||
name += self.screen.current_view.title
|
||||
self.dia.set_title(self.dia.get_title() + ' - ' + name)
|
||||
if menuitem_title:
|
||||
menuitem_title.get_child().set_text(name)
|
||||
|
||||
viewport.add(self.screen.widget)
|
||||
width, height = self.screen.screen_container.size_get()
|
||||
@@ -86,6 +206,79 @@ class Dialog(object):
|
||||
self.dia.show_all()
|
||||
self.screen.display()
|
||||
|
||||
def on_keypress(self, widget, event):
|
||||
if (event.keyval in (gtk.keysyms.N, gtk.keysyms.n) \
|
||||
and event.state & gtk.gdk.CONTROL_MASK) \
|
||||
or event.keyval == gtk.keysyms.F1:
|
||||
self._sig_new(widget, event)
|
||||
return False
|
||||
if event.keyval == gtk.keysyms.F2:
|
||||
self._sig_edit(widget, event)
|
||||
return False
|
||||
if (event.keyval in (gtk.keysyms.L, gtk.keysyms.l) \
|
||||
and event.state & gtk.gdk.CONTROL_MASK):
|
||||
self.switch_view(widget, event)
|
||||
return False
|
||||
|
||||
def switch_view(self, btn, arg):
|
||||
self.screen.switch_view()
|
||||
|
||||
def _sig_new(self, widget, event):
|
||||
if event.type in (gtk.gdk.BUTTON_PRESS, gtk.gdk.KEY_PRESS):
|
||||
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, event=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, event):
|
||||
if event.type == gtk.gdk.BUTTON_PRESS:
|
||||
self.screen.display_next()
|
||||
|
||||
def _sig_previous(self, widget, event):
|
||||
if event.type == gtk.gdk.BUTTON_PRESS:
|
||||
self.screen.display_prev()
|
||||
|
||||
def _sig_remove(self, widget, event):
|
||||
if event.type == gtk.gdk.BUTTON_PRESS:
|
||||
self.screen.remove()
|
||||
if not self.screen.models.models:
|
||||
self.screen.current_view.widget.set_sensitive(False)
|
||||
|
||||
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):
|
||||
pass
|
||||
|
||||
def new(self):
|
||||
model = self.screen.new(context=self.default_get_ctx)
|
||||
self.screen.models.model_add(model)
|
||||
@@ -97,7 +290,8 @@ class Dialog(object):
|
||||
while not end:
|
||||
res = self.dia.run()
|
||||
end = (res != gtk.RESPONSE_OK) \
|
||||
or self.screen.current_model.validate()
|
||||
or (not self.screen.current_model \
|
||||
or self.screen.current_model.validate())
|
||||
if not end:
|
||||
self.screen.display()
|
||||
self.but_cancel.set_label(gtk.STOCK_CLOSE)
|
||||
@@ -122,99 +316,8 @@ class One2Many(WidgetInterface):
|
||||
|
||||
self.widget = gtk.VBox(homogeneous=False, spacing=5)
|
||||
|
||||
hbox = gtk.HBox(homogeneous=False, spacing=5)
|
||||
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)
|
||||
hbox, menuitem_title = _create_menu(self)
|
||||
|
||||
menuitem_title = gtk.ImageMenuItem(stock_id='gtk-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 Default'), True)
|
||||
menuitem_set_default.connect('activate',
|
||||
lambda *x: self._menu_sig_default_set())
|
||||
menu_title.add(menuitem_set_default)
|
||||
menuitem_title.set_submenu(menu_title)
|
||||
|
||||
menubar.add(menuitem_title)
|
||||
hbox.pack_start(menubar, expand=True, fill=True)
|
||||
|
||||
tooltips = gtk.Tooltips()
|
||||
|
||||
self.eb_new = gtk.EventBox()
|
||||
tooltips.set_tip(self.eb_new, _('Create a new entry'))
|
||||
self.eb_new.set_events(gtk.gdk.BUTTON_PRESS)
|
||||
self.eb_new.connect('button_press_event', self._sig_new)
|
||||
img_new = gtk.Image()
|
||||
img_new.set_from_stock('gtk-new', gtk.ICON_SIZE_MENU)
|
||||
img_new.set_alignment(0.5, 0.5)
|
||||
self.eb_new.add(img_new)
|
||||
hbox.pack_start(self.eb_new, expand=False, fill=False)
|
||||
|
||||
self.eb_open = gtk.EventBox()
|
||||
tooltips.set_tip(self.eb_open, _('Edit this entry'))
|
||||
self.eb_open.set_events(gtk.gdk.BUTTON_PRESS)
|
||||
self.eb_open.connect('button_press_event', self._sig_edit)
|
||||
img_open = gtk.Image()
|
||||
img_open.set_from_stock('gtk-open', gtk.ICON_SIZE_MENU)
|
||||
img_open.set_alignment(0.5, 0.5)
|
||||
self.eb_open.add(img_open)
|
||||
hbox.pack_start(self.eb_open, expand=False, fill=False)
|
||||
|
||||
self.eb_del = gtk.EventBox()
|
||||
tooltips.set_tip(self.eb_del, _('Remove this entry'))
|
||||
self.eb_del.set_events(gtk.gdk.BUTTON_PRESS)
|
||||
self.eb_del.connect('button_press_event', self._sig_remove)
|
||||
img_del = gtk.Image()
|
||||
img_del.set_from_stock('gtk-delete', gtk.ICON_SIZE_MENU)
|
||||
img_del.set_alignment(0.5, 0.5)
|
||||
self.eb_del.add(img_del)
|
||||
hbox.pack_start(self.eb_del, expand=False, fill=False)
|
||||
|
||||
hbox.pack_start(gtk.VSeparator(), expand=False, fill=True)
|
||||
|
||||
eb_pre = gtk.EventBox()
|
||||
tooltips.set_tip(eb_pre, _('Previous'))
|
||||
eb_pre.set_events(gtk.gdk.BUTTON_PRESS)
|
||||
eb_pre.connect('button_press_event', self._sig_previous)
|
||||
img_pre = gtk.Image()
|
||||
img_pre.set_from_stock('gtk-go-back', gtk.ICON_SIZE_MENU)
|
||||
img_pre.set_alignment(0.5, 0.5)
|
||||
eb_pre.add(img_pre)
|
||||
hbox.pack_start(eb_pre, expand=False, fill=False)
|
||||
|
||||
self.label = gtk.Label('(0,0)')
|
||||
hbox.pack_start(self.label, expand=False, fill=False)
|
||||
|
||||
eb_next = gtk.EventBox()
|
||||
tooltips.set_tip(eb_next, _('Next'))
|
||||
eb_next.set_events(gtk.gdk.BUTTON_PRESS)
|
||||
eb_next.connect('button_press_event', self._sig_next)
|
||||
img_next = gtk.Image()
|
||||
img_next.set_from_stock('gtk-go-forward', gtk.ICON_SIZE_MENU)
|
||||
img_next.set_alignment(0.5, 0.5)
|
||||
eb_next.add(img_next)
|
||||
hbox.pack_start(eb_next, expand=False, fill=False)
|
||||
|
||||
hbox.pack_start(gtk.VSeparator(), expand=False, fill=True)
|
||||
|
||||
eb_switch = gtk.EventBox()
|
||||
tooltips.set_tip(eb_switch, _('Switch'))
|
||||
eb_switch.set_events(gtk.gdk.BUTTON_PRESS)
|
||||
eb_switch.connect('button_press_event', self.switch_view)
|
||||
img_switch = gtk.Image()
|
||||
img_switch.set_from_stock('gtk-justify-left', gtk.ICON_SIZE_MENU)
|
||||
img_switch.set_alignment(0.5, 0.5)
|
||||
eb_switch.add(img_switch)
|
||||
hbox.pack_start(eb_switch, expand=False, fill=False)
|
||||
|
||||
tooltips.enable()
|
||||
self.widget.pack_start(hbox, expand=False, fill=True)
|
||||
|
||||
self.screen = Screen(attrs['relation'], self._window,
|
||||
|
||||
@@ -81,7 +81,7 @@ class EditableTreeView(gtk.TreeView):
|
||||
self.screen.form.message_state(_('Relation Field: F1: New F2: Open/Search'))
|
||||
elif focus_column and (focus_column._type in ('one2many')) \
|
||||
and self.screen.form:
|
||||
self.screen.form.message_state(_('Relation Field: F1: New'))
|
||||
self.screen.form.message_state(_('Relation Field: F2: Open'))
|
||||
elif focus_column and (focus_column._type in ('boolean')):
|
||||
start_editing = False
|
||||
elif self.screen.form:
|
||||
|
||||
@@ -10,11 +10,13 @@ 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
|
||||
|
||||
import tryton.rpc as rpc
|
||||
import datetime as DT
|
||||
from tryton.common import DT_FORMAT, DHM_FORMAT, COLORS, node_attributes
|
||||
from tryton.common import DT_FORMAT, DHM_FORMAT, COLORS, node_attributes, TRYTON_ICON
|
||||
|
||||
if not hasattr(locale, 'nl_langinfo'):
|
||||
locale.nl_langinfo = lambda *a: '%x'
|
||||
@@ -458,21 +460,15 @@ class O2M(Char):
|
||||
pass
|
||||
|
||||
def open_remote(self, model, create=True, changed=False, text=None):
|
||||
if not create:
|
||||
raise NotImplementedError
|
||||
models = model.value[self.field_name]
|
||||
modelfield = model.mgroup.mfields[self.field_name]
|
||||
relation = modelfield.attrs['relation']
|
||||
context = modelfield.context_get(model)
|
||||
|
||||
dia = O2MDialog(relation, parent=model, attrs=modelfield.attrs,
|
||||
default_get_ctx=context, window=self.window)
|
||||
res = True
|
||||
while res:
|
||||
res, value = dia.run()
|
||||
if res:
|
||||
model.value[self.field_name].model_add(value)
|
||||
value.signal('record-changed', value.parent)
|
||||
dia.new()
|
||||
dia = O2MDialog(relation, parent=model, model=models,
|
||||
attrs=modelfield.attrs, default_get_ctx=context,
|
||||
window=self.window)
|
||||
res, value = dia.run()
|
||||
dia.destroy()
|
||||
return False, False
|
||||
|
||||
|
||||
Reference in new issue
Block a user