diff --git a/tryton/gui/window/view_form/screen/screen.py b/tryton/gui/window/view_form/screen/screen.py index 77a5c2b07e..6b42ea02ed 100644 --- a/tryton/gui/window/view_form/screen/screen.py +++ b/tryton/gui/window/view_form/screen/screen.py @@ -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:] diff --git a/tryton/gui/window/view_form/view/form_gtk/one2many.py b/tryton/gui/window/view_form/view/form_gtk/one2many.py index 68e5485f59..1a82be510d 100644 --- a/tryton/gui/window/view_form/view/form_gtk/one2many.py +++ b/tryton/gui/window/view_form/view/form_gtk/one2many.py @@ -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, diff --git a/tryton/gui/window/view_form/view/list_gtk/editabletree.py b/tryton/gui/window/view_form/view/list_gtk/editabletree.py index 248763958e..369bdd0f0b 100644 --- a/tryton/gui/window/view_form/view/list_gtk/editabletree.py +++ b/tryton/gui/window/view_form/view/list_gtk/editabletree.py @@ -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: diff --git a/tryton/gui/window/view_form/view/list_gtk/parser.py b/tryton/gui/window/view_form/view/list_gtk/parser.py index ef7691346e..e37cdcd8ed 100644 --- a/tryton/gui/window/view_form/view/list_gtk/parser.py +++ b/tryton/gui/window/view_form/view/list_gtk/parser.py @@ -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