Beispiel #1
0
class Selection(Gtk.ScrolledWindow):
    def __init__(self, selections):
        super(Selection, self).__init__()
        self.treeview = TreeViewControl()
        model = Gtk.ListStore(GObject.TYPE_STRING)
        for selection in selections:
            model.append((selection, ))
        self.treeview.set_model(model)

        column = Gtk.TreeViewColumn()
        cell = Gtk.CellRendererText()
        column.pack_start(cell, expand=True)
        column.add_attribute(cell, 'text', 0)
        self.treeview.append_column(column)
        self.treeview.get_selection().set_mode(Gtk.SelectionMode.MULTIPLE)
        self.treeview.set_headers_visible(False)
        self.add(self.treeview)
        self.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC)
        self.set_shadow_type(Gtk.ShadowType.ETCHED_IN)
        self.set_min_content_height(min(20 * len(selections), 200))
        self.set_max_content_height(200)

    def get_value(self):
        values = []
        model, paths = self.treeview.get_selection().get_selected_rows()
        if not paths:
            return
        for path in paths:
            iter_ = model.get_iter(path)
            values.append(model.get_value(iter_, 0))
        return ';'.join(quote(v) for v in values)
Beispiel #2
0
class Selection(gtk.ScrolledWindow):
    def __init__(self, selections):
        super(Selection, self).__init__()
        self.treeview = TreeViewControl()
        model = gtk.ListStore(gobject.TYPE_STRING)
        for selection in selections:
            model.append((selection, ))
        self.treeview.set_model(model)

        column = gtk.TreeViewColumn()
        cell = gtk.CellRendererText()
        column.pack_start(cell)
        column.add_attribute(cell, 'text', 0)
        self.treeview.append_column(column)
        self.treeview.get_selection().set_mode(gtk.SELECTION_MULTIPLE)
        self.treeview.set_headers_visible(False)
        self.add(self.treeview)
        self.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
        self.set_shadow_type(gtk.SHADOW_ETCHED_IN)

    def get_value(self):
        values = []
        model, paths = self.treeview.get_selection().get_selected_rows()
        if not paths:
            return
        for path in paths:
            iter_ = model.get_iter(path)
            values.append(model.get_value(iter_, 0))
        return ';'.join(quote(v) for v in values)
Beispiel #3
0
class Selection(gtk.ScrolledWindow):

    def __init__(self, selections):
        super(Selection, self).__init__()
        self.treeview = TreeViewControl()
        model = gtk.ListStore(gobject.TYPE_STRING)
        for selection in selections:
            model.append((selection,))
        self.treeview.set_model(model)

        column = gtk.TreeViewColumn()
        cell = gtk.CellRendererText()
        column.pack_start(cell)
        column.add_attribute(cell, 'text', 0)
        self.treeview.append_column(column)
        self.treeview.get_selection().set_mode(gtk.SELECTION_MULTIPLE)
        self.treeview.set_headers_visible(False)
        self.add(self.treeview)
        self.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
        self.set_shadow_type(gtk.SHADOW_ETCHED_IN)

    def get_value(self):
        values = []
        model, paths = self.treeview.get_selection().get_selected_rows()
        if not paths:
            return
        for path in paths:
            iter_ = model.get_iter(path)
            values.append(model.get_value(iter_, 0))
        return ';'.join(quote(v) for v in values)
Beispiel #4
0
class DictMultiSelectionEntry(DictEntry):
    expand = False

    def create_widget(self):
        widget = Gtk.ScrolledWindow()
        widget.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC)
        widget.set_shadow_type(Gtk.ShadowType.ETCHED_IN)
        widget.set_size_request(100, 100)

        model = Gtk.ListStore(GObject.TYPE_STRING, GObject.TYPE_STRING)
        self.tree = TreeViewControl()
        self.tree.set_model(model)
        self.tree.set_search_column(1)
        self.tree.connect('focus-out-event',
                          lambda w, e: self.parent_widget._focus_out())
        self.tree.set_headers_visible(False)
        selection = self.tree.get_selection()
        selection.set_mode(Gtk.SelectionMode.MULTIPLE)
        selection.connect('changed', self._changed)
        widget.add(self.tree)

        self.selection = self.definition['selection']
        if self.definition.get('sort', True):
            self.selection.sort(key=operator.itemgetter(1))
        for value, name in self.selection:
            name = str(name)
            model.append((value, name))

        name_column = Gtk.TreeViewColumn()
        name_cell = Gtk.CellRendererText()
        name_column.pack_start(name_cell, expand=True)
        name_column.add_attribute(name_cell, 'text', 1)
        self.tree.append_column(name_column)

        return widget

    def get_value(self):
        model, paths = self.tree.get_selection().get_selected_rows()
        return [model[path][0] for path in paths]

    def set_value(self, value):
        value2path = {v: idx for idx, (v, _) in enumerate(self.selection)}
        selection = self.tree.get_selection()
        selection.handler_block_by_func(self._changed)
        try:
            selection.unselect_all()
            for v in value:
                if v in value2path:
                    selection.select_path(value2path[v])
        finally:
            selection.handler_unblock_by_func(self._changed)

    def _changed(self, selection):
        GLib.idle_add(self.parent_widget._focus_out)

    def set_readonly(self, readonly):
        selection = self.tree.get_selection()
        selection.set_select_function(lambda *a: not readonly)
class MultiSelection(Widget, SelectionMixin):
    expand = True

    def __init__(self, view, attrs):
        super(MultiSelection, self).__init__(view, attrs)

        if int(attrs.get('yexpand', self.expand)):
            self.widget = gtk.ScrolledWindow()
            self.widget.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
            self.widget.set_shadow_type(gtk.SHADOW_ETCHED_IN)
        else:
            self.widget = gtk.VBox()
        self.widget.get_accessible().set_name(attrs.get('string', ''))

        self.model = gtk.ListStore(gobject.TYPE_INT, gobject.TYPE_STRING)
        self.tree = TreeViewControl()
        self.tree.set_model(self.model)
        self.tree.set_search_column(1)
        self.tree.connect('focus-out-event', lambda *a: self._focus_out())
        self.tree.set_headers_visible(False)
        selection = self.tree.get_selection()
        selection.set_mode(gtk.SELECTION_MULTIPLE)
        selection.connect('changed', self.changed)
        self.widget.add(self.tree)
        name_column = gtk.TreeViewColumn()
        name_cell = gtk.CellRendererText()
        name_column.pack_start(name_cell)
        name_column.add_attribute(name_cell, 'text', 1)
        self.tree.append_column(name_column)

        self.nullable_widget = False
        self.init_selection()
        self.id2path = {}

    def _color_widget(self):
        return self.tree

    def _readonly_set(self, readonly):
        super(MultiSelection, self)._readonly_set(readonly)
        set_widget_style(self.tree, not readonly)
        selection = self.tree.get_selection()
        selection.set_select_function(lambda *a: not readonly)

    @property
    def modified(self):
        if self.record and self.field:
            group = set(r.id for r in self.field.get_client(self.record))
            value = set(self.get_value())
            return value != group
        return False

    def changed(self, selection):
        def focus_out():
            if self.widget.props.window:
                self._focus_out()
        # Must be deferred because it triggers a display of the form
        gobject.idle_add(focus_out)

    def get_value(self):
        model, paths = self.tree.get_selection().get_selected_rows()
        return [model[path][0] for path in paths]

    def set_value(self, record, field):
        field.set_client(record, self.get_value())

    def display(self, record, field):
        selection = self.tree.get_selection()
        selection.handler_block_by_func(self.changed)
        try:
            # Remove select_function to allow update,
            # it will be set back in the super call
            selection.set_select_function(lambda *a: True)
            self.update_selection(record, field)
            self.model.clear()
            if field is None:
                return
            id2path = {}
            for idx, (value, name) in enumerate(self.selection):
                self.model.append((value, name))
                id2path[value] = idx
            selection.unselect_all()
            group = field.get_client(record)
            for element in group:
                if (element not in group.record_removed
                        and element not in group.record_deleted
                        and element.id in id2path):
                    selection.select_path(id2path[element.id])
            super(MultiSelection, self).display(record, field)
        finally:
            selection.handler_unblock_by_func(self.changed)
Beispiel #6
0
class Email(NoModal):
    def __init__(self, name, record, prints, template=None):
        super().__init__()
        self.record = record
        self.dialog = Gtk.Dialog(transient_for=self.parent,
                                 destroy_with_parent=True)
        Main().add_window(self.dialog)
        self.dialog.set_position(Gtk.WindowPosition.CENTER_ON_PARENT)
        self.dialog.set_icon(TRYTON_ICON)
        self.dialog.set_default_size(*self.default_size())
        self.dialog.connect('response', self.response)

        self.dialog.set_title(_('E-mail %s') % name)

        grid = Gtk.Grid(column_spacing=3, row_spacing=3, border_width=3)
        self.dialog.vbox.pack_start(grid, expand=True, fill=True, padding=0)

        label = Gtk.Label(set_underline(_("To:")),
                          use_underline=True,
                          halign=Gtk.Align.END)
        grid.attach(label, 0, 0, 1, 1)
        self.to = EmailEntry(hexpand=True, activates_default=True)
        widget_class(self.to, 'required', True)
        label.set_mnemonic_widget(self.to)
        grid.attach(self.to, 1, 0, 1, 1)

        label = Gtk.Label(set_underline(_("Cc:")),
                          use_underline=True,
                          halign=Gtk.Align.END)
        grid.attach(label, 0, 1, 1, 1)
        self.cc = EmailEntry(hexpand=True, activates_default=True)
        label.set_mnemonic_widget(self.cc)
        grid.attach(self.cc, 1, 1, 1, 1)

        label = Gtk.Label(set_underline(_("Bcc:")),
                          use_underline=True,
                          halign=Gtk.Align.END)
        grid.attach(label, 0, 2, 1, 1)
        self.bcc = EmailEntry(hexpand=True, activates_default=True)
        label.set_mnemonic_widget(self.bcc)
        grid.attach(self.bcc, 1, 2, 1, 1)

        label = Gtk.Label(set_underline(_("Subject:")),
                          use_underline=True,
                          halign=Gtk.Align.END)
        grid.attach(label, 0, 3, 1, 1)
        self.subject = Gtk.Entry(hexpand=True, activates_default=True)
        label.set_mnemonic_widget(self.subject)
        grid.attach(self.subject, 1, 3, 1, 1)

        self.body = Gtk.TextView()
        body_frame = Gtk.Frame()
        label = Gtk.Label(set_underline(_("Body")),
                          use_underline=True,
                          halign=Gtk.Align.END)
        label.set_mnemonic_widget(self.body)
        body_frame.set_label_widget(label)
        grid.attach(body_frame, 0, 4, 2, 1)
        body_box = Gtk.VBox(hexpand=True, vexpand=True)
        body_frame.add(body_box)
        register_format(self.body)
        body_toolbar = add_toolbar(self.body)
        body_box.pack_start(body_toolbar, expand=False, fill=True, padding=0)
        body_box.pack_start(self.body, expand=True, fill=True, padding=0)

        if GtkSpell and CONFIG['client.spellcheck']:
            checker = GtkSpell.Checker()
            checker.attach(self.body)
            language = os.environ.get('LANGUAGE', 'en')
            try:
                checker.set_language(language)
            except Exception:
                logger.error('Could not set spell checker for "%s"', language)
                checker.detach()

        attachments_box = Gtk.HBox()
        grid.attach(attachments_box, 0, 5, 2, 1)

        print_frame = Gtk.Frame(shadow_type=Gtk.ShadowType.NONE)
        print_frame.set_label(_("Reports"))
        attachments_box.pack_start(print_frame,
                                   expand=True,
                                   fill=True,
                                   padding=0)
        print_box = Gtk.VBox()
        print_frame.add(print_box)
        print_flowbox = Gtk.FlowBox(selection_mode=Gtk.SelectionMode.NONE)
        print_box.pack_start(print_flowbox,
                             expand=False,
                             fill=False,
                             padding=0)
        self.print_actions = {}
        for print_ in prints:
            print_check = Gtk.CheckButton.new_with_mnemonic(
                set_underline(print_['name']))
            self.print_actions[print_['id']] = print_check
            print_flowbox.add(print_check)

        attachment_frame = Gtk.Frame(shadow_type=Gtk.ShadowType.NONE)
        attachment_frame.set_label(_("Attachments"))
        attachments_box.pack_start(attachment_frame,
                                   expand=True,
                                   fill=True,
                                   padding=0)
        try:
            attachments = RPCExecute('model',
                                     'ir.attachment',
                                     'search_read', [
                                         ('resource', '=', '%s,%s' %
                                          (record.model_name, record.id)),
                                         [
                                             'OR',
                                             ('data', '!=', None),
                                             ('file_id', '!=', None),
                                         ],
                                     ],
                                     0,
                                     None,
                                     None, ['rec_name'],
                                     context=record.get_context())
        except RPCException:
            logger.error('Could not fetch attachment for "%s"', record)
            attachments = []
        scrolledwindow = Gtk.ScrolledWindow()
        if len(attachments) > 2:
            scrolledwindow.set_size_request(-1, 100)
        attachment_frame.add(scrolledwindow)
        scrolledwindow.set_policy(Gtk.PolicyType.AUTOMATIC,
                                  Gtk.PolicyType.AUTOMATIC)
        self.attachments = TreeViewControl()
        self.attachments.set_headers_visible(False)
        scrolledwindow.add(self.attachments)
        self.attachments.get_selection().set_mode(Gtk.SelectionMode.MULTIPLE)
        self.attachments.append_column(
            Gtk.TreeViewColumn("Name", Gtk.CellRendererText(), text=0))
        model = Gtk.ListStore(GObject.TYPE_STRING, GObject.TYPE_INT)
        for attachment in attachments:
            model.append((attachment['rec_name'], attachment['id']))
        self.attachments.set_model(model)
        self.attachments.set_search_column(0)

        file_frame = Gtk.Frame(shadow_type=Gtk.ShadowType.NONE)
        file_frame.set_label(_("Files"))
        attachments_box.pack_start(file_frame,
                                   expand=True,
                                   fill=True,
                                   padding=0)
        self.files = Gtk.VBox(spacing=6)
        file_frame.add(self.files)
        self._add_file_button()

        button_cancel = self.dialog.add_button(set_underline(_("Cancel")),
                                               Gtk.ResponseType.CANCEL)
        button_cancel.set_image(
            IconFactory.get_image('tryton-cancel', Gtk.IconSize.BUTTON))

        button_send = self.dialog.add_button(set_underline(_("Send")),
                                             Gtk.ResponseType.OK)
        button_send.set_image(
            IconFactory.get_image('tryton-send', Gtk.IconSize.BUTTON))
        self.dialog.set_default_response(Gtk.ResponseType.OK)

        self._fill_with(template)

        self.dialog.show_all()
        self.register()

    def _add_file_button(self):
        tooltips = Tooltips()
        box = Gtk.HBox(spacing=3)
        self.files.pack_start(box, expand=False, fill=True, padding=0)
        file_ = Gtk.FileChooserButton(title=_("Select File"))
        box.pack_start(file_, expand=True, fill=True, padding=0)
        button = Gtk.Button()
        button.set_image(
            IconFactory.get_image('tryton-remove', Gtk.IconSize.BUTTON))
        tooltips.set_tip(button, _("Remove File"))
        button.set_sensitive(False)
        box.pack_start(button, expand=False, fill=True, padding=0)

        box.show_all()

        file_.connect('file-set', self._file_set, button)
        button.connect('clicked', self._file_remove)

    def _file_set(self, file_, button):
        button.set_sensitive(True)
        self._add_file_button()

    def _file_remove(self, button):
        self.files.remove(button.get_parent())

    def get_files(self):
        for box in self.files:
            file_ = list(box)[0]
            filename = file_.get_filename()
            if not filename:
                continue
            with open(filename, 'rb') as fp:
                data = fp.read()
            name = os.path.basename(filename)
            yield (name, data)

    def get_attachments(self):
        model, paths = self.attachments.get_selection().get_selected_rows()
        return [model[path][1] for path in paths]

    def _fill_with(self, template=None):
        try:
            if template:
                values = RPCExecute('model', 'ir.email.template', 'get',
                                    template, self.record.id)
            else:
                values = RPCExecute('model', 'ir.email.template',
                                    'get_default', self.record.model_name,
                                    self.record.id)
        except RPCException:
            return
        self.to.set_text(', '.join(values.get('to', [])))
        self.cc.set_text(', '.join(values.get('cc', [])))
        self.bcc.set_text(', '.join(values.get('bcc', [])))
        self.subject.set_text(values.get('subject', ''))
        set_content(self.body, values.get('body', ''))
        print_ids = values.get('reports', [])
        for print_id, print_check in self.print_actions.items():
            print_check.set_active(print_id in print_ids)

    def validate(self):
        valid = True
        if not self.subject.get_text():
            valid = False
            widget_class(self.subject, 'invalid', True)
            self.subject.grab_focus()
        else:
            widget_class(self.subject, 'invalid', False)
        if not self.to.get_text():
            valid = False
            widget_class(self.to, 'invalid', True)
            self.to.grab_focus()
        else:
            widget_class(self.to, 'invalid', False)
        return valid

    def response(self, dialog, response):
        if response == Gtk.ResponseType.OK:
            if not self.validate():
                return
            to = self.to.get_text()
            cc = self.cc.get_text()
            bcc = self.bcc.get_text()
            subject = self.subject.get_text()
            body = get_content(self.body)
            files = list(self.get_files())
            reports = [
                id_ for id_, check in self.print_actions.items()
                if check.get_active()
            ]
            attachments = self.get_attachments()
            try:
                RPCExecute('model', 'ir.email', 'send', to, cc, bcc, subject,
                           body, files,
                           [self.record.model_name, self.record.id], reports,
                           attachments)
            except RPCException:
                return
        self.destroy()

    def destroy(self):
        super().destroy()
        self.dialog.destroy()
class MultiSelection(Widget, SelectionMixin):
    expand = True

    def __init__(self, view, attrs):
        super(MultiSelection, self).__init__(view, attrs)

        self.widget = gtk.ScrolledWindow()
        self.widget.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
        self.widget.set_shadow_type(gtk.SHADOW_ETCHED_IN)
        self.widget.get_accessible().set_name(attrs.get('string', ''))

        self.model = gtk.ListStore(gobject.TYPE_INT, gobject.TYPE_STRING)
        self.tree = TreeViewControl()
        self.tree.set_model(self.model)
        self.tree.set_search_column(1)
        self.tree.connect('focus-out-event', lambda *a: self._focus_out())
        self.tree.set_headers_visible(False)
        selection = self.tree.get_selection()
        selection.set_mode(gtk.SELECTION_MULTIPLE)
        selection.connect('changed', self.changed)
        self.widget.add(self.tree)
        name_column = gtk.TreeViewColumn()
        name_cell = gtk.CellRendererText()
        name_column.pack_start(name_cell)
        name_column.add_attribute(name_cell, 'text', 1)
        self.tree.append_column(name_column)

        self.nullable_widget = False
        self.init_selection()
        self.id2path = {}

    @property
    def modified(self):
        if self.record and self.field:
            group = set(r.id for r in self.field.get_client(self.record))
            value = set(self.get_value())
            return value != group
        return False

    def changed(self, selection):
        def focus_out():
            if self.widget.props.window:
                self._focus_out()
        # Must be deferred because it triggers a display of the form
        gobject.idle_add(focus_out)

    def get_value(self):
        model, paths = self.tree.get_selection().get_selected_rows()
        return [model[path][0] for path in paths]

    def set_value(self, record, field):
        field.set_client(record, self.get_value())

    def display(self, record, field):
        selection = self.tree.get_selection()
        selection.handler_block_by_func(self.changed)
        try:
            self.update_selection(record, field)
            super(MultiSelection, self).display(record, field)
            self.model.clear()
            if field is None:
                return
            id2path = {}
            for idx, (value, name) in enumerate(self.selection):
                self.model.append((value, name))
                id2path[value] = idx
            selection.unselect_all()
            group = field.get_client(record)
            for element in group:
                if (element not in group.record_removed
                        and element not in group.record_deleted
                        and element.id in id2path):
                    selection.select_path(id2path[element.id])
        finally:
            selection.handler_unblock_by_func(self.changed)