Exemplo n.º 1
0
    def _sig_edit(self):
        if not self.screen.current_record:
            return
        # Create a new screen that is not linked to the parent otherwise on the
        # save of the record will trigger the save of the parent
        domain = self.field.domain_get(self.record)
        add_remove = self.record.expr_eval(self.attrs.get('add_remove'))
        if add_remove:
            domain = [domain, add_remove]
        context = self.field.context_get(self.record)

        screen = Screen(self.attrs['relation'], domain=domain,
            view_ids=self.attrs.get('view_ids', '').split(','),
            mode=['form'], views_preload=self.attrs.get('views', {}),
            readonly=self.attrs.get('readonly', False),
            context=context)
        screen.load([self.screen.current_record.id])

        def callback(result):
            if result:
                screen.current_record.save()
                # Force a reload on next display
                self.screen.current_record.cancel()
                # Force a display to clear the CellCache
                self.screen.display()
        WinForm(screen, callback)
Exemplo n.º 2
0
 def __init__(self, record, callback=None):
     self.resource = '%s,%s' % (record.model_name, record.id)
     self.note_callback = callback
     context = record.context_get()
     context['resource'] = self.resource
     screen = Screen('ir.note', domain=[
             ('resource', '=', self.resource),
             ], mode=['tree', 'form'], context=context,
         exclude_field='resource')
     super(Note, self).__init__(screen, self.callback, view_type='tree')
     screen.search_filter()
 def __init__(self, model_name, record_id, callback=None):
     self.resource = '%s,%s' % (model_name, record_id)
     self.attachment_callback = callback
     screen = Screen('ir.attachment', domain=[
         ('resource', '=', self.resource),
         ], mode=['tree', 'form'], context={
             'resource': self.resource,
         }, exclude_field='resource')
     screen.search_filter()
     screen.parent = True
     super(Attachment, self).__init__(screen, self.callback,
         view_type='tree')
Exemplo n.º 4
0
    def open_remote(self, record, create=True, changed=False, text=None,
            callback=None):
        field = record.group.fields[self.field_name]
        relation = field.attrs['relation']

        domain = field.domain_get(record)
        context = field.context_get(record)
        if create:
            obj_id = None
        elif not changed:
            obj_id = field.get(record)
        else:
            if text:
                dom = [('rec_name', 'ilike', '%' + text + '%'), domain]
            else:
                dom = domain
            try:
                ids = RPCExecute('model', relation, 'search', dom, 0, None,
                    None, context=context)
            except RPCException:
                field.set_client(record, False)
                if callback:
                    callback()
                return
            if len(ids) == 1:
                field.set_client(record, ids[0])
                if callback:
                    callback()
                return
            self.search_remote(record, relation, ids, domain=domain,
                context=context, callback=callback)
            return
        screen = Screen(relation, domain=domain, context=context,
            mode=['form'])

        def open_callback(result):
            if result and screen.save_current():
                value = (screen.current_record.id,
                    screen.current_record.rec_name())
                field.set_client(record, value, force_change=True)
            elif result:
                screen.display()
                return WinForm(screen, open_callback)
            if callback:
                callback()
        if obj_id:
            screen.load([obj_id])
            WinForm(screen, open_callback)
        else:
            WinForm(screen, open_callback, new=True)
Exemplo n.º 5
0
    def open_remote(self, record, create=True, changed=False, text=None,
            callback=None):
        group = record.value[self.field_name]
        field = record.group.fields[self.field_name]
        relation = field.attrs['relation']
        context = field.context_get(record)

        screen = Screen(relation, mode=['tree', 'form'],
            exclude_field=field.attrs.get('relation_field'))
        screen.group = group

        def open_callback(result):
            if callback:
                callback()
        WinForm(screen, open_callback, view_type='tree', context=context)
Exemplo n.º 6
0
    def __init__(self, view, attrs):
        super(Many2ManySelection, self).__init__(view, attrs)

        self.widget = gtk.VBox(homogeneous=False, spacing=5)

        hbox = gtk.HBox(homogeneous=False, spacing=0)
        hbox.set_border_width(2)

        label = gtk.Label(attrs.get("string", ""))
        label.set_alignment(0.0, 0.5)
        hbox.pack_start(label, expand=True, fill=True)

        frame = gtk.Frame()
        frame.add(hbox)
        frame.set_shadow_type(gtk.SHADOW_OUT)
        self.widget.pack_start(frame, expand=False, fill=True)

        self.screen = Screen(
            attrs["relation"],
            view_ids=attrs.get("view_ids", "").split(","),
            mode=["tree"],
            views_preload=attrs.get("views", {}),
        )
        self.screen.new_group()
        self.treeview = self.screen.current_view.treeview
        self.treeview.get_selection().connect("changed", self.changed)
        self.treeview.connect("focus-out-event", lambda *a: self._focus_out())

        self.treeview.connect("button-press-event", self.button_press_event)
        self.treeview.connect("key-press-event", self.key_press_event)

        self.widget.pack_start(self.screen.widget, expand=True, fill=True)

        self.nullable_widget = False
        self.init_selection()
Exemplo n.º 7
0
    def __init__(self, user, callback):
        NoModal.__init__(self)
        self.callback = callback
        self.win = gtk.Dialog(_("Preferences"), self.parent, gtk.DIALOG_DESTROY_WITH_PARENT)
        self.win.set_position(gtk.WIN_POS_CENTER_ON_PARENT)
        self.win.set_has_separator(False)
        self.win.set_icon(TRYTON_ICON)

        self.accel_group = gtk.AccelGroup()
        self.win.add_accel_group(self.accel_group)

        self.but_cancel = self.win.add_button(gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL)
        self.but_ok = self.win.add_button(gtk.STOCK_OK, gtk.RESPONSE_OK)
        self.but_ok.add_accelerator(
            "clicked", self.accel_group, gtk.keysyms.Return, gtk.gdk.CONTROL_MASK, gtk.ACCEL_VISIBLE
        )

        self.win.set_default_response(gtk.RESPONSE_OK)
        self.win.connect("response", self.response)

        try:
            view = RPCExecute("model", "res.user", "get_preferences_fields_view")
        except RPCException:
            self.win.destroy()
            self.win = None
            return

        title = gtk.Label(_("Edit User Preferences"))
        title.show()
        self.win.vbox.pack_start(title, expand=False, fill=True)
        self.screen = Screen("res.user", mode=[])
        # Reset readonly set automaticly by MODELACCESS
        self.screen.readonly = False
        self.screen.group.readonly = False
        self.screen.group.skip_model_access = True
        self.screen.add_view(view)
        self.screen.switch_view()
        self.screen.new(default=False)

        try:
            preferences = RPCExecute("model", "res.user", "get_preferences", False)
        except RPCException:
            self.win.destroy()
            self.win = None
            return
        self.screen.current_record.set(preferences)
        self.screen.current_record.id = rpc._USER
        self.screen.current_record.validate(softvalidation=True)
        self.screen.display(set_cursor=True)

        self.screen.widget.show()
        self.win.vbox.pack_start(self.screen.widget)
        self.win.set_title(_("Preference"))

        width, height = self.parent.get_size()
        self.win.set_default_size(int(width * 0.95), int(height * 0.95))

        self.register()
        self.win.show()
Exemplo n.º 8
0
    def open_remote(self, record, create=True, changed=False, text=None,
            callback=None):
        group = record.value[self.attrs['name']]
        field = record.group.fields[self.attrs['name']]
        relation = field.attrs['relation']
        context = field.get_context(record)
        domain = field.domain_get(record)

        screen = Screen(relation, mode=['tree', 'form'],
            view_ids=self.attrs.get('view_ids', '').split(','),
            exclude_field=field.attrs.get('relation_field'))
        screen.group = group

        def open_callback(result):
            if callback:
                callback()
        WinForm(screen, open_callback, view_type='tree', domain=domain,
            context=context, title=field.attrs.get('string'))
Exemplo n.º 9
0
 def get_screen(self):
     domain = self.field.domain_get(self.record)
     context = self.field.get_context(self.record)
     # Remove first tree view as mode is form only
     view_ids = self.attrs.get('view_ids', '').split(',')[1:]
     return Screen(self.get_model(), domain=domain, context=context,
         mode=['form'], view_ids=view_ids,
         views_preload=self.attrs.get('views', {}), readonly=self._readonly,
         exclude_field=self.attrs.get('relation_field'))
Exemplo n.º 10
0
    def __init__(self, model, res_id=None, name='', **attributes):
        super(Form, self).__init__(**attributes)

        self.model = model
        self.res_id = res_id
        self.mode = attributes.get('mode')
        self.view_ids = attributes.get('view_ids')
        self.dialogs = []

        if not name:
            name = common.MODELNAME.get(model)
        self.name = name

        self.screen = Screen(self.model, breadcrumb=[self.name], **attributes)
        self.screen.widget.show()

        self.create_tabcontent()

        self.set_buttons_sensitive()

        self.screen.signal_connect(self, 'record-message',
            self._record_message)

        self.screen.signal_connect(self, 'record-modified',
            lambda *a: GLib.idle_add(self._record_modified, *a))
        self.screen.signal_connect(self, 'record-saved', self._record_saved)
        self.screen.signal_connect(
            self, 'resources',
            lambda screen, resources: self.update_resources(resources))

        self.attachment_screen = None

        if res_id not in (None, False):
            if isinstance(res_id, int):
                res_id = [res_id]
            self.screen.load(res_id)
        else:
            if self.screen.current_view.view_type == 'form':
                self.sig_new(None, autosave=False)
            if self.screen.current_view.view_type \
                    in ('tree', 'graph', 'calendar'):
                self.screen.search_filter()

        self.update_revision()
Exemplo n.º 11
0
    def __init__(self, model, res_id=False, domain=None, mode=None,
            view_ids=None, context=None, name=False, limit=None,
            auto_refresh=False, search_value=None):
        super(Form, self).__init__()

        if not mode:
            mode = ['tree', 'form']
        if domain is None:
            domain = []
        if view_ids is None:
            view_ids = []
        if context is None:
            context = {}

        self.model = model
        self.res_id = res_id
        self.domain = domain
        self.mode = mode
        self.context = context
        self.auto_refresh = auto_refresh
        self.view_ids = view_ids
        self.dialogs = []

        self.screen = Screen(self.model, mode=mode, context=self.context,
            view_ids=view_ids, domain=domain, limit=limit,
            readonly=bool(auto_refresh), search_value=search_value)
        self.screen.widget.show()

        if not name:
            self.name = self.screen.current_view.title
        else:
            self.name = name

        self.create_tabcontent()
        self.screen.signal_connect(self, 'record-message',
            self._record_message)
        self.screen.signal_connect(self, 'record-modified',
            lambda *a: gobject.idle_add(self._record_modified, *a))
        self.screen.signal_connect(self, 'record-saved', self._record_saved)
        self.screen.signal_connect(self, 'attachment-count',
                self._attachment_count)

        if res_id not in (None, False):
            if isinstance(res_id, (int, long)):
                res_id = [res_id]
            self.screen.load(res_id)
        else:
            if self.screen.current_view.view_type == 'form':
                self.sig_new(None, autosave=False)
            if self.screen.current_view.view_type \
                    in ('tree', 'graph', 'calendar'):
                self.screen.search_filter()

        if auto_refresh and int(auto_refresh):
            gobject.timeout_add(int(auto_refresh) * 1000, self.sig_reload)
Exemplo n.º 12
0
    def open_remote(self, record, create=True, changed=False, text=None,
            callback=None):
        group = record.value[self.attrs['name']]
        field = record.group.fields[self.attrs['name']]
        relation = field.attrs['relation']
        context = field.context_get(record)

        access = common.MODELACCESS[relation]
        if not access['read']:
            return

        screen = Screen(relation, mode=['tree', 'form'],
            exclude_field=field.attrs.get('relation_field'))
        screen.pre_validate = bool(int(self.attrs.get('pre_validate', 0)))
        screen.group = group

        def open_callback(result):
            if callback:
                callback()
        WinForm(screen, open_callback, view_type='tree', context=context)
Exemplo n.º 13
0
 def click_and_relate(self, action, value, path):
     data = {}
     context = {}
     act = action.copy()
     if not(value):
         message(_('You must select a record to use the relation!'))
         return False
     from tryton.gui.window.view_form.screen import Screen
     screen = Screen(self.screen.group.fields[
         path[1].name].attrs['relation'])
     screen.load([value])
     encoder = PYSONEncoder()
     act['domain'] = encoder.encode(screen.current_record.expr_eval(
         act.get('domain', []), check_load=False))
     act['context'] = encoder.encode(screen.current_record.expr_eval(
         act.get('context', {}), check_load=False))
     data['model'] = self.screen.model_name
     data['id'] = value
     data['ids'] = [value]
     return Action._exec_action(act, data, context)
Exemplo n.º 14
0
    def open_remote(self, record, create=True, changed=False, text=None,
            callback=None):
        group = record.value[self.field_name]
        field = record.group.fields[self.field_name]
        relation = field.attrs['relation']
        context = field.context_get(record)

        access = common.MODELACCESS[relation]
        if not access['read']:
            return

        screen = Screen(relation, mode=['tree', 'form'],
            exclude_field=field.attrs.get('relation_field'))
        screen.pre_validate = bool(int(self.attrs.get('pre_validate', 0)))
        screen.group = group

        def open_callback(result):
            if callback:
                callback()
        WinForm(screen, open_callback, view_type='tree', context=context)
Exemplo n.º 15
0
 def get_screen(self):
     domain = self.field.domain_get(self.record)
     context = self.field.context_get(self.record)
     return Screen(self.get_model(),
                   domain=domain,
                   context=context,
                   mode=['form'],
                   view_ids=self.attrs.get('view_ids', '').split(','),
                   views_preload=self.attrs.get('views', {}),
                   readonly=self._readonly,
                   exclude_field=self.attrs.get('relation_field'))
Exemplo n.º 16
0
    def __init__(self, model, res_id=None, name='', **attributes):
        super(Form, self).__init__()

        self.model = model
        self.res_id = res_id
        self.mode = attributes.get('mode')
        self.view_ids = attributes.get('view_ids')
        self.dialogs = []

        self.screen = Screen(self.model, **attributes)
        self.screen.widget.show()

        self.name = name

        self.create_tabcontent()

        self.set_buttons_sensitive()

        self.screen.signal_connect(self, 'record-message',
                                   self._record_message)

        self.screen.signal_connect(
            self, 'record-modified',
            lambda *a: gobject.idle_add(self._record_modified, *a))
        self.screen.signal_connect(self, 'record-saved', self._record_saved)
        self.screen.signal_connect(self, 'attachment-count',
                                   self._attachment_count)
        self.screen.signal_connect(self, 'unread-note', self._unread_note)

        if res_id not in (None, False):
            if isinstance(res_id, (int, long)):
                res_id = [res_id]
            self.screen.load(res_id)
        else:
            if self.screen.current_view.view_type == 'form':
                self.sig_new(None, autosave=False)
            if self.screen.current_view.view_type \
                    in ('tree', 'graph', 'calendar'):
                self.screen.search_filter()

        self.update_revision()
Exemplo n.º 17
0
 def _get_screen_form(self):
     domain = self.field.domain_get(self.record)
     add_remove = self.record.expr_eval(self.attrs.get('add_remove'))
     if add_remove:
         domain = [domain, add_remove]
     context = self.field.get_context(self.record)
     # Remove the first tree view as mode is form only
     view_ids = self.attrs.get('view_ids', '').split(',')[1:]
     return Screen(self.attrs['relation'], domain=domain,
         view_ids=view_ids,
         mode=['form'], views_preload=self.attrs.get('views', {}),
         context=context)
Exemplo n.º 18
0
    def open_remote(self, record, create=True, changed=False, text=None,
            callback=None):
        field = record.group.fields[self.attrs['name']]
        relation = field.attrs['relation']

        access = common.MODELACCESS[relation]
        if (create
                and not (self.attrs.get('create', True) and access['create'])):
            return
        elif not access['read']:
            return

        domain = field.domain_get(record)
        context = field.get_context(record)
        if create:
            obj_id = None
        elif not changed:
            obj_id = field.get(record)
        else:
            self.search_remote(record, field, text, callback=callback).show()
            return

        screen = Screen(relation, domain=domain, context=context,
            mode=['form'], view_ids=self.attrs.get('view_ids', '').split(','),
            exclude_field=field.attrs.get('relation_field'))

        def open_callback(result):
            if result:
                value = (screen.current_record.id,
                    screen.current_record.rec_name())
                field.set_client(record, value, force_change=True)
            if callback:
                callback()
        if obj_id:
            screen.load([obj_id])
            WinForm(screen, open_callback, save_current=True,
                title=field.attrs.get('string'))
        else:
            WinForm(screen, open_callback, new=True, save_current=True,
                title=field.attrs.get('string'), rec_name=text)
Exemplo n.º 19
0
    def __init__(self, model, res_id=None, name='', **attributes):
        super(Form, self).__init__(**attributes)

        self.model = model
        self.res_id = res_id
        self.mode = attributes.get('mode')
        self.view_ids = attributes.get('view_ids')
        self.dialogs = []

        if not name:
            name = common.MODELNAME.get(model)
        self.name = name

        loading_ids = res_id not in (None, False)
        if loading_ids:
            attributes.pop('tab_domain', None)
        self.screen = Screen(self.model, breadcrumb=[self.name], **attributes)
        self.screen.widget.show()
        self.screen.windows.append(self)

        self.create_tabcontent()

        self.set_buttons_sensitive()

        self.attachment_screen = None

        if loading_ids:
            if isinstance(res_id, int):
                res_id = [res_id]
            self.screen.load(res_id)
        else:
            if self.screen.current_view.view_type == 'form':
                self.sig_new(None, autosave=False)
            if self.screen.current_view.view_type \
                    in ('tree', 'graph', 'calendar'):
                self.screen.search_filter()

        self.update_revision()
        self.activate_save()
    def __init__(self, user):
        self.parent = common.get_toplevel_window()
        self.win = gtk.Dialog(_("Preferences"), self.parent, gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT)
        self.win.set_position(gtk.WIN_POS_CENTER_ON_PARENT)
        self.win.set_has_separator(False)
        self.win.set_icon(TRYTON_ICON)

        self.accel_group = gtk.AccelGroup()
        self.win.add_accel_group(self.accel_group)

        self.but_cancel = self.win.add_button(gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL)
        self.but_ok = self.win.add_button(gtk.STOCK_OK, gtk.RESPONSE_OK)
        self.but_ok.add_accelerator(
            "clicked", self.accel_group, gtk.keysyms.Return, gtk.gdk.CONTROL_MASK, gtk.ACCEL_VISIBLE
        )

        self.win.set_default_response(gtk.RESPONSE_OK)

        try:
            view = RPCExecute("model", "res.user", "get_preferences_fields_view")
        except RPCException:
            self.win.destroy()
            self.win = None
            return

        title = gtk.Label(_("Edit User Preferences"))
        title.show()
        self.win.vbox.pack_start(title, expand=False, fill=True)
        self.screen = Screen("res.user", mode=[])
        self.screen.add_view(view)
        self.screen.new(default=False)

        try:
            preferences = RPCExecute("model", "res.user", "get_preferences", False)
        except RPCException:
            self.win.destroy()
            self.win = None
            return
        self.screen.current_record.set(preferences)
        self.screen.current_record.validate(softvalidation=True)
        self.screen.screen_container.set(self.screen.current_view.widget)
        self.screen.display(set_cursor=True)

        self.screen.widget.show()
        self.win.vbox.pack_start(self.screen.widget)
        self.win.set_title(_("Preference"))

        width, height = self.parent.get_size()
        self.win.set_default_size(int(width * 0.9), int(height * 0.9))

        self.win.show()
Exemplo n.º 21
0
    def open_remote(self, record, create=True, changed=False, text=None,
            callback=None):
        field = record.group.fields[self.attrs['name']]
        relation = field.attrs['relation']

        access = common.MODELACCESS[relation]
        if (create
                and not (self.attrs.get('create', True) and access['create'])):
            return
        elif not access['read']:
            return

        domain = field.domain_get(record)
        context = field.context_get(record)
        if create:
            obj_id = None
        elif not changed:
            obj_id = field.get(record)
        else:
            self.search_remote(record, relation, text, domain=domain,
                context=context, callback=callback).show()
            return
        screen = Screen(relation, domain=domain, context=context,
            mode=['form'], view_ids=self.attrs.get('view_ids', '').split(','),
            exclude_field=field.attrs.get('relation_field'))

        def open_callback(result):
            if result:
                value = (screen.current_record.id,
                    screen.current_record.rec_name())
                field.set_client(record, value, force_change=True)
            if callback:
                callback()
        if obj_id:
            screen.load([obj_id])
            WinForm(screen, open_callback, save_current=True)
        else:
            WinForm(screen, open_callback, new=True, save_current=True)
Exemplo n.º 22
0
    def _attachment_preview_widget(self):
        vbox = Gtk.VBox(homogeneous=False, spacing=2)
        vbox.set_margin_start(4)
        hbox = Gtk.HBox(homogeneous=False, spacing=0)
        hbox.set_halign(Gtk.Align.CENTER)
        vbox.pack_start(hbox, expand=False, fill=True, padding=0)
        hbox.set_border_width(2)
        tooltips = common.Tooltips()

        but_prev = Gtk.Button()
        tooltips.set_tip(but_prev, _("Previous"))
        but_prev.add(
            common.IconFactory.get_image('tryton-back',
                                         Gtk.IconSize.SMALL_TOOLBAR))
        but_prev.set_relief(Gtk.ReliefStyle.NONE)
        hbox.pack_start(but_prev, expand=False, fill=False, padding=0)

        label = Gtk.Label(label='(0,0)')
        hbox.pack_start(label, expand=False, fill=False, padding=0)

        but_next = Gtk.Button()
        tooltips.set_tip(but_next, _("Next"))
        but_next.add(
            common.IconFactory.get_image('tryton-forward',
                                         Gtk.IconSize.SMALL_TOOLBAR))
        but_next.set_relief(Gtk.ReliefStyle.NONE)
        hbox.pack_start(but_next, expand=False, fill=False, padding=0)

        vbox.show_all()
        self.attachment_screen = screen = Screen('ir.attachment',
                                                 readonly=True,
                                                 mode=['form'],
                                                 context={
                                                     'preview': True,
                                                 })
        screen.widget.show()

        but_prev.connect('clicked', lambda *a: screen.display_prev())
        but_next.connect('clicked', lambda *a: screen.display_next())

        class Preview():
            def record_message(self, position, length, *args):
                label.set_text('(%s/%s)' % (position or '_', length))
                but_prev.set_sensitive(position and position > 1)
                but_next.set_sensitive(position and position < length)

        screen.windows.append(Preview())

        vbox.pack_start(screen.widget, expand=True, fill=True, padding=0)
        return vbox
Exemplo n.º 23
0
 def _get_screen_form(self):
     domain = self.field.domain_get(self.record)
     add_remove = self.record.expr_eval(self.attrs.get('add_remove'))
     if add_remove:
         domain = [domain, add_remove]
     context = self.field.get_context(self.record)
     # Remove the first tree view as mode is form only
     view_ids = self.attrs.get('view_ids', '').split(',')[1:]
     model = self.attrs['relation']
     breadcrumb = list(self.view.screen.breadcrumb)
     breadcrumb.append(
         self.attrs.get('string') or common.MODELNAME.get(model))
     return Screen(model, domain=domain,
         view_ids=view_ids,
         mode=['form'], views_preload=self.attrs.get('views', {}),
         context=context, breadcrumb=breadcrumb)
Exemplo n.º 24
0
 def get_screen(self, search=False):
     domain = self.field.domain_get(self.record)
     if search:
         context = self.field.get_search_context(self.record)
     else:
         context = self.field.get_context(self.record)
     # Remove first tree view as mode is form only
     view_ids = self.attrs.get('view_ids', '').split(',')[1:]
     model = self.get_model()
     breadcrumb = list(self.view.screen.breadcrumb)
     breadcrumb.append(
         self.attrs.get('string') or common.MODELNAME.get(model))
     return Screen(model, domain=domain, context=context,
         mode=['form'], view_ids=view_ids,
         views_preload=self.attrs.get('views', {}), readonly=self._readonly,
         exclude_field=self.attrs.get('relation_field'),
         breadcrumb=breadcrumb)
Exemplo n.º 25
0
    def _completion_action_activated(self, completion, index):
        if index == 0:
            self._sig_add(win_search=True)
            self.wid_text.grab_focus()
        elif index == 1:
            model = self.attrs['relation']
            domain = self.field.domain_get(self.record)
            context = self.field.context_get(self.record)

            screen = Screen(model, domain, context=context, mode=['form'])

            def callback(result):
                self.focus_out = True
                if result:
                    record = screen.current_record
                    self.screen.load([record.id], modified=True)
                self.wid_text.set_text('')
                self.wid_text.grab_focus()

            self.focus_out = False
            WinForm(screen, callback, new=True, save_current=True)
Exemplo n.º 26
0
    def response(self, win, response_id):
        res = None
        if response_id == gtk.RESPONSE_OK:
            res = [r.id for r in self.screen.selected_records]
        elif response_id == gtk.RESPONSE_APPLY:
            self.screen.search_filter(self.screen.screen_container.get_text())
            return
        elif response_id == gtk.RESPONSE_ACCEPT:
            # Remove first tree view as mode if form only
            view_ids = self.view_ids[1:]
            screen = Screen(self.model_name,
                            domain=self.domain,
                            context=self.context,
                            order=self.order,
                            mode=['form'],
                            view_ids=view_ids,
                            views_preload=self.views_preload)

            def callback(result):
                # JMO : TODO : see if that diff from tryton is needed
                if result and screen.save_current():
                    record = screen.current_record
                    res = [(record.id, record.value.get('rec_name', ''))]
                    self.callback(res)
                else:
                    self.callback(None)

            self.destroy()
            WinForm(screen,
                    callback,
                    new=True,
                    save_current=True,
                    title=self.title)
            return
        if res:
            group = self.screen.group
            res = [(id_, group.get(id_).value.get('rec_name', ''))
                   for id_ in res]
        self.callback(res)
        self.destroy()
Exemplo n.º 27
0
    def response(self, win, response_id):
        res = None
        if response_id == Gtk.ResponseType.OK:
            res = [r.id for r in self.screen.selected_records]
        elif response_id == Gtk.ResponseType.APPLY:
            self.screen.search_filter(self.screen.screen_container.get_text())
            return
        elif response_id == Gtk.ResponseType.ACCEPT:
            # Remove first tree view as mode if form only
            view_ids = self.view_ids[1:]
            screen = Screen(self.model_name,
                            domain=self.domain,
                            context=self.context,
                            order=self.order,
                            mode=['form'],
                            view_ids=view_ids,
                            views_preload=self.views_preload,
                            exclude_field=self.exclude_field,
                            breadcrumb=[self.title])

            def callback(result):
                if result:
                    record = screen.current_record
                    res = [(record.id, record.value.get('rec_name', ''))]
                    self.callback(res)
                else:
                    self.callback(None)

            self.destroy()
            WinForm(screen, callback, new=True, save_current=True)
            return
        if res:
            group = self.screen.group
            res = [(id_, group.get(id_).value.get('rec_name', ''))
                   for id_ in res]
        self.callback(res)
        self.destroy()
Exemplo n.º 28
0
    def _sig_new(self):
        domain = self.field.domain_get(self.record)
        add_remove = self.record.expr_eval(self.attrs.get('add_remove'))
        if add_remove:
            domain = [domain, add_remove]
        context = self.field.context_get(self.record)

        screen = Screen(self.attrs['relation'],
                        domain=domain,
                        view_ids=self.attrs.get('view_ids', '').split(','),
                        mode=['form'],
                        views_preload=self.attrs.get('views', {}),
                        context=context)

        def callback(result):
            self.focus_out = True
            if result:
                record = screen.current_record
                self.screen.load([record.id], modified=True)
            self.wid_text.set_text('')
            self.wid_text.grab_focus()

        self.focus_out = False
        WinForm(screen, callback, new=True, save_current=True)
Exemplo n.º 29
0
    def __init__(self, model, res_id=False, domain=None, order=None, mode=None,
            view_ids=None, context=None, name=False, limit=None,
            search_value=None, tab_domain=None, context_model=None):
        super(Form, self).__init__()

        if not mode:
            mode = ['tree', 'form']
        if domain is None:
            domain = []
        if view_ids is None:
            view_ids = []

        self.model = model
        self.res_id = res_id
        self.domain = domain
        self.mode = mode
        self.context = context
        self.view_ids = view_ids
        self.dialogs = []

        self.screen = Screen(self.model, mode=mode, context=context,
            view_ids=view_ids, domain=domain, limit=limit, order=order,
            search_value=search_value, tab_domain=tab_domain,
            context_model=context_model)
        self.screen.widget.show()

        if not name:
            self.name = self.screen.current_view.title
        else:
            self.name = name

        if self.model not in common.MODELHISTORY:
            self.menu_def = self.menu_def[:]
            # Remove callback to revision
            self.menu_def[11] = (self.menu_def[11][:2] + (None,)
                + self.menu_def[11][3:])

        self.create_tabcontent()

        self.url_entry = url_entry = gtk.Entry()
        url_entry.show()
        url_entry.set_editable(False)
        style = url_entry.get_style()
        url_entry.modify_bg(gtk.STATE_ACTIVE,
            style.bg[gtk.STATE_INSENSITIVE])
        self.widget.pack_start(url_entry, False, False)

        self.set_buttons_sensitive()

        self.screen.signal_connect(self, 'record-message',
            self._record_message)

        self.screen.signal_connect(self, 'record-modified',
            lambda *a: gobject.idle_add(self._record_modified, *a))
        self.screen.signal_connect(self, 'record-saved', self._record_saved)
        self.screen.signal_connect(self, 'attachment-count',
                self._attachment_count)
        self.screen.signal_connect(self, 'unread-note', self._unread_note)

        if res_id not in (None, False):
            if isinstance(res_id, (int, long)):
                res_id = [res_id]
            self.screen.load(res_id)
        else:
            if self.screen.current_view.view_type == 'form':
                self.sig_new(None, autosave=False)
            if self.screen.current_view.view_type \
                    in ('tree', 'graph', 'calendar'):
                self.screen.search_filter()

        self.update_revision()
Exemplo n.º 30
0
    def __init__(self, view, attrs):
        super(One2Many, self).__init__(view, attrs)

        self.widget = Gtk.Frame()
        self.widget.set_shadow_type(Gtk.ShadowType.NONE)
        self.widget.get_accessible().set_name(attrs.get('string', ''))
        vbox = Gtk.VBox(homogeneous=False, spacing=2)
        self.widget.add(vbox)
        self._readonly = True
        self._required = False
        self._position = 0
        self._length = 0

        self.title_box = hbox = Gtk.HBox(homogeneous=False, spacing=0)
        hbox.set_border_width(2)

        self.title = Gtk.Label(label=set_underline(attrs.get('string', '')),
                               use_underline=True,
                               halign=Gtk.Align.START)
        hbox.pack_start(self.title, expand=True, fill=True, padding=0)

        hbox.pack_start(Gtk.VSeparator(), expand=False, fill=True, padding=0)

        tooltips = common.Tooltips()

        but_switch = Gtk.Button(can_focus=False)
        tooltips.set_tip(but_switch, _('Switch'))
        but_switch.connect('clicked', self.switch_view)
        but_switch.add(
            common.IconFactory.get_image('tryton-switch',
                                         Gtk.IconSize.SMALL_TOOLBAR))
        but_switch.set_relief(Gtk.ReliefStyle.NONE)
        hbox.pack_start(but_switch, expand=False, fill=False, padding=0)

        self.but_pre = Gtk.Button(can_focus=False)
        tooltips.set_tip(self.but_pre, _('Previous'))
        self.but_pre.connect('clicked', self._sig_previous)
        self.but_pre.add(
            common.IconFactory.get_image('tryton-back',
                                         Gtk.IconSize.SMALL_TOOLBAR))
        self.but_pre.set_relief(Gtk.ReliefStyle.NONE)
        hbox.pack_start(self.but_pre, expand=False, fill=False, padding=0)

        self.label = Gtk.Label(label='(0,0)')
        hbox.pack_start(self.label, expand=False, fill=False, padding=0)

        self.but_next = Gtk.Button(can_focus=False)
        tooltips.set_tip(self.but_next, _('Next'))
        self.but_next.connect('clicked', self._sig_next)
        self.but_next.add(
            common.IconFactory.get_image('tryton-forward',
                                         Gtk.IconSize.SMALL_TOOLBAR))
        self.but_next.set_relief(Gtk.ReliefStyle.NONE)
        hbox.pack_start(self.but_next, expand=False, fill=False, padding=0)

        hbox.pack_start(Gtk.VSeparator(), expand=False, fill=True, padding=0)

        self.focus_out = True
        self.wid_completion = None
        if attrs.get('add_remove'):

            self.wid_text = Gtk.Entry()
            self.wid_text.set_placeholder_text(_('Search'))
            self.wid_text.set_property('width_chars', 13)
            self.wid_text.connect('focus-out-event', self._focus_out)
            hbox.pack_start(self.wid_text, expand=True, fill=True, padding=0)

            if int(self.attrs.get('completion', 1)):
                self.wid_completion = get_completion(search=self.read_access,
                                                     create=self.create_access)
                self.wid_completion.connect('match-selected',
                                            self._completion_match_selected)
                self.wid_completion.connect('action-activated',
                                            self._completion_action_activated)
                self.wid_text.set_completion(self.wid_completion)
                self.wid_text.connect('changed', self._update_completion)

            self.but_add = Gtk.Button(can_focus=False)
            tooltips.set_tip(self.but_add, _('Add existing record'))
            self.but_add.connect('clicked', self._sig_add)
            self.but_add.add(
                common.IconFactory.get_image('tryton-add',
                                             Gtk.IconSize.SMALL_TOOLBAR))
            self.but_add.set_relief(Gtk.ReliefStyle.NONE)
            hbox.pack_start(self.but_add, expand=False, fill=False, padding=0)

            self.but_remove = Gtk.Button(can_focus=False)
            tooltips.set_tip(self.but_remove, _('Remove selected record'))
            self.but_remove.connect('clicked', self._sig_remove, True)
            self.but_remove.add(
                common.IconFactory.get_image('tryton-remove',
                                             Gtk.IconSize.SMALL_TOOLBAR))
            self.but_remove.set_relief(Gtk.ReliefStyle.NONE)
            hbox.pack_start(self.but_remove,
                            expand=False,
                            fill=False,
                            padding=0)

            hbox.pack_start(Gtk.VSeparator(),
                            expand=False,
                            fill=True,
                            padding=0)

        self.but_new = Gtk.Button(can_focus=False)
        tooltips.set_tip(self.but_new, _('Create a new record'))
        self.but_new.connect('clicked', self._sig_new)
        self.but_new.add(
            common.IconFactory.get_image('tryton-create',
                                         Gtk.IconSize.SMALL_TOOLBAR))
        self.but_new.set_relief(Gtk.ReliefStyle.NONE)
        hbox.pack_start(self.but_new, expand=False, fill=False, padding=0)

        self.but_open = Gtk.Button(can_focus=False)
        tooltips.set_tip(self.but_open, _('Edit selected record'))
        self.but_open.connect('clicked', self._sig_edit)
        self.but_open.add(
            common.IconFactory.get_image('tryton-open',
                                         Gtk.IconSize.SMALL_TOOLBAR))
        self.but_open.set_relief(Gtk.ReliefStyle.NONE)
        hbox.pack_start(self.but_open, expand=False, fill=False, padding=0)

        self.but_del = Gtk.Button(can_focus=False)
        tooltips.set_tip(self.but_del, _('Delete selected record'))
        self.but_del.connect('clicked', self._sig_remove, False)
        self.but_del.add(
            common.IconFactory.get_image('tryton-delete',
                                         Gtk.IconSize.SMALL_TOOLBAR))
        self.but_del.set_relief(Gtk.ReliefStyle.NONE)
        hbox.pack_start(self.but_del, expand=False, fill=False, padding=0)

        self.but_undel = Gtk.Button(can_focus=False)
        tooltips.set_tip(self.but_undel, _('Undelete selected record <Ins>'))
        self.but_undel.connect('clicked', self._sig_undelete)
        self.but_undel.add(
            common.IconFactory.get_image('tryton-undo',
                                         Gtk.IconSize.SMALL_TOOLBAR))
        self.but_undel.set_relief(Gtk.ReliefStyle.NONE)
        hbox.pack_start(self.but_undel, expand=False, fill=False, padding=0)

        tooltips.enable()

        frame = Gtk.Frame()
        frame.add(hbox)
        frame.set_shadow_type(Gtk.ShadowType.OUT)
        vbox.pack_start(frame, expand=False, fill=True, padding=0)

        model = attrs['relation']
        breadcrumb = list(self.view.screen.breadcrumb)
        breadcrumb.append(attrs.get('string') or common.MODELNAME.get(model))
        self.screen = Screen(model,
                             mode=attrs.get('mode', 'tree,form').split(','),
                             view_ids=attrs.get('view_ids', '').split(','),
                             views_preload=attrs.get('views', {}),
                             order=attrs.get('order'),
                             row_activate=self._on_activate,
                             exclude_field=attrs.get('relation_field', None),
                             limit=None,
                             breadcrumb=breadcrumb)
        self.screen.pre_validate = bool(int(attrs.get('pre_validate', 0)))
        self.screen.windows.append(self)

        vbox.pack_start(self.screen.widget, expand=True, fill=True, padding=0)

        self.title.set_mnemonic_widget(
            self.screen.current_view.mnemonic_widget)

        self.screen.widget.connect('key_press_event', self.on_keypress)
        if self.attrs.get('add_remove'):
            self.wid_text.connect('key_press_event', self.on_keypress)

        but_switch.props.sensitive = self.screen.number_of_views > 1
Exemplo n.º 31
0
    def __init__(self, view, attrs):
        super(Many2Many, self).__init__(view, attrs)

        self.widget = gtk.Frame()
        self.widget.set_shadow_type(gtk.SHADOW_NONE)
        self.widget.get_accessible().set_name(attrs.get('string', ''))
        vbox = gtk.VBox(homogeneous=False, spacing=5)
        self.widget.add(vbox)
        self._readonly = True
        self._required = False
        self._position = 0

        hbox = gtk.HBox(homogeneous=False, spacing=0)
        hbox.set_border_width(2)

        self.title = gtk.Label(attrs.get('string', ''))
        self.title.set_alignment(0.0, 0.5)
        hbox.pack_start(self.title, expand=True, fill=True)

        hbox.pack_start(gtk.VSeparator(), expand=False, fill=True)

        tooltips = common.Tooltips()

        self.wid_text = PlaceholderEntry()
        self.wid_text.set_placeholder_text(_('Search'))
        self.wid_text.set_property('width_chars', 13)
        self.wid_text.connect('focus-out-event', lambda *a: self._focus_out())
        self.focus_out = True
        hbox.pack_start(self.wid_text, expand=True, fill=True)

        if int(self.attrs.get('completion', 1)):
            self.wid_completion = get_completion(
                create=self.attrs.get('create', True)
                and common.MODELACCESS[self.attrs['relation']]['create'])
            self.wid_completion.connect('match-selected',
                                        self._completion_match_selected)
            self.wid_completion.connect('action-activated',
                                        self._completion_action_activated)
            self.wid_text.set_completion(self.wid_completion)
            self.wid_text.connect('changed', self._update_completion)
        else:
            self.wid_completion = None

        self.but_add = gtk.Button()
        tooltips.set_tip(self.but_add, _('Add existing record'))
        self.but_add.connect('clicked', self._sig_add)
        img_add = gtk.Image()
        img_add.set_from_stock('tryton-list-add', gtk.ICON_SIZE_SMALL_TOOLBAR)
        img_add.set_alignment(0.5, 0.5)
        self.but_add.add(img_add)
        self.but_add.set_relief(gtk.RELIEF_NONE)
        hbox.pack_start(self.but_add, expand=False, fill=False)

        self.but_remove = gtk.Button()
        tooltips.set_tip(self.but_remove, _('Remove selected record <Del>'))
        self.but_remove.connect('clicked', self._sig_remove)
        img_remove = gtk.Image()
        img_remove.set_from_stock('tryton-list-remove',
                                  gtk.ICON_SIZE_SMALL_TOOLBAR)
        img_remove.set_alignment(0.5, 0.5)
        self.but_remove.add(img_remove)
        self.but_remove.set_relief(gtk.RELIEF_NONE)
        hbox.pack_start(self.but_remove, expand=False, fill=False)

        hbox.set_focus_chain([self.wid_text])

        tooltips.enable()

        frame = gtk.Frame()
        frame.add(hbox)
        frame.set_shadow_type(gtk.SHADOW_OUT)
        vbox.pack_start(frame, expand=False, fill=True)

        self.screen = Screen(attrs['relation'],
                             view_ids=attrs.get('view_ids', '').split(','),
                             mode=['tree'],
                             views_preload=attrs.get('views', {}),
                             row_activate=self._on_activate,
                             limit=None)
        self.screen.signal_connect(self, 'record-message', self._sig_label)

        vbox.pack_start(self.screen.widget, expand=True, fill=True)

        self.screen.widget.connect('key_press_event', self.on_keypress)
        self.wid_text.connect('key_press_event', self.on_keypress)
Exemplo n.º 32
0
    def __init__(self, model, callback, sel_multi=True, context=None,
            domain=None, order=None, view_ids=None,
            views_preload=None, new=True, title='', exclude_field=None):
        NoModal.__init__(self)
        if view_ids is None:
            view_ids = []
        if views_preload is None:
            views_preload = {}
        self.domain = domain or []
        self.context = context or {}
        self.order = order
        self.view_ids = view_ids
        self.views_preload = views_preload
        self.sel_multi = sel_multi
        self.callback = callback
        self.title = title
        self.exclude_field = exclude_field

        self.win = Gtk.Dialog(
            title=_('Search'), transient_for=self.parent,
            destroy_with_parent=True)
        Main().add_window(self.win)
        self.win.set_icon(TRYTON_ICON)
        self.win.set_position(Gtk.WindowPosition.CENTER_ON_PARENT)
        self.win.set_default_response(Gtk.ResponseType.APPLY)
        self.win.connect('response', self.response)

        self.win.set_default_size(*self.default_size())

        self.accel_group = Gtk.AccelGroup()
        self.win.add_accel_group(self.accel_group)

        self.but_cancel = self.win.add_button(
            set_underline(_("Cancel")), Gtk.ResponseType.CANCEL)
        self.but_cancel.set_image(common.IconFactory.get_image(
                'tryton-cancel', Gtk.IconSize.BUTTON))
        self.but_cancel.set_always_show_image(True)
        self.but_find = self.win.add_button(
            set_underline(_("Search")), Gtk.ResponseType.APPLY)
        self.but_find.set_image(common.IconFactory.get_image(
                'tryton-search', Gtk.IconSize.BUTTON))
        self.but_find.set_always_show_image(True)
        if new and common.MODELACCESS[model]['create']:
            self.but_new = self.win.add_button(
                set_underline(_("New")), Gtk.ResponseType.ACCEPT)
            self.but_new.set_image(common.IconFactory.get_image(
                    'tryton-create', Gtk.IconSize.BUTTON))
            self.but_new.set_always_show_image(True)
            self.but_new.set_accel_path('<tryton>/Form/New', self.accel_group)

        self.but_ok = self.win.add_button(
            set_underline(_("OK")), Gtk.ResponseType.OK)
        self.but_ok.set_image(common.IconFactory.get_image(
                'tryton-ok', Gtk.IconSize.BUTTON))
        self.but_ok.set_always_show_image(True)
        self.but_ok.add_accelerator(
            'clicked', self.accel_group, Gdk.KEY_Return,
            Gdk.ModifierType.CONTROL_MASK, Gtk.AccelFlags.VISIBLE)

        hbox = Gtk.HBox()
        hbox.show()
        self.win.vbox.pack_start(hbox, expand=False, fill=True, padding=0)
        self.win.vbox.pack_start(
            Gtk.HSeparator(), expand=False, fill=True, padding=0)

        self.screen = Screen(model, domain=domain, mode=['tree'], order=order,
            context=context, view_ids=view_ids, views_preload=views_preload,
            row_activate=self.sig_activate, readonly=True)
        self.view = self.screen.current_view
        # Prevent to set tree_state
        self.screen.tree_states_done.add(id(self.view))
        sel = self.view.treeview.get_selection()
        self.win.set_title(_('Search %s') % self.title)

        if not sel_multi:
            sel.set_mode(Gtk.SelectionMode.SINGLE)
        else:
            sel.set_mode(Gtk.SelectionMode.MULTIPLE)
        self.win.vbox.pack_start(
            self.screen.widget, expand=True, fill=True, padding=0)
        self.screen.widget.show()

        self.model_name = model

        self.register()
Exemplo n.º 33
0
    def __init__(self, view, attrs):
        super(One2Many, self).__init__(view, attrs)

        self.widget = gtk.Frame()
        self.widget.set_shadow_type(gtk.SHADOW_NONE)
        self.widget.get_accessible().set_name(attrs.get('string', ''))
        vbox = gtk.VBox(homogeneous=False, spacing=2)
        self.widget.add(vbox)
        self._readonly = True
        self._position = 0
        self._length = 0

        self.title_box = hbox = gtk.HBox(homogeneous=False, spacing=0)
        hbox.set_border_width(2)

        label = gtk.Label(attrs.get('string', ''))
        label.set_alignment(0.0, 0.5)
        hbox.pack_start(label, expand=True, fill=True)

        hbox.pack_start(gtk.VSeparator(), expand=False, fill=True)

        tooltips = common.Tooltips()

        self.focus_out = True
        self.wid_completion = None
        if attrs.get('add_remove'):

            self.wid_text = PlaceholderEntry()
            self.wid_text.set_placeholder_text(_('Search'))
            self.wid_text.set_property('width_chars', 13)
            self.wid_text.connect('focus-out-event',
                lambda *a: self._focus_out())
            hbox.pack_start(self.wid_text, expand=True, fill=True)

            if int(self.attrs.get('completion', 1)):
                access = common.MODELACCESS[attrs['relation']]
                self.wid_completion = get_completion(
                    search=access['read'] and access['write'],
                    create=attrs.get('create', True) and access['create'])
                self.wid_completion.connect('match-selected',
                    self._completion_match_selected)
                self.wid_completion.connect('action-activated',
                    self._completion_action_activated)
                self.wid_text.set_completion(self.wid_completion)
                self.wid_text.connect('changed', self._update_completion)

            self.but_add = gtk.Button()
            tooltips.set_tip(self.but_add, _('Add existing record'))
            self.but_add.connect('clicked', self._sig_add)
            img_add = gtk.Image()
            img_add.set_from_stock('tryton-list-add',
                gtk.ICON_SIZE_SMALL_TOOLBAR)
            img_add.set_alignment(0.5, 0.5)
            self.but_add.add(img_add)
            self.but_add.set_relief(gtk.RELIEF_NONE)
            hbox.pack_start(self.but_add, expand=False, fill=False)

            self.but_remove = gtk.Button()
            tooltips.set_tip(self.but_remove,
                _('Remove selected record'))
            self.but_remove.connect('clicked', self._sig_remove, True)
            img_remove = gtk.Image()
            img_remove.set_from_stock('tryton-list-remove',
                gtk.ICON_SIZE_SMALL_TOOLBAR)
            img_remove.set_alignment(0.5, 0.5)
            self.but_remove.add(img_remove)
            self.but_remove.set_relief(gtk.RELIEF_NONE)
            hbox.pack_start(self.but_remove, expand=False, fill=False)

            hbox.pack_start(gtk.VSeparator(), expand=False, fill=True)

        self.but_new = gtk.Button()
        tooltips.set_tip(self.but_new, _('Create a new record <F3>'))
        self.but_new.connect('clicked', self._sig_new)
        img_new = gtk.Image()
        img_new.set_from_stock('tryton-new', gtk.ICON_SIZE_SMALL_TOOLBAR)
        img_new.set_alignment(0.5, 0.5)
        self.but_new.add(img_new)
        self.but_new.set_relief(gtk.RELIEF_NONE)
        hbox.pack_start(self.but_new, expand=False, fill=False)

        self.but_open = gtk.Button()
        tooltips.set_tip(self.but_open, _('Edit selected record <F2>'))
        self.but_open.connect('clicked', self._sig_edit)
        img_open = gtk.Image()
        img_open.set_from_stock('tryton-open', gtk.ICON_SIZE_SMALL_TOOLBAR)
        img_open.set_alignment(0.5, 0.5)
        self.but_open.add(img_open)
        self.but_open.set_relief(gtk.RELIEF_NONE)
        hbox.pack_start(self.but_open, expand=False, fill=False)

        self.but_del = gtk.Button()
        tooltips.set_tip(self.but_del, _('Delete selected record <Del>'))
        self.but_del.connect('clicked', self._sig_remove, False)
        img_del = gtk.Image()
        img_del.set_from_stock('tryton-delete', gtk.ICON_SIZE_SMALL_TOOLBAR)
        img_del.set_alignment(0.5, 0.5)
        self.but_del.add(img_del)
        self.but_del.set_relief(gtk.RELIEF_NONE)
        hbox.pack_start(self.but_del, expand=False, fill=False)

        self.but_undel = gtk.Button()
        tooltips.set_tip(self.but_undel, _('Undelete selected record <Ins>'))
        self.but_undel.connect('clicked', self._sig_undelete)
        img_undel = gtk.Image()
        img_undel.set_from_stock('tryton-undo', gtk.ICON_SIZE_SMALL_TOOLBAR)
        img_undel.set_alignment(0.5, 0.5)
        self.but_undel.add(img_undel)
        self.but_undel.set_relief(gtk.RELIEF_NONE)
        hbox.pack_start(self.but_undel, expand=False, fill=False)

        hbox.pack_start(gtk.VSeparator(), expand=False, fill=True)

        self.but_pre = gtk.Button()
        tooltips.set_tip(self.but_pre, _('Previous'))
        self.but_pre.connect('clicked', self._sig_previous)
        img_pre = gtk.Image()
        img_pre.set_from_stock('tryton-go-previous',
            gtk.ICON_SIZE_SMALL_TOOLBAR)
        img_pre.set_alignment(0.5, 0.5)
        self.but_pre.add(img_pre)
        self.but_pre.set_relief(gtk.RELIEF_NONE)
        hbox.pack_start(self.but_pre, expand=False, fill=False)

        self.label = gtk.Label('(0,0)')
        hbox.pack_start(self.label, expand=False, fill=False)

        self.but_next = gtk.Button()
        tooltips.set_tip(self.but_next, _('Next'))
        self.but_next.connect('clicked', self._sig_next)
        img_next = gtk.Image()
        img_next.set_from_stock('tryton-go-next', gtk.ICON_SIZE_SMALL_TOOLBAR)
        img_next.set_alignment(0.5, 0.5)
        self.but_next.add(img_next)
        self.but_next.set_relief(gtk.RELIEF_NONE)
        hbox.pack_start(self.but_next, expand=False, fill=False)

        hbox.pack_start(gtk.VSeparator(), expand=False, fill=True)

        but_switch = gtk.Button()
        tooltips.set_tip(but_switch, _('Switch'))
        but_switch.connect('clicked', self.switch_view)
        img_switch = gtk.Image()
        img_switch.set_from_stock('tryton-fullscreen',
            gtk.ICON_SIZE_SMALL_TOOLBAR)
        img_switch.set_alignment(0.5, 0.5)
        but_switch.add(img_switch)
        but_switch.set_relief(gtk.RELIEF_NONE)
        hbox.pack_start(but_switch, expand=False, fill=False)

        if attrs.get('add_remove'):
            hbox.set_focus_chain([self.wid_text])
        else:
            hbox.set_focus_chain([])

        tooltips.enable()

        frame = gtk.Frame()
        frame.add(hbox)
        frame.set_shadow_type(gtk.SHADOW_OUT)
        vbox.pack_start(frame, expand=False, fill=True)

        self.screen = Screen(attrs['relation'],
            mode=attrs.get('mode', 'tree,form').split(','),
            view_ids=attrs.get('view_ids', '').split(','),
            views_preload=attrs.get('views', {}),
            row_activate=self._on_activate,
            readonly=self.attrs.get('readonly', False),
            exclude_field=attrs.get('relation_field', None))
        self.screen.pre_validate = bool(int(attrs.get('pre_validate', 0)))
        self.screen.signal_connect(self, 'record-message', self._sig_label)

        vbox.pack_start(self.screen.widget, expand=True, fill=True)

        self.screen.widget.connect('key_press_event', self.on_keypress)
        if self.attrs.get('add_remove'):
            self.wid_text.connect('key_press_event', self.on_keypress)

        but_switch.props.sensitive = self.screen.number_of_views > 1
Exemplo n.º 34
0
    def __init__(self, model, callback, sel_multi=True, context=None,
            domain=None, view_ids=None, views_preload=None, new=True,
            title=''):
        NoModal.__init__(self)
        if views_preload is None:
            views_preload = {}
        self.domain = domain or []
        self.context = context or {}
        self.sel_multi = sel_multi
        self.callback = callback
        self.title = title

        self.win = gtk.Dialog(_('Search'), self.parent,
            gtk.DIALOG_DESTROY_WITH_PARENT)
        self.win.set_icon(GNUHEALTH_ICON)
        self.win.set_default_response(gtk.RESPONSE_APPLY)
        self.win.connect('response', self.response)

        self.accel_group = gtk.AccelGroup()
        self.win.add_accel_group(self.accel_group)

        self.but_cancel = self.win.add_button(gtk.STOCK_CANCEL,
            gtk.RESPONSE_CANCEL)
        self.but_find = self.win.add_button(gtk.STOCK_FIND, gtk.RESPONSE_APPLY)
        if new and common.MODELACCESS[model]['create']:
            self.but_new = self.win.add_button(gtk.STOCK_NEW,
                gtk.RESPONSE_ACCEPT)
            self.but_new.set_accel_path('<tryton>/Form/New', self.accel_group)

        self.but_ok = self.win.add_button(gtk.STOCK_OK, gtk.RESPONSE_OK)
        self.but_ok.add_accelerator('clicked', self.accel_group,
                gtk.keysyms.Return, gtk.gdk.CONTROL_MASK, gtk.ACCEL_VISIBLE)

        hbox = gtk.HBox()
        hbox.show()
        self.win.vbox.pack_start(hbox, expand=False, fill=True)
        self.win.vbox.pack_start(gtk.HSeparator(), expand=False, fill=True)
        scrollwindow = gtk.ScrolledWindow()
        scrollwindow.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
        self.win.vbox.pack_start(scrollwindow, expand=True, fill=True)

        self.screen = Screen(model, domain=domain, mode=['tree'],
            context=context, view_ids=view_ids, views_preload=views_preload,
            row_activate=self.sig_activate)
        self.view = self.screen.current_view
        self.view.unset_editable()
        # Prevent to set tree_state
        self.screen.tree_states_done.add(id(self.view))
        sel = self.view.treeview.get_selection()
        self.win.set_title(_('Search %s') % self.title)

        if not sel_multi:
            sel.set_mode(gtk.SELECTION_SINGLE)
        else:
            sel.set_mode(gtk.SELECTION_MULTIPLE)
        viewport = gtk.Viewport()
        viewport.set_shadow_type(gtk.SHADOW_NONE)
        viewport.add(self.screen.widget)
        self.screen.widget.show()
        viewport.show()
        scrollwindow.add(viewport)
        scrollwindow.show()

        self.model_name = model

        self.win.set_default_size(700, 500)

        self.register()
        sensible_allocation = self.sensible_widget.get_allocation()
        self.win.set_default_size(int(sensible_allocation.width * 0.9),
            int(sensible_allocation.height * 0.9))
Exemplo n.º 35
0
    def __init__(self, model, callback, sel_multi=True, context=None,
            domain=None, view_ids=None, views_preload=None, new=True):
        NoModal.__init__(self)
        if views_preload is None:
            views_preload = {}
        self.domain = domain or []
        self.context = context or {}
        self.sel_multi = sel_multi
        self.callback = callback

        self.win = gtk.Dialog(_('Search'), self.parent,
            gtk.DIALOG_DESTROY_WITH_PARENT)
        self.win.set_icon(TRYTON_ICON)
        self.win.set_has_separator(True)
        self.win.set_default_response(gtk.RESPONSE_APPLY)
        self.win.connect('response', self.response)

        self.accel_group = gtk.AccelGroup()
        self.win.add_accel_group(self.accel_group)

        self.but_cancel = self.win.add_button(gtk.STOCK_CANCEL,
            gtk.RESPONSE_CANCEL)
        self.but_find = self.win.add_button(gtk.STOCK_FIND, gtk.RESPONSE_APPLY)
        if new and common.MODELACCESS[model]['create']:
            self.but_new = self.win.add_button(gtk.STOCK_NEW,
                gtk.RESPONSE_ACCEPT)
            self.but_new.set_accel_path('<tryton>/Form/New', self.accel_group)

        self.but_ok = self.win.add_button(gtk.STOCK_OK, gtk.RESPONSE_OK)
        self.but_ok.add_accelerator('clicked', self.accel_group,
                gtk.keysyms.Return, gtk.gdk.CONTROL_MASK, gtk.ACCEL_VISIBLE)

        hbox = gtk.HBox()
        hbox.show()
        self.win.vbox.pack_start(hbox, expand=False, fill=True)
        self.win.vbox.pack_start(gtk.HSeparator(), expand=False, fill=True)
        scrollwindow = gtk.ScrolledWindow()
        scrollwindow.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
        self.win.vbox.pack_start(scrollwindow, expand=True, fill=True)

        self.screen = Screen(model, domain=domain, mode=['tree'],
            context=context, view_ids=view_ids, views_preload=views_preload,
            row_activate=self.sig_activate)
        self.view = self.screen.current_view
        self.view.unset_editable()
        # Prevent to set tree_state
        self.screen.tree_states_done.add(id(self.view))
        sel = self.view.treeview.get_selection()

        if not sel_multi:
            sel.set_mode(gtk.SELECTION_SINGLE)
        else:
            sel.set_mode(gtk.SELECTION_MULTIPLE)
        viewport = gtk.Viewport()
        viewport.set_shadow_type(gtk.SHADOW_NONE)
        viewport.add(self.screen.widget)
        self.screen.widget.show()
        viewport.show()
        scrollwindow.add(viewport)
        scrollwindow.show()

        self.model_name = model

        self.win.set_default_size(700, 500)

        self.register()
        sensible_allocation = self.sensible_widget.get_allocation()
        self.win.set_default_size(int(sensible_allocation.width * 0.95),
            int(sensible_allocation.height * 0.95))
Exemplo n.º 36
0
class WinSearch(NoModal):

    def __init__(self, model, callback, sel_multi=True, context=None,
            domain=None, view_ids=None, views_preload=None, new=True):
        NoModal.__init__(self)
        if views_preload is None:
            views_preload = {}
        self.domain = domain or []
        self.context = context or {}
        self.sel_multi = sel_multi
        self.callback = callback

        self.win = gtk.Dialog(_('Search'), self.parent,
            gtk.DIALOG_DESTROY_WITH_PARENT)
        self.win.set_icon(TRYTON_ICON)
        self.win.set_has_separator(True)
        self.win.set_default_response(gtk.RESPONSE_APPLY)
        self.win.connect('response', self.response)

        self.accel_group = gtk.AccelGroup()
        self.win.add_accel_group(self.accel_group)

        self.but_cancel = self.win.add_button(gtk.STOCK_CANCEL,
            gtk.RESPONSE_CANCEL)
        self.but_find = self.win.add_button(gtk.STOCK_FIND, gtk.RESPONSE_APPLY)
        if new and common.MODELACCESS[model]['create']:
            self.but_new = self.win.add_button(gtk.STOCK_NEW,
                gtk.RESPONSE_ACCEPT)
            self.but_new.set_accel_path('<tryton>/Form/New', self.accel_group)

        self.but_ok = self.win.add_button(gtk.STOCK_OK, gtk.RESPONSE_OK)
        self.but_ok.add_accelerator('clicked', self.accel_group,
                gtk.keysyms.Return, gtk.gdk.CONTROL_MASK, gtk.ACCEL_VISIBLE)

        hbox = gtk.HBox()
        hbox.show()
        self.win.vbox.pack_start(hbox, expand=False, fill=True)
        self.win.vbox.pack_start(gtk.HSeparator(), expand=False, fill=True)
        scrollwindow = gtk.ScrolledWindow()
        scrollwindow.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
        self.win.vbox.pack_start(scrollwindow, expand=True, fill=True)

        self.screen = Screen(model, domain=domain, mode=['tree'],
            context=context, view_ids=view_ids, views_preload=views_preload,
            row_activate=self.sig_activate)
        self.view = self.screen.current_view
        self.view.unset_editable()
        # Prevent to set tree_state
        self.screen.tree_states_done.add(id(self.view))
        sel = self.view.treeview.get_selection()

        if not sel_multi:
            sel.set_mode(gtk.SELECTION_SINGLE)
        else:
            sel.set_mode(gtk.SELECTION_MULTIPLE)
        viewport = gtk.Viewport()
        viewport.set_shadow_type(gtk.SHADOW_NONE)
        viewport.add(self.screen.widget)
        self.screen.widget.show()
        viewport.show()
        scrollwindow.add(viewport)
        scrollwindow.show()

        self.model_name = model

        self.win.set_default_size(700, 500)

        self.register()
        sensible_allocation = self.sensible_widget.get_allocation()
        self.win.set_default_size(int(sensible_allocation.width * 0.95),
            int(sensible_allocation.height * 0.95))

    def sig_activate(self, *args):
        self.view.treeview.emit_stop_by_name('row_activated')
        self.win.response(gtk.RESPONSE_OK)
        return True

    def destroy(self):
        self.screen.destroy()
        self.win.destroy()
        NoModal.destroy(self)

    def show(self):
        self.win.show()
        common.center_window(self.win, self.parent, self.sensible_widget)

    def hide(self):
        self.win.hide()

    def response(self, win, response_id):
        res = None
        if response_id == gtk.RESPONSE_OK:
            res = [r.id for r in self.screen.selected_records]
        elif response_id == gtk.RESPONSE_APPLY:
            self.screen.search_filter(self.screen.screen_container.get_text())
            return
        elif response_id == gtk.RESPONSE_ACCEPT:
            screen = Screen(self.model_name, domain=self.domain,
                context=self.context, mode=['form'])

            def callback(result):
                if result and screen.save_current():
                    record = screen.current_record
                    res = [(record.id, record.value.get('rec_name', ''))]
                    self.callback(res)
                else:
                    self.callback(None)
            self.destroy()
            WinForm(screen, callback, new=True, save_current=True)
            return
        if res:
            group = self.screen.group
            res = [(id_, group.get(id_).value.get('rec_name', ''))
                for id_ in res]
        self.callback(res)
        self.destroy()
Exemplo n.º 37
0
    def __init__(self, field_name, model_name, attrs=None):
        super(One2Many, self).__init__(field_name, model_name, attrs=attrs)

        self.widget = gtk.VBox(homogeneous=False, spacing=2)
        self._readonly = True

        hbox = gtk.HBox(homogeneous=False, spacing=0)
        hbox.set_border_width(2)

        label = gtk.Label(attrs.get('string', ''))
        label.set_alignment(0.0, 0.5)
        hbox.pack_start(label, expand=True, fill=True)

        hbox.pack_start(gtk.VSeparator(), expand=False, fill=True)

        tooltips = common.Tooltips()

        if attrs.get('add_remove'):

            self.wid_text = gtk.Entry()
            self.wid_text.set_property('width_chars', 13)
            self.wid_text.connect('activate', self._sig_activate)
            self.wid_text.connect('focus-out-event', self._focus_out)
            hbox.pack_start(self.wid_text, expand=True, fill=True)

            self.but_add = gtk.Button()
            tooltips.set_tip(self.but_add, _('Add'))
            self.but_add.connect('clicked', self._sig_add)
            img_add = gtk.Image()
            img_add.set_from_stock('tryton-list-add',
                gtk.ICON_SIZE_SMALL_TOOLBAR)
            img_add.set_alignment(0.5, 0.5)
            self.but_add.add(img_add)
            self.but_add.set_relief(gtk.RELIEF_NONE)
            hbox.pack_start(self.but_add, expand=False, fill=False)

            self.but_remove = gtk.Button()
            tooltips.set_tip(self.but_remove, _('Remove <Del>'))
            self.but_remove.connect('clicked', self._sig_remove, True)
            img_remove = gtk.Image()
            img_remove.set_from_stock('tryton-list-remove',
                gtk.ICON_SIZE_SMALL_TOOLBAR)
            img_remove.set_alignment(0.5, 0.5)
            self.but_remove.add(img_remove)
            self.but_remove.set_relief(gtk.RELIEF_NONE)
            hbox.pack_start(self.but_remove, expand=False, fill=False)

            hbox.pack_start(gtk.VSeparator(), expand=False, fill=True)

        self.but_new = gtk.Button()
        tooltips.set_tip(self.but_new, _('Create a new record <F3>'))
        self.but_new.connect('clicked', self._sig_new)
        img_new = gtk.Image()
        img_new.set_from_stock('tryton-new', gtk.ICON_SIZE_SMALL_TOOLBAR)
        img_new.set_alignment(0.5, 0.5)
        self.but_new.add(img_new)
        self.but_new.set_relief(gtk.RELIEF_NONE)
        hbox.pack_start(self.but_new, expand=False, fill=False)

        self.but_open = gtk.Button()
        tooltips.set_tip(self.but_open, _('Edit selected record <F2>'))
        self.but_open.connect('clicked', self._sig_edit)
        img_open = gtk.Image()
        img_open.set_from_stock('tryton-open', gtk.ICON_SIZE_SMALL_TOOLBAR)
        img_open.set_alignment(0.5, 0.5)
        self.but_open.add(img_open)
        self.but_open.set_relief(gtk.RELIEF_NONE)
        hbox.pack_start(self.but_open, expand=False, fill=False)

        self.but_del = gtk.Button()
        tooltips.set_tip(self.but_del, _('Delete selected record <Del>'))
        self.but_del.connect('clicked', self._sig_remove, False)
        img_del = gtk.Image()
        img_del.set_from_stock('tryton-delete', gtk.ICON_SIZE_SMALL_TOOLBAR)
        img_del.set_alignment(0.5, 0.5)
        self.but_del.add(img_del)
        self.but_del.set_relief(gtk.RELIEF_NONE)
        hbox.pack_start(self.but_del, expand=False, fill=False)

        self.but_undel = gtk.Button()
        tooltips.set_tip(self.but_undel, _('Undelete selected record <Ins>'))
        self.but_undel.connect('clicked', self._sig_undelete)
        img_undel = gtk.Image()
        img_undel.set_from_stock('tryton-undo', gtk.ICON_SIZE_SMALL_TOOLBAR)
        img_undel.set_alignment(0.5, 0.5)
        self.but_undel.add(img_undel)
        self.but_undel.set_relief(gtk.RELIEF_NONE)
        hbox.pack_start(self.but_undel, expand=False, fill=False)

        hbox.pack_start(gtk.VSeparator(), expand=False, fill=True)

        self.but_pre = gtk.Button()
        tooltips.set_tip(self.but_pre, _('Previous'))
        self.but_pre.connect('clicked', self._sig_previous)
        img_pre = gtk.Image()
        img_pre.set_from_stock('tryton-go-previous',
            gtk.ICON_SIZE_SMALL_TOOLBAR)
        img_pre.set_alignment(0.5, 0.5)
        self.but_pre.add(img_pre)
        self.but_pre.set_relief(gtk.RELIEF_NONE)
        hbox.pack_start(self.but_pre, expand=False, fill=False)

        self.label = gtk.Label('(0,0)')
        hbox.pack_start(self.label, expand=False, fill=False)

        self.but_next = gtk.Button()
        tooltips.set_tip(self.but_next, _('Next'))
        self.but_next.connect('clicked', self._sig_next)
        img_next = gtk.Image()
        img_next.set_from_stock('tryton-go-next', gtk.ICON_SIZE_SMALL_TOOLBAR)
        img_next.set_alignment(0.5, 0.5)
        self.but_next.add(img_next)
        self.but_next.set_relief(gtk.RELIEF_NONE)
        hbox.pack_start(self.but_next, expand=False, fill=False)

        hbox.pack_start(gtk.VSeparator(), expand=False, fill=True)

        but_switch = gtk.Button()
        tooltips.set_tip(but_switch, _('Switch'))
        but_switch.connect('clicked', self.switch_view)
        img_switch = gtk.Image()
        img_switch.set_from_stock('tryton-fullscreen',
            gtk.ICON_SIZE_SMALL_TOOLBAR)
        img_switch.set_alignment(0.5, 0.5)
        but_switch.add(img_switch)
        but_switch.set_relief(gtk.RELIEF_NONE)
        hbox.pack_start(but_switch, expand=False, fill=False)

        if attrs.get('add_remove'):
            hbox.set_focus_chain([self.wid_text])
        else:
            hbox.set_focus_chain([])

        tooltips.enable()

        frame = gtk.Frame()
        frame.add(hbox)
        frame.set_shadow_type(gtk.SHADOW_OUT)
        self.widget.pack_start(frame, expand=False, fill=True)

        self.screen = Screen(attrs['relation'],
            mode=attrs.get('mode', 'tree,form').split(','),
            view_ids=attrs.get('view_ids', '').split(','),
            views_preload=attrs.get('views', {}),
            row_activate=self._on_activate,
            exclude_field=attrs.get('relation_field', None))
        self.screen.signal_connect(self, 'record-message', self._sig_label)

        self.widget.pack_start(self.screen.widget, expand=True, fill=True)

        self.screen.widget.connect('key_press_event', self.on_keypress)
        if self.attrs.get('add_remove'):
            self.wid_text.connect('key_press_event', self.on_keypress)
Exemplo n.º 38
0
class Preference(NoModal):
    "Preference window"

    def __init__(self, user, callback):
        NoModal.__init__(self)
        self.callback = callback
        self.win = gtk.Dialog(_('Preferences'), self.parent,
            gtk.DIALOG_DESTROY_WITH_PARENT)
        self.win.set_position(gtk.WIN_POS_CENTER_ON_PARENT)
        self.win.set_has_separator(False)
        self.win.set_icon(TRYTON_ICON)

        self.accel_group = gtk.AccelGroup()
        self.win.add_accel_group(self.accel_group)

        self.but_cancel = self.win.add_button(gtk.STOCK_CANCEL,
                gtk.RESPONSE_CANCEL)
        self.but_ok = self.win.add_button(gtk.STOCK_OK, gtk.RESPONSE_OK)
        self.but_ok.add_accelerator('clicked', self.accel_group,
                gtk.keysyms.Return, gtk.gdk.CONTROL_MASK, gtk.ACCEL_VISIBLE)

        self.win.set_default_response(gtk.RESPONSE_OK)
        self.win.connect('response', self.response)

        try:
            view = RPCExecute('model', 'res.user',
                'get_preferences_fields_view')
        except RPCException:
            self.win.destroy()
            self.win = None
            return

        title = gtk.Label(_('Edit User Preferences'))
        title.show()
        self.win.vbox.pack_start(title, expand=False, fill=True)
        self.screen = Screen('res.user', mode=[])
        # Reset readonly set automaticly by MODELACCESS
        self.screen.readonly = False
        self.screen.group.readonly = False
        self.screen.group.skip_model_access = True
        self.screen.add_view(view)
        self.screen.switch_view()
        self.screen.new(default=False)

        try:
            preferences = RPCExecute('model', 'res.user', 'get_preferences',
                False)
        except RPCException:
            self.win.destroy()
            self.win = None
            return
        self.screen.current_record.set(preferences)
        self.screen.current_record.id = rpc._USER
        self.screen.current_record.validate(softvalidation=True)
        self.screen.display(set_cursor=True)

        self.screen.widget.show()
        self.win.vbox.pack_start(self.screen.widget)
        self.win.set_title(_('Preference'))

        width, height = self.parent.get_size()
        self.win.set_default_size(int(width * 0.9), int(height * 0.9))

        self.register()
        self.win.show()

    def response(self, win, response_id):
        if response_id == gtk.RESPONSE_OK:
            if self.screen.current_record.validate():
                vals = copy.copy(self.screen.get())
                if 'password' in vals:
                    password = common.ask(_('Current Password:'******'model', 'res.user', 'set_preferences',
                        vals, password)
                except RPCException:
                    return
        self.parent.present()
        self.destroy()
        self.callback()

    def destroy(self):
        self.screen.destroy()
        self.win.destroy()
        NoModal.destroy(self)
Exemplo n.º 39
0
class Form(SignalEvent, TabContent):
    "Form"

    toolbar_def = [
        ('new', 'tryton-new', _('New'), _('Create a new record'),
            'sig_new'),
        ('save', 'tryton-save', _('Save'), _('Save this record'),
            'sig_save'),
        ('switch', 'tryton-fullscreen', _('Switch'), _('Switch view'),
            'sig_switch'),
        ('reload', 'tryton-refresh', _('_Reload'), _('Reload'),
            'sig_reload'),
        (None,) * 5,
        ('previous', 'tryton-go-previous', _('Previous'),
            _('Previous Record'), 'sig_previous'),
        ('next', 'tryton-go-next', _('Next'), _('Next Record'),
            'sig_next'),
        (None,) * 5,
        ('attach', 'tryton-attachment', _('Attachment(0)'),
            _('Add an attachment to the record'), 'sig_attach'),
        ('note', 'tryton-note', _('Note(0)'),
            _('Add a note to the record'), 'sig_note'),
    ]
    menu_def = [
        (_('_New'), 'tryton-new', 'sig_new', '<tryton>/Form/New'),
        (_('_Save'), 'tryton-save', 'sig_save', '<tryton>/Form/Save'),
        (_('_Switch View'), 'tryton-fullscreen', 'sig_switch',
            '<tryton>/Form/Switch View'),
        (_('_Reload/Undo'), 'tryton-refresh', 'sig_reload',
            '<tryton>/Form/Reload'),
        (_('_Duplicate'), 'tryton-copy', 'sig_copy',
            '<tryton>/Form/Duplicate'),
        (_('_Delete...'), 'tryton-delete', 'sig_remove',
            '<tryton>/Form/Delete'),
        (None,) * 4,
        (_('_Previous'), 'tryton-go-previous', 'sig_previous',
            '<tryton>/Form/Previous'),
        (_('_Next'), 'tryton-go-next', 'sig_next', '<tryton>/Form/Next'),
        (_('_Search'), 'tryton-find', 'sig_search', '<tryton>/Form/Search'),
        (_('View _Logs...'), None, 'sig_logs', None),
        (_('Show revisions...'), 'tryton-clock', 'revision', None),
        (None,) * 4,
        (_('_Close Tab'), 'tryton-close', 'sig_win_close',
            '<tryton>/Form/Close'),
        (None,) * 4,
        (_('A_ttachments...'), 'tryton-attachment', 'sig_attach',
            '<tryton>/Form/Attachments'),
        (_('_Notes...'), 'tryton-note', 'sig_note', '<tryton>/Form/Notes'),
        (_('_Actions...'), 'tryton-executable', 'sig_action',
            '<tryton>/Form/Actions'),
        (_('_Relate...'), 'tryton-go-jump', 'sig_relate',
            '<tryton>/Form/Relate'),
        (None,) * 4,
        (_('_Report...'), 'tryton-print-open', 'sig_print_open',
            '<tryton>/Form/Report'),
        (_('_E-Mail...'), 'tryton-print-email', 'sig_print_email',
            '<tryton>/Form/Email'),
        (_('_Print...'), 'tryton-print', 'sig_print',
            '<tryton>/Form/Print'),
        (None,) * 4,
        (_('_Export Data...'), 'tryton-save-as', 'sig_save_as',
            '<tryton>/Form/Export Data'),
        (_('_Import Data...'), None, 'sig_import',
            '<tryton>/Form/Import Data'),
    ]

    def __init__(self, model, res_id=False, domain=None, order=None, mode=None,
            view_ids=None, context=None, name=False, limit=None,
            search_value=None, tab_domain=None, context_model=None):
        super(Form, self).__init__()

        if not mode:
            mode = ['tree', 'form']
        if domain is None:
            domain = []
        if view_ids is None:
            view_ids = []

        self.model = model
        self.res_id = res_id
        self.domain = domain
        self.mode = mode
        self.context = context
        self.view_ids = view_ids
        self.dialogs = []

        self.screen = Screen(self.model, mode=mode, context=context,
            view_ids=view_ids, domain=domain, limit=limit, order=order,
            search_value=search_value, tab_domain=tab_domain,
            context_model=context_model)
        self.screen.widget.show()

        if not name:
            self.name = self.screen.current_view.title
        else:
            self.name = name

        if self.model not in common.MODELHISTORY:
            self.menu_def = self.menu_def[:]
            # Remove callback to revision
            self.menu_def[11] = (self.menu_def[11][:2] + (None,)
                + self.menu_def[11][3:])

        self.create_tabcontent()

        self.url_entry = url_entry = gtk.Entry()
        url_entry.show()
        url_entry.set_editable(False)
        style = url_entry.get_style()
        url_entry.modify_bg(gtk.STATE_ACTIVE,
            style.bg[gtk.STATE_INSENSITIVE])
        self.widget.pack_start(url_entry, False, False)

        self.set_buttons_sensitive()

        self.screen.signal_connect(self, 'record-message',
            self._record_message)

        self.screen.signal_connect(self, 'record-modified',
            lambda *a: gobject.idle_add(self._record_modified, *a))
        self.screen.signal_connect(self, 'record-saved', self._record_saved)
        self.screen.signal_connect(self, 'attachment-count',
                self._attachment_count)
        self.screen.signal_connect(self, 'unread-note', self._unread_note)

        if res_id not in (None, False):
            if isinstance(res_id, (int, long)):
                res_id = [res_id]
            self.screen.load(res_id)
        else:
            if self.screen.current_view.view_type == 'form':
                self.sig_new(None, autosave=False)
            if self.screen.current_view.view_type \
                    in ('tree', 'graph', 'calendar'):
                self.screen.search_filter()

        self.update_revision()

    def get_toolbars(self):
        try:
            return RPCExecute('model', self.model, 'view_toolbar_get',
                context=self.screen.context)
        except RPCException:
            return {}

    def widget_get(self):
        return self.screen.widget

    def __eq__(self, value):
        if not value:
            return False
        if not isinstance(value, Form):
            return False
        return (self.model == value.model
            and self.res_id == value.res_id
            and self.domain == value.domain
            and self.mode == value.mode
            and self.view_ids == value.view_ids
            and self.screen.context == value.screen.context
            and self.name == value.name
            and self.screen.limit == value.screen.limit
            and self.screen.search_value == value.screen.search_value)

    def destroy(self):
        self.screen.destroy()

    def sig_attach(self, widget=None):
        record = self.screen.current_record
        if not record or record.id < 0:
            return
        Attachment(record,
            lambda: self.update_attachment_count(reload=True))

    def update_attachment_count(self, reload=False):
        record = self.screen.current_record
        if record:
            attachment_count = record.get_attachment_count(reload=reload)
        else:
            attachment_count = 0
        self._attachment_count(None, attachment_count)

    def _attachment_count(self, widget, signal_data):
        label = _('Attachment(%d)') % signal_data
        self.buttons['attach'].set_label(label)
        if signal_data:
            self.buttons['attach'].set_stock_id('tryton-attachment-hi')
        else:
            self.buttons['attach'].set_stock_id('tryton-attachment')
        record = self.screen.current_record
        self.buttons['attach'].props.sensitive = bool(
            record.id >= 0 if record else False)

    def sig_note(self, widget=None):
        record = self.screen.current_record
        if not record or record.id < 0:
            return
        Note(record,
            lambda: self.update_unread_note(reload=True))

    def update_unread_note(self, reload=False):
        record = self.screen.current_record
        if record:
            unread = record.get_unread_note(reload=reload)
        else:
            unread = 0
        self._unread_note(None, unread)

    def _unread_note(self, widget, signal_data):
        label = _('Note(%d)') % signal_data
        self.buttons['note'].set_label(label)
        if signal_data:
            self.buttons['note'].set_stock_id('tryton-note-hi')
        else:
            self.buttons['note'].set_stock_id('tryton-note')
        record = self.screen.current_record
        if not record or record.id < 0:
            sensitive = False
        else:
            sensitive = True
        self.buttons['note'].props.sensitive = sensitive

    def sig_switch(self, widget=None):
        if not self.modified_save():
            return
        self.screen.switch_view()

    def sig_logs(self, widget=None):
        current_record = self.screen.current_record
        if not current_record or current_record.id < 0:
            self.message_info(
                _('You have to select one record.'), gtk.MESSAGE_INFO)
            return False

        fields = [
            ('id', _('ID:')),
            ('create_uid.rec_name', _('Creation User:'******'create_date', _('Creation Date:')),
            ('write_uid.rec_name', _('Latest Modification by:')),
            ('write_date', _('Latest Modification Date:')),
        ]

        try:
            res = RPCExecute('model', self.model, 'read', [current_record.id],
                [x[0] for x in fields], context=self.screen.context)
        except RPCException:
            return
        date_format = self.screen.context.get('date_format', '%x')
        datetime_format = date_format + ' %X.%f'
        message_str = ''
        for line in res:
            for (key, val) in fields:
                value = str(line.get(key, False) or '/')
                if line.get(key, False) \
                        and key in ('create_date', 'write_date'):
                    date = timezoned_date(line[key])
                    value = common.datetime_strftime(date, datetime_format)
                message_str += val + ' ' + value + '\n'
        message_str += _('Model:') + ' ' + self.model
        message(message_str)
        return True

    def revision(self, widget=None):
        if not self.modified_save():
            return
        current_id = (self.screen.current_record.id
            if self.screen.current_record else None)
        try:
            revisions = RPCExecute('model', self.model, 'history_revisions',
                [r.id for r in self.screen.selected_records])
        except RPCException:
            return
        revision = self.screen.context.get('_datetime')
        format_ = self.screen.context.get('date_format', '%x')
        format_ += ' %X.%f'
        revision = Revision(revisions, revision, format_).run()
        # Prevent too old revision in form view
        if (self.screen.current_view.view_type == 'form'
                and revision
                and revision < revisions[-1][0]):
                revision = revisions[-1][0]
        if revision != self.screen.context.get('_datetime'):
            self.screen.clear()
            # Update root group context that will be propagated
            self.screen.group._context['_datetime'] = revision
            if self.screen.current_view.view_type != 'form':
                self.screen.search_filter(
                    self.screen.screen_container.get_text())
            else:
                # Test if record exist in revisions
                self.screen.load([current_id])
            self.screen.display(set_cursor=True)
            self.update_revision()

    def update_revision(self):
        revision = self.screen.context.get('_datetime')
        if revision:
            format_ = self.screen.context.get('date_format', '%x')
            format_ += ' %X.%f'
            revision = datetime_strftime(revision, format_)
            self.title.set_label('%s @ %s' % (self.name, revision))
        else:
            self.title.set_label(self.name)
        self.set_buttons_sensitive(revision)

    def set_buttons_sensitive(self, revision=None):
        if not revision:
            access = common.MODELACCESS[self.model]
            self.buttons['new'].props.sensitive = access['create']
            self.buttons['save'].props.sensitive = (
                access['create'] or access['write'])
        else:
            for button in ['new', 'save']:
                self.buttons[button].props.sensitive = False

    def sig_remove(self, widget=None):
        if not common.MODELACCESS[self.model]['delete']:
            return
        if self.screen.current_view.view_type == 'form':
            msg = _('Are you sure to remove this record?')
        else:
            msg = _('Are you sure to remove those records?')
        if sur(msg):
            if not self.screen.remove(delete=True, force_remove=True):
                self.message_info(_('Records not removed.'), gtk.MESSAGE_ERROR)
            else:
                self.message_info(_('Records removed.'), gtk.MESSAGE_INFO)

    def sig_import(self, widget=None):
        WinImport(self.model, self.screen.context)

    def sig_save_as(self, widget=None):
        export = WinExport(self.model,
            [r.id for r in self.screen.selected_records],
            context=self.screen.context)
        for name in self.screen.current_view.get_fields():
            export.sel_field(name)

    def sig_new(self, widget=None, autosave=True):
        if not common.MODELACCESS[self.model]['create']:
            return
        if autosave:
            if not self.modified_save():
                return
        self.screen.new()
        self.message_info()
        self.activate_save()

    def sig_copy(self, widget=None):
        if not common.MODELACCESS[self.model]['create']:
            return
        if not self.modified_save():
            return
        if self.screen.copy():
            self.message_info(_('Working now on the duplicated record(s).'),
                gtk.MESSAGE_INFO)

    def sig_save(self, widget=None):
        if widget:
            # Called from button so we must save the tree state
            self.screen.save_tree_state()
        if not (common.MODELACCESS[self.model]['write']
                or common.MODELACCESS[self.model]['create']):
            return
        if self.screen.save_current():
            self.message_info(_('Record saved.'), gtk.MESSAGE_INFO)
            return True
        else:
            self.message_info(self.screen.invalid_message(), gtk.MESSAGE_ERROR)
            return False

    def sig_previous(self, widget=None):
        if not self.modified_save():
            return
        self.screen.display_prev()
        self.message_info()
        self.activate_save()

    def sig_next(self, widget=None):
        if not self.modified_save():
            return
        self.screen.display_next()
        self.message_info()
        self.activate_save()

    def sig_reload(self, test_modified=True):
        if test_modified:
            if not self.modified_save():
                return False
        else:
            self.screen.save_tree_state(store=False)
        self.screen.cancel_current()
        set_cursor = False
        record_id = (self.screen.current_record.id
            if self.screen.current_record else None)
        if self.screen.current_view.view_type != 'form':
            self.screen.search_filter(self.screen.screen_container.get_text())
            for record in self.screen.group:
                if record.id == record_id:
                    self.screen.current_record = record
                    set_cursor = True
                    break
        self.screen.display(set_cursor=set_cursor)
        self.message_info()
        self.activate_save()
        return True

    def sig_action(self, widget):
        if self.buttons['action'].props.sensitive:
            self.buttons['action'].props.active = True

    def sig_print(self, widget):
        if self.buttons['print'].props.sensitive:
            self.buttons['print'].props.active = True

    def sig_print_open(self, widget):
        if self.buttons['open'].props.sensitive:
            self.buttons['open'].props.active = True

    def sig_print_email(self, widget):
        if self.buttons['email'].props.sensitive:
            self.buttons['email'].props.active = True

    def sig_relate(self, widget):
        if self.buttons['relate'].props.sensitive:
            self.buttons['relate'].props.active = True

    def sig_search(self, widget):
        search_container = self.screen.screen_container
        if hasattr(search_container, 'search_entry'):
            search_container.search_entry.grab_focus()

    def action_popup(self, widget):
        button, = widget.get_children()
        button.grab_focus()
        menu = widget._menu
        if not widget.props.active:
            menu.popdown()
            return

        def menu_position(menu):
            parent = widget.get_toplevel()
            parent_x, parent_y = parent.window.get_origin()
            widget_allocation = widget.get_allocation()
            return (
                widget_allocation.x + parent_x,
                widget_allocation.y + widget_allocation.height + parent_y,
                False
            )
        menu.show_all()
        menu.popup(None, None, menu_position, 0, 0)

    def _record_message(self, screen, signal_data):
        name = '_'
        if signal_data[0]:
            name = str(signal_data[0])
        for button_id in ('print', 'relate', 'email', 'open', 'save',
                'attach'):
            button = self.buttons[button_id]
            can_be_sensitive = getattr(button, '_can_be_sensitive', True)
            button.props.sensitive = (bool(signal_data[0])
                and can_be_sensitive)
        button_switch = self.buttons['switch']
        button_switch.props.sensitive = self.screen.number_of_views > 1

        msg = name + ' / ' + str(signal_data[1])
        if signal_data[1] < signal_data[2]:
            msg += _(' of ') + str(signal_data[2])
        self.status_label.set_text(msg)
        self.message_info()
        self.activate_save()
        self.url_entry.set_text(self.screen.get_url())

    def _record_modified(self, screen, signal_data):
        # As it is called via idle_add, the form could have been destroyed in
        # the meantime.
        if self.widget_get().props.window:
            self.activate_save()

    def _record_saved(self, screen, signal_data):
        self.activate_save()
        self.update_attachment_count()

    def modified_save(self):
        self.screen.save_tree_state()
        self.screen.current_view.set_value()
        if self.screen.modified():
            value = sur_3b(
                _('This record has been modified\n'
                    'do you want to save it?'))
            if value == 'ok':
                return self.sig_save(None)
            if value == 'ko':
                return self.sig_reload(test_modified=False)
            return False
        return True

    def sig_close(self, widget=None):
        for dialog in self.dialogs[:]:
            dialog.destroy()
        return self.modified_save()

    def _action(self, action, atype):
        action = action.copy()
        if not self.screen.save_current():
            return
        record_id = (self.screen.current_record.id
            if self.screen.current_record else None)
        record_ids = [r.id for r in self.screen.selected_records]
        action = Action.evaluate(action, atype, self.screen.current_record)
        data = {
            'model': self.screen.model_name,
            'id': record_id,
            'ids': record_ids,
        }
        Action._exec_action(action, data, self.screen.context)

    def activate_save(self):
        self.buttons['save'].props.sensitive = self.screen.modified()

    def sig_win_close(self, widget):
        Main.get_main().sig_win_close(widget)

    def create_toolbar(self, toolbars):
        gtktoolbar = super(Form, self).create_toolbar(toolbars)

        attach_btn = self.buttons['attach']
        attach_btn.drag_dest_set(gtk.DEST_DEFAULT_ALL, [
                ('text/uri-list', 0, 0),
                ], gtk.gdk.ACTION_MOVE)
        attach_btn.connect('drag_data_received',
            self.attach_drag_data_received)

        iconstock = {
            'print': 'tryton-print',
            'action': 'tryton-executable',
            'relate': 'tryton-go-jump',
            'email': 'tryton-print-email',
            'open': 'tryton-print-open',
        }
        for action_type, special_action, action_name, tooltip in (
                ('action', 'action', _('Action'), _('Launch action')),
                ('relate', 'relate', _('Relate'), _('Open related records')),
                (None,) * 4,
                ('print', 'open', _('Report'), _('Open report')),
                ('print', 'email', _('E-Mail'), _('E-Mail report')),
                ('print', 'print', _('Print'), _('Print report')),
        ):
            if action_type is not None:
                tbutton = gtk.ToggleToolButton(iconstock.get(special_action))
                tbutton.set_label(action_name)
                tbutton._menu = self._create_popup_menu(tbutton,
                    action_type, toolbars[action_type], special_action)
                tbutton.connect('toggled', self.action_popup)
                self.tooltips.set_tip(tbutton, tooltip)
                self.buttons[special_action] = tbutton
                if action_type != 'action':
                    tbutton._can_be_sensitive = bool(
                        tbutton._menu.get_children())
            else:
                tbutton = gtk.SeparatorToolItem()
            gtktoolbar.insert(tbutton, -1)

        return gtktoolbar

    def _create_popup_menu(self, widget, keyword, actions, special_action):
        menu = gtk.Menu()
        menu.connect('deactivate', self._popup_menu_hide, widget)
        widget.connect('toggled', self._update_popup, menu, special_action)

        for action in actions:
            new_action = action.copy()
            if special_action == 'print':
                new_action['direct_print'] = True
            elif special_action == 'email':
                new_action['email_print'] = True
            action_name = action['name']
            if '_' not in action_name:
                action_name = '_' + action_name
            menuitem = gtk.MenuItem(action_name)
            menuitem.set_use_underline(True)
            menuitem.connect('activate', self._popup_menu_selected, widget,
                new_action, keyword)
            menu.add(menuitem)
        return menu

    def _popup_menu_selected(self, menuitem, togglebutton, action, keyword):
        event = gtk.get_current_event()
        allow_similar = False
        if (event.state & gtk.gdk.CONTROL_MASK
                or event.state & gtk.gdk.MOD1_MASK):
            allow_similar = True
        with Window(hide_current=True, allow_similar=allow_similar):
            self._action(action, keyword)
        togglebutton.props.active = False

    def _popup_menu_hide(self, menuitem, togglebutton):
        togglebutton.props.active = False

    def _update_popup(self, tbutton, menu, keyword):
        assert keyword in ['print','action','relate','email','open']
        for item in menu.get_children():
            if (getattr(item, '_update_action', False)
                    or isinstance(item, gtk.SeparatorMenuItem)):
                menu.remove(item)

        buttons = [button for button in self.screen.get_buttons()
            if keyword in button.attrs.get('keywords', 'action').split(',')]
        if buttons:
            menu.add(gtk.SeparatorMenuItem())
        for button in buttons:
            menuitem = gtk.ImageMenuItem(button.attrs.get('icon'))
            menuitem.set_label('_' + button.attrs.get('string', _('Unknown')))
            menuitem.set_use_underline(True)
            menuitem.connect('activate',
                lambda m, attrs: self.screen.button(attrs), button.attrs)
            menuitem._update_action = True
            menu.add(menuitem)

        if keyword == 'action':
            menu.add(gtk.SeparatorMenuItem())
            for plugin in plugins.MODULES:
                for name, func in plugin.get_plugins(self.model):
                    menuitem = gtk.MenuItem('_' + name)
                    menuitem.set_use_underline(True)
                    menuitem.connect('activate', lambda m, func: func({
                                'model': self.model,
                                'ids': [r.id
                                    for r in self.screen.selected_records],
                                'id': (self.screen.current_record.id
                                    if self.screen.current_record else None),
                                }), func)
                    menuitem._update_action = True
                    menu.add(menuitem)

    def set_cursor(self):
        if self.screen:
            self.screen.set_cursor(reset_view=False)

    def attach_drag_data_received(self, widget, context, x, y, selection, info,
            timestamp):
        record = self.screen.current_record
        if not record or record.id < 0:
            return
        win_attach = Attachment(record,
            lambda: self.update_attachment_count(reload=True))
        if info == 0:
            for uri in selection.data.splitlines():
                # Win32 cut&paste terminates the list with a NULL character
                if not uri or uri == '\0':
                    continue
                win_attach.add_uri(uri)
Exemplo n.º 40
0
class One2Many(Widget):
    expand = True

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

        self.widget = gtk.Frame()
        self.widget.set_shadow_type(gtk.SHADOW_NONE)
        self.widget.get_accessible().set_name(attrs.get('string', ''))
        vbox = gtk.VBox(homogeneous=False, spacing=2)
        self.widget.add(vbox)
        self._readonly = True
        self._required = False
        self._position = 0
        self._length = 0

        self.title_box = hbox = gtk.HBox(homogeneous=False, spacing=0)
        hbox.set_border_width(2)

        self.title = gtk.Label(attrs.get('string', ''))
        self.title.set_alignment(0.0, 0.5)
        hbox.pack_start(self.title, expand=True, fill=True)

        hbox.pack_start(gtk.VSeparator(), expand=False, fill=True)

        tooltips = common.Tooltips()

        self.focus_out = True
        self.wid_completion = None
        if attrs.get('add_remove'):

            self.wid_text = PlaceholderEntry()
            self.wid_text.set_placeholder_text(_('Search'))
            self.wid_text.set_property('width_chars', 13)
            self.wid_text.connect('focus-out-event',
                                  lambda *a: self._focus_out())
            hbox.pack_start(self.wid_text, expand=True, fill=True)

            if int(self.attrs.get('completion', 1)):
                access = common.MODELACCESS[attrs['relation']]
                self.wid_completion = get_completion(
                    search=access['read'] and access['write'],
                    create=attrs.get('create', True) and access['create'])
                self.wid_completion.connect('match-selected',
                                            self._completion_match_selected)
                self.wid_completion.connect('action-activated',
                                            self._completion_action_activated)
                self.wid_text.set_completion(self.wid_completion)
                self.wid_text.connect('changed', self._update_completion)

            self.but_add = gtk.Button()
            tooltips.set_tip(self.but_add, _('Add existing record'))
            self.but_add.connect('clicked', self._sig_add)
            img_add = gtk.Image()
            img_add.set_from_stock('tryton-list-add',
                                   gtk.ICON_SIZE_SMALL_TOOLBAR)
            img_add.set_alignment(0.5, 0.5)
            self.but_add.add(img_add)
            self.but_add.set_relief(gtk.RELIEF_NONE)
            hbox.pack_start(self.but_add, expand=False, fill=False)

            self.but_remove = gtk.Button()
            tooltips.set_tip(self.but_remove, _('Remove selected record'))
            self.but_remove.connect('clicked', self._sig_remove, True)
            img_remove = gtk.Image()
            img_remove.set_from_stock('tryton-list-remove',
                                      gtk.ICON_SIZE_SMALL_TOOLBAR)
            img_remove.set_alignment(0.5, 0.5)
            self.but_remove.add(img_remove)
            self.but_remove.set_relief(gtk.RELIEF_NONE)
            hbox.pack_start(self.but_remove, expand=False, fill=False)

            hbox.pack_start(gtk.VSeparator(), expand=False, fill=True)

        self.but_new = gtk.Button()
        tooltips.set_tip(self.but_new, _('Create a new record <F3>'))
        self.but_new.connect('clicked', self._sig_new)
        img_new = gtk.Image()
        img_new.set_from_stock('tryton-new', gtk.ICON_SIZE_SMALL_TOOLBAR)
        img_new.set_alignment(0.5, 0.5)
        self.but_new.add(img_new)
        self.but_new.set_relief(gtk.RELIEF_NONE)
        hbox.pack_start(self.but_new, expand=False, fill=False)

        self.but_open = gtk.Button()
        tooltips.set_tip(self.but_open, _('Edit selected record <F2>'))
        self.but_open.connect('clicked', self._sig_edit)
        img_open = gtk.Image()
        img_open.set_from_stock('tryton-open', gtk.ICON_SIZE_SMALL_TOOLBAR)
        img_open.set_alignment(0.5, 0.5)
        self.but_open.add(img_open)
        self.but_open.set_relief(gtk.RELIEF_NONE)
        hbox.pack_start(self.but_open, expand=False, fill=False)

        self.but_del = gtk.Button()
        tooltips.set_tip(self.but_del, _('Delete selected record <Del>'))
        self.but_del.connect('clicked', self._sig_remove, False)
        img_del = gtk.Image()
        img_del.set_from_stock('tryton-delete', gtk.ICON_SIZE_SMALL_TOOLBAR)
        img_del.set_alignment(0.5, 0.5)
        self.but_del.add(img_del)
        self.but_del.set_relief(gtk.RELIEF_NONE)
        hbox.pack_start(self.but_del, expand=False, fill=False)

        self.but_undel = gtk.Button()
        tooltips.set_tip(self.but_undel, _('Undelete selected record <Ins>'))
        self.but_undel.connect('clicked', self._sig_undelete)
        img_undel = gtk.Image()
        img_undel.set_from_stock('tryton-undo', gtk.ICON_SIZE_SMALL_TOOLBAR)
        img_undel.set_alignment(0.5, 0.5)
        self.but_undel.add(img_undel)
        self.but_undel.set_relief(gtk.RELIEF_NONE)
        hbox.pack_start(self.but_undel, expand=False, fill=False)

        hbox.pack_start(gtk.VSeparator(), expand=False, fill=True)

        self.but_pre = gtk.Button()
        tooltips.set_tip(self.but_pre, _('Previous'))
        self.but_pre.connect('clicked', self._sig_previous)
        img_pre = gtk.Image()
        img_pre.set_from_stock('tryton-go-previous',
                               gtk.ICON_SIZE_SMALL_TOOLBAR)
        img_pre.set_alignment(0.5, 0.5)
        self.but_pre.add(img_pre)
        self.but_pre.set_relief(gtk.RELIEF_NONE)
        hbox.pack_start(self.but_pre, expand=False, fill=False)

        self.label = gtk.Label('(0,0)')
        hbox.pack_start(self.label, expand=False, fill=False)

        self.but_next = gtk.Button()
        tooltips.set_tip(self.but_next, _('Next'))
        self.but_next.connect('clicked', self._sig_next)
        img_next = gtk.Image()
        img_next.set_from_stock('tryton-go-next', gtk.ICON_SIZE_SMALL_TOOLBAR)
        img_next.set_alignment(0.5, 0.5)
        self.but_next.add(img_next)
        self.but_next.set_relief(gtk.RELIEF_NONE)
        hbox.pack_start(self.but_next, expand=False, fill=False)

        hbox.pack_start(gtk.VSeparator(), expand=False, fill=True)

        but_switch = gtk.Button()
        tooltips.set_tip(but_switch, _('Switch'))
        but_switch.connect('clicked', self.switch_view)
        img_switch = gtk.Image()
        img_switch.set_from_stock('tryton-fullscreen',
                                  gtk.ICON_SIZE_SMALL_TOOLBAR)
        img_switch.set_alignment(0.5, 0.5)
        but_switch.add(img_switch)
        but_switch.set_relief(gtk.RELIEF_NONE)
        hbox.pack_start(but_switch, expand=False, fill=False)

        if attrs.get('add_remove'):
            hbox.set_focus_chain([self.wid_text])
        else:
            hbox.set_focus_chain([])

        tooltips.enable()

        frame = gtk.Frame()
        frame.add(hbox)
        frame.set_shadow_type(gtk.SHADOW_OUT)
        vbox.pack_start(frame, expand=False, fill=True)

        self.screen = Screen(attrs['relation'],
                             mode=attrs.get('mode', 'tree,form').split(','),
                             view_ids=attrs.get('view_ids', '').split(','),
                             views_preload=attrs.get('views', {}),
                             row_activate=self._on_activate,
                             exclude_field=attrs.get('relation_field', None))
        self.screen.pre_validate = bool(int(attrs.get('pre_validate', 0)))
        self.screen.signal_connect(self, 'record-message', self._sig_label)

        vbox.pack_start(self.screen.widget, expand=True, fill=True)

        self.screen.widget.connect('key_press_event', self.on_keypress)
        if self.attrs.get('add_remove'):
            self.wid_text.connect('key_press_event', self.on_keypress)

        but_switch.props.sensitive = self.screen.number_of_views > 1

    def on_keypress(self, widget, event):
        if (event.keyval == gtk.keysyms.F3) \
                and self.but_new.get_property('sensitive'):
            self._sig_new(widget)
            return True
        if event.keyval == gtk.keysyms.F2 \
                and widget == self.screen.widget:
            self._sig_edit(widget)
            return True
        if (event.keyval in (gtk.keysyms.Delete, gtk.keysyms.KP_Delete)
                and widget == self.screen.widget
                and self.but_del.get_property('sensitive')):
            self._sig_remove(widget)
            return True
        if event.keyval == gtk.keysyms.Insert and widget == self.screen.widget:
            self._sig_undelete(widget)
            return True
        if self.attrs.get('add_remove'):
            editable = self.wid_text.get_editable()
            activate_keys = [gtk.keysyms.Tab, gtk.keysyms.ISO_Left_Tab]
            if not self.wid_completion:
                activate_keys.append(gtk.keysyms.Return)
            if (widget == self.wid_text and event.keyval in activate_keys
                    and editable and self.wid_text.get_text()):
                self._sig_add()
                self.wid_text.grab_focus()
        return False

    def destroy(self):
        self.screen.destroy()

    def _on_activate(self):
        self._sig_edit()

    def switch_view(self, widget):
        self.screen.switch_view()

    @property
    def modified(self):
        return self.screen.current_view.modified

    def _readonly_set(self, value):
        self._readonly = value
        self._set_button_sensitive()
        self._set_label_state()

    def _required_set(self, value):
        self._required = value
        self._set_label_state()

    def _set_label_state(self):
        attrlist = common.get_label_attributes(self._readonly, self._required)
        self.title.set_attributes(attrlist)

    def _set_button_sensitive(self):
        access = common.MODELACCESS[self.screen.model_name]
        if self.record and self.field:
            field_size = self.record.expr_eval(self.attrs.get('size'))
            o2m_size = len(self.field.get_eval(self.record))
            size_limit = (field_size is not None
                          and o2m_size >= field_size >= 0)
        else:
            o2m_size = None
            size_limit = False

        self.but_new.set_sensitive(
            bool(not self._readonly and self.attrs.get('create', True)
                 and not size_limit and access['create']))
        self.but_del.set_sensitive(
            bool(not self._readonly and self.attrs.get('delete', True)
                 and self._position and access['delete']))
        self.but_undel.set_sensitive(
            bool(not self._readonly and not size_limit and self._position))
        self.but_open.set_sensitive(bool(self._position and access['read']))
        self.but_next.set_sensitive(
            bool(self._position and self._position < self._length))
        self.but_pre.set_sensitive(bool(self._position and self._position > 1))
        if self.attrs.get('add_remove'):
            self.but_add.set_sensitive(
                bool(not self._readonly and not size_limit and access['write']
                     and access['read']))
            self.but_remove.set_sensitive(
                bool(not self._readonly and self._position and access['write']
                     and access['read']))
            self.wid_text.set_sensitive(self.but_add.get_sensitive())

        # New button must be added to focus chain to allow keyboard only
        # creation when there is no existing record on form view.
        focus_chain = self.title_box.get_focus_chain() or []
        if o2m_size == 0 and self.screen.current_view.view_type == 'form':
            if self.but_new not in focus_chain:
                focus_chain.append(self.but_new)
        else:
            if self.but_new in focus_chain:
                focus_chain.remove(self.but_new)
        self.title_box.set_focus_chain(focus_chain)

    def _validate(self):
        self.view.set_value()
        record = self.screen.current_record
        if record:
            fields = self.screen.current_view.get_fields()
            if not record.validate(fields):
                self.screen.display(set_cursor=True)
                return False
            if self.screen.pre_validate and not record.pre_validate():
                return False
        return True

    def _sig_new(self, *args):
        if not common.MODELACCESS[self.screen.model_name]['create']:
            return
        if not self._validate():
            return

        if self.attrs.get('product'):
            self._new_product()
        else:
            self._new_single()

    def _new_single(self):
        ctx = {}
        ctx.update(self.field.context_get(self.record))
        sequence = None
        for view in self.screen.views:
            if view.view_type == 'tree':
                sequence = view.attributes.get('sequence')
                if sequence:
                    break

        def update_sequence():
            if sequence:
                self.screen.group.set_sequence(field=sequence)

        if self.screen.current_view.editable:
            self.screen.new()
            self.screen.current_view.widget.set_sensitive(True)
            update_sequence()
        else:
            field_size = self.record.expr_eval(self.attrs.get('size')) or -1
            field_size -= len(self.field.get_eval(self.record)) + 1
            WinForm(self.screen,
                    lambda a: update_sequence(),
                    new=True,
                    many=field_size,
                    context=ctx,
                    title=self.attrs.get('string'))

    def _new_product(self):
        fields = self.attrs['product'].split(',')
        product = {}

        first = self.screen.new(default=False)
        default = first.default_get()
        first.set_default(default)

        def search_set(*args):
            if not fields:
                return make_product()
            field = self.screen.group.fields[fields.pop()]
            relation = field.attrs.get('relation')
            if not relation:
                search_set()

            domain = field.domain_get(first)
            context = field.context_get(first)

            def callback(result):
                if result:
                    product[field.name] = result

            win_search = WinSearch(relation,
                                   callback,
                                   sel_multi=True,
                                   context=context,
                                   domain=domain,
                                   title=self.attrs.get('string'))
            win_search.win.connect('destroy', search_set)
            win_search.screen.search_filter()
            win_search.show()

        def make_product(first=first):
            if not product:
                self.screen.group.remove(first, remove=True)
                return

            fields = product.keys()
            for values in itertools.product(*product.values()):
                if first:
                    record = first
                    first = None
                else:
                    record = self.screen.new(default=False)
                default_value = default.copy()
                for field, value in zip(fields, values):
                    id_, rec_name = value
                    default_value[field] = id_
                    default_value[field + '.rec_name'] = rec_name
                record.set_default(default_value)

        search_set()

    def _sig_edit(self, widget=None):
        if not common.MODELACCESS[self.screen.model_name]['read']:
            return
        if not self._validate():
            return
        record = self.screen.current_record
        if record:
            WinForm(self.screen,
                    lambda a: None,
                    title=self.attrs.get('string'))

    def _sig_next(self, widget):
        if not self._validate():
            return
        self.screen.display_next()

    def _sig_previous(self, widget):
        if not self._validate():
            return
        self.screen.display_prev()

    def _sig_remove(self, widget, remove=False):
        access = common.MODELACCESS[self.screen.model_name]
        if remove:
            if not access['write'] or not access['read']:
                return
        else:
            if not access['delete']:
                return
        self.screen.remove(remove=remove)

    def _sig_undelete(self, button):
        self.screen.unremove()

    def _sig_add(self, *args):
        if not self.focus_out:
            return
        access = common.MODELACCESS[self.screen.model_name]
        if not access['write'] or not access['read']:
            return
        self.view.set_value()
        domain = self.field.domain_get(self.record)
        context = self.field.context_get(self.record)
        domain = [domain, self.record.expr_eval(self.attrs.get('add_remove'))]
        removed_ids = self.field.get_removed_ids(self.record)
        domain = ['OR', domain, ('id', 'in', removed_ids)]
        text = self.wid_text.get_text().decode('utf-8')

        self.focus_out = False

        sequence = None
        if self.screen.current_view.view_type == 'tree':
            sequence = self.screen.current_view.attributes.get('sequence')

        def callback(result):
            self.focus_out = True
            if result:
                ids = [x[0] for x in result]
                self.screen.load(ids, modified=True)
                self.screen.display(res_id=ids[0])
                if sequence:
                    self.screen.group.set_sequence(field=sequence)
            self.screen.set_cursor()
            self.wid_text.set_text('')

        win = WinSearch(self.attrs['relation'],
                        callback,
                        sel_multi=True,
                        context=context,
                        domain=domain,
                        view_ids=self.attrs.get('view_ids', '').split(','),
                        views_preload=self.attrs.get('views', {}),
                        new=self.but_new.get_property('sensitive'),
                        title=self.attrs.get('string'))
        win.screen.search_filter(quote(text))
        win.show()

    def _sig_label(self, screen, signal_data):
        self._position = signal_data[0]
        self._length = signal_data[1]
        if self._position >= 1:
            name = str(self._position)
        else:
            name = '_'
        line = '(%s/%s)' % (name, self._length)
        self.label.set_text(line)
        self._set_button_sensitive()

    def display(self, record, field):
        super(One2Many, self).display(record, field)

        self._set_button_sensitive()

        if field is None:
            self.screen.new_group()
            self.screen.current_record = None
            self.screen.parent = None
            self.screen.display()
            return False
        new_group = field.get_client(record)

        if id(self.screen.group) != id(new_group):
            self.screen.group = new_group
            if (self.screen.current_view.view_type == 'tree') \
                    and self.screen.current_view.editable:
                self.screen.current_record = None
        domain = []
        size_limit = None
        if record:
            domain = field.domain_get(record)
            size_limit = record.expr_eval(self.attrs.get('size'))
        if self.screen.domain != domain:
            self.screen.domain = domain
        self.screen.size_limit = size_limit
        self.screen.display()
        return True

    def set_value(self, record, field):
        self.screen.current_view.set_value()
        if self.screen.modified():  # TODO check if required
            record.modified_fields.setdefault(field.name)
            record.signal('record-modified')
        return True

    def _completion_match_selected(self, completion, model, iter_):
        record_id, = model.get(iter_, 1)
        self.screen.load([record_id], modified=True)
        self.wid_text.set_text('')
        self.wid_text.grab_focus()

        completion_model = self.wid_completion.get_model()
        completion_model.clear()
        completion_model.search_text = self.wid_text.get_text()
        return True

    def _update_completion(self, widget):
        if self._readonly:
            return
        if not self.record:
            return
        model = self.attrs['relation']
        domain = self.field.domain_get(self.record)
        domain = [domain, self.record.expr_eval(self.attrs.get('add_remove'))]
        removed_ids = self.field.get_removed_ids(self.record)
        domain = ['OR', domain, ('id', 'in', removed_ids)]
        update_completion(self.wid_text,
                          self.record,
                          self.field,
                          model,
                          domain=domain)

    def _completion_action_activated(self, completion, index):
        if index == 0:
            self._sig_add()
            self.wid_text.grab_focus()
        elif index == 1:
            self._sig_new()
Exemplo n.º 41
0
    def __init__(self, attrs=None, context=None):
        super(Action, self).__init__()
        self.name = attrs['name']
        self.context = context or {}

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

        view_ids = None
        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()
Exemplo n.º 42
0
class One2Many(WidgetInterface):

    def __init__(self, field_name, model_name, attrs=None):
        super(One2Many, self).__init__(field_name, model_name, attrs=attrs)

        self.widget = gtk.VBox(homogeneous=False, spacing=2)
        self._readonly = True

        hbox = gtk.HBox(homogeneous=False, spacing=0)
        hbox.set_border_width(2)

        label = gtk.Label(attrs.get('string', ''))
        label.set_alignment(0.0, 0.5)
        hbox.pack_start(label, expand=True, fill=True)

        hbox.pack_start(gtk.VSeparator(), expand=False, fill=True)

        tooltips = common.Tooltips()

        if attrs.get('add_remove'):

            self.wid_text = gtk.Entry()
            self.wid_text.set_property('width_chars', 13)
            self.wid_text.connect('activate', self._sig_activate)
            self.wid_text.connect('focus-out-event', self._focus_out)
            hbox.pack_start(self.wid_text, expand=True, fill=True)

            self.but_add = gtk.Button()
            tooltips.set_tip(self.but_add, _('Add'))
            self.but_add.connect('clicked', self._sig_add)
            img_add = gtk.Image()
            img_add.set_from_stock('tryton-list-add',
                gtk.ICON_SIZE_SMALL_TOOLBAR)
            img_add.set_alignment(0.5, 0.5)
            self.but_add.add(img_add)
            self.but_add.set_relief(gtk.RELIEF_NONE)
            hbox.pack_start(self.but_add, expand=False, fill=False)

            self.but_remove = gtk.Button()
            tooltips.set_tip(self.but_remove, _('Remove <Del>'))
            self.but_remove.connect('clicked', self._sig_remove, True)
            img_remove = gtk.Image()
            img_remove.set_from_stock('tryton-list-remove',
                gtk.ICON_SIZE_SMALL_TOOLBAR)
            img_remove.set_alignment(0.5, 0.5)
            self.but_remove.add(img_remove)
            self.but_remove.set_relief(gtk.RELIEF_NONE)
            hbox.pack_start(self.but_remove, expand=False, fill=False)

            hbox.pack_start(gtk.VSeparator(), expand=False, fill=True)

        self.but_new = gtk.Button()
        tooltips.set_tip(self.but_new, _('Create a new record <F3>'))
        self.but_new.connect('clicked', self._sig_new)
        img_new = gtk.Image()
        img_new.set_from_stock('tryton-new', gtk.ICON_SIZE_SMALL_TOOLBAR)
        img_new.set_alignment(0.5, 0.5)
        self.but_new.add(img_new)
        self.but_new.set_relief(gtk.RELIEF_NONE)
        hbox.pack_start(self.but_new, expand=False, fill=False)

        self.but_open = gtk.Button()
        tooltips.set_tip(self.but_open, _('Edit selected record <F2>'))
        self.but_open.connect('clicked', self._sig_edit)
        img_open = gtk.Image()
        img_open.set_from_stock('tryton-open', gtk.ICON_SIZE_SMALL_TOOLBAR)
        img_open.set_alignment(0.5, 0.5)
        self.but_open.add(img_open)
        self.but_open.set_relief(gtk.RELIEF_NONE)
        hbox.pack_start(self.but_open, expand=False, fill=False)

        self.but_del = gtk.Button()
        tooltips.set_tip(self.but_del, _('Delete selected record <Del>'))
        self.but_del.connect('clicked', self._sig_remove, False)
        img_del = gtk.Image()
        img_del.set_from_stock('tryton-delete', gtk.ICON_SIZE_SMALL_TOOLBAR)
        img_del.set_alignment(0.5, 0.5)
        self.but_del.add(img_del)
        self.but_del.set_relief(gtk.RELIEF_NONE)
        hbox.pack_start(self.but_del, expand=False, fill=False)

        self.but_undel = gtk.Button()
        tooltips.set_tip(self.but_undel, _('Undelete selected record <Ins>'))
        self.but_undel.connect('clicked', self._sig_undelete)
        img_undel = gtk.Image()
        img_undel.set_from_stock('tryton-undo', gtk.ICON_SIZE_SMALL_TOOLBAR)
        img_undel.set_alignment(0.5, 0.5)
        self.but_undel.add(img_undel)
        self.but_undel.set_relief(gtk.RELIEF_NONE)
        hbox.pack_start(self.but_undel, expand=False, fill=False)

        hbox.pack_start(gtk.VSeparator(), expand=False, fill=True)

        self.but_pre = gtk.Button()
        tooltips.set_tip(self.but_pre, _('Previous'))
        self.but_pre.connect('clicked', self._sig_previous)
        img_pre = gtk.Image()
        img_pre.set_from_stock('tryton-go-previous',
            gtk.ICON_SIZE_SMALL_TOOLBAR)
        img_pre.set_alignment(0.5, 0.5)
        self.but_pre.add(img_pre)
        self.but_pre.set_relief(gtk.RELIEF_NONE)
        hbox.pack_start(self.but_pre, expand=False, fill=False)

        self.label = gtk.Label('(0,0)')
        hbox.pack_start(self.label, expand=False, fill=False)

        self.but_next = gtk.Button()
        tooltips.set_tip(self.but_next, _('Next'))
        self.but_next.connect('clicked', self._sig_next)
        img_next = gtk.Image()
        img_next.set_from_stock('tryton-go-next', gtk.ICON_SIZE_SMALL_TOOLBAR)
        img_next.set_alignment(0.5, 0.5)
        self.but_next.add(img_next)
        self.but_next.set_relief(gtk.RELIEF_NONE)
        hbox.pack_start(self.but_next, expand=False, fill=False)

        hbox.pack_start(gtk.VSeparator(), expand=False, fill=True)

        but_switch = gtk.Button()
        tooltips.set_tip(but_switch, _('Switch'))
        but_switch.connect('clicked', self.switch_view)
        img_switch = gtk.Image()
        img_switch.set_from_stock('tryton-fullscreen',
            gtk.ICON_SIZE_SMALL_TOOLBAR)
        img_switch.set_alignment(0.5, 0.5)
        but_switch.add(img_switch)
        but_switch.set_relief(gtk.RELIEF_NONE)
        hbox.pack_start(but_switch, expand=False, fill=False)

        if attrs.get('add_remove'):
            hbox.set_focus_chain([self.wid_text])
        else:
            hbox.set_focus_chain([])

        tooltips.enable()

        frame = gtk.Frame()
        frame.add(hbox)
        frame.set_shadow_type(gtk.SHADOW_OUT)
        self.widget.pack_start(frame, expand=False, fill=True)

        self.screen = Screen(attrs['relation'],
            mode=attrs.get('mode', 'tree,form').split(','),
            view_ids=attrs.get('view_ids', '').split(','),
            views_preload=attrs.get('views', {}),
            row_activate=self._on_activate,
            exclude_field=attrs.get('relation_field', None))
        self.screen.signal_connect(self, 'record-message', self._sig_label)

        self.widget.pack_start(self.screen.widget, expand=True, fill=True)

        self.screen.widget.connect('key_press_event', self.on_keypress)
        if self.attrs.get('add_remove'):
            self.wid_text.connect('key_press_event', self.on_keypress)

    def _color_widget(self):
        if hasattr(self.screen.current_view, 'widget_tree'):
            return self.screen.current_view.widget_tree
        return super(One2Many, self)._color_widget()

    def grab_focus(self):
        return self.screen.widget.grab_focus()

    def on_keypress(self, widget, event):
        if (event.keyval == gtk.keysyms.F3) \
                and self.but_new.get_property('sensitive'):
            self._sig_new(widget)
            return False
        if event.keyval == gtk.keysyms.F2 \
                and widget == self.screen.widget:
            self._sig_edit(widget)
            return False
        if event.keyval in (gtk.keysyms.Delete, gtk.keysyms.KP_Delete) \
                and widget == self.screen.widget:
            self._sig_remove(widget)
            return False
        if event.keyval == gtk.keysyms.Insert and widget == self.screen.widget:
            self._sig_undelete(widget)
            return False

    def destroy(self):
        self.screen.destroy()

    def _on_activate(self):
        self._sig_edit()

    def switch_view(self, widget):
        self.screen.switch_view()
        self.color_set(self.color_name)

    @property
    def modified(self):
        return self.screen.current_view.modified

    def color_set(self, name):
        super(One2Many, self).color_set(name)
        widget = self._color_widget()
        # if the style to apply is different from readonly then insensitive
        # cellrenderers should use the default insensitive color
        if name != 'readonly':
            widget.modify_text(gtk.STATE_INSENSITIVE,
                    self.colors['text_color_insensitive'])

    def _readonly_set(self, value):
        self._readonly = value
        self.but_new.set_sensitive(not value)
        self.but_del.set_sensitive(not value)
        self.but_undel.set_sensitive(not value)
        if self.attrs.get('add_remove'):
            self.wid_text.set_sensitive(not value)
            self.but_add.set_sensitive(not value)
            self.but_remove.set_sensitive(not value)

    def _sig_new(self, widget):
        self.view.set_value()
        record = self.screen.current_record
        if record:
            fields = self.screen.current_view.get_fields()
            if not record.validate(fields):
                self.screen.display()
                return
        ctx = {}
        ctx.update(self.field.context_get(self.record))
        sequence = None
        if self.screen.current_view.view_type == 'tree':
            sequence = self.screen.current_view.widget_tree.sequence

        def update_sequence():
            if sequence:
                self.screen.group.set_sequence(field=sequence)

        if (self.screen.current_view.view_type == 'form') \
                or self.screen.editable_get():
            self.screen.new(context=ctx)
            self.screen.current_view.widget.set_sensitive(True)
            update_sequence()
        else:
            WinForm(self.screen, lambda a: update_sequence(), new=True,
                many=True, context=ctx)

    def _sig_edit(self, widget=None):
        self.view.set_value()
        record = self.screen.current_record
        if record:
            fields = self.screen.current_view.get_fields()
            if not record.validate(fields):
                self.screen.display()
                return
            WinForm(self.screen, lambda a: None)

    def _sig_next(self, widget):
        self.view.set_value()
        record = self.screen.current_record
        if record:
            fields = self.screen.current_view.get_fields()
            if not record.validate(fields):
                self.screen.display()
                return
        self.screen.display_next()

    def _sig_previous(self, widget):
        self.view.set_value()
        record = self.screen.current_record
        if record:
            fields = self.screen.current_view.get_fields()
            if not record.validate(fields):
                self.screen.display()
                return
        self.screen.display_prev()

    def _sig_remove(self, widget, remove=False):
        self.screen.remove(remove=remove)

    def _sig_undelete(self, button):
        self.screen.unremove()

    def _sig_activate(self, *args):
        self._sig_add()
        self.wid_text.grab_focus()

    def _focus_out(self, *args):
        if self.wid_text.get_text():
            self._sig_add()

    def _sig_add(self, *args):
        self.view.set_value()
        domain = self.field.domain_get(self.record)
        context = self.field.context_get(self.record)
        domain = domain[:]
        domain.extend(self.record.expr_eval(self.attrs.get('add_remove')))
        removed_ids = self.field.get_removed_ids(self.record)

        try:
            if self.wid_text.get_text():
                dom = [('rec_name', 'ilike',
                        '%' + self.wid_text.get_text() + '%'),
                    ['OR', domain, ('id', 'in', removed_ids)]]
            else:
                dom = ['OR', domain, ('id', 'in', removed_ids)]
            ids = RPCExecute('model', self.attrs['relation'], 'search', dom,
                    0, CONFIG['client.limit'], None, context=context)
        except RPCException:
            return False

        def callback(result):
            if result:
                ids = [x[0] for x in result]
                self.screen.load(ids, modified=True)
                self.screen.display(res_id=ids[0])
            self.screen.set_cursor()
            self.wid_text.set_text('')
        if len(ids) != 1:
            WinSearch(self.attrs['relation'], callback, sel_multi=True,
                ids=ids, context=context, domain=domain,
                view_ids=self.attrs.get('view_ids', '').split(','),
                views_preload=self.attrs.get('views', {}))
        else:
            callback([(i, None) for i in ids])

    def _sig_label(self, screen, signal_data):
        name = '_'
        if signal_data[0] >= 1:
            name = str(signal_data[0])
            self.but_open.set_sensitive(True)
            self.but_del.set_sensitive(not self._readonly)
            if self.attrs.get('add_remove'):
                self.but_remove.set_sensitive(not self._readonly)
            if signal_data[0] < signal_data[1]:
                self.but_next.set_sensitive(True)
            else:
                self.but_next.set_sensitive(False)
            if signal_data[0] > 1:
                self.but_pre.set_sensitive(True)
            else:
                self.but_pre.set_sensitive(False)
            self.but_del.set_sensitive(not self._readonly)
            self.but_undel.set_sensitive(not self._readonly)
        else:
            self.but_open.set_sensitive(False)
            self.but_del.set_sensitive(False)
            self.but_undel.set_sensitive(False)
            self.but_next.set_sensitive(False)
            self.but_pre.set_sensitive(False)
            if self.attrs.get('add_remove'):
                self.but_remove.set_sensitive(False)
        line = '(%s/%s)' % (name, signal_data[1])
        self.label.set_text(line)

    def display(self, record, field):
        super(One2Many, self).display(record, field)
        if field is None:
            self.screen.new_group()
            self.screen.current_record = None
            self.screen.parent = True
            self.screen.display()
            return False
        new_group = field.get_client(record)
        if id(self.screen.group) != id(new_group):
            self.screen.group = new_group
            if (self.screen.current_view.view_type == 'tree') \
                    and self.screen.editable_get():
                self.screen.current_record = None
            readonly = False
            domain = []
            if record:
                readonly = field.get_state_attrs(record).get('readonly', False)
                domain = field.domain_get(record)
            if self.screen.domain != domain:
                self.screen.domain = domain
            self.screen.group.readonly = readonly
        self.screen.display()
        return True

    def set_value(self, record, field):
        self.screen.save_tree_state()
        self.screen.current_view.set_value()
        if self.screen.modified():  # TODO check if required
            record.modified_fields.setdefault(field.name)
            record.signal('record-modified')
        return True
Exemplo n.º 43
0
class Many2ManySelection(Widget, SelectionMixin):
    expand = True

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

        self.widget = gtk.VBox(homogeneous=False, spacing=5)

        hbox = gtk.HBox(homogeneous=False, spacing=0)
        hbox.set_border_width(2)

        label = gtk.Label(attrs.get("string", ""))
        label.set_alignment(0.0, 0.5)
        hbox.pack_start(label, expand=True, fill=True)

        frame = gtk.Frame()
        frame.add(hbox)
        frame.set_shadow_type(gtk.SHADOW_OUT)
        self.widget.pack_start(frame, expand=False, fill=True)

        self.screen = Screen(
            attrs["relation"],
            view_ids=attrs.get("view_ids", "").split(","),
            mode=["tree"],
            views_preload=attrs.get("views", {}),
        )
        self.screen.new_group()
        self.treeview = self.screen.current_view.treeview
        self.treeview.get_selection().connect("changed", self.changed)
        self.treeview.connect("focus-out-event", lambda *a: self._focus_out())

        self.treeview.connect("button-press-event", self.button_press_event)
        self.treeview.connect("key-press-event", self.key_press_event)

        self.widget.pack_start(self.screen.widget, expand=True, fill=True)

        self.nullable_widget = False
        self.init_selection()

    @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 button_press_event(self, treeview, event):
        # grab focus because it doesn't whith CONTROL MASK
        treeview.grab_focus()
        if event.button == 1:
            event.state ^= gtk.gdk.CONTROL_MASK

    def key_press_event(self, treeview, event):
        if event.keyval in MOVEMENT_KEYS:
            event.state ^= gtk.gdk.CONTROL_MASK

    def get_value(self):
        return [r.id for r in self.screen.selected_records]

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

    def display(self, record, field):
        selection = self.treeview.get_selection()
        selection.handler_block_by_func(self.changed)
        try:
            self.update_selection(record, field)
            super(Many2ManySelection, self).display(record, field)
            if field is None:
                self.screen.clear()
                self.screen.current_record = None
                self.screen.parent = None
            else:
                self.screen.parent = record
                current_ids = [r.id for r in self.screen.group]
                new_ids = [s[0] for s in self.selection]
                if current_ids != new_ids:
                    self.screen.clear()
                    self.screen.load(new_ids)
                group = field.get_client(record)
                nodes = [[r.id] for r in group if r not in group.record_removed and r not in group.record_deleted]
                selection.unselect_all()
                self.screen.current_view.select_nodes(nodes)
            self.screen.display()
        finally:
            selection.handler_unblock_by_func(self.changed)
 def load(record):
     if isinstance(record, (int, long)):
         screen = Screen(model)
         screen.load([record])
         record = screen.current_record
     return record
Exemplo n.º 45
0
class WinSearch(NoModal):

    def __init__(self, model, callback, sel_multi=True, context=None,
            domain=None, view_ids=None, views_preload=None, new=True,
            title=''):
        NoModal.__init__(self)
        if views_preload is None:
            views_preload = {}
        self.domain = domain or []
        self.context = context or {}
        self.sel_multi = sel_multi
        self.callback = callback
        self.title = title

        self.win = gtk.Dialog(_('Search'), self.parent,
            gtk.DIALOG_DESTROY_WITH_PARENT)
        self.win.set_icon(GNUHEALTH_ICON)
        self.win.set_default_response(gtk.RESPONSE_APPLY)
        self.win.connect('response', self.response)

        self.accel_group = gtk.AccelGroup()
        self.win.add_accel_group(self.accel_group)

        self.but_cancel = self.win.add_button(gtk.STOCK_CANCEL,
            gtk.RESPONSE_CANCEL)
        self.but_find = self.win.add_button(gtk.STOCK_FIND, gtk.RESPONSE_APPLY)
        if new and common.MODELACCESS[model]['create']:
            self.but_new = self.win.add_button(gtk.STOCK_NEW,
                gtk.RESPONSE_ACCEPT)
            self.but_new.set_accel_path('<tryton>/Form/New', self.accel_group)

        self.but_ok = self.win.add_button(gtk.STOCK_OK, gtk.RESPONSE_OK)
        self.but_ok.add_accelerator('clicked', self.accel_group,
                gtk.keysyms.Return, gtk.gdk.CONTROL_MASK, gtk.ACCEL_VISIBLE)

        hbox = gtk.HBox()
        hbox.show()
        self.win.vbox.pack_start(hbox, expand=False, fill=True)
        self.win.vbox.pack_start(gtk.HSeparator(), expand=False, fill=True)
        scrollwindow = gtk.ScrolledWindow()
        scrollwindow.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
        self.win.vbox.pack_start(scrollwindow, expand=True, fill=True)

        self.screen = Screen(model, domain=domain, mode=['tree'],
            context=context, view_ids=view_ids, views_preload=views_preload,
            row_activate=self.sig_activate)
        self.view = self.screen.current_view
        self.view.unset_editable()
        # Prevent to set tree_state
        self.screen.tree_states_done.add(id(self.view))
        sel = self.view.treeview.get_selection()
        self.win.set_title(_('Search %s') % self.title)

        if not sel_multi:
            sel.set_mode(gtk.SELECTION_SINGLE)
        else:
            sel.set_mode(gtk.SELECTION_MULTIPLE)
        viewport = gtk.Viewport()
        viewport.set_shadow_type(gtk.SHADOW_NONE)
        viewport.add(self.screen.widget)
        self.screen.widget.show()
        viewport.show()
        scrollwindow.add(viewport)
        scrollwindow.show()

        self.model_name = model

        self.win.set_default_size(700, 500)

        self.register()
        sensible_allocation = self.sensible_widget.get_allocation()
        self.win.set_default_size(int(sensible_allocation.width * 0.9),
            int(sensible_allocation.height * 0.9))

    def sig_activate(self, *args):
        self.view.treeview.emit_stop_by_name('row_activated')
        self.win.response(gtk.RESPONSE_OK)
        return True

    def destroy(self):
        self.screen.destroy()
        self.win.destroy()
        NoModal.destroy(self)

    def show(self):
        self.win.show()
        common.center_window(self.win, self.parent, self.sensible_widget)

    def hide(self):
        self.win.hide()

    def response(self, win, response_id):
        res = None
        if response_id == gtk.RESPONSE_OK:
            res = [r.id for r in self.screen.selected_records]
        elif response_id == gtk.RESPONSE_APPLY:
            self.screen.search_filter(self.screen.screen_container.get_text())
            return
        elif response_id == gtk.RESPONSE_ACCEPT:
            screen = Screen(self.model_name, domain=self.domain,
                context=self.context, mode=['form'])

            def callback(result):
                if result and screen.save_current():
                    record = screen.current_record
                    res = [(record.id, record.value.get('rec_name', ''))]
                    self.callback(res)
                else:
                    self.callback(None)
            self.destroy()
            WinForm(screen, callback, new=True, title=self.title)
            return
        if res:
            group = self.screen.group
            res = [(id_, group.get(id_).value.get('rec_name', ''))
                for id_ in res]
        self.callback(res)
        self.destroy()
Exemplo n.º 46
0
class One2Many(Widget):
    expand = True

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

        self.widget = gtk.Frame()
        self.widget.set_shadow_type(gtk.SHADOW_NONE)
        self.widget.get_accessible().set_name(attrs.get("string", ""))
        vbox = gtk.VBox(homogeneous=False, spacing=2)
        self.widget.add(vbox)
        self._readonly = True
        self._position = 0
        self._length = 0

        self.title_box = hbox = gtk.HBox(homogeneous=False, spacing=0)
        hbox.set_border_width(2)

        label = gtk.Label(attrs.get("string", ""))
        label.set_alignment(0.0, 0.5)
        hbox.pack_start(label, expand=True, fill=True)

        hbox.pack_start(gtk.VSeparator(), expand=False, fill=True)

        tooltips = common.Tooltips()

        self.focus_out = True
        self.wid_completion = None
        if attrs.get("add_remove"):

            self.wid_text = PlaceholderEntry()
            self.wid_text.set_placeholder_text(_("Search"))
            self.wid_text.set_property("width_chars", 13)
            self.wid_text.connect("focus-out-event", lambda *a: self._focus_out())
            hbox.pack_start(self.wid_text, expand=True, fill=True)

            if int(self.attrs.get("completion", 1)):
                access = common.MODELACCESS[attrs["relation"]]
                self.wid_completion = get_completion(
                    search=access["read"] and access["write"], create=attrs.get("create", True) and access["create"]
                )
                self.wid_completion.connect("match-selected", self._completion_match_selected)
                self.wid_completion.connect("action-activated", self._completion_action_activated)
                self.wid_text.set_completion(self.wid_completion)
                self.wid_text.connect("changed", self._update_completion)

            self.but_add = gtk.Button()
            tooltips.set_tip(self.but_add, _("Add existing record"))
            self.but_add.connect("clicked", self._sig_add)
            img_add = gtk.Image()
            img_add.set_from_stock("tryton-list-add", gtk.ICON_SIZE_SMALL_TOOLBAR)
            img_add.set_alignment(0.5, 0.5)
            self.but_add.add(img_add)
            self.but_add.set_relief(gtk.RELIEF_NONE)
            hbox.pack_start(self.but_add, expand=False, fill=False)

            self.but_remove = gtk.Button()
            tooltips.set_tip(self.but_remove, _("Remove selected record"))
            self.but_remove.connect("clicked", self._sig_remove, True)
            img_remove = gtk.Image()
            img_remove.set_from_stock("tryton-list-remove", gtk.ICON_SIZE_SMALL_TOOLBAR)
            img_remove.set_alignment(0.5, 0.5)
            self.but_remove.add(img_remove)
            self.but_remove.set_relief(gtk.RELIEF_NONE)
            hbox.pack_start(self.but_remove, expand=False, fill=False)

            hbox.pack_start(gtk.VSeparator(), expand=False, fill=True)

        self.but_new = gtk.Button()
        tooltips.set_tip(self.but_new, _("Create a new record <F3>"))
        self.but_new.connect("clicked", self._sig_new)
        img_new = gtk.Image()
        img_new.set_from_stock("tryton-new", gtk.ICON_SIZE_SMALL_TOOLBAR)
        img_new.set_alignment(0.5, 0.5)
        self.but_new.add(img_new)
        self.but_new.set_relief(gtk.RELIEF_NONE)
        hbox.pack_start(self.but_new, expand=False, fill=False)

        self.but_open = gtk.Button()
        tooltips.set_tip(self.but_open, _("Edit selected record <F2>"))
        self.but_open.connect("clicked", self._sig_edit)
        img_open = gtk.Image()
        img_open.set_from_stock("tryton-open", gtk.ICON_SIZE_SMALL_TOOLBAR)
        img_open.set_alignment(0.5, 0.5)
        self.but_open.add(img_open)
        self.but_open.set_relief(gtk.RELIEF_NONE)
        hbox.pack_start(self.but_open, expand=False, fill=False)

        self.but_del = gtk.Button()
        tooltips.set_tip(self.but_del, _("Delete selected record <Del>"))
        self.but_del.connect("clicked", self._sig_remove, False)
        img_del = gtk.Image()
        img_del.set_from_stock("tryton-delete", gtk.ICON_SIZE_SMALL_TOOLBAR)
        img_del.set_alignment(0.5, 0.5)
        self.but_del.add(img_del)
        self.but_del.set_relief(gtk.RELIEF_NONE)
        hbox.pack_start(self.but_del, expand=False, fill=False)

        self.but_undel = gtk.Button()
        tooltips.set_tip(self.but_undel, _("Undelete selected record <Ins>"))
        self.but_undel.connect("clicked", self._sig_undelete)
        img_undel = gtk.Image()
        img_undel.set_from_stock("tryton-undo", gtk.ICON_SIZE_SMALL_TOOLBAR)
        img_undel.set_alignment(0.5, 0.5)
        self.but_undel.add(img_undel)
        self.but_undel.set_relief(gtk.RELIEF_NONE)
        hbox.pack_start(self.but_undel, expand=False, fill=False)

        hbox.pack_start(gtk.VSeparator(), expand=False, fill=True)

        self.but_pre = gtk.Button()
        tooltips.set_tip(self.but_pre, _("Previous"))
        self.but_pre.connect("clicked", self._sig_previous)
        img_pre = gtk.Image()
        img_pre.set_from_stock("tryton-go-previous", gtk.ICON_SIZE_SMALL_TOOLBAR)
        img_pre.set_alignment(0.5, 0.5)
        self.but_pre.add(img_pre)
        self.but_pre.set_relief(gtk.RELIEF_NONE)
        hbox.pack_start(self.but_pre, expand=False, fill=False)

        self.label = gtk.Label("(0,0)")
        hbox.pack_start(self.label, expand=False, fill=False)

        self.but_next = gtk.Button()
        tooltips.set_tip(self.but_next, _("Next"))
        self.but_next.connect("clicked", self._sig_next)
        img_next = gtk.Image()
        img_next.set_from_stock("tryton-go-next", gtk.ICON_SIZE_SMALL_TOOLBAR)
        img_next.set_alignment(0.5, 0.5)
        self.but_next.add(img_next)
        self.but_next.set_relief(gtk.RELIEF_NONE)
        hbox.pack_start(self.but_next, expand=False, fill=False)

        hbox.pack_start(gtk.VSeparator(), expand=False, fill=True)

        but_switch = gtk.Button()
        tooltips.set_tip(but_switch, _("Switch"))
        but_switch.connect("clicked", self.switch_view)
        img_switch = gtk.Image()
        img_switch.set_from_stock("tryton-fullscreen", gtk.ICON_SIZE_SMALL_TOOLBAR)
        img_switch.set_alignment(0.5, 0.5)
        but_switch.add(img_switch)
        but_switch.set_relief(gtk.RELIEF_NONE)
        hbox.pack_start(but_switch, expand=False, fill=False)

        if attrs.get("add_remove"):
            hbox.set_focus_chain([self.wid_text])
        else:
            hbox.set_focus_chain([])

        tooltips.enable()

        frame = gtk.Frame()
        frame.add(hbox)

        if attrs.get("expand_toolbar"):
            frame.set_shadow_type(gtk.SHADOW_NONE)
        else:
            frame.set_shadow_type(gtk.SHADOW_OUT)
            vbox.pack_start(frame, expand=False, fill=True)

        self.screen = Screen(
            attrs["relation"],
            mode=attrs.get("mode", "tree,form").split(","),
            view_ids=attrs.get("view_ids", "").split(","),
            views_preload=attrs.get("views", {}),
            row_activate=self._on_activate,
            readonly=self.attrs.get("readonly", False),
            exclude_field=attrs.get("relation_field", None),
        )
        self.screen.pre_validate = bool(int(attrs.get("pre_validate", 0)))
        self.screen.signal_connect(self, "record-message", self._sig_label)
        if self.attrs.get("group"):
            self.screen.signal_connect(
                self,
                "current-record-changed",
                lambda screen, _: gobject.idle_add(self.group_sync, screen, screen.current_record),
            )

        vbox.pack_start(self.screen.widget, expand=True, fill=True)

        self.screen.widget.connect("key_press_event", self.on_keypress)
        if self.attrs.get("add_remove"):
            self.wid_text.connect("key_press_event", self.on_keypress)

        but_switch.props.sensitive = self.screen.number_of_views > 1

    def _color_widget(self):
        if hasattr(self.screen.current_view, "treeview"):
            return self.screen.current_view.treeview
        return super(One2Many, self)._color_widget()

    def on_keypress(self, widget, event):
        if (event.keyval == gtk.keysyms.F3) and self.but_new.get_property("sensitive"):
            self._sig_new(widget)
            return True
        if event.keyval == gtk.keysyms.F2 and widget == self.screen.widget:
            self._sig_edit(widget)
            return True
        if (
            event.keyval in (gtk.keysyms.Delete, gtk.keysyms.KP_Delete)
            and widget == self.screen.widget
            and self.but_del.get_property("sensitive")
        ):
            self._sig_remove(widget)
            return True
        if event.keyval == gtk.keysyms.Insert and widget == self.screen.widget:
            self._sig_undelete(widget)
            return True
        if self.attrs.get("add_remove"):
            editable = self.wid_text.get_editable()
            activate_keys = [gtk.keysyms.Tab, gtk.keysyms.ISO_Left_Tab]
            if not self.wid_completion:
                activate_keys.append(gtk.keysyms.Return)
            if widget == self.wid_text and event.keyval in activate_keys and editable and self.wid_text.get_text():
                self._sig_add()
                self.wid_text.grab_focus()
        return False

    def destroy(self):
        self.screen.destroy()

    def _on_activate(self):
        self._sig_edit()

    def switch_view(self, widget):
        self.screen.switch_view()
        self.color_set(self.color_name)

    @property
    def modified(self):
        return self.screen.current_view.modified

    def color_set(self, name):
        super(One2Many, self).color_set(name)
        widget = self._color_widget()
        # if the style to apply is different from readonly then insensitive
        # cellrenderers should use the default insensitive color
        if name != "readonly":
            widget.modify_text(gtk.STATE_INSENSITIVE, self.colors["text_color_insensitive"])

    def _readonly_set(self, value):
        self._readonly = value
        self._set_button_sensitive()

    def _set_button_sensitive(self):
        access = common.MODELACCESS[self.screen.model_name]
        if self.record and self.field:
            field_size = self.record.expr_eval(self.attrs.get("size"))
            o2m_size = len(self.field.get_eval(self.record))
            size_limit = field_size is not None and o2m_size >= field_size >= 0
        else:
            o2m_size = None
            size_limit = False

        has_form = "form" in (x.view_type for x in self.screen.views) or "form" in self.screen.view_to_load

        self.but_new.set_sensitive(
            bool(
                not self._readonly
                and self.attrs.get("create", True)
                and not size_limit
                and access["create"]
                and (has_form or self.screen.current_view.editable)
            )
        )
        self.but_del.set_sensitive(
            bool(not self._readonly and self.attrs.get("delete", True) and self._position and access["delete"])
        )
        self.but_undel.set_sensitive(bool(not self._readonly and not size_limit and self._position))
        self.but_open.set_sensitive(bool(self._position and access["read"] and has_form))
        self.but_next.set_sensitive(bool(self._position and self._position < self._length))
        self.but_pre.set_sensitive(bool(self._position and self._position > 1))
        if self.attrs.get("add_remove"):
            self.but_add.set_sensitive(
                bool(not self._readonly and not size_limit and access["write"] and access["read"])
            )
            self.but_remove.set_sensitive(
                bool(not self._readonly and self._position and access["write"] and access["read"])
            )
            self.wid_text.set_sensitive(self.but_add.get_sensitive())

        # New button must be added to focus chain to allow keyboard only
        # creation when there is no existing record on form view.
        focus_chain = self.title_box.get_focus_chain() or []
        if o2m_size == 0 and self.screen.current_view.view_type == "form":
            if self.but_new not in focus_chain:
                focus_chain.append(self.but_new)
        else:
            if self.but_new in focus_chain:
                focus_chain.remove(self.but_new)
        self.title_box.set_focus_chain(focus_chain)

    def _validate(self):
        record = self.screen.current_record
        if record:
            fields = self.screen.current_view.get_fields()
            if not record.validate(fields):
                self.screen.display(set_cursor=True)
                return False
            if self.screen.pre_validate and not record.pre_validate():
                return False
        return True

    def _sig_new(self, *args):
        if not common.MODELACCESS[self.screen.model_name]["create"]:
            return
        if not self._validate():
            return

        if self.attrs.get("product"):
            self._new_product()
        else:
            self._new_single()

    def _new_single(self):
        ctx = {}
        ctx.update(self.field.context_get(self.record))
        sequence = None
        for view in self.screen.views:
            if view.view_type == "tree":
                sequence = view.attributes.get("sequence")
                if sequence:
                    break

        def update_sequence():
            if sequence:
                self.screen.group.set_sequence(field=sequence)

        for widget in [self] + self.view.widgets[self.field_name]:
            if (
                (self.attrs.get("group") and widget.attrs.get("group") != self.attrs["group"])
                or not widget.visible
                or not hasattr(widget, "screen")
            ):
                continue
            if (
                widget.screen.current_view.view_type == "form"
                or widget.screen.current_view.editable
                and not widget.screen.editable_open_get()
            ):
                widget.screen.new()
                widget.screen.current_view.widget.set_sensitive(True)
                update_sequence()
                break
        else:
            field_size = self.record.expr_eval(self.attrs.get("size")) or -1
            field_size -= len(self.field.get_eval(self.record)) + 1
            WinForm(self.screen, lambda a: update_sequence(), new=True, many=field_size, context=ctx)

    def _new_product(self):
        fields = self.attrs["product"].split(",")
        product = {}

        first = self.screen.new(default=False)
        default = first.default_get()
        first.set_default(default)

        def search_set(*args):
            if not fields:
                return make_product()
            field = self.screen.group.fields[fields.pop()]
            relation = field.attrs.get("relation")
            if not relation:
                search_set()

            domain = field.domain_get(first)
            context = field.context_get(first)

            def callback(result):
                if result:
                    product[field.name] = result

            win_search = WinSearch(relation, callback, sel_multi=True, context=context, domain=domain)
            win_search.win.connect("destroy", search_set)
            win_search.screen.search_filter()
            win_search.show()

        def make_product(first=first):
            if not product:
                self.screen.group.remove(first, remove=True)
                return

            fields = product.keys()
            for values in itertools.product(*product.values()):
                if first:
                    record = first
                    first = None
                else:
                    record = self.screen.new(default=False)
                default_value = default.copy()
                for field, value in zip(fields, values):
                    id_, rec_name = value
                    default_value[field] = id_
                    default_value[field + ".rec_name"] = rec_name
                record.set_default(default_value)

        search_set()

    def _sig_edit(self, widget=None):
        if not self.but_open.props.sensitive:
            return
        if not self._validate():
            return
        record = self.screen.current_record
        if record:
            WinForm(self.screen, lambda a: None)

    def _sig_next(self, widget):
        if not self._validate():
            return
        self.screen.display_next()

    def _sig_previous(self, widget):
        if not self._validate():
            return
        self.screen.display_prev()

    def _sig_remove(self, widget, remove=False):
        access = common.MODELACCESS[self.screen.model_name]
        if remove:
            if not access["write"] or not access["read"]:
                return
        else:
            if not access["delete"]:
                return
        self.screen.remove(remove=remove)

    def _sig_undelete(self, button):
        self.screen.unremove()

    def _sig_add(self, *args):
        if not self.focus_out:
            return
        access = common.MODELACCESS[self.screen.model_name]
        if not access["write"] or not access["read"]:
            return
        domain = self.field.domain_get(self.record)
        context = self.field.context_get(self.record)
        domain = [domain, self.record.expr_eval(self.attrs.get("add_remove"))]
        removed_ids = self.field.get_removed_ids(self.record)
        domain = ["OR", domain, ("id", "in", removed_ids)]
        text = self.wid_text.get_text().decode("utf-8")

        self.focus_out = False

        sequence = None
        if self.screen.current_view.view_type == "tree":
            sequence = self.screen.current_view.attributes.get("sequence")

        def callback(result):
            self.focus_out = True
            if result:
                ids = [x[0] for x in result]
                self.screen.load(ids, modified=True)
                self.screen.display(res_id=ids[0])
                if sequence:
                    self.screen.group.set_sequence(field=sequence)
            self.screen.set_cursor()
            self.wid_text.set_text("")

        win = WinSearch(
            self.attrs["relation"],
            callback,
            sel_multi=True,
            context=context,
            domain=domain,
            view_ids=self.attrs.get("view_ids", "").split(","),
            views_preload=self.attrs.get("views", {}),
            new=self.but_new.get_property("sensitive"),
        )
        win.screen.search_filter(quote(text))
        win.show()

    def _sig_label(self, screen, signal_data):
        self._position = signal_data[0]
        self._length = signal_data[1]
        if self._position >= 1:
            name = str(self._position)
        else:
            name = "_"
        line = "(%s/%s)" % (name, self._length)
        self.label.set_text(line)
        self._set_button_sensitive()

    def group_sync(self, screen, current_record):
        if not self.screen.widget.props.window:
            return
        if not self.view or not self.view.widgets:
            return
        if self.attrs.get("mode") == "form":
            return
        if screen.current_record != current_record:
            return

        def is_compatbile(screen, record):
            return not (
                screen.current_view.view_type == "form"
                and record is not None
                and screen.model_name != record.model_name
            )

        current_record = self.screen.current_record
        to_sync = []
        for widget in self.view.widgets[self.field_name]:
            if widget == self or widget.attrs.get("group") != self.attrs["group"] or not hasattr(widget, "screen"):
                continue
            if widget.screen.current_record == current_record:
                continue
            record = current_record
            if not is_compatbile(widget.screen, record):
                record = None
            if not widget._validate():

                def go_previous():
                    record = widget.screen.current_record
                    if not is_compatbile(screen, record):
                        record = None
                    screen.current_record = record
                    screen.display()

                gobject.idle_add(go_previous)
                return
            to_sync.append((widget, record))
        for widget, record in to_sync:
            if (
                widget.screen.current_view.view_type == "form"
                and record is not None
                and widget.screen.group.model_name == record.group.model_name
            ):
                fields = dict((name, field.attrs) for name, field in widget.screen.group.fields.iteritems())
                record.group.load_fields(fields)
            widget.screen.current_record = record
            widget.display(widget.record, widget.field)

    def display(self, record, field):
        super(One2Many, self).display(record, field)

        self._set_button_sensitive()

        if field is None:
            self.screen.new_group()
            self.screen.current_record = None
            self.screen.parent = None
            self.screen.display()
            return False
        new_group = field.get_client(record)

        if self.attrs.get("group") and self.attrs.get("mode") == "form":
            if self.screen.current_record is None:
                self.invisible_set(True)
        elif id(self.screen.group) != id(new_group):
            self.screen.group = new_group
            if (self.screen.current_view.view_type == "tree") and self.screen.current_view.editable:
                self.screen.current_record = None
        readonly = False
        domain = []
        size_limit = None
        if record:
            readonly = field.get_state_attrs(record).get("readonly", False)
            domain = field.domain_get(record)
            size_limit = record.expr_eval(self.attrs.get("size"))
        if self.screen.get_domain() != domain:
            self.screen.domain = domain
        self.screen.group.readonly = readonly
        self.screen.size_limit = size_limit
        self.screen.display()
        return True

    def set_value(self, record, field):
        if (
            self.screen.current_view.view_type == "form"
            and self.attrs.get("group")
            and self.screen.model_name != record.model_name
        ):
            return True
        self.screen.current_view.set_value()
        if self.screen.modified():  # TODO check if required
            record.modified_fields.setdefault(field.name)
            record.signal("record-modified")
        return True

    def _completion_match_selected(self, completion, model, iter_):
        record_id, = model.get(iter_, 1)
        self.screen.load([record_id], modified=True)
        self.wid_text.set_text("")
        self.wid_text.grab_focus()

        completion_model = self.wid_completion.get_model()
        completion_model.clear()
        completion_model.search_text = self.wid_text.get_text()
        return True

    def _update_completion(self, widget):
        if self._readonly:
            return
        if not self.record:
            return
        model = self.attrs["relation"]
        domain = self.field.domain_get(self.record)
        domain = [domain, self.record.expr_eval(self.attrs.get("add_remove"))]
        removed_ids = self.field.get_removed_ids(self.record)
        domain = ["OR", domain, ("id", "in", removed_ids)]
        update_completion(self.wid_text, self.record, self.field, model, domain=domain)

    def _completion_action_activated(self, completion, index):
        if index == 0:
            self._sig_add()
            self.wid_text.grab_focus()
        elif index == 1:
            self._sig_new()
Exemplo n.º 47
0
class Form(SignalEvent, TabContent):
    "Form"

    def __init__(self, model, res_id=None, name='', **attributes):
        super(Form, self).__init__()

        self.model = model
        self.res_id = res_id
        self.mode = attributes.get('mode')
        self.view_ids = attributes.get('view_ids')
        self.dialogs = []

        self.screen = Screen(self.model, **attributes)
        self.screen.widget.show()

        self.name = name

        self.create_tabcontent()

        self.set_buttons_sensitive()

        self.screen.signal_connect(self, 'record-message',
                                   self._record_message)

        self.screen.signal_connect(
            self, 'record-modified',
            lambda *a: gobject.idle_add(self._record_modified, *a))
        self.screen.signal_connect(self, 'record-saved', self._record_saved)
        self.screen.signal_connect(self, 'attachment-count',
                                   self._attachment_count)
        self.screen.signal_connect(self, 'unread-note', self._unread_note)

        if res_id not in (None, False):
            if isinstance(res_id, (int, long)):
                res_id = [res_id]
            self.screen.load(res_id)
        else:
            if self.screen.current_view.view_type == 'form':
                self.sig_new(None, autosave=False)
            if self.screen.current_view.view_type \
                    in ('tree', 'graph', 'calendar'):
                self.screen.search_filter()

        self.update_revision()

    def get_toolbars(self):
        try:
            return RPCExecute('model',
                              self.model,
                              'view_toolbar_get',
                              context=self.screen.context)
        except RPCException:
            return {}

    def widget_get(self):
        return self.screen.widget

    def __eq__(self, value):
        if not value:
            return False
        if not isinstance(value, Form):
            return False
        return (self.model == value.model and self.res_id == value.res_id
                and self.screen.domain == value.screen.domain
                and self.mode == value.mode and self.view_ids == value.view_ids
                and self.screen.context == value.screen.context
                and self.name == value.name
                and self.screen.limit == value.screen.limit
                and self.screen.search_value == value.screen.search_value)

    def destroy(self):
        super(Form, self).destroy()
        self.screen.signal_unconnect(self)
        self.screen.destroy()

    def sig_attach(self, widget=None):
        record = self.screen.current_record
        if not record or record.id < 0:
            return
        Attachment(record, lambda: self.update_attachment_count(reload=True))

    def update_attachment_count(self, reload=False):
        record = self.screen.current_record
        if record:
            attachment_count = record.get_attachment_count(reload=reload)
        else:
            attachment_count = 0
        self._attachment_count(None, attachment_count)

    def _attachment_count(self, widget, signal_data):
        label = _('Attachment(%d)') % signal_data
        self.buttons['attach'].set_label(label)
        if signal_data:
            self.buttons['attach'].set_stock_id('tryton-attachment-hi')
        else:
            self.buttons['attach'].set_stock_id('tryton-attachment')
        record = self.screen.current_record
        self.buttons['attach'].props.sensitive = bool(
            record.id >= 0 if record else False)

    def sig_note(self, widget=None):
        record = self.screen.current_record
        if not record or record.id < 0:
            return
        Note(record, lambda: self.update_unread_note(reload=True))

    def update_unread_note(self, reload=False):
        record = self.screen.current_record
        if record:
            unread = record.get_unread_note(reload=reload)
        else:
            unread = 0
        self._unread_note(None, unread)

    def _unread_note(self, widget, signal_data):
        label = _('Note(%d)') % signal_data
        self.buttons['note'].set_label(label)
        if signal_data:
            self.buttons['note'].set_stock_id('tryton-note-hi')
        else:
            self.buttons['note'].set_stock_id('tryton-note')
        record = self.screen.current_record
        if not record or record.id < 0:
            sensitive = False
        else:
            sensitive = True
        self.buttons['note'].props.sensitive = sensitive

    def sig_switch(self, widget=None):
        if not self.modified_save():
            return
        self.screen.switch_view()

    def sig_logs(self, widget=None):
        current_record = self.screen.current_record
        if not current_record or current_record.id < 0:
            self.message_info(_('You have to select one record.'),
                              gtk.MESSAGE_INFO)
            return False

        fields = [
            ('id', _('ID:')),
            ('create_uid.rec_name', _('Creation User:'******'create_date', _('Creation Date:')),
            ('write_uid.rec_name', _('Latest Modification by:')),
            ('write_date', _('Latest Modification Date:')),
        ]

        try:
            res = RPCExecute('model',
                             self.model,
                             'read', [current_record.id],
                             [x[0] for x in fields],
                             context=self.screen.context)
        except RPCException:
            return
        date_format = self.screen.context.get('date_format', '%x')
        datetime_format = date_format + ' %H:%M:%S.%f'
        message_str = ''
        for line in res:
            for (key, val) in fields:
                value = str(line.get(key, False) or '/')
                if line.get(key, False) \
                        and key in ('create_date', 'write_date'):
                    date = timezoned_date(line[key])
                    value = common.datetime_strftime(date, datetime_format)
                message_str += val + ' ' + value + '\n'
        message_str += _('Model:') + ' ' + self.model
        message(message_str)
        return True

    def sig_revision(self, widget=None):
        if not self.modified_save():
            return
        current_id = (self.screen.current_record.id
                      if self.screen.current_record else None)
        try:
            revisions = RPCExecute(
                'model', self.model, 'history_revisions',
                [r.id for r in self.screen.selected_records])
        except RPCException:
            return
        revision = self.screen.context.get('_datetime')
        format_ = self.screen.context.get('date_format', '%x')
        format_ += ' %H:%M:%S.%f'
        revision = Revision(revisions, revision, format_).run()
        # Prevent too old revision in form view
        if (self.screen.current_view.view_type == 'form' and revision
                and revision < revisions[-1][0]):
            revision = revisions[-1][0]
        if revision != self.screen.context.get('_datetime'):
            self.screen.clear()
            # Update root group context that will be propagated
            self.screen.group._context['_datetime'] = revision
            if self.screen.current_view.view_type != 'form':
                self.screen.search_filter(
                    self.screen.screen_container.get_text())
            else:
                # Test if record exist in revisions
                self.screen.load([current_id])
            self.screen.display(set_cursor=True)
            self.update_revision()

    def update_revision(self):
        revision = self.screen.context.get('_datetime')
        if revision:
            format_ = self.screen.context.get('date_format', '%x')
            format_ += ' %H:%M:%S.%f'
            revision = datetime_strftime(revision, format_)
            self.title.set_label('%s @ %s' % (self.name, revision))
        else:
            self.title.set_label(self.name)
        self.set_buttons_sensitive(revision)

    def set_buttons_sensitive(self, revision=None):
        if not revision:
            access = common.MODELACCESS[self.model]
            for name, sensitive in [
                ('new', access['create']),
                ('save', access['create'] or access['write']),
                ('remove', access['delete']),
                ('copy', access['create']),
                ('import', access['create']),
            ]:
                if name in self.buttons:
                    self.buttons[name].props.sensitive = sensitive
                if name in self.menu_buttons:
                    self.menu_buttons[name].props.sensitive = sensitive
        else:
            for name in ['new', 'save', 'remove', 'copy', 'import']:
                if name in self.buttons:
                    self.buttons[name].props.sensitive = False
                if name in self.menu_buttons:
                    self.menu_buttons[name].props.sensitive = False

    def sig_remove(self, widget=None):
        if not common.MODELACCESS[self.model]['delete']:
            return
        if self.screen.current_view.view_type == 'form':
            msg = _('Are you sure to remove this record?')
        else:
            msg = _('Are you sure to remove those records?')
        if sur(msg):
            if not self.screen.remove(delete=True, force_remove=True):
                self.message_info(_('Records not removed.'), gtk.MESSAGE_ERROR)
            else:
                self.message_info(_('Records removed.'), gtk.MESSAGE_INFO)
                self.screen.count_tab_domain()

    def sig_import(self, widget=None):
        WinImport(self.model, self.screen.context)

    def sig_export(self, widget=None):
        export = WinExport(self.model,
                           [r.id for r in self.screen.selected_records],
                           context=self.screen.context)
        for name in self.screen.current_view.get_fields():
            export.sel_field(name)

    def sig_new(self, widget=None, autosave=True):
        if not common.MODELACCESS[self.model]['create']:
            return
        if autosave:
            if not self.modified_save():
                return
        self.screen.new()
        self.message_info()
        self.activate_save()

    def sig_copy(self, widget=None):
        if not common.MODELACCESS[self.model]['create']:
            return
        if not self.modified_save():
            return
        if self.screen.copy():
            self.message_info(_('Working now on the duplicated record(s).'),
                              gtk.MESSAGE_INFO)
            self.screen.count_tab_domain()

    def sig_save(self, widget=None):
        if widget:
            # Called from button so we must save the tree state
            self.screen.save_tree_state()
        if not (common.MODELACCESS[self.model]['write']
                or common.MODELACCESS[self.model]['create']):
            return
        if self.screen.save_current():
            self.message_info(_('Record saved.'), gtk.MESSAGE_INFO)
            self.screen.count_tab_domain()
            return True
        else:
            self.message_info(self.screen.invalid_message(), gtk.MESSAGE_ERROR)
            return False

    def sig_previous(self, widget=None):
        if not self.modified_save():
            return
        self.screen.display_prev()
        self.message_info()
        self.activate_save()

    def sig_next(self, widget=None):
        if not self.modified_save():
            return
        self.screen.display_next()
        self.message_info()
        self.activate_save()

    def sig_reload(self, test_modified=True):
        if test_modified:
            if not self.modified_save():
                return False
        else:
            self.screen.save_tree_state(store=False)
        self.screen.cancel_current()
        set_cursor = False
        record_id = (self.screen.current_record.id
                     if self.screen.current_record else None)
        if self.screen.current_view.view_type != 'form':
            self.screen.search_filter(self.screen.screen_container.get_text())
            for record in self.screen.group:
                if record.id == record_id:
                    self.screen.current_record = record
                    set_cursor = True
                    break
        self.screen.display(set_cursor=set_cursor)
        self.message_info()
        self.activate_save()
        self.screen.count_tab_domain()
        return True

    def sig_action(self, widget):
        if self.buttons['action'].props.sensitive:
            self.buttons['action'].props.active = True

    def sig_print(self, widget):
        if self.buttons['print'].props.sensitive:
            self.buttons['print'].props.active = True

    def sig_print_open(self, widget):
        if self.buttons['open'].props.sensitive:
            self.buttons['open'].props.active = True

    def sig_print_email(self, widget):
        if self.buttons['email'].props.sensitive:
            self.buttons['email'].props.active = True

    def sig_relate(self, widget):
        if self.buttons['relate'].props.sensitive:
            self.buttons['relate'].props.active = True

    def sig_copy_url(self, widget):
        if self.buttons['copy_url'].props.sensitive:
            self.buttons['copy_url'].props.active = True

    def sig_search(self, widget):
        search_container = self.screen.screen_container
        if hasattr(search_container, 'search_entry'):
            search_container.search_entry.grab_focus()

    def action_popup(self, widget):
        button, = widget.get_children()
        button.grab_focus()
        menu = widget._menu
        if not widget.props.active:
            menu.popdown()
            return

        def menu_position(menu, data):
            widget_allocation = widget.get_allocation()
            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()
                x += widget_allocation.x
                y += widget_allocation.y
            return (x, y + widget_allocation.height, False)

        menu.show_all()
        menu.popup(None, None, menu_position, 0, gtk.get_current_event_time(),
                   None)

    def _record_message(self, screen, signal_data):
        name = '_'
        if signal_data[0]:
            name = str(signal_data[0])
        for button_id in ('print', 'relate', 'email', 'open', 'save',
                          'attach'):
            button = self.buttons[button_id]
            can_be_sensitive = getattr(button, '_can_be_sensitive', True)
            button.props.sensitive = (bool(signal_data[0])
                                      and can_be_sensitive)
        button_switch = self.buttons['switch']
        button_switch.props.sensitive = self.screen.number_of_views > 1

        msg = name + ' / ' + str(signal_data[1])
        if signal_data[1] < signal_data[2]:
            msg += _(' of ') + str(signal_data[2])
        self.status_label.set_text(msg)
        self.message_info()
        self.activate_save()

    def _record_modified(self, screen, signal_data):
        # As it is called via idle_add, the form could have been destroyed in
        # the meantime.
        if self.widget_get().props.window:
            self.activate_save()

    def _record_saved(self, screen, signal_data):
        self.activate_save()
        self.update_attachment_count()

    def modified_save(self):
        self.screen.save_tree_state()
        self.screen.current_view.set_value()
        if self.screen.modified():
            value = sur_3b(
                _('This record has been modified\n'
                  'do you want to save it?'))
            if value == 'ok':
                return self.sig_save(None)
            if value == 'ko':
                return self.sig_reload(test_modified=False)
            return False
        return True

    def sig_close(self, widget=None):
        for dialog in self.dialogs[:]:
            dialog.destroy()
        return self.modified_save()

    def _action(self, action, atype):
        action = action.copy()
        if not self.screen.save_current():
            return
        record_id = (self.screen.current_record.id
                     if self.screen.current_record else None)
        record_ids = [r.id for r in self.screen.selected_records]
        action = Action.evaluate(action, atype, self.screen.current_record)
        data = {
            'model': self.screen.model_name,
            'id': record_id,
            'ids': record_ids,
        }
        Action._exec_action(action, data, self.screen.context)

    def activate_save(self):
        self.buttons['save'].props.sensitive = self.screen.modified()

    def sig_win_close(self, widget):
        Main.get_main().sig_win_close(widget)

    def create_toolbar(self, toolbars):
        gtktoolbar = super(Form, self).create_toolbar(toolbars)

        attach_btn = self.buttons['attach']
        target_entry = gtk.TargetEntry.new('text/uri-list', 0, 0)
        attach_btn.drag_dest_set(gtk.DEST_DEFAULT_ALL, [
            target_entry,
        ], gtk.gdk.ACTION_MOVE | gtk.gdk.ACTION_COPY)
        attach_btn.connect('drag_data_received',
                           self.attach_drag_data_received)

        iconstock = {
            'print': 'tryton-print',
            'action': 'tryton-executable',
            'relate': 'tryton-go-jump',
            'email': 'tryton-print-email',
            'open': 'tryton-print-open',
        }
        for action_type, special_action, action_name, tooltip in (
            ('action', 'action', _('Action'), _('Launch action')),
            ('relate', 'relate', _('Relate'), _('Open related records')),
            (None, ) * 4,
            ('print', 'open', _('Report'), _('Open report')),
            ('print', 'email', _('E-Mail'), _('E-Mail report')),
            ('print', 'print', _('Print'), _('Print report')),
        ):
            if action_type is not None:
                tbutton = gtk.ToggleToolButton(iconstock.get(special_action))
                tbutton.set_label(action_name)
                tbutton._menu = self._create_popup_menu(
                    tbutton, action_type, toolbars[action_type],
                    special_action)
                tbutton.connect('toggled', self.action_popup)
                self.tooltips.set_tip(tbutton, tooltip)
                self.buttons[special_action] = tbutton
                if action_type != 'action':
                    tbutton._can_be_sensitive = bool(
                        tbutton._menu.get_children())
            else:
                tbutton = gtk.SeparatorToolItem()
            gtktoolbar.insert(tbutton, -1)

        gtktoolbar.insert(gtk.SeparatorToolItem(), -1)

        url_button = gtk.ToggleToolButton('tryton-web-browser')
        url_button.set_label(_('_Copy URL'))
        url_button.set_use_underline(True)
        self.tooltips.set_tip(url_button, _('Copy URL into clipboard'))
        url_button._menu = url_menu = gtk.Menu()
        url_menuitem = gtk.MenuItem()
        url_menuitem.connect('activate', self.url_copy)
        url_menu.add(url_menuitem)
        url_menu.show_all()
        url_menu.connect('deactivate', self._popup_menu_hide, url_button)
        url_button.connect('toggled', self.url_set, url_menuitem)
        url_button.connect('toggled', self.action_popup)
        self.buttons['copy_url'] = url_button
        gtktoolbar.insert(url_button, -1)
        return gtktoolbar

    def _create_popup_menu(self, widget, keyword, actions, special_action):
        menu = gtk.Menu()
        menu.connect('deactivate', self._popup_menu_hide, widget)
        widget.connect('toggled', self._update_popup, menu, special_action)

        for action in actions:
            new_action = action.copy()
            if special_action == 'print':
                new_action['direct_print'] = True
            elif special_action == 'email':
                new_action['email_print'] = True
            action_name = action['name']
            if '_' not in action_name:
                action_name = '_' + action_name
            menuitem = gtk.MenuItem(action_name)
            menuitem.set_use_underline(True)
            menuitem.connect('activate', self._popup_menu_selected, widget,
                             new_action, keyword)
            menu.add(menuitem)
        return menu

    def _popup_menu_selected(self, menuitem, togglebutton, action, keyword):
        event = gtk.get_current_event()
        allow_similar = False
        if (event.state & gtk.gdk.CONTROL_MASK
                or event.state & gtk.gdk.MOD1_MASK):
            allow_similar = True
        with Window(hide_current=True, allow_similar=allow_similar):
            self._action(action, keyword)
        togglebutton.props.active = False

    def _popup_menu_hide(self, menuitem, togglebutton):
        togglebutton.props.active = False

    def _update_popup(self, tbutton, menu, keyword):
        assert keyword in ['print', 'action', 'relate', 'email', 'open']
        for item in menu.get_children():
            if (getattr(item, '_update_action', False)
                    or isinstance(item, gtk.SeparatorMenuItem)):
                menu.remove(item)

        buttons = [
            button for button in self.screen.get_buttons()
            if keyword in button.attrs.get('keywords', 'action').split(',')
        ]
        if buttons:
            menu.add(gtk.SeparatorMenuItem())
        for button in buttons:
            menuitem = gtk.ImageMenuItem()
            menuitem.set_label('_' + button.attrs.get('string', _('Unknown')))
            menuitem.set_use_underline(True)
            if button.attrs.get('icon'):
                icon = gtk.Image()
                icon.set_from_stock(button.attrs['icon'], gtk.ICON_SIZE_MENU)
                menuitem.set_image(icon)
            menuitem.connect('activate',
                             lambda m, attrs: self.screen.button(attrs),
                             button.attrs)
            menuitem._update_action = True
            menu.add(menuitem)

        if keyword == 'action':
            menu.add(gtk.SeparatorMenuItem())
            for plugin in plugins.MODULES:
                for name, func in plugin.get_plugins(self.model):
                    menuitem = gtk.MenuItem('_' + name)
                    menuitem.set_use_underline(True)
                    menuitem.connect(
                        'activate', lambda m, func: func({
                            'model':
                            self.model,
                            'ids':
                            [r.id for r in self.screen.selected_records],
                            'id': (self.screen.current_record.id
                                   if self.screen.current_record else None),
                        }), func)
                    menuitem._update_action = True
                    menu.add(menuitem)

    def url_copy(self, menuitem):
        url = self.screen.get_url(self.name)
        for selection in [gtk.CLIPBOARD_PRIMARY, gtk.CLIPBOARD_CLIPBOARD]:
            clipboard = gtk.clipboard_get(selection)
            clipboard.set_text(url, -1)

    def url_set(self, button, menuitem):
        url = self.screen.get_url(self.name)
        size = 80
        if len(url) > size:
            url = url[:size // 2] + '...' + url[-size // 2:]
        menuitem.set_label(url)

    def set_cursor(self):
        if self.screen:
            self.screen.set_cursor(reset_view=False)

    def attach_drag_data_received(self, widget, context, x, y, selection, info,
                                  timestamp):
        record = self.screen.current_record
        if not record or record.id < 0:
            return
        win_attach = Attachment(
            record, lambda: self.update_attachment_count(reload=True))
        if info == 0:
            for uri in selection.data.splitlines():
                # Win32 cut&paste terminates the list with a NULL character
                if not uri or uri == '\0':
                    continue
                win_attach.add_uri(uri)
Exemplo n.º 48
0
    def __init__(self, view, attrs):
        super(One2Many, self).__init__(view, attrs)

        self.widget = gtk.Frame()
        self.widget.set_shadow_type(gtk.SHADOW_NONE)
        self.widget.get_accessible().set_name(attrs.get("string", ""))
        vbox = gtk.VBox(homogeneous=False, spacing=2)
        self.widget.add(vbox)
        self._readonly = True
        self._position = 0
        self._length = 0

        self.title_box = hbox = gtk.HBox(homogeneous=False, spacing=0)
        hbox.set_border_width(2)

        label = gtk.Label(attrs.get("string", ""))
        label.set_alignment(0.0, 0.5)
        hbox.pack_start(label, expand=True, fill=True)

        hbox.pack_start(gtk.VSeparator(), expand=False, fill=True)

        tooltips = common.Tooltips()

        self.focus_out = True
        self.wid_completion = None
        if attrs.get("add_remove"):

            self.wid_text = PlaceholderEntry()
            self.wid_text.set_placeholder_text(_("Search"))
            self.wid_text.set_property("width_chars", 13)
            self.wid_text.connect("focus-out-event", lambda *a: self._focus_out())
            hbox.pack_start(self.wid_text, expand=True, fill=True)

            if int(self.attrs.get("completion", 1)):
                access = common.MODELACCESS[attrs["relation"]]
                self.wid_completion = get_completion(
                    search=access["read"] and access["write"], create=attrs.get("create", True) and access["create"]
                )
                self.wid_completion.connect("match-selected", self._completion_match_selected)
                self.wid_completion.connect("action-activated", self._completion_action_activated)
                self.wid_text.set_completion(self.wid_completion)
                self.wid_text.connect("changed", self._update_completion)

            self.but_add = gtk.Button()
            tooltips.set_tip(self.but_add, _("Add existing record"))
            self.but_add.connect("clicked", self._sig_add)
            img_add = gtk.Image()
            img_add.set_from_stock("tryton-list-add", gtk.ICON_SIZE_SMALL_TOOLBAR)
            img_add.set_alignment(0.5, 0.5)
            self.but_add.add(img_add)
            self.but_add.set_relief(gtk.RELIEF_NONE)
            hbox.pack_start(self.but_add, expand=False, fill=False)

            self.but_remove = gtk.Button()
            tooltips.set_tip(self.but_remove, _("Remove selected record"))
            self.but_remove.connect("clicked", self._sig_remove, True)
            img_remove = gtk.Image()
            img_remove.set_from_stock("tryton-list-remove", gtk.ICON_SIZE_SMALL_TOOLBAR)
            img_remove.set_alignment(0.5, 0.5)
            self.but_remove.add(img_remove)
            self.but_remove.set_relief(gtk.RELIEF_NONE)
            hbox.pack_start(self.but_remove, expand=False, fill=False)

            hbox.pack_start(gtk.VSeparator(), expand=False, fill=True)

        self.but_new = gtk.Button()
        tooltips.set_tip(self.but_new, _("Create a new record <F3>"))
        self.but_new.connect("clicked", self._sig_new)
        img_new = gtk.Image()
        img_new.set_from_stock("tryton-new", gtk.ICON_SIZE_SMALL_TOOLBAR)
        img_new.set_alignment(0.5, 0.5)
        self.but_new.add(img_new)
        self.but_new.set_relief(gtk.RELIEF_NONE)
        hbox.pack_start(self.but_new, expand=False, fill=False)

        self.but_open = gtk.Button()
        tooltips.set_tip(self.but_open, _("Edit selected record <F2>"))
        self.but_open.connect("clicked", self._sig_edit)
        img_open = gtk.Image()
        img_open.set_from_stock("tryton-open", gtk.ICON_SIZE_SMALL_TOOLBAR)
        img_open.set_alignment(0.5, 0.5)
        self.but_open.add(img_open)
        self.but_open.set_relief(gtk.RELIEF_NONE)
        hbox.pack_start(self.but_open, expand=False, fill=False)

        self.but_del = gtk.Button()
        tooltips.set_tip(self.but_del, _("Delete selected record <Del>"))
        self.but_del.connect("clicked", self._sig_remove, False)
        img_del = gtk.Image()
        img_del.set_from_stock("tryton-delete", gtk.ICON_SIZE_SMALL_TOOLBAR)
        img_del.set_alignment(0.5, 0.5)
        self.but_del.add(img_del)
        self.but_del.set_relief(gtk.RELIEF_NONE)
        hbox.pack_start(self.but_del, expand=False, fill=False)

        self.but_undel = gtk.Button()
        tooltips.set_tip(self.but_undel, _("Undelete selected record <Ins>"))
        self.but_undel.connect("clicked", self._sig_undelete)
        img_undel = gtk.Image()
        img_undel.set_from_stock("tryton-undo", gtk.ICON_SIZE_SMALL_TOOLBAR)
        img_undel.set_alignment(0.5, 0.5)
        self.but_undel.add(img_undel)
        self.but_undel.set_relief(gtk.RELIEF_NONE)
        hbox.pack_start(self.but_undel, expand=False, fill=False)

        hbox.pack_start(gtk.VSeparator(), expand=False, fill=True)

        self.but_pre = gtk.Button()
        tooltips.set_tip(self.but_pre, _("Previous"))
        self.but_pre.connect("clicked", self._sig_previous)
        img_pre = gtk.Image()
        img_pre.set_from_stock("tryton-go-previous", gtk.ICON_SIZE_SMALL_TOOLBAR)
        img_pre.set_alignment(0.5, 0.5)
        self.but_pre.add(img_pre)
        self.but_pre.set_relief(gtk.RELIEF_NONE)
        hbox.pack_start(self.but_pre, expand=False, fill=False)

        self.label = gtk.Label("(0,0)")
        hbox.pack_start(self.label, expand=False, fill=False)

        self.but_next = gtk.Button()
        tooltips.set_tip(self.but_next, _("Next"))
        self.but_next.connect("clicked", self._sig_next)
        img_next = gtk.Image()
        img_next.set_from_stock("tryton-go-next", gtk.ICON_SIZE_SMALL_TOOLBAR)
        img_next.set_alignment(0.5, 0.5)
        self.but_next.add(img_next)
        self.but_next.set_relief(gtk.RELIEF_NONE)
        hbox.pack_start(self.but_next, expand=False, fill=False)

        hbox.pack_start(gtk.VSeparator(), expand=False, fill=True)

        but_switch = gtk.Button()
        tooltips.set_tip(but_switch, _("Switch"))
        but_switch.connect("clicked", self.switch_view)
        img_switch = gtk.Image()
        img_switch.set_from_stock("tryton-fullscreen", gtk.ICON_SIZE_SMALL_TOOLBAR)
        img_switch.set_alignment(0.5, 0.5)
        but_switch.add(img_switch)
        but_switch.set_relief(gtk.RELIEF_NONE)
        hbox.pack_start(but_switch, expand=False, fill=False)

        if attrs.get("add_remove"):
            hbox.set_focus_chain([self.wid_text])
        else:
            hbox.set_focus_chain([])

        tooltips.enable()

        frame = gtk.Frame()
        frame.add(hbox)

        if attrs.get("expand_toolbar"):
            frame.set_shadow_type(gtk.SHADOW_NONE)
        else:
            frame.set_shadow_type(gtk.SHADOW_OUT)
            vbox.pack_start(frame, expand=False, fill=True)

        self.screen = Screen(
            attrs["relation"],
            mode=attrs.get("mode", "tree,form").split(","),
            view_ids=attrs.get("view_ids", "").split(","),
            views_preload=attrs.get("views", {}),
            row_activate=self._on_activate,
            readonly=self.attrs.get("readonly", False),
            exclude_field=attrs.get("relation_field", None),
        )
        self.screen.pre_validate = bool(int(attrs.get("pre_validate", 0)))
        self.screen.signal_connect(self, "record-message", self._sig_label)
        if self.attrs.get("group"):
            self.screen.signal_connect(
                self,
                "current-record-changed",
                lambda screen, _: gobject.idle_add(self.group_sync, screen, screen.current_record),
            )

        vbox.pack_start(self.screen.widget, expand=True, fill=True)

        self.screen.widget.connect("key_press_event", self.on_keypress)
        if self.attrs.get("add_remove"):
            self.wid_text.connect("key_press_event", self.on_keypress)

        but_switch.props.sensitive = self.screen.number_of_views > 1
Exemplo n.º 49
0
class WinSearch(NoModal):

    def __init__(self, model, callback, sel_multi=True, context=None,
            domain=None, order=None, view_ids=None,
            views_preload=None, new=True, title='', exclude_field=None):
        NoModal.__init__(self)
        if view_ids is None:
            view_ids = []
        if views_preload is None:
            views_preload = {}
        self.domain = domain or []
        self.context = context or {}
        self.order = order
        self.view_ids = view_ids
        self.views_preload = views_preload
        self.sel_multi = sel_multi
        self.callback = callback
        self.title = title
        self.exclude_field = exclude_field

        self.win = Gtk.Dialog(
            title=_('Search'), transient_for=self.parent,
            destroy_with_parent=True)
        Main().add_window(self.win)
        self.win.set_icon(TRYTON_ICON)
        self.win.set_position(Gtk.WindowPosition.CENTER_ON_PARENT)
        self.win.set_default_response(Gtk.ResponseType.APPLY)
        self.win.connect('response', self.response)

        self.win.set_default_size(*self.default_size())

        self.accel_group = Gtk.AccelGroup()
        self.win.add_accel_group(self.accel_group)

        self.but_cancel = self.win.add_button(
            set_underline(_("Cancel")), Gtk.ResponseType.CANCEL)
        self.but_cancel.set_image(common.IconFactory.get_image(
                'tryton-cancel', Gtk.IconSize.BUTTON))
        self.but_cancel.set_always_show_image(True)
        self.but_find = self.win.add_button(
            set_underline(_("Search")), Gtk.ResponseType.APPLY)
        self.but_find.set_image(common.IconFactory.get_image(
                'tryton-search', Gtk.IconSize.BUTTON))
        self.but_find.set_always_show_image(True)
        if new and common.MODELACCESS[model]['create']:
            self.but_new = self.win.add_button(
                set_underline(_("New")), Gtk.ResponseType.ACCEPT)
            self.but_new.set_image(common.IconFactory.get_image(
                    'tryton-create', Gtk.IconSize.BUTTON))
            self.but_new.set_always_show_image(True)
            self.but_new.set_accel_path('<tryton>/Form/New', self.accel_group)

        self.but_ok = self.win.add_button(
            set_underline(_("OK")), Gtk.ResponseType.OK)
        self.but_ok.set_image(common.IconFactory.get_image(
                'tryton-ok', Gtk.IconSize.BUTTON))
        self.but_ok.set_always_show_image(True)
        self.but_ok.add_accelerator(
            'clicked', self.accel_group, Gdk.KEY_Return,
            Gdk.ModifierType.CONTROL_MASK, Gtk.AccelFlags.VISIBLE)

        hbox = Gtk.HBox()
        hbox.show()
        self.win.vbox.pack_start(hbox, expand=False, fill=True, padding=0)
        self.win.vbox.pack_start(
            Gtk.HSeparator(), expand=False, fill=True, padding=0)

        self.screen = Screen(model, domain=domain, mode=['tree'], order=order,
            context=context, view_ids=view_ids, views_preload=views_preload,
            row_activate=self.sig_activate, readonly=True)
        self.view = self.screen.current_view
        # Prevent to set tree_state
        self.screen.tree_states_done.add(id(self.view))
        sel = self.view.treeview.get_selection()
        self.win.set_title(_('Search %s') % self.title)

        if not sel_multi:
            sel.set_mode(Gtk.SelectionMode.SINGLE)
        else:
            sel.set_mode(Gtk.SelectionMode.MULTIPLE)
        self.win.vbox.pack_start(
            self.screen.widget, expand=True, fill=True, padding=0)
        self.screen.widget.show()

        self.model_name = model

        self.register()

    def sig_activate(self, *args):
        self.view.treeview.stop_emission_by_name('row_activated')
        self.win.response(Gtk.ResponseType.OK)
        return True

    def destroy(self):
        self.screen.destroy()
        self.win.destroy()
        NoModal.destroy(self)

    def show(self):
        self.win.show()

    def hide(self):
        self.win.hide()

    def response(self, win, response_id):
        res = None
        if response_id == Gtk.ResponseType.OK:
            res = [r.id for r in self.screen.selected_records]
        elif response_id == Gtk.ResponseType.APPLY:
            self.screen.search_filter(self.screen.screen_container.get_text())
            return
        elif response_id == Gtk.ResponseType.ACCEPT:
            # Remove first tree view as mode if form only
            view_ids = self.view_ids[1:]
            screen = Screen(self.model_name, domain=self.domain,
                context=self.context, order=self.order, mode=['form'],
                view_ids=view_ids, views_preload=self.views_preload,
                exclude_field=self.exclude_field)

            def callback(result):
                if result:
                    record = screen.current_record
                    res = [(record.id, record.value.get('rec_name', ''))]
                    self.callback(res)
                else:
                    self.callback(None)
            self.destroy()
            WinForm(
                screen, callback, new=True, save_current=True,
                title=self.title)
            return
        if res:
            group = self.screen.group
            res = [(id_, group.get(id_).value.get('rec_name', ''))
                for id_ in res]
        self.callback(res)
        self.destroy()
Exemplo n.º 50
0
class Many2Many(Widget):
    expand = True

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

        self.widget = gtk.Frame()
        self.widget.set_shadow_type(gtk.SHADOW_NONE)
        self.widget.get_accessible().set_name(attrs.get('string', ''))
        vbox = gtk.VBox(homogeneous=False, spacing=5)
        self.widget.add(vbox)
        self._readonly = True
        self._position = 0

        hbox = gtk.HBox(homogeneous=False, spacing=0)
        hbox.set_border_width(2)

        label = gtk.Label(attrs.get('string', ''))
        label.set_alignment(0.0, 0.5)
        hbox.pack_start(label, expand=True, fill=True)

        hbox.pack_start(gtk.VSeparator(), expand=False, fill=True)

        tooltips = common.Tooltips()

        self.wid_text = PlaceholderEntry()
        self.wid_text.set_placeholder_text(_('Search'))
        self.wid_text.set_property('width_chars', 13)
        self.wid_text.connect('focus-out-event', lambda *a: self._focus_out())
        self.focus_out = True
        hbox.pack_start(self.wid_text, expand=True, fill=True)

        if int(self.attrs.get('completion', 1)):
            self.wid_completion = get_completion(
                create=self.attrs.get('create', True)
                and common.MODELACCESS[self.attrs['relation']]['create'])
            self.wid_completion.connect('match-selected',
                self._completion_match_selected)
            self.wid_completion.connect('action-activated',
                self._completion_action_activated)
            self.wid_text.set_completion(self.wid_completion)
            self.wid_text.connect('changed', self._update_completion)
        else:
            self.wid_completion = None

        self.but_add = gtk.Button()
        tooltips.set_tip(self.but_add, _('Add existing record'))
        self.but_add.connect('clicked', self._sig_add)
        img_add = gtk.Image()
        img_add.set_from_stock('tryton-list-add',
            gtk.ICON_SIZE_SMALL_TOOLBAR)
        img_add.set_alignment(0.5, 0.5)
        self.but_add.add(img_add)
        self.but_add.set_relief(gtk.RELIEF_NONE)
        hbox.pack_start(self.but_add, expand=False, fill=False)

        self.but_remove = gtk.Button()
        tooltips.set_tip(self.but_remove, _('Remove selected record <Del>'))
        self.but_remove.connect('clicked', self._sig_remove)
        img_remove = gtk.Image()
        img_remove.set_from_stock('tryton-list-remove',
            gtk.ICON_SIZE_SMALL_TOOLBAR)
        img_remove.set_alignment(0.5, 0.5)
        self.but_remove.add(img_remove)
        self.but_remove.set_relief(gtk.RELIEF_NONE)
        hbox.pack_start(self.but_remove, expand=False, fill=False)

        hbox.set_focus_chain([self.wid_text])

        tooltips.enable()

        frame = gtk.Frame()
        frame.add(hbox)
        if attrs.get('expand_toolbar'):
            frame.set_shadow_type(gtk.SHADOW_NONE)
        else:
            frame.set_shadow_type(gtk.SHADOW_OUT)
            vbox.pack_start(frame, expand=False, fill=True)

        self.screen = Screen(attrs['relation'],
            view_ids=attrs.get('view_ids', '').split(','),
            mode=['tree'], views_preload=attrs.get('views', {}),
            row_activate=self._on_activate)
        self.screen.signal_connect(self, 'record-message', self._sig_label)

        vbox.pack_start(self.screen.widget, expand=True, fill=True)

        self.screen.widget.connect('key_press_event', self.on_keypress)
        self.wid_text.connect('key_press_event', self.on_keypress)

    def _color_widget(self):
        if hasattr(self.screen.current_view, 'treeview'):
            return self.screen.current_view.treeview
        return super(Many2Many, self)._color_widget()

    def on_keypress(self, widget, event):
        editable = self.wid_text.get_editable()
        activate_keys = [gtk.keysyms.Tab, gtk.keysyms.ISO_Left_Tab]
        remove_keys = [gtk.keysyms.Delete, gtk.keysyms.KP_Delete]
        if not self.wid_completion:
            activate_keys.append(gtk.keysyms.Return)
        if widget == self.screen.widget:
            if event.keyval == gtk.keysyms.F3 and editable:
                self._sig_add()
                return True
            elif event.keyval == gtk.keysyms.F2:
                self._sig_edit()
                return True
            elif event.keyval in remove_keys and editable:
                self._sig_remove()
                return True
        elif widget == self.wid_text:
            if event.keyval == gtk.keysyms.F3:
                self._sig_new()
                return True
            elif event.keyval == gtk.keysyms.F2:
                self._sig_add()
                return True
            elif event.keyval in activate_keys and self.wid_text.get_text():
                self._sig_add()
                self.wid_text.grab_focus()
        return False

    def destroy(self):
        self.screen.destroy()

    def color_set(self, name):
        super(Many2Many, self).color_set(name)
        widget = self._color_widget()
        # if the style to apply is different from readonly then insensitive
        # cellrenderers should use the default insensitive color
        if name != 'readonly':
            widget.modify_text(gtk.STATE_INSENSITIVE,
                    self.colors['text_color_insensitive'])

    def _sig_add(self, *args):
        if not self.focus_out:
            return
        domain = self.field.domain_get(self.record)
        add_remove = self.record.expr_eval(self.attrs.get('add_remove'))
        if add_remove:
            domain = [domain, add_remove]
        context = self.field.context_get(self.record)
        value = self.wid_text.get_text().decode('utf-8')

        self.focus_out = False

        def callback(result):
            self.focus_out = True
            if result:
                ids = [x[0] for x in result]
                self.screen.load(ids, modified=True)
                self.screen.display(res_id=ids[0])
            self.screen.set_cursor()
            self.wid_text.set_text('')
        win = WinSearch(self.attrs['relation'], callback, sel_multi=True,
            context=context, domain=domain,
            view_ids=self.attrs.get('view_ids', '').split(','),
            views_preload=self.attrs.get('views', {}),
            new=self.attrs.get('create', True))
        win.screen.search_filter(quote(value))
        win.show()

    def _sig_remove(self, *args):
        self.screen.remove(remove=True)

    def _on_activate(self):
        self._sig_edit()

    def _sig_edit(self):
        if not self.screen.current_record:
            return
        # Create a new screen that is not linked to the parent otherwise on the
        # save of the record will trigger the save of the parent
        domain = self.field.domain_get(self.record)
        add_remove = self.record.expr_eval(self.attrs.get('add_remove'))
        if add_remove:
            domain = [domain, add_remove]
        context = self.field.context_get(self.record)

        screen = Screen(self.attrs['relation'], domain=domain,
            view_ids=self.attrs.get('view_ids', '').split(','),
            mode=['form'], views_preload=self.attrs.get('views', {}),
            readonly=self.attrs.get('readonly', False),
            context=context)
        screen.load([self.screen.current_record.id])

        def callback(result):
            if result:
                screen.current_record.save()
                # Force a reload on next display
                self.screen.current_record.cancel()
                # Force a display to clear the CellCache
                self.screen.display()
        WinForm(screen, callback)

    def _sig_new(self):
        domain = self.field.domain_get(self.record)
        add_remove = self.record.expr_eval(self.attrs.get('add_remove'))
        if add_remove:
            domain = [domain, add_remove]
        context = self.field.context_get(self.record)

        screen = Screen(self.attrs['relation'], domain=domain,
            view_ids=self.attrs.get('view_ids', '').split(','),
            mode=['form'], views_preload=self.attrs.get('views', {}),
            context=context)

        def callback(result):
            self.focus_out = True
            if result:
                record = screen.current_record
                self.screen.load([record.id], modified=True)
            self.wid_text.set_text('')
            self.wid_text.grab_focus()

        self.focus_out = False
        WinForm(screen, callback, new=True, save_current=True)

    def _readonly_set(self, value):
        self._readonly = value
        self._set_button_sensitive()
        self.wid_text.set_sensitive(not value)

    def _set_button_sensitive(self):
        if self.record and self.field:
            field_size = self.record.expr_eval(self.attrs.get('size'))
            m2m_size = len(self.field.get_eval(self.record))
            size_limit = (field_size is not None
                and m2m_size >= field_size >= 0)
        else:
            size_limit = False

        self.but_add.set_sensitive(bool(
                not self._readonly
                and not size_limit))
        self.but_remove.set_sensitive(bool(
                not self._readonly
                and self._position))

    def _sig_label(self, screen, signal_data):
        self._position = signal_data[0]
        self._set_button_sensitive()

    def display(self, record, field):
        super(Many2Many, self).display(record, field)
        if field is None:
            self.screen.new_group()
            self.screen.current_record = None
            self.screen.parent = None
            self.screen.display()
            return False
        new_group = field.get_client(record)
        if id(self.screen.group) != id(new_group):
            self.screen.group = new_group
        self.screen.display()
        return True

    def set_value(self, record, field):
        self.screen.current_view.set_value()
        return True

    def _completion_match_selected(self, completion, model, iter_):
        record_id, = model.get(iter_, 1)
        self.screen.load([record_id], modified=True)
        self.wid_text.set_text('')
        self.wid_text.grab_focus()

        completion_model = self.wid_completion.get_model()
        completion_model.clear()
        completion_model.search_text = self.wid_text.get_text()
        return True

    def _update_completion(self, widget):
        if self._readonly:
            return
        if not self.record:
            return
        model = self.attrs['relation']
        update_completion(self.wid_text, self.record, self.field, model)

    def _completion_action_activated(self, completion, index):
        if index == 0:
            self._sig_add()
            self.wid_text.grab_focus()
        elif index == 1:
            self._sig_new()
Exemplo n.º 51
0
class Many2Many(Widget):
    expand = True

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

        self.widget = gtk.Frame()
        self.widget.set_shadow_type(gtk.SHADOW_NONE)
        self.widget.get_accessible().set_name(attrs.get('string', ''))
        vbox = gtk.VBox(homogeneous=False, spacing=5)
        self.widget.add(vbox)
        self._readonly = True
        self._required = False
        self._position = 0

        hbox = gtk.HBox(homogeneous=False, spacing=0)
        hbox.set_border_width(2)

        self.title = gtk.Label(attrs.get('string', ''))
        self.title.set_alignment(0.0, 0.5)
        hbox.pack_start(self.title, expand=True, fill=True)

        hbox.pack_start(gtk.VSeparator(), expand=False, fill=True)

        tooltips = common.Tooltips()

        self.wid_text = PlaceholderEntry()
        self.wid_text.set_placeholder_text(_('Search'))
        self.wid_text.set_property('width_chars', 13)
        self.wid_text.connect('focus-out-event', lambda *a: self._focus_out())
        self.focus_out = True
        hbox.pack_start(self.wid_text, expand=True, fill=True)

        if int(self.attrs.get('completion', 1)):
            self.wid_completion = get_completion(
                create=self.attrs.get('create', True)
                and common.MODELACCESS[self.attrs['relation']]['create'])
            self.wid_completion.connect('match-selected',
                                        self._completion_match_selected)
            self.wid_completion.connect('action-activated',
                                        self._completion_action_activated)
            self.wid_text.set_completion(self.wid_completion)
            self.wid_text.connect('changed', self._update_completion)
        else:
            self.wid_completion = None

        self.but_add = gtk.Button()
        tooltips.set_tip(self.but_add, _('Add existing record'))
        self.but_add.connect('clicked', self._sig_add)
        img_add = gtk.Image()
        img_add.set_from_stock('tryton-list-add', gtk.ICON_SIZE_SMALL_TOOLBAR)
        img_add.set_alignment(0.5, 0.5)
        self.but_add.add(img_add)
        self.but_add.set_relief(gtk.RELIEF_NONE)
        hbox.pack_start(self.but_add, expand=False, fill=False)

        self.but_remove = gtk.Button()
        tooltips.set_tip(self.but_remove, _('Remove selected record <Del>'))
        self.but_remove.connect('clicked', self._sig_remove)
        img_remove = gtk.Image()
        img_remove.set_from_stock('tryton-list-remove',
                                  gtk.ICON_SIZE_SMALL_TOOLBAR)
        img_remove.set_alignment(0.5, 0.5)
        self.but_remove.add(img_remove)
        self.but_remove.set_relief(gtk.RELIEF_NONE)
        hbox.pack_start(self.but_remove, expand=False, fill=False)

        hbox.set_focus_chain([self.wid_text])

        tooltips.enable()

        frame = gtk.Frame()
        frame.add(hbox)
        frame.set_shadow_type(gtk.SHADOW_OUT)
        vbox.pack_start(frame, expand=False, fill=True)

        self.screen = Screen(attrs['relation'],
                             view_ids=attrs.get('view_ids', '').split(','),
                             mode=['tree'],
                             views_preload=attrs.get('views', {}),
                             row_activate=self._on_activate,
                             limit=None)
        self.screen.signal_connect(self, 'record-message', self._sig_label)

        vbox.pack_start(self.screen.widget, expand=True, fill=True)

        self.screen.widget.connect('key_press_event', self.on_keypress)
        self.wid_text.connect('key_press_event', self.on_keypress)

    def on_keypress(self, widget, event):
        editable = self.wid_text.get_editable()
        activate_keys = [gtk.keysyms.Tab, gtk.keysyms.ISO_Left_Tab]
        remove_keys = [gtk.keysyms.Delete, gtk.keysyms.KP_Delete]
        if not self.wid_completion:
            activate_keys.append(gtk.keysyms.Return)
        if widget == self.screen.widget:
            if event.keyval == gtk.keysyms.F3 and editable:
                self._sig_add()
                return True
            elif event.keyval == gtk.keysyms.F2:
                self._sig_edit()
                return True
            elif event.keyval in remove_keys and editable:
                self._sig_remove()
                return True
        elif widget == self.wid_text:
            if event.keyval == gtk.keysyms.F3:
                self._sig_new()
                return True
            elif event.keyval == gtk.keysyms.F2:
                self._sig_add()
                return True
            elif event.keyval in activate_keys and self.wid_text.get_text():
                self._sig_add()
                self.wid_text.grab_focus()
        return False

    def destroy(self):
        self.screen.destroy()

    def _sig_add(self, *args):
        if not self.focus_out:
            return
        domain = self.field.domain_get(self.record)
        add_remove = self.record.expr_eval(self.attrs.get('add_remove'))
        if add_remove:
            domain = [domain, add_remove]
        context = self.field.get_context(self.record)
        value = self.wid_text.get_text().decode('utf-8')

        self.focus_out = False

        def callback(result):
            self.focus_out = True
            if result:
                ids = [x[0] for x in result]
                self.screen.load(ids, modified=True)
                self.screen.display(res_id=ids[0])
            self.screen.set_cursor()
            self.wid_text.set_text('')

        win = WinSearch(self.attrs['relation'],
                        callback,
                        sel_multi=True,
                        context=context,
                        domain=domain,
                        view_ids=self.attrs.get('view_ids', '').split(','),
                        views_preload=self.attrs.get('views', {}),
                        new=self.attrs.get('create', True),
                        title=self.attrs.get('string'))
        win.screen.search_filter(quote(value))
        win.show()

    def _sig_remove(self, *args):
        self.screen.remove(remove=True)

    def _on_activate(self):
        self._sig_edit()

    def _get_screen_form(self):
        domain = self.field.domain_get(self.record)
        add_remove = self.record.expr_eval(self.attrs.get('add_remove'))
        if add_remove:
            domain = [domain, add_remove]
        context = self.field.get_context(self.record)
        # Remove the first tree view as mode is form only
        view_ids = self.attrs.get('view_ids', '').split(',')[1:]
        return Screen(self.attrs['relation'],
                      domain=domain,
                      view_ids=view_ids,
                      mode=['form'],
                      views_preload=self.attrs.get('views', {}),
                      context=context)

    def _sig_edit(self):
        if not self.screen.current_record:
            return
        # Create a new screen that is not linked to the parent otherwise on the
        # save of the record will trigger the save of the parent
        screen = self._get_screen_form()
        screen.load([self.screen.current_record.id])

        def callback(result):
            if result:
                screen.current_record.save()
                # Force a reload on next display
                self.screen.current_record.cancel()
                # Force a display to clear the CellCache
                self.screen.display()

        WinForm(screen, callback, title=self.attrs.get('string'))

    def _sig_new(self):
        screen = self._get_screen_form()

        def callback(result):
            self.focus_out = True
            if result:
                record = screen.current_record
                self.screen.load([record.id], modified=True)
            self.wid_text.set_text('')
            self.wid_text.grab_focus()

        self.focus_out = False
        WinForm(screen,
                callback,
                new=True,
                save_current=True,
                title=self.attrs.get('string'),
                rec_name=self.wid_text.get_text())

    def _readonly_set(self, value):
        self._readonly = value
        self._set_button_sensitive()
        self.wid_text.set_sensitive(not value)
        self._set_label_state()

    def _required_set(self, value):
        self._required = value
        self._set_label_state()

    def _set_label_state(self):
        attrlist = common.get_label_attributes(self._readonly, self._required)
        self.title.set_attributes(attrlist)
        widget_class(self.title, 'readonly', self._readonly)
        widget_class(self.title, 'required', self._required)

    def _set_button_sensitive(self):
        if self.record and self.field:
            field_size = self.record.expr_eval(self.attrs.get('size'))
            m2m_size = len(self.field.get_eval(self.record))
            size_limit = (field_size is not None
                          and m2m_size >= field_size >= 0)
        else:
            size_limit = False

        self.but_add.set_sensitive(bool(not self._readonly and not size_limit))
        self.but_remove.set_sensitive(
            bool(not self._readonly and self._position))

    def _sig_label(self, screen, signal_data):
        self._position = signal_data[0]
        self._set_button_sensitive()

    def display(self, record, field):
        super(Many2Many, self).display(record, field)
        if field is None:
            self.screen.new_group()
            self.screen.current_record = None
            self.screen.parent = None
            self.screen.display()
            return False
        new_group = field.get_client(record)
        if id(self.screen.group) != id(new_group):
            self.screen.group = new_group
        self.screen.display()
        return True

    def set_value(self, record, field):
        self.screen.current_view.set_value()
        return True

    def _completion_match_selected(self, completion, model, iter_):
        record_id, = model.get(iter_, 1)
        self.screen.load([record_id], modified=True)
        self.wid_text.set_text('')
        self.wid_text.grab_focus()

        completion_model = self.wid_completion.get_model()
        completion_model.clear()
        completion_model.search_text = self.wid_text.get_text()
        return True

    def _update_completion(self, widget):
        if self._readonly:
            return
        if not self.record:
            return
        model = self.attrs['relation']
        update_completion(self.wid_text, self.record, self.field, model)

    def _completion_action_activated(self, completion, index):
        if index == 0:
            self._sig_add()
            self.wid_text.grab_focus()
        elif index == 1:
            self._sig_new()
class Preference(object):
    "Preference window"

    def __init__(self, user):
        self.parent = common.get_toplevel_window()
        self.win = gtk.Dialog(_("Preferences"), self.parent, gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT)
        self.win.set_position(gtk.WIN_POS_CENTER_ON_PARENT)
        self.win.set_has_separator(False)
        self.win.set_icon(TRYTON_ICON)

        self.accel_group = gtk.AccelGroup()
        self.win.add_accel_group(self.accel_group)

        self.but_cancel = self.win.add_button(gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL)
        self.but_ok = self.win.add_button(gtk.STOCK_OK, gtk.RESPONSE_OK)
        self.but_ok.add_accelerator(
            "clicked", self.accel_group, gtk.keysyms.Return, gtk.gdk.CONTROL_MASK, gtk.ACCEL_VISIBLE
        )

        self.win.set_default_response(gtk.RESPONSE_OK)

        try:
            view = RPCExecute("model", "res.user", "get_preferences_fields_view")
        except RPCException:
            self.win.destroy()
            self.win = None
            return

        title = gtk.Label(_("Edit User Preferences"))
        title.show()
        self.win.vbox.pack_start(title, expand=False, fill=True)
        self.screen = Screen("res.user", mode=[])
        self.screen.add_view(view)
        self.screen.new(default=False)

        try:
            preferences = RPCExecute("model", "res.user", "get_preferences", False)
        except RPCException:
            self.win.destroy()
            self.win = None
            return
        self.screen.current_record.set(preferences)
        self.screen.current_record.validate(softvalidation=True)
        self.screen.screen_container.set(self.screen.current_view.widget)
        self.screen.display(set_cursor=True)

        self.screen.widget.show()
        self.win.vbox.pack_start(self.screen.widget)
        self.win.set_title(_("Preference"))

        width, height = self.parent.get_size()
        self.win.set_default_size(int(width * 0.9), int(height * 0.9))

        self.win.show()

    def run(self):
        "Run the window"
        if not self.win:
            return False
        res = False
        while True:
            if self.win.run() == gtk.RESPONSE_OK:
                if self.screen.current_record.validate():
                    vals = copy.copy(self.screen.get(get_modifiedonly=True))
                    if "password" in vals:
                        password = common.ask(_("Current Password:"******"model", "res.user", "set_preferences", vals, password)
                    except RPCException:
                        continue
                    res = True
                    break
            else:
                break
        self.parent.present()
        self.win.destroy()
        return res
Exemplo n.º 53
0
class One2Many(Widget):
    expand = True

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

        self.widget = Gtk.Frame()
        self.widget.set_shadow_type(Gtk.ShadowType.NONE)
        self.widget.get_accessible().set_name(attrs.get('string', ''))
        vbox = Gtk.VBox(homogeneous=False, spacing=2)
        self.widget.add(vbox)
        self._readonly = True
        self._required = False
        self._position = 0
        self._length = 0

        self.title_box = hbox = Gtk.HBox(homogeneous=False, spacing=0)
        hbox.set_border_width(2)

        self.title = Gtk.Label(label=set_underline(attrs.get('string', '')),
                               use_underline=True,
                               halign=Gtk.Align.START)
        hbox.pack_start(self.title, expand=True, fill=True, padding=0)

        hbox.pack_start(Gtk.VSeparator(), expand=False, fill=True, padding=0)

        tooltips = common.Tooltips()

        but_switch = Gtk.Button(can_focus=False)
        tooltips.set_tip(but_switch, _('Switch'))
        but_switch.connect('clicked', self.switch_view)
        but_switch.add(
            common.IconFactory.get_image('tryton-switch',
                                         Gtk.IconSize.SMALL_TOOLBAR))
        but_switch.set_relief(Gtk.ReliefStyle.NONE)
        hbox.pack_start(but_switch, expand=False, fill=False, padding=0)

        self.but_pre = Gtk.Button(can_focus=False)
        tooltips.set_tip(self.but_pre, _('Previous'))
        self.but_pre.connect('clicked', self._sig_previous)
        self.but_pre.add(
            common.IconFactory.get_image('tryton-back',
                                         Gtk.IconSize.SMALL_TOOLBAR))
        self.but_pre.set_relief(Gtk.ReliefStyle.NONE)
        hbox.pack_start(self.but_pre, expand=False, fill=False, padding=0)

        self.label = Gtk.Label(label='(0,0)')
        hbox.pack_start(self.label, expand=False, fill=False, padding=0)

        self.but_next = Gtk.Button(can_focus=False)
        tooltips.set_tip(self.but_next, _('Next'))
        self.but_next.connect('clicked', self._sig_next)
        self.but_next.add(
            common.IconFactory.get_image('tryton-forward',
                                         Gtk.IconSize.SMALL_TOOLBAR))
        self.but_next.set_relief(Gtk.ReliefStyle.NONE)
        hbox.pack_start(self.but_next, expand=False, fill=False, padding=0)

        hbox.pack_start(Gtk.VSeparator(), expand=False, fill=True, padding=0)

        self.focus_out = True
        self.wid_completion = None
        if attrs.get('add_remove'):

            self.wid_text = Gtk.Entry()
            self.wid_text.set_placeholder_text(_('Search'))
            self.wid_text.set_property('width_chars', 13)
            self.wid_text.connect('focus-out-event', self._focus_out)
            hbox.pack_start(self.wid_text, expand=True, fill=True, padding=0)

            if int(self.attrs.get('completion', 1)):
                self.wid_completion = get_completion(search=self.read_access,
                                                     create=self.create_access)
                self.wid_completion.connect('match-selected',
                                            self._completion_match_selected)
                self.wid_completion.connect('action-activated',
                                            self._completion_action_activated)
                self.wid_text.set_completion(self.wid_completion)
                self.wid_text.connect('changed', self._update_completion)

            self.but_add = Gtk.Button(can_focus=False)
            tooltips.set_tip(self.but_add, _('Add existing record'))
            self.but_add.connect('clicked', self._sig_add)
            self.but_add.add(
                common.IconFactory.get_image('tryton-add',
                                             Gtk.IconSize.SMALL_TOOLBAR))
            self.but_add.set_relief(Gtk.ReliefStyle.NONE)
            hbox.pack_start(self.but_add, expand=False, fill=False, padding=0)

            self.but_remove = Gtk.Button(can_focus=False)
            tooltips.set_tip(self.but_remove, _('Remove selected record'))
            self.but_remove.connect('clicked', self._sig_remove, True)
            self.but_remove.add(
                common.IconFactory.get_image('tryton-remove',
                                             Gtk.IconSize.SMALL_TOOLBAR))
            self.but_remove.set_relief(Gtk.ReliefStyle.NONE)
            hbox.pack_start(self.but_remove,
                            expand=False,
                            fill=False,
                            padding=0)

            hbox.pack_start(Gtk.VSeparator(),
                            expand=False,
                            fill=True,
                            padding=0)

        self.but_new = Gtk.Button(can_focus=False)
        tooltips.set_tip(self.but_new, _('Create a new record'))
        self.but_new.connect('clicked', self._sig_new)
        self.but_new.add(
            common.IconFactory.get_image('tryton-create',
                                         Gtk.IconSize.SMALL_TOOLBAR))
        self.but_new.set_relief(Gtk.ReliefStyle.NONE)
        hbox.pack_start(self.but_new, expand=False, fill=False, padding=0)

        self.but_open = Gtk.Button(can_focus=False)
        tooltips.set_tip(self.but_open, _('Edit selected record'))
        self.but_open.connect('clicked', self._sig_edit)
        self.but_open.add(
            common.IconFactory.get_image('tryton-open',
                                         Gtk.IconSize.SMALL_TOOLBAR))
        self.but_open.set_relief(Gtk.ReliefStyle.NONE)
        hbox.pack_start(self.but_open, expand=False, fill=False, padding=0)

        self.but_del = Gtk.Button(can_focus=False)
        tooltips.set_tip(self.but_del, _('Delete selected record'))
        self.but_del.connect('clicked', self._sig_remove, False)
        self.but_del.add(
            common.IconFactory.get_image('tryton-delete',
                                         Gtk.IconSize.SMALL_TOOLBAR))
        self.but_del.set_relief(Gtk.ReliefStyle.NONE)
        hbox.pack_start(self.but_del, expand=False, fill=False, padding=0)

        self.but_undel = Gtk.Button(can_focus=False)
        tooltips.set_tip(self.but_undel, _('Undelete selected record <Ins>'))
        self.but_undel.connect('clicked', self._sig_undelete)
        self.but_undel.add(
            common.IconFactory.get_image('tryton-undo',
                                         Gtk.IconSize.SMALL_TOOLBAR))
        self.but_undel.set_relief(Gtk.ReliefStyle.NONE)
        hbox.pack_start(self.but_undel, expand=False, fill=False, padding=0)

        tooltips.enable()

        frame = Gtk.Frame()
        frame.add(hbox)
        frame.set_shadow_type(Gtk.ShadowType.OUT)
        vbox.pack_start(frame, expand=False, fill=True, padding=0)

        model = attrs['relation']
        breadcrumb = list(self.view.screen.breadcrumb)
        breadcrumb.append(attrs.get('string') or common.MODELNAME.get(model))
        self.screen = Screen(model,
                             mode=attrs.get('mode', 'tree,form').split(','),
                             view_ids=attrs.get('view_ids', '').split(','),
                             views_preload=attrs.get('views', {}),
                             order=attrs.get('order'),
                             row_activate=self._on_activate,
                             exclude_field=attrs.get('relation_field', None),
                             limit=None,
                             breadcrumb=breadcrumb)
        self.screen.pre_validate = bool(int(attrs.get('pre_validate', 0)))
        self.screen.windows.append(self)

        vbox.pack_start(self.screen.widget, expand=True, fill=True, padding=0)

        self.title.set_mnemonic_widget(
            self.screen.current_view.mnemonic_widget)

        self.screen.widget.connect('key_press_event', self.on_keypress)
        if self.attrs.get('add_remove'):
            self.wid_text.connect('key_press_event', self.on_keypress)

        but_switch.props.sensitive = self.screen.number_of_views > 1

    def get_access(self, type_):
        model = self.attrs['relation']
        if model:
            return common.MODELACCESS[model][type_]
        else:
            return True

    @property
    def read_access(self):
        return self.get_access('read')

    @property
    def create_access(self):
        return int(self.attrs.get('create', 1)) and self.get_access('create')

    @property
    def write_access(self):
        return self.get_access('write')

    @property
    def delete_access(self):
        return int(self.attrs.get('delete', 1)) and self.get_access('delete')

    def on_keypress(self, widget, event):
        if ((event.keyval == Gdk.KEY_F3)
                and self.but_new.get_property('sensitive')):
            self._sig_new(widget)
            return True
        if event.keyval == Gdk.KEY_F2:
            if widget == self.screen.widget:
                self._sig_edit(widget)
                return True
            elif widget == self.wid_text:
                self._sig_add(widget)
                return True
        if event.keyval == Gdk.KEY_F4:
            self.switch_view(widget)
        if (event.keyval in [Gdk.KEY_Delete, Gdk.KEY_KP_Delete]
                and widget == self.screen.widget):
            remove = not (event.state & Gdk.ModifierType.CONTROL_MASK)
            if remove and self.attrs.get('add_remove'):
                but = self.but_remove
            else:
                remove = False
                but = self.but_del
            if but.get_property('sensitive'):
                self._sig_remove(widget, remove)
                return True
        if event.keyval == Gdk.KEY_Insert and widget == self.screen.widget:
            self._sig_undelete(widget)
            return True
        if self.attrs.get('add_remove'):
            editable = self.wid_text.get_editable()
            activate_keys = [Gdk.KEY_Tab, Gdk.KEY_ISO_Left_Tab]
            if not self.wid_completion:
                activate_keys.append(Gdk.KEY_Return)
            if (widget == self.wid_text and event.keyval in activate_keys
                    and editable and self.wid_text.get_text()):
                self._sig_add()
                self.wid_text.grab_focus()
        return False

    def destroy(self):
        if self.attrs.get('add_remove'):
            self.wid_text.disconnect_by_func(self._focus_out)
        self.screen.destroy()

    def _on_activate(self):
        self._sig_edit()

    def switch_view(self, widget):
        self.screen.switch_view()
        mnemonic_widget = self.screen.current_view.mnemonic_widget
        string = self.attrs.get('string', '')
        if mnemonic_widget:
            string = set_underline(string)
        self.title.set_mnemonic_widget(mnemonic_widget)
        self.title.set_label(string)

    @property
    def modified(self):
        return self.screen.current_view.modified

    def _readonly_set(self, value):
        self._readonly = value
        self._set_button_sensitive()
        self._set_label_state()

    def _required_set(self, value):
        self._required = value
        self._set_label_state()

    def _set_label_state(self):
        common.apply_label_attributes(self.title, self._readonly,
                                      self._required)

    def _set_button_sensitive(self):
        if self.record and self.field:
            field_size = self.record.expr_eval(self.attrs.get('size'))
            o2m_size = len(self.field.get_eval(self.record))
            size_limit = (field_size is not None
                          and o2m_size >= field_size >= 0)
        else:
            o2m_size = None
            size_limit = False

        first = last = False
        if isinstance(self._position, int):
            first = self._position <= 1
            last = self._position >= self._length
        deletable = self.screen.deletable

        self.but_new.set_sensitive(
            bool(not self._readonly and self.create_access and not size_limit))
        self.but_del.set_sensitive(
            bool(not self._readonly and self.delete_access and deletable
                 and self._position))
        self.but_undel.set_sensitive(
            bool(not self._readonly and not size_limit and self._position))
        self.but_open.set_sensitive(bool(self._position and self.read_access))
        self.but_next.set_sensitive(bool(self._position and not last))
        self.but_pre.set_sensitive(bool(self._position and not first))
        if self.attrs.get('add_remove'):
            self.but_add.set_sensitive(
                bool(not self._readonly and not size_limit
                     and self.write_access and self.read_access))
            self.but_remove.set_sensitive(
                bool(not self._readonly and self._position
                     and self.write_access and self.read_access))
            self.wid_text.set_sensitive(self.but_add.get_sensitive())
            self.wid_text.set_editable(self.but_add.get_sensitive())

    def _validate(self):
        self.view.set_value()
        record = self.screen.current_record
        if record:
            fields = self.screen.current_view.get_fields()
            if not record.validate(fields):
                self.screen.display(set_cursor=True)
                return False
            if self.screen.pre_validate and not record.pre_validate():
                return False
        return True

    def _sequence(self):
        for view in self.screen.views:
            if view.view_type == 'tree':
                sequence = view.attributes.get('sequence')
                if sequence:
                    return sequence

    def _sig_new(self, *args):
        if not self.create_access:
            return
        if not self._validate():
            return

        if self.attrs.get('product'):
            self._new_product()
        else:
            self._new_single()

    def _new_single(self):
        sequence = self._sequence()

        def update_sequence():
            if sequence:
                self.screen.group.set_sequence(
                    field=sequence, position=self.screen.new_position)

        if self.screen.current_view.creatable:
            self.screen.new()
            self.screen.current_view.widget.set_sensitive(True)
            update_sequence()
        else:
            field_size = self.record.expr_eval(self.attrs.get('size')) or -1
            field_size -= len(self.field.get_eval(self.record)) + 1
            WinForm(self.screen,
                    lambda a: update_sequence(),
                    new=True,
                    many=field_size)

    def _new_product(self):
        fields = self.attrs['product'].split(',')
        product = {}

        first = self.screen.new(default=False)
        default = first.default_get()
        first.set_default(default)

        def search_set(*args):
            if not fields:
                return make_product()
            field = self.screen.group.fields[fields.pop()]
            relation = field.attrs.get('relation')
            if not relation:
                search_set()

            domain = field.domain_get(first)
            context = field.get_search_context(first)
            order = field.get_search_order(first)

            def callback(result):
                if result:
                    product[field.name] = result

            win_search = WinSearch(relation,
                                   callback,
                                   sel_multi=True,
                                   context=context,
                                   domain=domain,
                                   order=order,
                                   title=self.attrs.get('string'))
            win_search.win.connect('destroy', search_set)
            win_search.screen.search_filter()
            win_search.show()

        def make_product():
            self.screen.group.remove(first, remove=True)
            if not product:
                return

            fields = list(product.keys())
            for values in itertools.product(*list(product.values())):
                record = self.screen.new(default=False)
                default_value = default.copy()
                for field, value in zip(fields, values):
                    id_, rec_name = value
                    default_value[field] = id_
                    default_value[field + '.rec_name'] = rec_name
                record.set_default(default_value)

            sequence = self._sequence()
            if sequence:
                self.screen.group.set_sequence(
                    field=sequence, position=self.screen.new_position)

        search_set()

    def _sig_edit(self, widget=None):
        if not common.MODELACCESS[self.screen.model_name]['read']:
            return
        if not self._validate():
            return
        record = self.screen.current_record
        if record:
            WinForm(self.screen, lambda a: None)

    def _sig_next(self, widget):
        if not self._validate():
            return
        self.screen.display_next()

    def _sig_previous(self, widget):
        if not self._validate():
            return
        self.screen.display_prev()

    def _sig_remove(self, widget, remove=False):
        writable = not self.screen.readonly
        deletable = self.screen.deletable
        if remove:
            if not self.write_access or not writable or not self.read_access:
                return
        else:
            if not self.delete_access or not deletable:
                return
        self.screen.remove(remove=remove)

    def _sig_undelete(self, button):
        self.screen.unremove()

    def _sig_add(self, *args):
        if not self.focus_out:
            return
        if not self.write_access or not self.read_access:
            return
        self.view.set_value()
        domain = self.field.domain_get(self.record)
        context = self.field.get_search_context(self.record)
        domain = [domain, self.record.expr_eval(self.attrs.get('add_remove'))]
        removed_ids = self.field.get_removed_ids(self.record)
        domain = ['OR', domain, ('id', 'in', removed_ids)]
        text = self.wid_text.get_text()

        self.focus_out = False

        sequence = self._sequence()

        def callback(result):
            self.focus_out = True
            if result:
                ids = [x[0] for x in result]
                self.screen.load(ids, modified=True)
                self.screen.display(res_id=ids[0])
                if sequence:
                    self.screen.group.set_sequence(
                        field=sequence, position=self.screen.new_position)
            self.screen.set_cursor()
            self.wid_text.set_text('')

        order = self.field.get_search_order(self.record)
        win = WinSearch(self.attrs['relation'],
                        callback,
                        sel_multi=True,
                        context=context,
                        domain=domain,
                        order=order,
                        view_ids=self.attrs.get('view_ids', '').split(','),
                        views_preload=self.attrs.get('views', {}),
                        new=self.but_new.get_property('sensitive'),
                        title=self.attrs.get('string'),
                        exclude_field=self.attrs.get('relation_field'))
        win.screen.search_filter(quote(text))
        win.show()

    def record_message(self, position, size, *args):
        self._position = position
        self._length = size
        if self._position:
            name = str(self._position)
        else:
            name = '_'
        line = '(%s/%s)' % (name, self._length)
        self.label.set_text(line)
        self._set_button_sensitive()

    def display(self):
        super(One2Many, self).display()

        self._set_button_sensitive()

        if not self.field:
            self.screen.new_group()
            self.screen.current_record = None
            self.screen.parent = None
            self.screen.display()
            return False
        new_group = self.field.get_client(self.record)

        if id(self.screen.group) != id(new_group):
            self.screen.group = new_group
            if (self.screen.current_view.view_type == 'tree') \
                    and self.screen.current_view.editable:
                self.screen.current_record = None
        domain = []
        size_limit = None
        if self.record:
            domain = self.field.domain_get(self.record)
            size_limit = self.record.expr_eval(self.attrs.get('size'))
        if self._readonly:
            if size_limit is None:
                size_limit = len(self.screen.group)
            else:
                size_limit = min(size_limit, len(self.screen.group))
        if self.screen.domain != domain:
            self.screen.domain = domain
        self.screen.size_limit = size_limit
        self.screen.display()
        return True

    def set_value(self):
        self.screen.current_view.set_value()
        if self.screen.modified():  # TODO check if required
            self.view.screen.record_modified(display=False)
        return True

    def _completion_match_selected(self, completion, model, iter_):
        record_id, = model.get(iter_, 1)
        self.screen.load([record_id], modified=True)
        self.wid_text.set_text('')
        self.wid_text.grab_focus()

        completion_model = self.wid_completion.get_model()
        completion_model.clear()
        completion_model.search_text = self.wid_text.get_text()
        return True

    def _update_completion(self, widget):
        if self._readonly:
            return
        if not self.record:
            return
        model = self.attrs['relation']
        domain = self.field.domain_get(self.record)
        domain = [domain, self.record.expr_eval(self.attrs.get('add_remove'))]
        removed_ids = self.field.get_removed_ids(self.record)
        domain = ['OR', domain, ('id', 'in', removed_ids)]
        update_completion(self.wid_text,
                          self.record,
                          self.field,
                          model,
                          domain=domain)

    def _completion_action_activated(self, completion, index):
        if index == 0:
            self._sig_add()
            self.wid_text.grab_focus()
        elif index == 1:
            self._sig_new()
Exemplo n.º 54
0
    def __init__(self, view, attrs):
        super(Many2Many, self).__init__(view, attrs)

        self.widget = gtk.Frame()
        self.widget.set_shadow_type(gtk.SHADOW_NONE)
        self.widget.get_accessible().set_name(attrs.get('string', ''))
        vbox = gtk.VBox(homogeneous=False, spacing=5)
        self.widget.add(vbox)
        self._readonly = True
        self._position = 0

        hbox = gtk.HBox(homogeneous=False, spacing=0)
        hbox.set_border_width(2)

        label = gtk.Label(attrs.get('string', ''))
        label.set_alignment(0.0, 0.5)
        hbox.pack_start(label, expand=True, fill=True)

        hbox.pack_start(gtk.VSeparator(), expand=False, fill=True)

        tooltips = common.Tooltips()

        self.wid_text = PlaceholderEntry()
        self.wid_text.set_placeholder_text(_('Search'))
        self.wid_text.set_property('width_chars', 13)
        self.wid_text.connect('focus-out-event', lambda *a: self._focus_out())
        self.focus_out = True
        hbox.pack_start(self.wid_text, expand=True, fill=True)

        if int(self.attrs.get('completion', 1)):
            self.wid_completion = get_completion(
                create=self.attrs.get('create', True)
                and common.MODELACCESS[self.attrs['relation']]['create'])
            self.wid_completion.connect('match-selected',
                self._completion_match_selected)
            self.wid_completion.connect('action-activated',
                self._completion_action_activated)
            self.wid_text.set_completion(self.wid_completion)
            self.wid_text.connect('changed', self._update_completion)
        else:
            self.wid_completion = None

        self.but_add = gtk.Button()
        tooltips.set_tip(self.but_add, _('Add existing record'))
        self.but_add.connect('clicked', self._sig_add)
        img_add = gtk.Image()
        img_add.set_from_stock('tryton-list-add',
            gtk.ICON_SIZE_SMALL_TOOLBAR)
        img_add.set_alignment(0.5, 0.5)
        self.but_add.add(img_add)
        self.but_add.set_relief(gtk.RELIEF_NONE)
        hbox.pack_start(self.but_add, expand=False, fill=False)

        self.but_remove = gtk.Button()
        tooltips.set_tip(self.but_remove, _('Remove selected record <Del>'))
        self.but_remove.connect('clicked', self._sig_remove)
        img_remove = gtk.Image()
        img_remove.set_from_stock('tryton-list-remove',
            gtk.ICON_SIZE_SMALL_TOOLBAR)
        img_remove.set_alignment(0.5, 0.5)
        self.but_remove.add(img_remove)
        self.but_remove.set_relief(gtk.RELIEF_NONE)
        hbox.pack_start(self.but_remove, expand=False, fill=False)

        hbox.set_focus_chain([self.wid_text])

        tooltips.enable()

        frame = gtk.Frame()
        frame.add(hbox)
        if attrs.get('expand_toolbar'):
            frame.set_shadow_type(gtk.SHADOW_NONE)
        else:
            frame.set_shadow_type(gtk.SHADOW_OUT)
            vbox.pack_start(frame, expand=False, fill=True)

        self.screen = Screen(attrs['relation'],
            view_ids=attrs.get('view_ids', '').split(','),
            mode=['tree'], views_preload=attrs.get('views', {}),
            row_activate=self._on_activate)
        self.screen.signal_connect(self, 'record-message', self._sig_label)

        vbox.pack_start(self.screen.widget, expand=True, fill=True)

        self.screen.widget.connect('key_press_event', self.on_keypress)
        self.wid_text.connect('key_press_event', self.on_keypress)
Exemplo n.º 55
0
class Action(SignalEvent):
    def __init__(self, attrs=None, context=None):
        super(Action, self).__init__()
        self.name = attrs['name']
        self.context = context or {}

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

        view_ids = None
        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()

    def row_activate(self):
        if not self.screen.current_record:
            return

        if (self.screen.current_view.view_type == 'tree' and int(
                self.screen.current_view.attributes.get('keyword_open', 0))):
            GenericAction.exec_keyword('tree_open', {
                'model':
                self.screen.model_name,
                'id': (self.screen.current_record.id
                       if self.screen.current_record else None),
                'ids': [r.id for r in self.screen.selected_records],
            },
                                       context=self.screen.context.copy(),
                                       warning=False)
        else:

            def callback(result):
                if result:
                    self.screen.current_record.save()
                else:
                    self.screen.current_record.cancel()

            WinForm(self.screen, callback)

    def set_value(self, mode, model_field):
        self.screen.current_view.set_value()
        return True

    def display(self):
        self.screen.search_filter(self.screen.screen_container.get_text())

    def _active_changed(self, *args):
        self.signal('active-changed')

    def _get_active(self):
        if self.screen and self.screen.current_record:
            return common.EvalEnvironment(self.screen.current_record)

    active = property(_get_active)

    def update_domain(self, actions):
        domain_ctx = self.context.copy()
        domain_ctx['context'] = domain_ctx
        domain_ctx['_user'] = rpc._USER
        for action in actions:
            if action.active:
                domain_ctx[action.name] = action.active
        new_domain = PYSONDecoder(domain_ctx).decode(
            self.action['pyson_domain'])
        if self.domain == new_domain:
            return
        del self.domain[:]
        self.domain.extend(new_domain)
        if hasattr(self, 'screen'):  # Catch early update
            # Using idle_add to prevent corruption of the event who triggered
            # the update.
            def display():
                if self.screen.widget.props.window:
                    self.display()

            gtk.idle_add(display)
Exemplo n.º 56
0
class Many2Many(WidgetInterface):

    def __init__(self, field_name, model_name, attrs=None):
        super(Many2Many, self).__init__(field_name, model_name, attrs=attrs)

        self.widget = gtk.VBox(homogeneous=False, spacing=5)
        self._readonly = True
        self._position = 0

        hbox = gtk.HBox(homogeneous=False, spacing=0)
        hbox.set_border_width(2)

        label = gtk.Label(attrs.get('string', ''))
        label.set_alignment(0.0, 0.5)
        hbox.pack_start(label, expand=True, fill=True)

        hbox.pack_start(gtk.VSeparator(), expand=False, fill=True)

        tooltips = common.Tooltips()

        self.wid_text = PlaceholderEntry()
        self.wid_text.set_placeholder_text(_('Search'))
        self.wid_text.set_property('width_chars', 13)
        self.wid_text.connect('focus-out-event', lambda *a: self._focus_out())
        self.focus_out = True
        hbox.pack_start(self.wid_text, expand=True, fill=True)

        if int(self.attrs.get('completion', 1)):
            self.wid_completion = get_completion()
            self.wid_completion.connect('match-selected',
                self._completion_match_selected)
            self.wid_completion.connect('action-activated',
                self._completion_action_activated)
            self.wid_text.set_completion(self.wid_completion)
            self.wid_text.connect('changed', self._update_completion)
        else:
            self.wid_completion = None

        self.but_add = gtk.Button()
        tooltips.set_tip(self.but_add, _('Add existing record'))
        self.but_add.connect('clicked', self._sig_add)
        img_add = gtk.Image()
        img_add.set_from_stock('tryton-list-add',
            gtk.ICON_SIZE_SMALL_TOOLBAR)
        img_add.set_alignment(0.5, 0.5)
        self.but_add.add(img_add)
        self.but_add.set_relief(gtk.RELIEF_NONE)
        hbox.pack_start(self.but_add, expand=False, fill=False)

        self.but_remove = gtk.Button()
        tooltips.set_tip(self.but_remove, _('Remove selected record <Del>'))
        self.but_remove.connect('clicked', self._sig_remove)
        img_remove = gtk.Image()
        img_remove.set_from_stock('tryton-list-remove',
            gtk.ICON_SIZE_SMALL_TOOLBAR)
        img_remove.set_alignment(0.5, 0.5)
        self.but_remove.add(img_remove)
        self.but_remove.set_relief(gtk.RELIEF_NONE)
        hbox.pack_start(self.but_remove, expand=False, fill=False)

        hbox.set_focus_chain([self.wid_text])

        tooltips.enable()

        frame = gtk.Frame()
        frame.add(hbox)
        frame.set_shadow_type(gtk.SHADOW_OUT)
        self.widget.pack_start(frame, expand=False, fill=True)

        self.screen = Screen(attrs['relation'],
            view_ids=attrs.get('view_ids', '').split(','),
            mode=['tree'], views_preload=attrs.get('views', {}),
            row_activate=self._on_activate)
        self.screen.signal_connect(self, 'record-message', self._sig_label)

        self.widget.pack_start(self.screen.widget, expand=True, fill=True)

        self.screen.widget.connect('key_press_event', self.on_keypress)
        self.wid_text.connect('key_press_event', self.on_keypress)

    def _color_widget(self):
        if hasattr(self.screen.current_view, 'widget_tree'):
            return self.screen.current_view.widget_tree
        return super(Many2Many, self)._color_widget()

    def grab_focus(self):
        return self.wid_text.grab_focus()

    def on_keypress(self, widget, event):
        editable = self.wid_text.get_editable()
        activate_keys = [gtk.keysyms.Tab, gtk.keysyms.ISO_Left_Tab]
        if not self.wid_completion:
            activate_keys.append(gtk.keysyms.Return)
        if event.keyval == gtk.keysyms.F3:
            self._sig_add()
            return True
        if event.keyval == gtk.keysyms.F2 \
                and widget == self.screen.widget:
            self._sig_edit()
            return True
        if event.keyval in (gtk.keysyms.Delete, gtk.keysyms.KP_Delete) \
                and widget == self.screen.widget:
            self._sig_remove()
            return True
        if (widget == self.wid_text
                and event.keyval in activate_keys
                and editable
                and self.wid_text.get_text()):
            self._sig_add()
            self.wid_text.grab_focus()
        return False

    def destroy(self):
        self.screen.destroy()
        self.widget.destroy()
        del self.widget

    def color_set(self, name):
        super(Many2Many, self).color_set(name)
        widget = self._color_widget()
        # if the style to apply is different from readonly then insensitive
        # cellrenderers should use the default insensitive color
        if name != 'readonly':
            widget.modify_text(gtk.STATE_INSENSITIVE,
                    self.colors['text_color_insensitive'])

    def _sig_add(self, *args, **kwargs):
        if not self.focus_out:
            return
        domain = self.field.domain_get(self.record)
        context = self.field.context_get(self.record)
        value = self.wid_text.get_text()

        self.focus_out = False
        try:
            if value:
                dom = [('rec_name', 'ilike', '%' + value + '%'), domain]
            else:
                dom = domain
            ids = RPCExecute('model', self.attrs['relation'], 'search',
                dom, 0, CONFIG['client.limit'], None, context=context)
        except RPCException:
            self.focus_out = True
            return False

        def callback(result):
            self.focus_out = True
            if result:
                ids = [x[0] for x in result]
                self.screen.load(ids, modified=True)
                self.screen.display(res_id=ids[0])
            self.screen.set_cursor()
            self.wid_text.set_text('')
        if len(ids) != 1 or not value or kwargs.get('win_search', False):
            WinSearch(self.attrs['relation'], callback, sel_multi=True,
                ids=ids, context=context, domain=domain,
                view_ids=self.attrs.get('view_ids', '').split(','),
                views_preload=self.attrs.get('views', {}),
                new=self.attrs.get('create', True))
        else:
            callback([(i, None) for i in ids])

    def _sig_remove(self, *args):
        self.screen.remove(remove=True)

    def _on_activate(self):
        self._sig_edit()

    def _sig_edit(self):
        if self.screen.current_record:
            def callback(result):
                if result:
                    self.screen.current_record.save()
                else:
                    self.screen.current_record.cancel()
            WinForm(self.screen, callback)

    def _readonly_set(self, value):
        self._readonly = value
        self._set_button_sensitive()

    def _set_button_sensitive(self):
        if self.record and self.field:
            field_size = self.record.expr_eval(self.attrs.get('size'))
            m2m_size = len(self.field.get_eval(self.record))
            size_limit = (field_size is not None
                and m2m_size >= field_size >= 0)
        else:
            size_limit = False

        self.wid_text.set_sensitive(not self._readonly)
        self.but_add.set_sensitive(bool(
                not self._readonly
                and not size_limit))
        self.but_remove.set_sensitive(bool(
                not self._readonly
                and self._position))

    def _sig_label(self, screen, signal_data):
        self._position = signal_data[0]
        self._set_button_sensitive()

    def display(self, record, field):
        super(Many2Many, self).display(record, field)
        if field is None:
            self.screen.new_group()
            self.screen.current_record = None
            self.screen.parent = True
            self.screen.display()
            return False
        new_group = field.get_client(record)
        if id(self.screen.group) != id(new_group):
            self.screen.group = new_group
        self.screen.display()
        return True

    def set_value(self, record, field):
        self.screen.save_tree_state()
        self.screen.current_view.set_value()
        return True

    def _completion_match_selected(self, completion, model, iter_):
        record_id, = model.get(iter_, 1)
        self.screen.load([record_id], modified=True)
        self.wid_text.set_text('')
        self.wid_text.grab_focus()

        completion_model = self.wid_completion.get_model()
        completion_model.clear()
        completion_model.search_text = self.wid_text.get_text()
        return True

    def _update_completion(self, widget):
        if self._readonly:
            return
        if not self.record:
            return
        model = self.attrs['relation']
        update_completion(self.wid_text, self.record, self.field, model)

    def _completion_action_activated(self, completion, index):
        if index == 0:
            self._sig_add(win_search=True)
            self.wid_text.grab_focus()
        elif index == 1:
            model = self.attrs['relation']
            domain = self.field.domain_get(self.record)
            context = self.field.context_get(self.record)

            screen = Screen(model, domain, context=context, mode=['form'])

            def callback(result):
                self.focus_out = True
                if result:
                    record = screen.current_record
                    self.screen.load([record.id], modified=True)
                self.wid_text.set_text('')
                self.wid_text.grab_focus()

            self.focus_out = False
            WinForm(screen, callback, new=True, save_current=True)
Exemplo n.º 57
0
class Form(SignalEvent, TabContent):
    "Form"

    def __init__(self, model, res_id=None, name='', **attributes):
        super(Form, self).__init__(**attributes)

        self.model = model
        self.res_id = res_id
        self.mode = attributes.get('mode')
        self.view_ids = attributes.get('view_ids')
        self.dialogs = []

        self.screen = Screen(self.model, **attributes)
        self.screen.widget.show()

        self.name = name

        self.create_tabcontent()

        self.set_buttons_sensitive()

        self.screen.signal_connect(self, 'record-message',
                                   self._record_message)

        self.screen.signal_connect(
            self, 'record-modified',
            lambda *a: GLib.idle_add(self._record_modified, *a))
        self.screen.signal_connect(self, 'record-saved', self._record_saved)
        self.screen.signal_connect(
            self, 'resources',
            lambda screen, resources: self.update_resources(resources))

        if res_id not in (None, False):
            if isinstance(res_id, int):
                res_id = [res_id]
            self.screen.load(res_id)
        else:
            if self.screen.current_view.view_type == 'form':
                self.sig_new(None, autosave=False)
            if self.screen.current_view.view_type \
                    in ('tree', 'graph', 'calendar'):
                self.screen.search_filter()

        self.update_revision()

    def get_toolbars(self):
        try:
            return RPCExecute('model',
                              self.model,
                              'view_toolbar_get',
                              context=self.screen.context)
        except RPCException:
            return {}

    def widget_get(self):
        return self.screen.widget

    def compare(self, model, attributes):
        if not attributes:
            return False
        return (self.model == model and self.res_id == attributes.get('res_id')
                and self.attributes.get('domain') == attributes.get('domain')
                and self.attributes.get('view_ids')
                == attributes.get('view_ids')
                and (attributes.get('view_ids') or
                     (self.attributes.get('mode') or ['tree', 'form'])
                     == (attributes.get('mode') or ['tree', 'form']))
                and self.screen.local_context == attributes.get('context')
                and self.attributes.get('search_value')
                == (attributes.get('search_value')))

    def __hash__(self):
        return id(self)

    def destroy(self):
        super(Form, self).destroy()
        self.screen.signal_unconnect(self)
        self.screen.destroy()

    def sig_attach(self, widget=None):
        def window(widget):
            return Attachment(record,
                              lambda: self.refresh_resources(reload=True))

        def add_file(widget):
            filenames = common.file_selection(_("Select"), multi=True)
            if filenames:
                attachment = window(widget)
                for filename in filenames:
                    attachment.add_file(filename)

        def activate(widget, callback):
            callback()

        button = self.buttons['attach']
        if widget != button:
            if button.props.sensitive:
                button.props.active = True
            return
        record = self.screen.current_record
        menu = button._menu = Gtk.Menu()
        for name, callback in Attachment.get_attachments(record):
            item = Gtk.MenuItem(label=name)
            item.connect('activate', activate, callback)
            menu.add(item)
        menu.add(Gtk.SeparatorMenuItem())
        add_item = Gtk.MenuItem(label=_("Add..."))
        add_item.connect('activate', add_file)
        menu.add(add_item)
        manage_item = Gtk.MenuItem(label=_("Manage..."))
        manage_item.connect('activate', window)
        menu.add(manage_item)
        menu.show_all()
        menu.connect('deactivate', self._popup_menu_hide, button)
        self.action_popup(button)

    def sig_note(self, widget=None):
        record = self.screen.current_record
        if not record or record.id < 0:
            return
        Note(record, lambda: self.refresh_resources(reload=True))

    def refresh_resources(self, reload=False):
        record = self.screen.current_record
        self.update_resources(
            record.get_resources(reload=reload) if record else None)

    def update_resources(self, resources):
        if not resources:
            resources = {}
        record = self.screen.current_record
        sensitive = record.id >= 0 if record else False

        def update(name, label, icon, badge):
            button = self.buttons[name]
            button.set_label(label)
            image = common.IconFactory.get_image(icon,
                                                 Gtk.IconSize.LARGE_TOOLBAR,
                                                 badge=badge)
            image.show()
            button.set_icon_widget(image)
            button.props.sensitive = sensitive

        attachment_count = resources.get('attachment_count', 0)
        badge = 1 if attachment_count else None
        label = _("Attachment (%s)") % attachment_count
        update('attach', label, 'tryton-attach', badge)

        note_count = resources.get('note_count', 0)
        note_unread = resources.get('note_unread', 0)
        if note_unread:
            badge = 2
        elif note_count:
            badge = 1
        else:
            badge = None
        label = _("Note (%d/%d)") % (note_unread, note_count)
        update('note', label, 'tryton-note', badge)

    def sig_switch(self, widget=None):
        if not self.modified_save():
            return
        self.screen.switch_view()

    def sig_logs(self, widget=None):
        current_record = self.screen.current_record
        if not current_record or current_record.id < 0:
            self.message_info(_('You have to select one record.'),
                              Gtk.MessageType.INFO)
            return False

        fields = [
            ('id', _('ID:')),
            ('create_uid.rec_name', _('Created by:')),
            ('create_date', _('Created at:')),
            ('write_uid.rec_name', _('Edited by:')),
            ('write_date', _('Edited at:')),
        ]

        try:
            data = RPCExecute('model',
                              self.model,
                              'read', [current_record.id],
                              [x[0] for x in fields],
                              context=self.screen.context)[0]
        except RPCException:
            return
        date_format = self.screen.context.get('date_format', '%x')
        datetime_format = date_format + ' %H:%M:%S.%f'
        message_str = ''
        for (key, label) in fields:
            value = data
            keys = key.split('.')
            name = keys.pop(-1)
            for key in keys:
                value = value.get(key + '.', {})
            value = (value or {}).get(name, '/')
            if isinstance(value, datetime.datetime):
                value = timezoned_date(value).strftime(datetime_format)
            message_str += '%s %s\n' % (label, value)
        message_str += _('Model:') + ' ' + self.model
        message(message_str)
        return True

    def sig_revision(self, widget=None):
        if not self.modified_save():
            return
        current_id = (self.screen.current_record.id
                      if self.screen.current_record else None)
        try:
            revisions = RPCExecute(
                'model', self.model, 'history_revisions',
                [r.id for r in self.screen.selected_records])
        except RPCException:
            return
        revision = self.screen.context.get('_datetime')
        format_ = self.screen.context.get('date_format', '%x')
        format_ += ' %H:%M:%S.%f'
        revision = Revision(revisions, revision, format_).run()
        # Prevent too old revision in form view
        if (self.screen.current_view.view_type == 'form' and revision
                and revision < revisions[-1][0]):
            revision = revisions[-1][0]
        if revision != self.screen.context.get('_datetime'):
            self.screen.clear()
            # Update root group context that will be propagated
            self.screen.group._context['_datetime'] = revision
            if self.screen.current_view.view_type != 'form':
                self.screen.search_filter(
                    self.screen.screen_container.get_text())
            else:
                # Test if record exist in revisions
                self.screen.load([current_id])
            self.screen.display(set_cursor=True)
            self.update_revision()

    def update_revision(self):
        tooltips = common.Tooltips()
        revision = self.screen.context.get('_datetime')
        if revision:
            format_ = self.screen.context.get('date_format', '%x')
            format_ += ' %H:%M:%S.%f'
            revision_label = ' @ %s' % revision.strftime(format_)
            label = common.ellipsize(self.name,
                                     80 - len(revision_label)) + revision_label
            tooltip = self.name + revision_label
        else:
            label = common.ellipsize(self.name, 80)
            tooltip = self.name
        self.title.set_markup(label)
        tooltips.set_tip(self.title, tooltip)
        self.set_buttons_sensitive(revision)

    def set_buttons_sensitive(self, revision=None):
        if not revision:
            access = common.MODELACCESS[self.model]
            for name, sensitive in [
                ('new', access['create']),
                ('save', access['create'] or access['write']),
                ('remove', access['delete']),
                ('copy', access['create']),
                ('import', access['create']),
            ]:
                if name in self.buttons:
                    self.buttons[name].props.sensitive = sensitive
                if name in self.menu_buttons:
                    self.menu_buttons[name].props.sensitive = sensitive
        else:
            for name in ['new', 'save', 'remove', 'copy', 'import']:
                if name in self.buttons:
                    self.buttons[name].props.sensitive = False
                if name in self.menu_buttons:
                    self.menu_buttons[name].props.sensitive = False

    def sig_remove(self, widget=None):
        if not common.MODELACCESS[self.model]['delete']:
            return
        if self.screen.current_view.view_type == 'form':
            msg = _('Are you sure to remove this record?')
        else:
            msg = _('Are you sure to remove those records?')
        if sur(msg):
            if not self.screen.remove(delete=True, force_remove=True):
                self.message_info(_('Records not removed.'),
                                  Gtk.MessageType.ERROR)
            else:
                self.message_info(_('Records removed.'), Gtk.MessageType.INFO)
                self.screen.count_tab_domain()

    def sig_import(self, widget=None):
        WinImport(self.title.get_text(), self.model, self.screen.context)

    def sig_export(self, widget=None):
        if not self.modified_save():
            return
        export = WinExport(self.title.get_text(),
                           self.model,
                           [r.id for r in self.screen.selected_records],
                           context=self.screen.context)
        for name in self.screen.current_view.get_fields():
            type = self.screen.group.fields[name].attrs['type']
            if type == 'selection':
                export.sel_field(name + '.translated')
            elif type == 'reference':
                export.sel_field(name + '.translated')
                export.sel_field(name + '/rec_name')
            else:
                export.sel_field(name)

    def do_export(self, widget, export):
        if not self.modified_save():
            return
        ids = [r.id for r in self.screen.selected_records]
        fields = [f['name'] for f in export['export_fields.']]
        data = RPCExecute('model',
                          self.model,
                          'export_data',
                          ids,
                          fields,
                          context=self.screen.context)
        delimiter = ','
        if os.name == 'nt' and ',' == locale.localeconv()['decimal_point']:
            delimiter = ';'
        fileno, fname = tempfile.mkstemp('.csv',
                                         common.slugify(export['name']) + '_')
        with open(fname, 'w') as fp:
            writer = csv.writer(fp, delimiter=delimiter)
            writer.writerow(fields)
            for row in data:
                writer.writerow(WinExport.format_row(row))
        os.close(fileno)
        common.file_open(fname, 'csv')

    def sig_new(self, widget=None, autosave=True):
        if not common.MODELACCESS[self.model]['create']:
            return
        if autosave:
            if not self.modified_save():
                return
        self.screen.new()
        self.message_info()
        self.activate_save()

    def sig_copy(self, widget=None):
        if not common.MODELACCESS[self.model]['create']:
            return
        if not self.modified_save():
            return
        if self.screen.copy():
            self.message_info(_('Working now on the duplicated record(s).'),
                              Gtk.MessageType.INFO)
            self.screen.count_tab_domain()

    def sig_save(self, widget=None):
        if widget:
            # Called from button so we must save the tree state
            self.screen.save_tree_state()
        if not (common.MODELACCESS[self.model]['write']
                or common.MODELACCESS[self.model]['create']):
            return
        if self.screen.save_current():
            self.message_info(_('Record saved.'), Gtk.MessageType.INFO)
            self.screen.count_tab_domain()
            return True
        else:
            self.message_info(self.screen.invalid_message(),
                              Gtk.MessageType.ERROR)
            return False

    def sig_previous(self, widget=None):
        if not self.modified_save():
            return
        self.screen.display_prev()
        self.message_info()
        self.activate_save()

    def sig_next(self, widget=None):
        if not self.modified_save():
            return
        self.screen.display_next()
        self.message_info()
        self.activate_save()

    def sig_reload(self, test_modified=True):
        if test_modified:
            if not self.modified_save():
                return False
        else:
            self.screen.save_tree_state(store=False)
        self.screen.cancel_current()
        set_cursor = False
        record_id = (self.screen.current_record.id
                     if self.screen.current_record else None)
        if self.screen.current_view.view_type != 'form':
            self.screen.search_filter(self.screen.screen_container.get_text())
            for record in self.screen.group:
                if record.id == record_id:
                    self.screen.current_record = record
                    set_cursor = True
                    break
        self.screen.display(set_cursor=set_cursor)
        self.message_info()
        self.activate_save()
        self.screen.count_tab_domain()
        return True

    def sig_action(self, widget):
        if self.buttons['action'].props.sensitive:
            self.buttons['action'].props.active = True

    def sig_print(self, widget):
        if self.buttons['print'].props.sensitive:
            self.buttons['print'].props.active = True

    def sig_print_open(self, widget):
        if self.buttons['open'].props.sensitive:
            self.buttons['open'].props.active = True

    def sig_print_email(self, widget):
        if self.buttons['email'].props.sensitive:
            self.buttons['email'].props.active = True

    def sig_relate(self, widget):
        if self.buttons['relate'].props.sensitive:
            self.buttons['relate'].props.active = True

    def sig_copy_url(self, widget):
        if self.buttons['copy_url'].props.sensitive:
            self.buttons['copy_url'].props.active = True

    def sig_search(self, widget):
        search_container = self.screen.screen_container
        if hasattr(search_container, 'search_entry'):
            search_container.search_entry.grab_focus()

    def action_popup(self, widget):
        button, = widget.get_children()
        button.grab_focus()
        menu = widget._menu
        if not widget.props.active:
            menu.popdown()
            return

        def menu_position(menu, x, y, user_data):
            widget_allocation = widget.get_allocation()
            x, y = widget.get_window().get_root_coords(widget_allocation.x,
                                                       widget_allocation.y)
            return (x, y + widget_allocation.height, False)

        menu.show_all()
        if hasattr(menu, 'popup_at_widget'):
            menu.popup_at_widget(widget, Gdk.Gravity.SOUTH_WEST,
                                 Gdk.Gravity.NORTH_WEST,
                                 Gtk.get_current_event())
        else:
            menu.popup(None, None, menu_position, None, 0,
                       Gtk.get_current_event_time())

    def _record_message(self, screen, signal_data):
        name = '_'
        if signal_data[0]:
            name = str(signal_data[0])
        for button_id in ('print', 'relate', 'email', 'open', 'save',
                          'attach'):
            button = self.buttons[button_id]
            can_be_sensitive = getattr(button, '_can_be_sensitive', True)
            if button_id in {'print', 'relate', 'email', 'open'}:
                action_type = button_id
                if button_id in {'email', 'open'}:
                    action_type = 'print'
                can_be_sensitive |= any(
                    b.attrs.get('keyword', 'action') == action_type
                    for b in screen.get_buttons())
            button.props.sensitive = (bool(signal_data[0])
                                      and can_be_sensitive)
        button_switch = self.buttons['switch']
        button_switch.props.sensitive = self.screen.number_of_views > 1

        msg = name + ' / ' + str(signal_data[1])
        if signal_data[1] < signal_data[2]:
            msg += _(' of ') + str(signal_data[2])
        self.status_label.set_text(msg)
        self.message_info()
        self.activate_save()

    def _record_modified(self, screen, signal_data):
        # As it is called via idle_add, the form could have been destroyed in
        # the meantime.
        if self.widget_get().props.window:
            self.activate_save()

    def _record_saved(self, screen, signal_data):
        self.activate_save()
        self.refresh_resources()

    def modified_save(self):
        self.screen.save_tree_state()
        self.screen.current_view.set_value()
        if self.screen.modified():
            value = sur_3b(
                _('This record has been modified\n'
                  'do you want to save it?'))
            if value == 'ok':
                return self.sig_save(None)
            if value == 'ko':
                return self.sig_reload(test_modified=False)
            return False
        return True

    def sig_close(self, widget=None):
        for dialog in reversed(self.dialogs[:]):
            dialog.destroy()
        return self.modified_save()

    def _action(self, action, atype):
        if not self.modified_save():
            return
        action = action.copy()
        record_id = (self.screen.current_record.id
                     if self.screen.current_record else None)
        record_ids = [r.id for r in self.screen.selected_records]
        action = Action.evaluate(action, atype, self.screen.current_record)
        data = {
            'model': self.screen.model_name,
            'id': record_id,
            'ids': record_ids,
        }
        Action.execute(action, data, context=self.screen.local_context)

    def activate_save(self):
        self.buttons['save'].props.sensitive = self.screen.modified()

    def sig_win_close(self, widget):
        Main().sig_win_close(widget)

    def create_toolbar(self, toolbars):
        gtktoolbar = super(Form, self).create_toolbar(toolbars)

        attach_btn = self.buttons['attach']
        attach_btn.drag_dest_set(Gtk.DestDefaults.ALL, [
            Gtk.TargetEntry.new('text/uri-list', 0, 0),
            Gtk.TargetEntry.new('text/plain', 0, 0),
        ], Gdk.DragAction.MOVE | Gdk.DragAction.COPY)
        attach_btn.connect('drag_data_received',
                           self.attach_drag_data_received)

        iconstock = {
            'print': 'tryton-print',
            'action': 'tryton-launch',
            'relate': 'tryton-link',
            'email': 'tryton-email',
            'open': 'tryton-open',
        }
        for action_type, special_action, action_name, tooltip in (
            ('action', 'action', _('Action'), _('Launch action')),
            ('relate', 'relate', _('Relate'), _('Open related records')),
            (None, ) * 4,
            ('print', 'open', _('Report'), _('Open report')),
            ('print', 'email', _('E-Mail'), _('E-Mail report')),
            ('print', 'print', _('Print'), _('Print report')),
        ):
            if action_type is not None:
                tbutton = Gtk.ToggleToolButton()
                tbutton.set_icon_widget(
                    common.IconFactory.get_image(iconstock.get(special_action),
                                                 Gtk.IconSize.LARGE_TOOLBAR))
                tbutton.set_label(action_name)
                tbutton._menu = self._create_popup_menu(
                    tbutton, action_type, toolbars[action_type],
                    special_action)
                tbutton.connect('toggled', self.action_popup)
                self.tooltips.set_tip(tbutton, tooltip)
                self.buttons[special_action] = tbutton
                if action_type != 'action':
                    tbutton._can_be_sensitive = bool(
                        tbutton._menu.get_children())
            else:
                tbutton = Gtk.SeparatorToolItem()
            gtktoolbar.insert(tbutton, -1)

        exports = toolbars['exports']
        if exports:
            tbutton = self.buttons['open']
            tbutton._can_be_sensitive = True
            menu = tbutton._menu
            if menu.get_children():
                menu.add(Gtk.SeparatorMenuItem())
            for export in exports:
                menuitem = Gtk.MenuItem(set_underline(export['name']))
                menuitem.set_use_underline(True)
                menuitem.connect('activate', self.do_export, export)
                menu.add(menuitem)

        gtktoolbar.insert(Gtk.SeparatorToolItem(), -1)

        url_button = Gtk.ToggleToolButton()
        url_button.set_icon_widget(
            common.IconFactory.get_image('tryton-public',
                                         Gtk.IconSize.LARGE_TOOLBAR))
        url_button.set_label(_('_Copy URL'))
        url_button.set_use_underline(True)
        self.tooltips.set_tip(url_button, _('Copy URL into clipboard'))
        url_button._menu = url_menu = Gtk.Menu()
        url_menuitem = Gtk.MenuItem()
        url_menuitem.connect('activate', self.url_copy)
        url_menu.add(url_menuitem)
        url_menu.show_all()
        url_menu.connect('deactivate', self._popup_menu_hide, url_button)
        url_button.connect('toggled', self.url_set, url_menuitem)
        url_button.connect('toggled', self.action_popup)
        self.buttons['copy_url'] = url_button
        gtktoolbar.insert(url_button, -1)
        return gtktoolbar

    def _create_popup_menu(self, widget, keyword, actions, special_action):
        menu = Gtk.Menu()
        menu.connect('deactivate', self._popup_menu_hide, widget)
        widget.connect('toggled', self._update_popup_menu, menu, keyword)

        for action in actions:
            new_action = action.copy()
            if special_action == 'print':
                new_action['direct_print'] = True
            elif special_action == 'email':
                new_action['email_print'] = True
            menuitem = Gtk.MenuItem(label=set_underline(action['name']))
            menuitem.set_use_underline(True)
            menuitem.connect('activate', self._popup_menu_selected, widget,
                             new_action, keyword)
            menu.add(menuitem)
        return menu

    def _popup_menu_selected(self, menuitem, togglebutton, action, keyword):
        event = Gtk.get_current_event()
        allow_similar = False
        if (event.state & Gdk.ModifierType.CONTROL_MASK
                or event.state & Gdk.ModifierType.MOD1_MASK):
            allow_similar = True
        with Window(hide_current=True, allow_similar=allow_similar):
            self._action(action, keyword)
        togglebutton.props.active = False

    def _popup_menu_hide(self, menuitem, togglebutton):
        togglebutton.props.active = False

    def _update_popup_menu(self, tbutton, menu, keyword):
        for item in menu.get_children():
            if getattr(item, '_update_action', False):
                menu.remove(item)

        buttons = [
            b for b in self.screen.get_buttons()
            if keyword == b.attrs.get('keyword', 'action')
        ]
        if buttons and menu.get_children():
            separator = Gtk.SeparatorMenuItem()
            separator._update_action = True
            menu.add(separator)
        for button in buttons:
            menuitem = Gtk.MenuItem(label=set_underline(
                button.attrs.get('string', _('Unknown'))),
                                    use_underline=True)
            menuitem.connect('activate',
                             lambda m, attrs: self.screen.button(attrs),
                             button.attrs)
            menuitem._update_action = True
            menu.add(menuitem)

        kw_plugins = []
        for plugin in plugins.MODULES:
            for plugin_spec in plugin.get_plugins(self.model):
                name, func = plugin_spec[:2]
                try:
                    plugin_keyword = plugin_spec[2]
                except IndexError:
                    plugin_keyword = 'action'
                if keyword != plugin_keyword:
                    continue
                kw_plugins.append((name, func))

        if kw_plugins:
            separator = Gtk.SeparatorMenuItem()
            separator._update_action = True
            menu.add(separator)
        for name, func in kw_plugins:
            menuitem = Gtk.MenuItem(label=set_underline(name))
            menuitem.set_use_underline(True)
            menuitem.connect(
                'activate', lambda m, func: func({
                    'model':
                    self.model,
                    'ids': [r.id for r in self.screen.selected_records],
                    'id': (self.screen.current_record.id
                           if self.screen.current_record else None),
                }), func)
            menuitem._update_action = True
            menu.add(menuitem)

    def url_copy(self, menuitem):
        url = self.screen.get_url(self.name)
        for selection in [
                Gdk.Atom.intern('PRIMARY', True),
                Gdk.Atom.intern('CLIPBOARD', True),
        ]:
            clipboard = Gtk.Clipboard.get(selection)
            clipboard.set_text(url, -1)

    def url_set(self, button, menuitem):
        url = self.screen.get_url(self.name)
        size = 80
        if len(url) > size:
            url = url[:size // 2] + '...' + url[-size // 2:]
        menuitem.set_label(url)

    def set_cursor(self):
        if self.screen:
            self.screen.set_cursor(reset_view=False)

    def attach_drag_data_received(self, widget, context, x, y, selection, info,
                                  timestamp):
        record = self.screen.current_record
        if not record or record.id < 0:
            return
        win_attach = Attachment(record,
                                lambda: self.refresh_resources(reload=True))
        if info == 0:
            if selection.get_uris():
                for uri in selection.get_uris():
                    # Win32 cut&paste terminates the list with a NULL character
                    if not uri or uri == '\0':
                        continue
                    win_attach.add_uri(uri)
            else:
                win_attach.add_uri(selection.get_text())
Exemplo n.º 58
0
class Action(SignalEvent):

    def __init__(self, attrs=None, context=None):
        super(Action, self).__init__()
        self.act_id = int(attrs['name'])
        self.context = context or {}

        try:
            self.action = RPCExecute('model', 'ir.action.act_window', 'read',
                self.act_id, False)
        except RPCException:
            raise

        view_ids = None
        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)
        name = self.screen.current_view.title
        self.screen.signal_connect(self, 'record-message',
            self._active_changed)

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

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

        self.screen.search_filter()

    def row_activate(self):
        if not self.screen.current_record:
            return

        def callback(result):
            if result:
                self.screen.current_record.save()
            else:
                self.screen.current_record.cancel()
        WinForm(self.screen, callback)

    def set_value(self, mode, model_field):
        self.screen.current_view.set_value()
        return True

    def display(self):
        self.screen.search_filter(self.screen.screen_container.get_text())

    def _active_changed(self, *args):
        self.signal('active-changed')

    def _get_active(self):
        if self.screen and self.screen.current_record:
            return common.EvalEnvironment(self.screen.current_record, False)

    active = property(_get_active)

    def update_domain(self, actions):
        domain_ctx = self.context.copy()
        domain_ctx['context'] = domain_ctx
        domain_ctx['_user'] = rpc._USER
        for action in actions:
            if action.active:
                domain_ctx['_active_%s' % action.act_id] = action.active
        new_domain = PYSONDecoder(domain_ctx).decode(
                self.action['pyson_domain'])
        if self.domain == new_domain:
            return
        del self.domain[:]
        self.domain.extend(new_domain)
        if hasattr(self, 'screen'):  # Catch early update
            self.display()
Exemplo n.º 59
0
    def __init__(self, view, attrs):
        super(One2Many, self).__init__(view, attrs)

        self.widget = gtk.Frame()
        self.widget.set_shadow_type(gtk.SHADOW_NONE)
        self.widget.get_accessible().set_name(attrs.get('string', ''))
        vbox = gtk.VBox(homogeneous=False, spacing=2)
        self.widget.add(vbox)
        self._readonly = True
        self._required = False
        self._position = 0
        self._length = 0

        self.title_box = hbox = gtk.HBox(homogeneous=False, spacing=0)
        hbox.set_border_width(2)

        self.title = gtk.Label(attrs.get('string', ''))
        self.title.set_alignment(0.0, 0.5)
        hbox.pack_start(self.title, expand=True, fill=True)

        hbox.pack_start(gtk.VSeparator(), expand=False, fill=True)

        tooltips = common.Tooltips()

        self.focus_out = True
        self.wid_completion = None
        if attrs.get('add_remove'):

            self.wid_text = PlaceholderEntry()
            self.wid_text.set_placeholder_text(_('Search'))
            self.wid_text.set_property('width_chars', 13)
            self.wid_text.connect('focus-out-event',
                                  lambda *a: self._focus_out())
            hbox.pack_start(self.wid_text, expand=True, fill=True)

            if int(self.attrs.get('completion', 1)):
                access = common.MODELACCESS[attrs['relation']]
                self.wid_completion = get_completion(
                    search=access['read'] and access['write'],
                    create=attrs.get('create', True) and access['create'])
                self.wid_completion.connect('match-selected',
                                            self._completion_match_selected)
                self.wid_completion.connect('action-activated',
                                            self._completion_action_activated)
                self.wid_text.set_completion(self.wid_completion)
                self.wid_text.connect('changed', self._update_completion)

            self.but_add = gtk.Button()
            tooltips.set_tip(self.but_add, _('Add existing record'))
            self.but_add.connect('clicked', self._sig_add)
            img_add = gtk.Image()
            img_add.set_from_stock('tryton-list-add',
                                   gtk.ICON_SIZE_SMALL_TOOLBAR)
            img_add.set_alignment(0.5, 0.5)
            self.but_add.add(img_add)
            self.but_add.set_relief(gtk.RELIEF_NONE)
            hbox.pack_start(self.but_add, expand=False, fill=False)

            self.but_remove = gtk.Button()
            tooltips.set_tip(self.but_remove, _('Remove selected record'))
            self.but_remove.connect('clicked', self._sig_remove, True)
            img_remove = gtk.Image()
            img_remove.set_from_stock('tryton-list-remove',
                                      gtk.ICON_SIZE_SMALL_TOOLBAR)
            img_remove.set_alignment(0.5, 0.5)
            self.but_remove.add(img_remove)
            self.but_remove.set_relief(gtk.RELIEF_NONE)
            hbox.pack_start(self.but_remove, expand=False, fill=False)

            hbox.pack_start(gtk.VSeparator(), expand=False, fill=True)

        self.but_new = gtk.Button()
        tooltips.set_tip(self.but_new, _('Create a new record <F3>'))
        self.but_new.connect('clicked', self._sig_new)
        img_new = gtk.Image()
        img_new.set_from_stock('tryton-new', gtk.ICON_SIZE_SMALL_TOOLBAR)
        img_new.set_alignment(0.5, 0.5)
        self.but_new.add(img_new)
        self.but_new.set_relief(gtk.RELIEF_NONE)
        hbox.pack_start(self.but_new, expand=False, fill=False)

        self.but_open = gtk.Button()
        tooltips.set_tip(self.but_open, _('Edit selected record <F2>'))
        self.but_open.connect('clicked', self._sig_edit)
        img_open = gtk.Image()
        img_open.set_from_stock('tryton-open', gtk.ICON_SIZE_SMALL_TOOLBAR)
        img_open.set_alignment(0.5, 0.5)
        self.but_open.add(img_open)
        self.but_open.set_relief(gtk.RELIEF_NONE)
        hbox.pack_start(self.but_open, expand=False, fill=False)

        self.but_del = gtk.Button()
        tooltips.set_tip(self.but_del, _('Delete selected record <Del>'))
        self.but_del.connect('clicked', self._sig_remove, False)
        img_del = gtk.Image()
        img_del.set_from_stock('tryton-delete', gtk.ICON_SIZE_SMALL_TOOLBAR)
        img_del.set_alignment(0.5, 0.5)
        self.but_del.add(img_del)
        self.but_del.set_relief(gtk.RELIEF_NONE)
        hbox.pack_start(self.but_del, expand=False, fill=False)

        self.but_undel = gtk.Button()
        tooltips.set_tip(self.but_undel, _('Undelete selected record <Ins>'))
        self.but_undel.connect('clicked', self._sig_undelete)
        img_undel = gtk.Image()
        img_undel.set_from_stock('tryton-undo', gtk.ICON_SIZE_SMALL_TOOLBAR)
        img_undel.set_alignment(0.5, 0.5)
        self.but_undel.add(img_undel)
        self.but_undel.set_relief(gtk.RELIEF_NONE)
        hbox.pack_start(self.but_undel, expand=False, fill=False)

        hbox.pack_start(gtk.VSeparator(), expand=False, fill=True)

        self.but_pre = gtk.Button()
        tooltips.set_tip(self.but_pre, _('Previous'))
        self.but_pre.connect('clicked', self._sig_previous)
        img_pre = gtk.Image()
        img_pre.set_from_stock('tryton-go-previous',
                               gtk.ICON_SIZE_SMALL_TOOLBAR)
        img_pre.set_alignment(0.5, 0.5)
        self.but_pre.add(img_pre)
        self.but_pre.set_relief(gtk.RELIEF_NONE)
        hbox.pack_start(self.but_pre, expand=False, fill=False)

        self.label = gtk.Label('(0,0)')
        hbox.pack_start(self.label, expand=False, fill=False)

        self.but_next = gtk.Button()
        tooltips.set_tip(self.but_next, _('Next'))
        self.but_next.connect('clicked', self._sig_next)
        img_next = gtk.Image()
        img_next.set_from_stock('tryton-go-next', gtk.ICON_SIZE_SMALL_TOOLBAR)
        img_next.set_alignment(0.5, 0.5)
        self.but_next.add(img_next)
        self.but_next.set_relief(gtk.RELIEF_NONE)
        hbox.pack_start(self.but_next, expand=False, fill=False)

        hbox.pack_start(gtk.VSeparator(), expand=False, fill=True)

        but_switch = gtk.Button()
        tooltips.set_tip(but_switch, _('Switch'))
        but_switch.connect('clicked', self.switch_view)
        img_switch = gtk.Image()
        img_switch.set_from_stock('tryton-fullscreen',
                                  gtk.ICON_SIZE_SMALL_TOOLBAR)
        img_switch.set_alignment(0.5, 0.5)
        but_switch.add(img_switch)
        but_switch.set_relief(gtk.RELIEF_NONE)
        hbox.pack_start(but_switch, expand=False, fill=False)

        if attrs.get('add_remove'):
            hbox.set_focus_chain([self.wid_text])
        else:
            hbox.set_focus_chain([])

        tooltips.enable()

        frame = gtk.Frame()
        frame.add(hbox)
        frame.set_shadow_type(gtk.SHADOW_OUT)
        vbox.pack_start(frame, expand=False, fill=True)

        self.screen = Screen(attrs['relation'],
                             mode=attrs.get('mode', 'tree,form').split(','),
                             view_ids=attrs.get('view_ids', '').split(','),
                             views_preload=attrs.get('views', {}),
                             row_activate=self._on_activate,
                             exclude_field=attrs.get('relation_field', None))
        self.screen.pre_validate = bool(int(attrs.get('pre_validate', 0)))
        self.screen.signal_connect(self, 'record-message', self._sig_label)

        vbox.pack_start(self.screen.widget, expand=True, fill=True)

        self.screen.widget.connect('key_press_event', self.on_keypress)
        if self.attrs.get('add_remove'):
            self.wid_text.connect('key_press_event', self.on_keypress)

        but_switch.props.sensitive = self.screen.number_of_views > 1
Exemplo n.º 60
0
    def __init__(self, attrs=None, context=None):
        super(Action, self).__init__()
        self.act_id = int(attrs['name'])
        self.context = context or {}

        try:
            self.action = RPCExecute('model', 'ir.action.act_window', 'read',
                self.act_id, False)
        except RPCException:
            raise

        view_ids = None
        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)
        name = self.screen.current_view.title
        self.screen.signal_connect(self, 'record-message',
            self._active_changed)

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

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

        self.screen.search_filter()