From 0db930385fba9b44aa9548d954da8da7058faec7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Thu, 17 Apr 2008 15:03:39 +0200 Subject: [PATCH] Add board view and remove old action tag in view_form --- tryton/gui/window/board.py | 50 +++++ tryton/gui/window/view_board/__init__.py | 1 + tryton/gui/window/view_board/action.py | 192 ++++++++++++++++++ tryton/gui/window/view_board/parser.py | 179 ++++++++++++++++ tryton/gui/window/view_board/view_board.py | 26 +++ tryton/gui/window/view_form/view/form.py | 1 - .../window/view_form/view/form_gtk/action.py | 105 ---------- .../window/view_form/view/form_gtk/parser.py | 8 - tryton/gui/window/window.py | 4 + 9 files changed, 452 insertions(+), 114 deletions(-) create mode 100644 tryton/gui/window/board.py create mode 100644 tryton/gui/window/view_board/__init__.py create mode 100644 tryton/gui/window/view_board/action.py create mode 100644 tryton/gui/window/view_board/parser.py create mode 100644 tryton/gui/window/view_board/view_board.py delete mode 100644 tryton/gui/window/view_form/view/form_gtk/action.py diff --git a/tryton/gui/window/board.py b/tryton/gui/window/board.py new file mode 100644 index 0000000000..2f6d4bedcb --- /dev/null +++ b/tryton/gui/window/board.py @@ -0,0 +1,50 @@ +"Board" +import gtk +from tryton.signal_event import SignalEvent +import tryton.rpc as rpc +from tryton.gui.window.view_board import ViewBoard + + +class Board(SignalEvent): + 'Board' + + def __init__(self, window, view_id, context=None, name=False, auto_refresh=False): + super(Board, self).__init__() + + try: + view = rpc.execute('object', 'execute', 'ir.ui.view', 'read', + view_id, ['arch'], context) + except Exception, exception: + rpc.process_exception(exception, window) + raise + + self.board = ViewBoard(view['arch'], window, context=context) + + if not name: + self.name = self.board.name + else: + self.name = name + + self.widget = gtk.VBox() + + viewport = gtk.Viewport() + viewport.set_shadow_type(gtk.SHADOW_NONE) + viewport.add(self.board.widget_get()) + viewport.show() + self.scrolledwindow = gtk.ScrolledWindow() + self.scrolledwindow.set_shadow_type(gtk.SHADOW_NONE) + self.scrolledwindow.set_policy(gtk.POLICY_AUTOMATIC, + gtk.POLICY_AUTOMATIC) + self.scrolledwindow.add(viewport) + self.scrolledwindow.show() + + self.widget.pack_start(self.scrolledwindow) + self.widget.show() + + self.handlers = { + 'but_reload': self.sig_reload, + } + + def sig_reload(self, test_modified=True): + self.board.reload() + return True diff --git a/tryton/gui/window/view_board/__init__.py b/tryton/gui/window/view_board/__init__.py new file mode 100644 index 0000000000..bae9b41ca6 --- /dev/null +++ b/tryton/gui/window/view_board/__init__.py @@ -0,0 +1 @@ +from view_board import * diff --git a/tryton/gui/window/view_board/action.py b/tryton/gui/window/view_board/action.py new file mode 100644 index 0000000000..8d133a85a5 --- /dev/null +++ b/tryton/gui/window/view_board/action.py @@ -0,0 +1,192 @@ +'Action' +import gtk +from tryton.gui.window.view_form.screen import Screen +import tryton.rpc as rpc +import time +import datetime +from tryton.gui.window.win_search import WinSearch +from tryton.action import Action as Action2 + + +class Action(object): + + def __init__(self, window, attrs=None): + self.act_id = int(attrs['name']) + self._window = window + + try: + self.action = rpc.execute('object', 'execute', + 'ir.action.act_window', 'read', self.act_id, False, + rpc.CONTEXT) + except Exception, exception: + rpc.process_exception(exception, self._window) + raise + + if self.action.get('views', []): + view_ids = [x[0] for x in self.action['views']] + self.action['view_mode'] = [x[1] for x in self.action['views']] + elif self.action.get('view_id', False): + view_ids = [self.action['view_id'][0]] + + if 'view_mode' in attrs: + self.action['view_mode'] = attrs['view_mode'] + + self.action.setdefault('domain', '[]') + self.context = {'active_id': False, 'active_ids': []} + self.context.update(eval(self.action.get('context', '{}'), + self.context.copy())) + + eval_ctx = self.context.copy() + eval_ctx['datetime'] = datetime + self.context.update(eval(self.action.get('context', '{}'), eval_ctx)) + + domain_ctx = self.context.copy() + domain_ctx['time'] = time + domain_ctx['datetime'] = datetime + self.domain = eval(self.action['domain'] or '[]', domain_ctx) + + + self.widget = gtk.Frame() + self.widget.set_border_width(5) + + hbox = gtk.HBox(homogeneous=False, spacing=5) + self.widget.set_label_widget(hbox) + self.widget.set_label_align(1, 0.5) + + self.title = gtk.Label() + hbox.pack_start(self.title, expand=True, fill=True) + + tooltips = gtk.Tooltips() + + hbox.pack_start(gtk.VSeparator(), expand=False, fill=True) + + eb_search = gtk.EventBox() + tooltips.set_tip(eb_search, _('Search')) + eb_search.set_events(gtk.gdk.BUTTON_PRESS) + eb_search.connect('button_press_event', self._sig_search) + img_search = gtk.Image() + img_search.set_from_stock('gtk-find', gtk.ICON_SIZE_MENU) + img_search.set_alignment(0.5, 0.5) + eb_search.add(img_search) + hbox.pack_start(eb_search, expand=False, fill=False) + + eb_open = gtk.EventBox() + tooltips.set_tip(eb_open, _('Open')) + eb_open.set_events(gtk.gdk.BUTTON_PRESS) + eb_open.connect('button_press_event', self._sig_open) + img_open = gtk.Image() + img_open.set_from_stock('gtk-open', gtk.ICON_SIZE_MENU) + img_open.set_alignment(0.5, 0.5) + eb_open.add(img_open) + hbox.pack_start(eb_open, expand=False, fill=False) + + hbox.pack_start(gtk.VSeparator(), expand=False, fill=True) + + eb_previous = gtk.EventBox() + tooltips.set_tip(eb_previous, _('Previous')) + eb_previous.set_events(gtk.gdk.BUTTON_PRESS) + eb_previous.connect('button_press_event', self._sig_previous) + img_previous = gtk.Image() + img_previous.set_from_stock('gtk-go-back', gtk.ICON_SIZE_MENU) + img_previous.set_alignment(0.5, 0.5) + eb_previous.add(img_previous) + hbox.pack_start(eb_previous, 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._sig_switch) + 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) + + alignment = gtk.Alignment(0.5, 0.5, 1.0, 1.0) + alignment.set_padding(8, 0, 0, 0) + self.widget.add(alignment) + + self.widget.show_all() + + if self.action['view_type'] == 'form': + 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.title.set_text(attrs.get('string', + self.screen.current_view.title)) + self.screen.signal_connect(self, 'record-message', self._sig_label) + elif self.action['view_type'] == 'tree': + pass #TODO + self.widget.set_size_request(int(attrs.get('width',-1)), + int(attrs.get('height', -1))) + self.display() + + def _sig_switch(self, *args): + self.screen.switch_view() + + def _sig_search(self, widget, event): + if event.type == gtk.gdk.BUTTON_PRESS: + win = WinSearch(self.action['res_model'], domain=self.domain, + context=self.context, parent=self._window) + res = win.run() + if res: + self.screen.clear() + self.screen.load(res) + + def _sig_open(self, widget, event): + if event.type == gtk.gdk.BUTTON_PRESS: + try: + action_id = rpc.execute('object', 'execute', 'ir.action', + 'get_action_id', self.act_id, + rpc.CONTEXT) + except Exception, exception: + rpc.process_exception(exception, self._window) + if action_id: + Action2.execute(action_id, {}) + + def _sig_previous(self, widget, event): + if event.type == gtk.gdk.BUTTON_PRESS: + self.screen.display_prev() + + def _sig_next(self, widget, event): + if event.type == gtk.gdk.BUTTON_PRESS: + self.screen.display_next() + + 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 set_value(self, mode, model_field): + self.screen.current_view.set_value() + return True + + def display(self): + try: + res_id = rpc.execute('object', 'execute', + self.action['res_model'], 'search', self.domain, 0, + self.action.get('limit', 80)) + except Exception, exception: + rpc.process_exception(exception, self._window) + return False + self.screen.clear() + self.screen.load(res_id) + return True diff --git a/tryton/gui/window/view_board/parser.py b/tryton/gui/window/view_board/parser.py new file mode 100644 index 0000000000..1f6291238c --- /dev/null +++ b/tryton/gui/window/view_board/parser.py @@ -0,0 +1,179 @@ +'Parser' +import gtk +from tryton.gui.window.view_form.view.form_gtk.parser import _container +import tryton.common as common +from action import Action +from tryton.config import CONFIG, TRYTON_ICON + + +class ParserBoard(object): + + def __init__(self, window): + self.window = window + self.title = None + + def parse(self, root_node, notebook=None, paned=None, tooltips=None): + widgets = [] + + attrs = common.node_attributes(root_node) + if not tooltips: + tooltips = gtk.Tooltips() + + container = _container(tooltips) + container.new(col=int(attrs.get('col', 4))) + + if not self.title: + self.title = attrs.get('string', 'Unknown') + + for node in root_node.childNodes: + if not node.nodeType == node.ELEMENT_NODE: + continue + attrs = common.node_attributes(node) + if node.localName == 'image': + icon = gtk.Image() + icon.set_from_stock(attrs['name'], gtk.ICON_SIZE_DIALOG) + container.wid_add(icon, colspan=int(attrs.get('colspan', 1)), + expand=int(attrs.get('expand',0)), ypadding=10, + help_tip=attrs.get('help', False), + fill=int(attrs.get('fill', 0))) + elif node.localName == 'separator': + text = attrs.get('string', '') + 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']]: + attrs['states'] = \ + fields[attrs['name']]['states'] + text = fields[attrs['name']]['string'] + vbox = VBox(attrs=attrs) + if text: + label = gtk.Label(text) + label.set_use_markup(True) + label.set_alignment(float(attrs.get('align', 0.0)), 0.5) + vbox.pack_start(label) + vbox.pack_start(gtk.HSeparator()) + container.wid_add(vbox, colspan=int(attrs.get('colspan', 1)), + expand=int(attrs.get('expand', 0)), + ypadding=10, help_tip=attrs.get('help', False), + fill=int(attrs.get('fill', 0))) + elif node.localName == 'label': + text = attrs.get('string', '') + if not text: + if 'name' in attrs and attrs['name'] in fields: + if 'states' in fields[attrs['name']]: + attrs['states'] = fields[attrs['name']]['states'] + if gtk.widget_get_default_direction() == gtk.TEXT_DIR_RTL: + text = _(':') + fields[attrs['name']]['string'] + else: + text = fields[attrs['name']]['string'] + _(':') + if 'align' not in attrs: + attrs['align'] = 1.0 + else: + for node in node.childNodes: + if node.nodeType == node.TEXT_NODE: + text += node.data + else: + text += node.toxml() + if not text: + container.empty_add(int(attrs.get('colspan', 1))) + continue + label = gtk.Label(text) + label.set_use_markup(True) + if 'align' in attrs: + label.set_alignment(float(attrs['align'] or 0.0), 0.5) + label.set_angle(int(attrs.get('angle', 0))) + expand = False + if 'expand' in attrs: + expand = bool(eval(attrs['expand'])) + fill = False + if 'fill' in attrs: + fill = bool(eval(attrs['fill'])) + xexpand = False + if 'xexpand' in attrs: + xexpand = bool(eval(attrs['xexpand'])) + xfill = True + if 'xfill' in attrs: + xfill = bool(eval(attrs['xfill'])) + container.wid_add(label, + colspan=int(attrs.get('colspan', 1)), + expand=expand, help_tip=attrs.get('help', False), + fill=fill, xexpand=xexpand, xfill=xfill) + elif node.localName == 'newline': + container.newline() + elif node.localName == 'notebook': + notebook = gtk.Notebook() + if attrs and 'tabpos' in attrs: + pos = {'up':gtk.POS_TOP, + 'down':gtk.POS_BOTTOM, + 'left':gtk.POS_LEFT, + 'right':gtk.POS_RIGHT + }[attrs['tabpos']] + else: + if CONFIG['client.form_tab'] == 'top': + pos = gtk.POS_TOP + elif CONFIG['client.form_tab'] == 'left': + pos = gtk.POS_LEFT + elif CONFIG['client.form_tab'] == 'right': + pos = gtk.POS_RIGHT + elif CONFIG['client.form_tab'] == 'bottom': + pos = gtk.POS_BOTTOM + notebook.set_tab_pos(pos) + notebook.set_border_width(3) + container.wid_add(notebook, colspan=attrs.get('colspan', 3), + expand=True, fill=True) + widget, new_widgets = self.parse(node, notebook, tooltips=tooltips) + widgets += new_widgets + elif node.localName == 'page': + if attrs and 'angle' in attrs: + angle = int(attrs['angle']) + else: + angle = int(CONFIG['client.form_tab_orientation']) + label = gtk.Label(attrs.get('string','No String Attr.')) + label.set_angle(angle) + widget, new_widgets = self.parse(node, notebook, tooltips=tooltips) + widgets += new_widgets + notebook.append_page(widget, label) + elif node.localName == 'group': + widget, new_widgets = self.parse(node, tooltips=tooltips) + widgets += new_widgets + if attrs.get('string', None): + frame = gtk.Frame(attrs['string']) + frame.add(widget) + else: + frame = widget + container.wid_add(frame, colspan=int(attrs.get('colspan', 1)), + expand=int(attrs.get('expand', 0)), + rowspan=int(attrs.get('rowspan', 1)), ypadding=0, + fill=int(attrs.get('fill', 1))) + elif node.localName == 'hpaned': + hpaned = gtk.HPaned() + container.wid_add(hpaned, colspan=int(attrs.get('colspan', 4)), + expand=True, fill=True) + widget, new_widgets = self.parse(node, paned=hpaned, tooltips=tooltips) + widgets += new_widgets + if 'position' in attrs: + hpaned.set_position(int(attrs['position'])) + elif node.localName == 'vpaned': + vpaned = gtk.VPaned() + container.wid_add(vpaned, colspan=int(attrs.get('colspan', 4)), + expand=True, fill=True) + widget, new_widgets = self.parse(node, paned=vpaned, tooltips=tooltips) + widgets += new_widgets + if 'position' in attrs: + vpaned.set_position(int(attrs['position'])) + elif node.localName == 'child1': + widget, new_widgets = self.parse(node, paned=paned, tooltips=tooltips) + widgets += new_widgets + paned.pack1(widget, resize=True, shrink=True) + elif node.localName == 'child2': + widget, new_widgets = self.parse(node, paned=paned, tooltips=tooltips) + widgets += new_widgets + paned.pack2(widget, resize=True, shrink=True) + elif node.localName == 'action': + name = str(attrs['name']) + widget_act = Action(self.window, attrs) + widgets.append(widget_act) + container.wid_add(widget_act.widget, + colspan=int(attrs.get('colspan', 1)), + expand=True, fill=True) + return container.pop(), widgets diff --git a/tryton/gui/window/view_board/view_board.py b/tryton/gui/window/view_board/view_board.py new file mode 100644 index 0000000000..ff8501b089 --- /dev/null +++ b/tryton/gui/window/view_board/view_board.py @@ -0,0 +1,26 @@ +'View board' + +from parser import ParserBoard +import xml.dom.minidom + +class ViewBoard(object): + 'View board' + + def __init__(self, arch, window, context=None): + self.window = window + + xml_dom = xml.dom.minidom.parseString(arch) + parser = ParserBoard(window) + for node in xml_dom.childNodes: + if not node.nodeType == node.ELEMENT_NODE: + continue + self.widget, self.widgets = parser.parse(node) + break + self.widget.show_all() + + def widget_get(self): + return self.widget + + def reload(self): + for widget in self.widgets: + widget.display() diff --git a/tryton/gui/window/view_form/view/form.py b/tryton/gui/window/view_form/view/form.py index 116efe2f82..863282a315 100644 --- a/tryton/gui/window/view_form/view/form.py +++ b/tryton/gui/window/view_form/view/form.py @@ -2,7 +2,6 @@ import gtk import gettext from tryton.common import message, TRYTON_ICON import tryton.rpc as rpc -from tryton.gui.window.view_form.view.form_gtk.action import Action from interface import ParserView from tryton.action import Action from tryton.config import CONFIG diff --git a/tryton/gui/window/view_form/view/form_gtk/action.py b/tryton/gui/window/view_form/view/form_gtk/action.py deleted file mode 100644 index 98159c24d4..0000000000 --- a/tryton/gui/window/view_form/view/form_gtk/action.py +++ /dev/null @@ -1,105 +0,0 @@ -from interface import WidgetInterface -from tryton.gui.window.view_form.screen import Screen -import tryton.rpc as rpc -import time -import datetime -from tryton.gui.window.win_search import WinSearch -from tryton.action import Action as Action2 - - -class Action(WidgetInterface): - - def __init__(self, window, parent, model, attrs=None): - super(Action, self).__init__(window, parent, model, attrs) - - self.act_id = attrs['name'] - try: - res = rpc.execute('object', 'execute', - 'ir.actions.actions', 'read', [self.act_id], ['type'], - rpc.CONTEXT) - except Exception, exception: - rpc.process_exception(exception, self._window) - raise - if not res: - raise Exception('ActionNotFound') - - atype = res[0]['type'] - try: - self.action = rpc.execute('object', 'execute', atype, - 'read', self.act_id, False, rpc.CONTEXT) - except Exception, exception: - rpc.process_exception(exception, self._window) - raise - if 'view_mode' in attrs: - self.action['view_mode'] = attrs['view_mode'] - - if self.action['type'] == 'ir.actions.act_window': - self.action.setdefault('domain', '[]') - self.context = {'active_id': False, 'active_ids': []} - self.context.update(eval(self.action.get('context', '{}'), - self.context.copy())) - ctx = self.context.copy() - ctx['time'] = time - ctx['datetime'] = datetime - self.domain = eval(self.action['domain'], ctx) - - view_id = [] - if self.action['view_id']: - view_id = [self.action['view_id'][0]] - if self.action['view_type'] == 'form': - mode = (self.action['view_mode'] or 'form,tree').split(',') - self.screen = Screen(self.action['res_model'], self._window, - view_type=mode, context=self.context, view_ids=view_id, - domain=self.domain) -# self.win_gl = glade.XML(common.terp_path("terp.glade"), -# 'widget_paned', gettext.textdomain()) -# -# self.win_gl.signal_connect( -# 'on_switch_button_press_event', -# self._sig_switch) -# self.win_gl.signal_connect( -# 'on_search_button_press_event', -# self._sig_search) -# self.win_gl.signal_connect( -# 'on_open_button_press_event', self._sig_open) -# label=self.win_gl.get_widget('widget_paned_lab') -# label.set_text(attrs.get('string', -# self.screen.current_view.title)) -# vbox=self.win_gl.get_widget('widget_paned_vbox') -# vbox.add(self.screen.widget) -# self.widget=self.win_gl.get_widget('widget_paned') -# self.widget.set_size_request( -# int(attrs.get('width', -1)), -# int(attrs.get('height', -1))) - elif self.action['view_type']=='tree': - pass #TODO - - def _sig_switch(self, *args): - self.screen.switch_view() - - def _sig_search(self, *args): - win = WinSearch(self.action['res_model'], domain=self.domain, - context=self.context) - res = win.run() - if res: - self.screen.clear() - self.screen.load(res) - - def _sig_open(self, *args): - Action2.execute(self.act_id, {}) - - def set_value(self, mode, model_field): - self.screen.current_view.set_value() - return True - - def display(self, model, model_field): - try: - res_id = rpc.execute('object', 'execute', - self.action['res_model'], 'search', self.domain, 0, - self.action.get('limit', 80)) - except Exception, exception: - rpc.process_exception(exception, self._window) - return False - self.screen.clear() - self.screen.load(res_id) - return True diff --git a/tryton/gui/window/view_form/view/form_gtk/parser.py b/tryton/gui/window/view_form/view/form_gtk/parser.py index 0db391d207..570adc1e23 100644 --- a/tryton/gui/window/view_form/view/form_gtk/parser.py +++ b/tryton/gui/window/view_form/view/form_gtk/parser.py @@ -447,14 +447,6 @@ class ParserForm(ParserInterface): button_list += buttons dict_widget.update(widgets) paned.pack2(widget, resize=True, shrink=True) - elif node.localName == 'action': - from action import action - name = str(attrs['name']) - widget_act = action(self.window, self.parent, model, attrs) - dict_widget[name] = widget_act - container.wid_add(widget_act.widget, - colspan=int(attrs.get('colspan', 3)), - expand=True, fill=True) for (button, src, name, widget) in container.trans_box: button.connect('clicked', self.translate, model, name, src, widget) diff --git a/tryton/gui/window/window.py b/tryton/gui/window/window.py index 834919072f..7f001ce427 100644 --- a/tryton/gui/window/window.py +++ b/tryton/gui/window/window.py @@ -24,6 +24,10 @@ class Window(object): win = Tree(model, window, res_id, view_ids and view_ids[0] or None, domain, context, name=name) Main.get_main().win_add(win) + elif view_type == 'board': + from board import Board + win = Board(window, view_ids[0], context=context, name=name, auto_refresh=auto_refresh) + Main.get_main().win_add(win) else: import logging log = logging.getLogger('view')