Пример #1
0
def time_format(field):
    return PYSONDecoder({}).decode(field['format'])
Пример #2
0
    def sig_win_menu(self, prefs=None):
        from tryton.gui.window.view_form.screen import Screen

        if not prefs:
            try:
                prefs = RPCExecute('model', 'res.user', 'get_preferences',
                    False)
            except RPCException:
                return False

        if self.menu_screen:
            self.menu_screen.save_tree_state()
        for child in self.menu.get_children():
            self.menu.remove(child)

        action = PYSONDecoder().decode(prefs['pyson_menu'])
        view_ids = []
        if action.get('views', []):
            view_ids = [x[0] for x in action['views']]
        elif action.get('view_id', False):
            view_ids = [action['view_id'][0]]
        ctx = rpc.CONTEXT.copy()
        decoder = PYSONDecoder(ctx)
        action_ctx = decoder.decode(action.get('pyson_context') or '{}')
        # Postpone domain eval
        domain = action['pyson_domain']
        screen = Screen(action['res_model'], mode=['tree'], view_ids=view_ids,
            domain=domain, context=action_ctx, readonly=True, limit=None,
            row_activate=self.menu_row_activate)
        # Use alternate view to not show search box
        screen.screen_container.alternate_view = True
        screen.switch_view(view_type=screen.current_view.view_type)

        self.menu.pack_start(
            screen.screen_container.alternate_viewport,
            expand=True, fill=True, padding=0)
        treeview = screen.current_view.treeview
        treeview.set_headers_visible(False)

        # Favorite column
        column = Gtk.TreeViewColumn()
        column.name = None
        column._type = None
        favorite_renderer = CellRendererClickablePixbuf()
        column.pack_start(favorite_renderer, expand=False)

        def favorite_setter(column, cell, store, iter_, user_data=None):
            menu = store.get_value(iter_, 0)
            favorite = menu.value.get('favorite')
            if favorite:
                icon = 'tryton-star'
            elif favorite is False:
                icon = 'tryton-star-border'
            else:
                icon = None
            if icon:
                pixbuf = common.IconFactory.get_pixbuf(
                    icon, Gtk.IconSize.MENU)
            else:
                pixbuf = None
            cell.set_property('pixbuf', pixbuf)
        column.set_cell_data_func(favorite_renderer, favorite_setter)

        def toggle_favorite(renderer, path, treeview):
            if treeview.props.window:
                self.toggle_favorite(renderer, path, treeview)
        favorite_renderer.connect('clicked',
            lambda *a: GLib.idle_add(toggle_favorite, *a), treeview)
        # Unset fixed height mode to add column
        treeview.set_fixed_height_mode(False)
        treeview.set_property(
            'enable-grid-lines', Gtk.TreeViewGridLines.NONE)
        treeview.append_column(column)

        screen.search_filter()
        screen.display(set_cursor=True)
        self.menu_screen = screen
Пример #3
0
    def search_box(self, widget):
        def window_hide(window, *args):
            window.hide()
            self.search_entry.grab_focus()

        def key_press(widget, event):
            if event.keyval == gtk.keysyms.Escape:
                window_hide(widget)
                return True
            return False

        def search():
            self.search_window.hide()
            text = ''
            for label, entry in self.search_table.fields:
                if isinstance(entry, gtk.ComboBox):
                    value = quote(entry.get_active_text()) or None
                elif isinstance(entry, (Dates, Selection)):
                    value = entry.get_value()
                else:
                    value = quote(entry.get_text()) or None
                if value is not None:
                    text += quote(label) + ': ' + value + ' '
            self.set_text(text)
            self.do_search()
            # Store text after doing the search
            # because domain parser could simplify the text
            self.last_search_text = self.get_text()

        if not self.search_window:
            self.search_window = gtk.Window()
            Main().add_window(self.search_window)
            self.search_window.set_transient_for(widget.get_toplevel())
            self.search_window.set_type_hint(
                gtk.gdk.WINDOW_TYPE_HINT_POPUP_MENU)
            self.search_window.set_destroy_with_parent(True)
            self.search_window.set_decorated(False)
            self.search_window.set_deletable(False)
            self.search_window.connect('delete-event', window_hide)
            self.search_window.connect('key-press-event', key_press)
            self.search_window.connect('focus-out-event', window_hide)

            def toggle_window_hide(combobox, shown):
                if combobox.props.popup_shown:
                    self.search_window.handler_block_by_func(window_hide)
                else:
                    self.search_window.handler_unblock_by_func(window_hide)

            vbox = gtk.VBox()
            fields = [
                f for f in self.screen.domain_parser.fields.values()
                if f.get('searchable', True)
            ]
            self.search_table = gtk.Table(rows=len(fields), columns=2)
            self.search_table.set_homogeneous(False)
            self.search_table.set_border_width(5)
            self.search_table.set_row_spacings(2)
            self.search_table.set_col_spacings(2)

            # Fill table with fields
            self.search_table.fields = []
            for i, field in enumerate(fields):
                label = gtk.Label(field['string'])
                label.set_alignment(0.0, 0.0)
                self.search_table.attach(label,
                                         0,
                                         1,
                                         i,
                                         i + 1,
                                         yoptions=gtk.FILL)
                yoptions = False
                if field['type'] == 'boolean':
                    if hasattr(gtk, 'ComboBoxText'):
                        entry = gtk.ComboBoxText()
                    else:
                        entry = gtk.combo_box_new_text()
                    entry.connect('notify::popup-shown', toggle_window_hide)
                    entry.append_text('')
                    selections = (_('True'), _('False'))
                    for selection in selections:
                        entry.append_text(selection)
                elif field['type'] == 'selection':
                    selections = tuple(x[1] for x in field['selection'])
                    entry = Selection(selections)
                    yoptions = gtk.FILL | gtk.EXPAND
                elif field['type'] in ('date', 'datetime', 'time'):
                    date_format = common.date_format(
                        self.screen.context.get('date_format'))
                    if field['type'] == 'date':
                        entry = Dates(date_format)
                    elif field['type'] in ('datetime', 'time'):
                        time_format = PYSONDecoder({}).decode(field['format'])
                        if field['type'] == 'time':
                            entry = Times(time_format)
                        elif field['type'] == 'datetime':
                            entry = DateTimes(date_format, time_format)
                    entry.connect_activate(lambda *a: search())
                    entry.connect_combo(toggle_window_hide)
                else:
                    entry = gtk.Entry()
                    entry.connect('activate', lambda *a: search())
                label.set_mnemonic_widget(entry)
                self.search_table.attach(entry,
                                         1,
                                         2,
                                         i,
                                         i + 1,
                                         yoptions=yoptions)
                self.search_table.fields.append((field['string'], entry))

            scrolled = gtk.ScrolledWindow()
            scrolled.add_with_viewport(self.search_table)
            scrolled.set_shadow_type(gtk.SHADOW_NONE)
            scrolled.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
            vbox.pack_start(scrolled, expand=True, fill=True)
            find_button = gtk.Button(_('Find'))
            find_button.connect('clicked', lambda *a: search())
            find_button.set_image(
                common.IconFactory.get_image('tryton-search',
                                             gtk.ICON_SIZE_SMALL_TOOLBAR))
            hbuttonbox = gtk.HButtonBox()
            hbuttonbox.set_spacing(5)
            hbuttonbox.pack_start(find_button)
            hbuttonbox.set_layout(gtk.BUTTONBOX_END)
            vbox.pack_start(hbuttonbox, expand=False, fill=True)
            self.search_window.add(vbox)
            vbox.show_all()

            new_size = list(
                map(
                    sum,
                    list(
                        zip(self.search_table.size_request(),
                            scrolled.size_request()))))
            self.search_window.set_default_size(*new_size)

        parent = widget.get_toplevel()
        widget_x, widget_y = widget.translate_coordinates(parent, 0, 0)
        widget_allocation = widget.get_allocation()

        # Resize the window to not be out of the parent
        width, height = self.search_window.get_default_size()
        allocation = parent.get_allocation()
        delta_width = allocation.width - (widget_x + width)
        delta_height = allocation.height - (widget_y +
                                            widget_allocation.height + height)
        if delta_width < 0:
            width += delta_width
        if delta_height < 0:
            height += delta_height
        self.search_window.resize(width, height)

        # Move the window under the button
        if hasattr(widget.window, 'get_root_coords'):
            x, y = widget.window.get_root_coords(widget_allocation.x,
                                                 widget_allocation.y)
        else:
            x, y = widget.window.get_origin()
        self.search_window.move(x, y + widget_allocation.height)
        self.search_window.show()
        self.search_window.grab_focus()

        if self.last_search_text.strip() != self.get_text().strip():
            for label, entry in self.search_table.fields:
                if isinstance(entry, gtk.ComboBox):
                    entry.set_active(-1)
                elif isinstance(entry, Dates):
                    entry.set_values(None, None)
                elif isinstance(entry, Selection):
                    entry.treeview.get_selection().unselect_all()
                else:
                    entry.set_text('')
            if self.search_table.fields:
                self.search_table.fields[0][1].grab_focus()
Пример #4
0
    def search_box(self, widget):
        def window_hide(window, *args):
            window.hide()
            self.search_entry.grab_focus()

        def search():
            self.search_popover.popdown()
            text = ''
            for label, entry in self.search_grid.fields:
                if isinstance(entry, Gtk.ComboBoxText):
                    value = quote(entry.get_active_text()) or None
                elif isinstance(entry, (Between, Selection)):
                    value = entry.get_value()
                else:
                    value = quote(entry.get_text()) or None
                if value is not None:
                    text += quote(label) + ': ' + value + ' '
            self.set_text(text)
            self.do_search()
            # Store text after doing the search
            # because domain parser could simplify the text
            self.last_search_text = self.get_text()

        if not self.search_popover:
            self.search_popover = Gtk.Popover()
            self.search_popover.set_relative_to(widget)

            vbox = Gtk.VBox()
            fields = [f for f in self.screen.domain_parser.fields.values()
                if f.get('searchable', True) and '.' not in f['name']]
            self.search_grid = Gtk.Grid(column_spacing=3, row_spacing=3)

            # Fill table with fields
            self.search_grid.fields = []
            for i, field in enumerate(fields):
                label = Gtk.Label(
                    label=field['string'],
                    halign=Gtk.Align.START, valign=Gtk.Align.START)
                self.search_grid.attach(label, 0, i, 1, 1)
                if field['type'] == 'boolean':
                    entry = Gtk.ComboBoxText()
                    entry.append_text('')
                    selections = (_('True'), _('False'))
                    for selection in selections:
                        entry.append_text(selection)
                elif field['type'] == 'selection':
                    selections = tuple(x[1] for x in field['selection'])
                    entry = Selection(selections)
                    entry.set_vexpand(True)
                elif field['type'] in ('date', 'datetime', 'time'):
                    date_format = common.date_format(
                        self.screen.context.get('date_format'))
                    if field['type'] == 'date':
                        entry = Dates(date_format)
                    elif field['type'] in ('datetime', 'time'):
                        time_format = PYSONDecoder({}).decode(field['format'])
                        if field['type'] == 'time':
                            entry = Times(time_format)
                        elif field['type'] == 'datetime':
                            entry = DateTimes(date_format, time_format)
                    entry.connect('activate', lambda *a: search())
                elif field['type'] in ['integer', 'float', 'numeric']:
                    entry = Numbers()
                    entry.connect('activate', lambda *a: search())
                else:
                    entry = Gtk.Entry()
                    entry.connect('activate', lambda *a: search())
                label.set_mnemonic_widget(entry)
                self.search_grid.attach(entry, 1, i, 1, 1)
                self.search_grid.fields.append((field['string'], entry))

            scrolled = Gtk.ScrolledWindow()
            scrolled.add(self.search_grid)
            scrolled.set_shadow_type(Gtk.ShadowType.NONE)
            scrolled.set_policy(
                Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC)
            vbox.pack_start(scrolled, expand=True, fill=True, padding=0)
            find_button = Gtk.Button(label=_('Find'))
            find_button.connect('clicked', lambda *a: search())
            find_button.set_image(common.IconFactory.get_image(
                    'tryton-search', Gtk.IconSize.SMALL_TOOLBAR))
            find_button.set_can_default(True)
            self.search_popover.set_default_widget(find_button)
            hbuttonbox = Gtk.HButtonBox()
            hbuttonbox.pack_start(
                find_button, expand=False, fill=False, padding=0)
            hbuttonbox.set_layout(Gtk.ButtonBoxStyle.END)
            vbox.pack_start(hbuttonbox, expand=False, fill=True, padding=0)
            self.search_popover.add(vbox)
            vbox.show_all()
            scrolled.set_size_request(
                -1, min(self.search_grid.get_preferred_height()[1], 400))

        self.search_popover.set_pointing_to(
            widget.get_icon_area(Gtk.EntryIconPosition.PRIMARY))
        self.search_popover.popup()
        if self.search_grid.fields:
            self.search_grid.fields[0][1].grab_focus()

        if self.last_search_text.strip() != self.get_text().strip():
            for label, entry in self.search_grid.fields:
                if isinstance(entry, Gtk.ComboBoxText):
                    entry.set_active(-1)
                elif isinstance(entry, Between):
                    entry.set_value(None, None)
                elif isinstance(entry, Selection):
                    entry.treeview.get_selection().unselect_all()
                else:
                    entry.set_text('')
Пример #5
0
    def _exec_action(action, data=None, context=None):
        from tryton.gui.window import Window
        if context is None:
            context = {}
        else:
            context = context.copy()
        if data is None:
            data = {}
        else:
            data = data.copy()
        if 'type' not in (action or {}):
            return

        context.pop('active_id', None)
        context.pop('active_ids', None)
        context.pop('active_model', None)

        def add_name_suffix(name, context=None):
            if not data.get('ids') or not data.get('model'):
                return name
            max_records = 5
            ids = list(filter(lambda id: id >= 0, data['ids']))[:max_records]
            if not ids:
                return name
            rec_names = RPCExecute('model', data['model'],
                'read', ids, ['rec_name'],
                context=context)
            name_suffix = _(', ').join([x['rec_name'] for x in rec_names])
            if len(data['ids']) > len(ids):
                name_suffix += _(',...')
            return _('%s (%s)') % (name, name_suffix)

        data['action_id'] = action['id']
        if action['type'] == 'ir.action.act_window':
            view_ids = []
            view_mode = None
            if action.get('views', []):
                view_ids = [x[0] for x in action['views']]
                view_mode = [x[1] for x in action['views']]
            elif action.get('view_id', False):
                view_ids = [action['view_id'][0]]

            action.setdefault('pyson_domain', '[]')
            ctx = {
                'active_model': data.get('model'),
                'active_id': data.get('id'),
                'active_ids': data.get('ids', []),
            }
            ctx.update(rpc.CONTEXT)
            ctx['_user'] = rpc._USER
            decoder = PYSONDecoder(ctx)
            action_ctx = context.copy()
            action_ctx.update(
                decoder.decode(action.get('pyson_context') or '{}'))
            ctx.update(action_ctx)

            ctx['context'] = ctx
            decoder = PYSONDecoder(ctx)
            domain = decoder.decode(action['pyson_domain'])
            order = decoder.decode(action['pyson_order'])
            search_value = decoder.decode(action['pyson_search_value'] or '[]')
            tab_domain = [(n, decoder.decode(d), c)
                for n, d, c in action['domains']]

            name = action.get('name', '')
            if action.get('keyword', ''):
                name = add_name_suffix(name, action_ctx)

            res_model = action.get('res_model', data.get('res_model'))
            res_id = action.get('res_id', data.get('res_id'))
            limit = action.get('limit')
            if limit is None:
                limit = CONFIG['client.limit']

            Window.create(res_model,
                view_ids=view_ids,
                res_id=res_id,
                domain=domain,
                context=action_ctx,
                order=order,
                mode=view_mode,
                name=name,
                limit=limit,
                search_value=search_value,
                icon=(action.get('icon.rec_name') or ''),
                tab_domain=tab_domain,
                context_model=action['context_model'],
                context_domain=action['context_domain'])
        elif action['type'] == 'ir.action.wizard':
            name = action.get('name', '')
            if action.get('keyword', 'form_action') == 'form_action':
                name = add_name_suffix(name, context)
            Window.create_wizard(action['wiz_name'], data,
                direct_print=action.get('direct_print', False),
                name=name,
                context=context, icon=(action.get('icon.rec_name') or ''),
                window=action.get('window', False))

        elif action['type'] == 'ir.action.report':
            Action.exec_report(
                action['report_name'], data,
                direct_print=action.get('direct_print', False),
                context=context)

        elif action['type'] == 'ir.action.url':
            if action['url']:
                webbrowser.open(action['url'], new=2)
Пример #6
0
    def _exec_action(action, data=None, context=None):
        if context is None:
            context = {}
        if data is None:
            data = {}
        else:
            data = data.copy()
        if 'type' not in (action or {}):
            return

        def add_name_suffix(name):
            if not data.get('ids') or not data.get('model'):
                return name
            max_records = 5
            rec_names = RPCExecute('model', data['model'],
                'read', data['ids'][:max_records], ['rec_name'])
            name_suffix = _(', ').join([x['rec_name'] for x in rec_names])
            if len(data['ids']) > max_records:
                name_suffix += _(u',\u2026')
            return _('%s (%s)') % (name, name_suffix)

        data['action_id'] = action['id']
        if action['type'] == 'ir.action.act_window':
            view_ids = False
            view_mode = None
            if action.get('views', []):
                view_ids = [x[0] for x in action['views']]
                view_mode = [x[1] for x in action['views']]
            elif action.get('view_id', False):
                view_ids = [action['view_id'][0]]

            action.setdefault('pyson_domain', '[]')
            ctx = {
                'active_model': data.get('model'),
                'active_id': data.get('id'),
                'active_ids': data.get('ids', []),
            }
            ctx.update(rpc.CONTEXT)
            ctx['_user'] = rpc._USER
            decoder = PYSONDecoder(ctx)
            action_ctx = context.copy()
            action_ctx.update(
                decoder.decode(action.get('pyson_context') or '{}'))
            ctx.update(action_ctx)
            ctx.update(context)

            ctx['context'] = ctx
            decoder = PYSONDecoder(ctx)
            domain = decoder.decode(action['pyson_domain'])
            order = decoder.decode(action['pyson_order'])
            search_value = decoder.decode(action['pyson_search_value'] or '[]')
            tab_domain = [(n, decoder.decode(d), c)
                for n, d, c in action['domains']]

            name = action.get('name', '')
            if action.get('keyword', '') == 'form_relate':
                name = add_name_suffix(name)

            res_model = action.get('res_model', data.get('res_model'))
            res_id = action.get('res_id', data.get('res_id'))

            Window.create(view_ids, res_model, res_id, domain,
                    action_ctx, order, view_mode, name=name,
                    limit=action.get('limit'),
                    search_value=search_value,
                    icon=(action.get('icon.rec_name') or ''),
                    tab_domain=tab_domain,
                    context_model=action['context_model'])
        elif action['type'] == 'ir.action.wizard':
            name = action.get('name', '')
            if action.get('keyword', 'form_action') == 'form_action':
                name = add_name_suffix(name)
            Window.create_wizard(action['wiz_name'], data,
                direct_print=action.get('direct_print', False),
                email_print=action.get('email_print', False),
                email=action.get('email'), name=name,
                context=context, icon=(action.get('icon.rec_name') or ''),
                window=action.get('window', False))

        elif action['type'] == 'ir.action.report':
            Action.exec_report(action['report_name'], data,
                    direct_print=action.get('direct_print', False),
                    email_print=action.get('email_print', False),
                    email=action.get('email'), context=context)

        elif action['type'] == 'ir.action.url':
            if action['url']:
                webbrowser.open(action['url'], new=2)
Пример #7
0
 def __init__(self, view, attrs):
     super(PYSON, self).__init__(view, attrs)
     self.encoder = PYSONEncoder()
     self.decoder = PYSONDecoder(noeval=True)
     self.entry.connect('key-release-event', self.validate_pyson)
Пример #8
0
    def __init__(self, attrs=None, context=None):
        if context is None:
            context = {}
        super(Action, self).__init__()
        self.name = attrs['name']
        self.context = context.copy()

        try:
            self.action = RPCExecute('model', 'ir.action.act_window', 'get',
                self.name)
        except RPCException:
            raise

        view_ids = []
        self.action['view_mode'] = None
        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('pyson_domain', '[]')
        self.context.update(rpc.CONTEXT)
        self.context['_user'] = rpc._USER
        self.context.update(PYSONDecoder(self.context).decode(
            self.action.get('pyson_context', '{}')))

        eval_ctx = self.context.copy()
        self.context.update(PYSONDecoder(eval_ctx).decode(
            self.action.get('pyson_context', '{}')))

        self.domain = []
        self.update_domain([])

        search_context = self.context.copy()
        search_context['context'] = self.context
        search_context['_user'] = rpc._USER
        search_value = PYSONDecoder(search_context).decode(
            self.action['pyson_search_value'] or '[]')

        self.widget = gtk.Frame()
        self.widget.set_border_width(0)

        vbox = gtk.VBox(homogeneous=False, spacing=3)
        self.widget.add(vbox)

        self.title = gtk.Label()
        self.widget.set_label_widget(self.title)
        self.widget.set_label_align(0.0, 0.5)
        self.widget.show_all()

        self.screen = Screen(self.action['res_model'],
            mode=self.action['view_mode'], context=self.context,
            view_ids=view_ids, domain=self.domain,
            search_value=search_value, row_activate=self.row_activate)
        vbox.pack_start(self.screen.widget, expand=True, fill=True)
        self.screen.signal_connect(self, 'record-message',
            self._active_changed)

        if attrs.get('string'):
            self.title.set_text(attrs['string'])
        else:
            self.title.set_text(self.action['name'])

        self.widget.set_size_request(int(attrs.get('width', -1)),
                int(attrs.get('height', -1)))

        self.screen.search_filter()
Пример #9
0
    def state_set(self, record):
        super().state_set(record)
        if not self.get_visible():
            return
        if CONFIG['client.modepda']:
            self.hide()
            return
        if record:
            data = {
                'model': record.model_name,
                'id': record.id,
                'ids': [record.id],
            }
            context = record.get_context()
            pyson_ctx = {
                'active_model': record.model_name,
                'active_id': record.id,
                'active_ids': [record.id],
            }
            self._current = record.id
        else:
            data = {}
            context = {}
            pyson_ctx = {}
            self._current = None
        pyson_ctx['context'] = context
        try:
            self.disconnect_by_func(self.__class__.clicked)
        except TypeError:
            pass
        self.connect('clicked', self.__class__.clicked, [data, context])
        action = common.RPCExecute('model',
                                   'ir.action',
                                   'get_action_value',
                                   self.action_id,
                                   context=context)
        self.set_label(action['name'])

        decoder = PYSONDecoder(pyson_ctx)
        domain = decoder.decode(action['pyson_domain'])
        if action.get('pyson_search_value'):
            domain = [domain, decoder.decode(action['pyson_search_value'])]
        tab_domains = [(n, decoder.decode(d)) for n, d, c in action['domains']
                       if c]
        if tab_domains:
            label = ('%s\n' % action['name']) + '\n'.join(
                '%s (%%d)' % n for n, _ in tab_domains)
        else:
            label = '%s (%%d)' % action['name']
        if record and self.action_id in record.links_counts:
            counter = record.links_counts[self.action_id]
            self._set_label_counter(label, counter)
        else:
            counter = [0] * (len(tab_domains) or 1)
            if record:
                record.links_counts[self.action_id] = counter
            if tab_domains:
                for i, (_, tab_domain) in enumerate(tab_domains):
                    common.RPCExecute(
                        'model',
                        action['res_model'],
                        'search_count', ['AND', domain, tab_domain],
                        context=context,
                        callback=functools.partial(self._set_count,
                                                   idx=i,
                                                   current=self._current,
                                                   counter=counter,
                                                   label=label))
            else:
                common.RPCExecute('model',
                                  action['res_model'],
                                  'search_count',
                                  domain,
                                  context=context,
                                  callback=functools.partial(
                                      self._set_count,
                                      current=self._current,
                                      counter=counter,
                                      label=label))
Пример #10
0
    def display(self, force=False):
        self.treeview.display_counter += 1
        current_record = self.record
        if (force or not self.treeview.get_model()
                or self.group != self.treeview.get_model().group):
            model = AdaptModelGroup(self.group, self.children_field)
            self.treeview.set_model(model)
            # __select_changed resets current_record to None
            self.record = current_record
            if current_record:
                selection = self.treeview.get_selection()
                path = current_record.get_index_path(model.group)
                selection.select_path(path)
            # The search column must be set each time the model is changed
            self.treeview.set_search_column(0)
        if not current_record:
            selection = self.treeview.get_selection()
            selection.unselect_all()
        self.treeview.queue_draw()
        if self.editable:
            self.set_state()
        self.update_arrow()
        self.update_sum()

        # Set column visibility depending on attributes and domain
        domain = []
        if self.screen.domain:
            domain.append(self.screen.domain)
        tab_domain = self.screen.screen_container.get_tab_domain()
        if tab_domain:
            domain.append(tab_domain)
        domain = simplify(domain)
        decoder = PYSONDecoder(self.screen.context)
        tree_column_optional = self.screen.tree_column_optional.get(
            self.view_id, {})
        for column in self.treeview.get_columns():
            name = column.name
            if not name:
                continue
            widget = self.get_column_widget(column)
            widget.set_editable()
            if column.name in tree_column_optional:
                optional = tree_column_optional[column.name]
            else:
                optional = bool(int(widget.attrs.get('optional', '0')))
            invisible = decoder.decode(widget.attrs.get('tree_invisible', '0'))
            if invisible or optional:
                column.set_visible(False)
            elif name == self.screen.exclude_field:
                column.set_visible(False)
            else:
                inv_domain = domain_inversion(domain, name)
                if not isinstance(inv_domain, bool):
                    inv_domain = simplify(inv_domain)
                unique, _, _ = unique_value(inv_domain)
                column.set_visible(not unique or bool(self.children_field))
        if self.children_field:
            for i, column in enumerate(self.treeview.get_columns()):
                if self.draggable and not i:
                    continue
                if column.get_visible():
                    self.treeview.set_expander_column(column)
                    break
Пример #11
0
 def get_domain(self):
     if not self.domain or not isinstance(self.domain, str):
         return self.domain
     decoder = PYSONDecoder(self.context)
     return decoder.decode(self.domain)
Пример #12
0
 def updateDatas(self, group):
     self.datas = {}
     self.labels = {}
     self.ids = {}
     self.group = group
     minx = None
     maxx = None
     for model in group:
         x = model[self.xfield['name']].get(model)
         if not minx:
             minx = x
         if not maxx:
             maxx = x
         if minx is None and maxx is None:
             if isinstance(x, datetime.datetime):
                 minx, maxx = datetime.datetime.min, datetime.datetime.max
             elif isinstance(x, datetime.date):
                 minx, maxx = datetime.date.min, datetime.date.max
             elif isinstance(x, datetime.timedelta):
                 minx, maxx = datetime.timedelta.min, datetime.timedelta.max
         try:
             minx = min(minx, x)
             maxx = max(maxx, x)
         except TypeError:
             continue
         self.labels[x] = model[self.xfield['name']].get_client(model)
         self.ids.setdefault(x, [])
         self.ids[x].append(model.id)
         self.datas.setdefault(x, {})
         for yfield in self.yfields:
             key = yfield.get('key', yfield['name'])
             self.datas[x].setdefault(key, 0.0)
             if yfield.get('domain'):
                 context = rpc.CONTEXT.copy()
                 context['context'] = context.copy()
                 context['_user'] = rpc._USER
                 for field in model.group.fields:
                     context[field] = model[field].get(model)
                 if not PYSONDecoder(context).decode(yfield['domain']):
                     continue
             if yfield['name'] == '#':
                 self.datas[x][key] += 1
             else:
                 value = model[yfield['name']].get(model)
                 if isinstance(value, datetime.timedelta):
                     value = value.total_seconds()
                 self.datas[x][key] += float(value or 0)
     date_format = self.view.screen.context.get('date_format', '%x')
     datetime_format = date_format + ' %X'
     if isinstance(minx, datetime.datetime):
         date = minx
         while date <= maxx:
             self.labels[date] = date.strftime(datetime_format)
             self.datas.setdefault(date, {})
             for yfield in self.yfields:
                 self.datas[date].setdefault(
                     yfield.get('key', yfield['name']), 0.0)
             date += relativedelta(days=1)
     elif isinstance(minx, datetime.date):
         date = minx
         while date <= maxx:
             self.labels[date] = date.strftime(date_format)
             self.datas.setdefault(date, {})
             for yfield in self.yfields:
                 self.datas[date].setdefault(
                     yfield.get('key', yfield['name']), 0.0)
             date += relativedelta(days=1)
Пример #13
0
    def search_box(self, button):
        def key_press(window, event):
            if event.keyval == gtk.keysyms.Escape:
                button.set_active(False)
                window.hide()

        def search():
            button.set_active(False)
            self.search_window.hide()
            text = ''
            for label, entry in self.search_table.fields:
                if isinstance(entry, gtk.ComboBox):
                    value = quote(entry.get_active_text()) or None
                elif isinstance(entry, (Dates, Selection)):
                    value = entry.get_value()
                else:
                    value = quote(entry.get_text()) or None
                if value is not None:
                    text += quote(label) + ': ' + value + ' '
            self.set_text(text)
            self.do_search()
            # Store text after doing the search
            # because domain parser could simplify the text
            self.last_search_text = self.get_text()

        if not self.search_window:
            self.search_window = gtk.Window()
            self.search_window.set_transient_for(button.get_toplevel())
            self.search_window.set_type_hint(
                gtk.gdk.WINDOW_TYPE_HINT_POPUP_MENU)
            self.search_window.set_destroy_with_parent(True)
            self.search_window.set_title('coog')
            self.search_window.set_icon(TRYTON_ICON)
            self.search_window.set_decorated(False)
            # set_deletable is False on tryton master repo
            # But this is not working on each graphical environnement
            # Further more, setting theses windows deletable does not seems
            # to bring any trouble.
            self.search_window.set_deletable(True)
            self.search_window.connect('delete-event', lambda *a: True)
            self.search_window.connect('key-press-event', key_press)
            vbox = gtk.VBox()
            fields = [
                f for f in self.screen.domain_parser.fields.itervalues()
                if f.get('searchable', True)
            ]
            self.search_table = gtk.Table(rows=len(fields), columns=2)
            self.search_table.set_homogeneous(False)
            self.search_table.set_border_width(5)
            self.search_table.set_row_spacings(2)
            self.search_table.set_col_spacings(2)

            # Fill table with fields
            self.search_table.fields = []
            for i, field in enumerate(fields):
                label = gtk.Label(field['string'])
                label.set_alignment(0.0, 0.0)
                self.search_table.attach(label,
                                         0,
                                         1,
                                         i,
                                         i + 1,
                                         yoptions=gtk.FILL)
                yoptions = False
                if field['type'] == 'boolean':
                    if hasattr(gtk, 'ComboBoxText'):
                        entry = gtk.ComboBoxText()
                    else:
                        entry = gtk.combo_box_new_text()
                    entry.append_text('')
                    selections = (_('True'), _('False'))
                    for selection in selections:
                        entry.append_text(selection)
                elif field['type'] == 'selection':
                    selections = tuple(x[1] for x in field['selection'])
                    entry = Selection(selections)
                    yoptions = gtk.FILL | gtk.EXPAND
                elif field['type'] in ('date', 'datetime', 'time'):
                    date_format = self.screen.context.get('date_format', '%x')
                    if field['type'] == 'date':
                        entry = Dates(date_format)
                    elif field['type'] in ('datetime', 'time'):
                        time_format = PYSONDecoder({}).decode(field['format'])
                        if field['type'] == 'time':
                            entry = Times(time_format)
                        elif field['type'] == 'datetime':
                            entry = DateTimes(date_format, time_format)
                    entry.connect_activate(lambda *a: search())
                else:
                    entry = gtk.Entry()
                    entry.connect('activate', lambda *a: search())
                label.set_mnemonic_widget(entry)
                self.search_table.attach(entry,
                                         1,
                                         2,
                                         i,
                                         i + 1,
                                         yoptions=yoptions)
                self.search_table.fields.append((field['string'], entry))

            scrolled = gtk.ScrolledWindow()
            scrolled.add_with_viewport(self.search_table)
            scrolled.set_shadow_type(gtk.SHADOW_NONE)
            scrolled.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
            vbox.pack_start(scrolled, expand=True, fill=True)
            find_button = gtk.Button(_('Find'))
            find_button.connect('clicked', lambda *a: search())
            find_img = gtk.Image()
            find_img.set_from_stock('tryton-find', gtk.ICON_SIZE_SMALL_TOOLBAR)
            find_button.set_image(find_img)
            hbuttonbox = gtk.HButtonBox()
            hbuttonbox.set_spacing(5)
            hbuttonbox.pack_start(find_button)
            hbuttonbox.set_layout(gtk.BUTTONBOX_END)
            vbox.pack_start(hbuttonbox, expand=False, fill=True)
            self.search_window.add(vbox)
            vbox.show_all()

            new_size = map(
                sum,
                zip(self.search_table.size_request(), scrolled.size_request()))
            self.search_window.set_default_size(*new_size)

        parent = button.get_toplevel()
        button_x, button_y = button.translate_coordinates(parent, 0, 0)
        button_allocation = button.get_allocation()

        # Resize the window to not be out of the parent
        width, height = self.search_window.get_default_size()
        allocation = parent.get_allocation()
        delta_width = allocation.width - (button_x + width)
        delta_height = allocation.height - (button_y +
                                            button_allocation.height + height)
        if delta_width < 0:
            width += delta_width
        if delta_height < 0:
            height += delta_height
        self.search_window.resize(width, height)

        # Move the window under the button
        x, y = button.window.get_origin()
        self.search_window.move(
            x + button_allocation.x,
            y + button_allocation.y + button_allocation.height)

        from tryton.gui.main import Main
        page = Main.get_main().get_page()
        if button.get_active():
            if page and self.search_window not in page.dialogs:
                page.dialogs.append(self.search_window)
            self.search_window.show()

            if self.last_search_text.strip() != self.get_text().strip():
                for label, entry in self.search_table.fields:
                    if isinstance(entry, gtk.ComboBox):
                        entry.set_active(-1)
                    elif isinstance(entry, Dates):
                        entry.set_values(None, None)
                    elif isinstance(entry, Selection):
                        entry.treeview.get_selection().unselect_all()
                    else:
                        entry.set_text('')
                if self.search_table.fields:
                    self.search_table.fields[0][1].grab_focus()

        else:
            self.search_window.hide()
            if page and self.search_window in page.dialogs:
                page.dialogs.remove(self.search_window)
Пример #14
0
    def _exec_action(action, data=None, context=None):
        if context is None:
            context = {}
        else:
            context = context.copy()
        if 'date_format' not in context:
            context['date_format'] = rpc.CONTEXT.get(
                'locale', {}).get('date', '%x')
        if data is None:
            data = {}
        else:
            data = data.copy()
        if 'type' not in (action or {}):
            return

        data['action_id'] = action['id']
        if action['type'] == 'ir.action.act_window':
            view_ids = False
            view_mode = None
            if action.get('views', []):
                view_ids = [x[0] for x in action['views']]
                view_mode = [x[1] for x in action['views']]
            elif action.get('view_id', False):
                view_ids = [action['view_id'][0]]

            action.setdefault('pyson_domain', '[]')
            ctx = {
                'active_model': data.get('model'),
                'active_id': data.get('id'),
                'active_ids': data.get('ids', []),
            }
            ctx.update(rpc.CONTEXT)
            ctx['_user'] = rpc._USER
            decoder = PYSONDecoder(ctx)
            action_ctx = decoder.decode(action.get('pyson_context') or '{}')
            ctx.update(action_ctx)
            ctx.update(context)
            action_ctx.update(context)

            ctx['context'] = ctx
            decoder = PYSONDecoder(ctx)
            domain = decoder.decode(action['pyson_domain'])
            order = decoder.decode(action['pyson_order'])
            search_value = decoder.decode(action['pyson_search_value'] or '[]')
            tab_domain = [(n, decoder.decode(d)) for n, d in action['domains']]

            name = False
            if action.get('window_name', True):
                name = action.get('name', False)

            res_model = action.get('res_model', data.get('res_model'))
            res_id = action.get('res_id', data.get('res_id'))

            Window.create(view_ids, res_model, res_id, domain,
                    action_ctx, order, view_mode, name=name,
                    limit=action.get('limit'),
                    search_value=search_value,
                    icon=(action.get('icon.rec_name') or ''),
                    tab_domain=tab_domain)
        elif action['type'] == 'ir.action.wizard':
            Window.create_wizard(action['wiz_name'], data,
                direct_print=action.get('direct_print', False),
                email_print=action.get('email_print', False),
                email=action.get('email'), name=action.get('name', False),
                context=context, icon=(action.get('icon.rec_name') or ''),
                window=action.get('window', False))

        elif action['type'] == 'ir.action.report':
            Action.exec_report(action['report_name'], data,
                    direct_print=action.get('direct_print', False),
                    email_print=action.get('email_print', False),
                    email=action.get('email'), context=context)

        elif action['type'] == 'ir.action.url':
            if action['url']:
                webbrowser.open(action['url'], new=2)