Add multiselection widget for many2many

review3151003
issue3634
This commit is contained in:
Nicolas Évrard committed 2014-03-16 21:14:43 +01:00
1 parent d04b101539
commit 3ffbf5edce
5 files changed
+109 -3

No files matched your search

+1
View File
@@ -1,3 +1,4 @@
* Add a multi selection widget for many2many
* Remove auto-refresh
* Add support of domain for non-relation field
* Allow drag & drop on the attachment button
+3 -1
View File
@@ -14,6 +14,7 @@ class SelectionMixin(object):
def __init__(self, *args, **kwargs):
super(SelectionMixin, self).__init__(*args, **kwargs)
self.nullable_widget = True
self.selection = None
self.inactive_selection = []
self._last_domain = None
@@ -73,7 +74,8 @@ class SelectionMixin(object):
result = False
if isinstance(result, list):
selection = [(x['id'], x['rec_name']) for x in result]
selection.append((None, ''))
if self.nullable_widget:
selection.append((None, ''))
self._last_domain = (domain, context)
self._domain_cache[domain_cache_key] = selection
else:
+4 -2
View File
@@ -603,7 +603,8 @@ class O2MField(CharField):
if mode == 'list ids':
for old_record in group:
group.remove(old_record, remove=True, signal=False)
if old_record.id not in value:
group.remove(old_record, remove=True, signal=False)
group.load(value)
else:
for vals in value:
@@ -645,7 +646,8 @@ class O2MField(CharField):
previous_ids = [r.id for r in record.value.get(self.name) or []]
self._set_value(record, value)
if previous_ids != value:
# The order of the ids is not significant
if set(previous_ids) != set(value):
record.modified_fields.setdefault(self.name)
record.signal('record-modified')
self.sig_changed(record)
@@ -0,0 +1,99 @@
# This file is part of Tryton. The COPYRIGHT file at the top level of this
# repository contains the full copyright notices and license terms.
import gtk
import gobject
from .interface import WidgetInterface
from tryton.common.selection import SelectionMixin
MOVEMENT_KEYS = {gtk.keysyms.Up, gtk.keysyms.Down, gtk.keysyms.space,
gtk.keysyms.Left, gtk.keysyms.KP_Left,
gtk.keysyms.Right, gtk.keysyms.KP_Right,
gtk.keysyms.Home, gtk.keysyms.KP_Home,
gtk.keysyms.End, gtk.keysyms.KP_End}
class MultiSelection(WidgetInterface, SelectionMixin):
def __init__(self, field_name, model_name, attrs=None):
super(MultiSelection, self).__init__(field_name, model_name,
attrs=attrs)
self.widget = viewport = gtk.Viewport()
viewport.set_shadow_type(gtk.SHADOW_ETCHED_IN)
scroll = gtk.ScrolledWindow()
scroll.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
scroll.set_placement(gtk.CORNER_TOP_LEFT)
viewport.add(scroll)
self.model = gtk.ListStore(gobject.TYPE_INT, gobject.TYPE_STRING)
self.tree = gtk.TreeView()
self.tree.set_model(self.model)
self.tree.set_search_column(1)
self.tree.connect('focus-out-event', lambda *a: self._focus_out())
self.tree.connect('button-press-event', self.__button_press)
self.tree.connect('key_press_event', self.__key_press)
selection = self.tree.get_selection()
selection.set_mode(gtk.SELECTION_MULTIPLE)
selection.connect('changed', self.send_modified)
scroll.add(self.tree)
name_column = gtk.TreeViewColumn(attrs.get('string', ''))
name_cell = gtk.CellRendererText()
name_column.pack_start(name_cell)
name_column.add_attribute(name_cell, 'text', 1)
self.tree.append_column(name_column)
self.nullable_widget = False
self.init_selection()
self.id2path = {}
def _color_widget(self):
return self.tree
def grab_focus(self):
self.tree.grab_focus()
@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 send_modified(self, *args):
if self.record:
self.record.signal('record-modified')
def get_value(self):
model, paths = self.tree.get_selection().get_selected_rows()
return [model[path][0] for path in paths]
def set_value(self, record, field):
field.set_client(record, self.get_value())
def display(self, record, field):
self.update_selection(record, field)
super(MultiSelection, self).display(record, field)
self.model.clear()
if field is None:
return
id2path = {}
for idx, (value, name) in enumerate(self.selection):
self.model.append((value, name))
id2path[value] = idx
selection = self.tree.get_selection()
selection.unselect_all()
group = field.get_client(record)
for element in group:
if (element not in group.record_removed
and element not in group.record_deleted):
selection.select_path(id2path[element.id])
def __button_press(self, treeview, event):
if event.button == 1:
event.state |= gtk.gdk.CONTROL_MASK
def __key_press(self, treeview, event):
if event.keyval in MOVEMENT_KEYS:
event.state |= gtk.gdk.CONTROL_MASK
@@ -537,6 +537,7 @@ from progressbar import ProgressBar
from one2one import One2One
from richtextbox import RichTextBox
from dictionary import DictWidget
from multiselection import MultiSelection
WIDGETS_TYPE = {
@@ -567,4 +568,5 @@ WIDGETS_TYPE = {
'one2one': (One2One, 1, False, False),
'richtext': (RichTextBox, 1, True, True),
'dict': (DictWidget, 1, False, False),
'multiselection': (MultiSelection, 1, True, True),
}