Add button to list view
This commit is contained in:
@@ -0,0 +1,76 @@
|
||||
#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
|
||||
import pango
|
||||
|
||||
|
||||
class CellRendererButton(gtk.GenericCellRenderer):
|
||||
#TODO Add keyboard editing
|
||||
__gproperties__ = {
|
||||
"text": (gobject.TYPE_STRING, None, "Text",
|
||||
"Displayed text", gobject.PARAM_READWRITE),
|
||||
}
|
||||
|
||||
__gsignals__ = {
|
||||
'clicked': (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE,
|
||||
(gobject.TYPE_STRING, )),
|
||||
}
|
||||
|
||||
def __init__(self, text=""):
|
||||
self.__gobject_init__()
|
||||
self.text = text
|
||||
self.set_property('mode', gtk.CELL_RENDERER_MODE_EDITABLE)
|
||||
self.clicking = False
|
||||
|
||||
def do_set_property(self, pspec, value):
|
||||
setattr(self, pspec.name, value)
|
||||
|
||||
def do_get_property(self, pspec):
|
||||
return getattr(self, pspec.name)
|
||||
|
||||
def on_render(self, window, widget, background_area, cell_area,
|
||||
expose_area, flags):
|
||||
state = gtk.STATE_NORMAL
|
||||
shadow = gtk.SHADOW_OUT
|
||||
if self.clicking and flags & gtk.CELL_RENDERER_SELECTED:
|
||||
state = gtk.STATE_ACTIVE
|
||||
shadow = gtk.SHADOW_IN
|
||||
widget.style.paint_box(window, state, shadow,
|
||||
None, widget, "button",
|
||||
cell_area.x, cell_area.y,
|
||||
cell_area.width, cell_area.height)
|
||||
layout = widget.create_pango_layout('')
|
||||
layout.set_font_description(widget.style.font_desc)
|
||||
w, h = layout.get_size()
|
||||
x = cell_area.x
|
||||
y = int(cell_area.y + (cell_area.height - h / pango.SCALE) / 2)
|
||||
window.draw_layout(widget.style.text_gc[0], x, y, layout)
|
||||
|
||||
layout = widget.create_pango_layout(self.text)
|
||||
layout.set_font_description(widget.style.font_desc)
|
||||
w, h = layout.get_size()
|
||||
x = cell_area.x + 3
|
||||
y = int(cell_area.y + (cell_area.height - h / pango.SCALE) / 2)
|
||||
window.draw_layout(widget.style.text_gc[0], x, y, layout)
|
||||
|
||||
def on_get_size(self, widget, cell_area=None):
|
||||
if cell_area is None:
|
||||
return (0, 0, 30, 18)
|
||||
else:
|
||||
return (cell_area.x, cell_area.y, cell_area.width, cell_area.height)
|
||||
|
||||
def on_start_editing(self, event, widget, path, background_area,
|
||||
cell_area, flags):
|
||||
if event is not None and ((event.type == gtk.gdk.BUTTON_PRESS) \
|
||||
or (event.type == gtk.gdk.KEY_PRESS \
|
||||
and event.keyval == gtk.keysyms.space)):
|
||||
self.clicking = True
|
||||
widget.queue_draw()
|
||||
gtk.main_iteration()
|
||||
self.emit("clicked", path)
|
||||
def timeout(self, widget):
|
||||
self.clicking = False
|
||||
widget.queue_draw()
|
||||
gobject.timeout_add(60, timeout, self, widget)
|
||||
|
||||
gobject.type_register(CellRendererButton)
|
||||
@@ -10,6 +10,7 @@ from tryton.common import message
|
||||
import gettext
|
||||
import tryton.common as common
|
||||
from tryton.config import CONFIG
|
||||
from tryton.common.cellrendererbutton import CellRendererButton
|
||||
|
||||
_ = gettext.gettext
|
||||
|
||||
@@ -507,7 +508,8 @@ class ViewList(ParserView):
|
||||
renderer = renderers[0]
|
||||
if isinstance(renderer, gtk.CellRendererToggle):
|
||||
editable = renderer.get_property('activatable')
|
||||
elif isinstance(renderer, gtk.CellRendererProgress):
|
||||
elif isinstance(renderer,
|
||||
(gtk.CellRendererProgress, CellRendererButton)):
|
||||
editable = False
|
||||
else:
|
||||
editable = renderer.get_property('editable')
|
||||
@@ -540,7 +542,8 @@ class ViewList(ParserView):
|
||||
for renderer in col.get_cell_renderers():
|
||||
if isinstance(renderer, gtk.CellRendererToggle):
|
||||
renderer.set_property('activatable', False)
|
||||
elif isinstance(renderer, gtk.CellRendererProgress):
|
||||
elif isinstance(renderer,
|
||||
(gtk.CellRendererProgress, CellRendererButton)):
|
||||
pass
|
||||
else:
|
||||
renderer.set_property('editable', False)
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
import gtk
|
||||
import parser
|
||||
import gettext
|
||||
from tryton.common.cellrendererbutton import CellRendererButton
|
||||
|
||||
_ = gettext.gettext
|
||||
|
||||
@@ -74,7 +75,8 @@ class EditableTreeView(gtk.TreeView):
|
||||
renderer = cols[idx].get_cell_renderers()[0]
|
||||
if isinstance(renderer, gtk.CellRendererToggle):
|
||||
editable = renderer.get_property('activatable')
|
||||
elif isinstance(renderer, gtk.CellRendererProgress):
|
||||
elif isinstance(renderer,
|
||||
(gtk.CellRendererProgress, CellRendererButton)):
|
||||
editable = False
|
||||
else:
|
||||
editable = renderer.get_property('editable')
|
||||
@@ -90,7 +92,8 @@ class EditableTreeView(gtk.TreeView):
|
||||
renderer = cols[idx].get_cell_renderers()[0]
|
||||
if isinstance(renderer, gtk.CellRendererToggle):
|
||||
editable = renderer.get_property('activatable')
|
||||
elif isinstance(renderer, gtk.CellRendererProgress):
|
||||
elif isinstance(renderer,
|
||||
(gtk.CellRendererProgress, CellRendererButton)):
|
||||
editable = False
|
||||
else:
|
||||
editable = renderer.get_property('editable')
|
||||
@@ -187,7 +190,8 @@ class EditableTreeView(gtk.TreeView):
|
||||
renderer = column.get_cell_renderers()[0]
|
||||
if isinstance(renderer, gtk.CellRendererToggle):
|
||||
editable = renderer.get_property('activatable')
|
||||
elif isinstance(renderer, gtk.CellRendererProgress):
|
||||
elif isinstance(renderer,
|
||||
(gtk.CellRendererProgress, CellRendererButton)):
|
||||
editable = False
|
||||
else:
|
||||
editable = renderer.get_property('editable')
|
||||
|
||||
@@ -20,6 +20,8 @@ import datetime as DT
|
||||
from tryton.common import DT_FORMAT, DHM_FORMAT, COLORS, node_attributes, TRYTON_ICON
|
||||
import tryton.common as common
|
||||
from _strptime import LocaleTime
|
||||
from tryton.common.cellrendererbutton import CellRendererButton
|
||||
from tryton.action import Action
|
||||
|
||||
def send_keys(renderer, editable, position, treeview):
|
||||
editable.connect('key_press_event', treeview.on_keypressed)
|
||||
@@ -61,6 +63,7 @@ class ParserTree(ParserInterface):
|
||||
|
||||
def parse(self, model, root_node, fields):
|
||||
dict_widget = {}
|
||||
button_list = []
|
||||
attrs = node_attributes(root_node)
|
||||
on_write = attrs.get('on_write', '')
|
||||
editable = attrs.get('editable', False)
|
||||
@@ -101,7 +104,8 @@ class ParserTree(ParserInterface):
|
||||
if editable and not node_attrs.get('readonly', False):
|
||||
if isinstance(renderer, gtk.CellRendererToggle):
|
||||
renderer.set_property('activatable', True)
|
||||
elif isinstance(renderer, gtk.CellRendererProgress):
|
||||
elif isinstance(renderer,
|
||||
(gtk.CellRendererProgress, CellRendererButton)):
|
||||
pass
|
||||
else:
|
||||
renderer.set_property('editable', True)
|
||||
@@ -179,6 +183,38 @@ class ParserTree(ParserInterface):
|
||||
digits = fields.get('digits', (16, 2))[1]
|
||||
dict_widget[i] = (fname, label, label_sum, digits,
|
||||
label_bold)
|
||||
elif node.localName == 'button':
|
||||
#TODO add shortcut
|
||||
cell = Button(treeview, node_attrs, self.window, self.screen)
|
||||
button_list.append(cell)
|
||||
renderer = cell.renderer
|
||||
string = node_attrs.get('string', _('Unknown'))
|
||||
col = gtk.TreeViewColumn(string, renderer)
|
||||
col.name = None
|
||||
|
||||
label = gtk.Label(string)
|
||||
label.show()
|
||||
help = string
|
||||
if node_attrs.get('help'):
|
||||
help += '\n' + node_attrs['help']
|
||||
tooltips.set_tip(label, help)
|
||||
tooltips.enable()
|
||||
arrow = gtk.Arrow(gtk.ARROW_DOWN, gtk.SHADOW_IN)
|
||||
col.arrow = arrow
|
||||
col.arrow_show = False
|
||||
col.set_widget(label)
|
||||
|
||||
col._type = 'button'
|
||||
if 'width' in node_attrs:
|
||||
width = int(node_attrs['width'])
|
||||
else:
|
||||
width = 80
|
||||
col.width = width
|
||||
if width > 0:
|
||||
col.set_fixed_width(width)
|
||||
col.set_resizable(True)
|
||||
col.set_sizing(gtk.TREE_VIEW_COLUMN_FIXED)
|
||||
i = treeview.append_column(col)
|
||||
if not bool(int(attrs.get('fill', '0'))):
|
||||
col = gtk.TreeViewColumn()
|
||||
col.name = None
|
||||
@@ -188,7 +224,7 @@ class ParserTree(ParserInterface):
|
||||
col.set_sizing(gtk.TREE_VIEW_COLUMN_FIXED)
|
||||
treeview.append_column(col)
|
||||
treeview.set_fixed_height_mode(True)
|
||||
return treeview, dict_widget, [], on_write, [], None
|
||||
return treeview, dict_widget, button_list, on_write, [], None
|
||||
|
||||
|
||||
class Char(object):
|
||||
@@ -633,6 +669,79 @@ class ProgressBar(object):
|
||||
def value_from_text(self, model, text):
|
||||
return float(text)
|
||||
|
||||
|
||||
class Button(object):
|
||||
|
||||
def __init__(self, treeview=None, attrs=None, window=None, screen=None):
|
||||
super(Button, self).__init__()
|
||||
self.attrs = attrs or {}
|
||||
self.renderer = CellRendererButton(attrs.get('string', _('Unknown')))
|
||||
self.treeview = treeview
|
||||
self.window = window
|
||||
self.screen = screen
|
||||
|
||||
self.renderer.connect('clicked', self.button_clicked)
|
||||
|
||||
def button_clicked(self, widget, path):
|
||||
if not path:
|
||||
return True
|
||||
store = self.treeview.get_model()
|
||||
model = store.get_value(store.get_iter(path), 0)
|
||||
|
||||
state_changes = self.attrs.get('states', {})
|
||||
if isinstance(state_changes, basestring):
|
||||
state_changes = eval(state_changes)
|
||||
if 'invisible' in state_changes:
|
||||
if model.expr_eval(state_changes['invisible'], check_load=False):
|
||||
return True
|
||||
if 'readonly' in state_changes:
|
||||
if model.expr_eval(state_changes['readonly'], check_load=False):
|
||||
return True
|
||||
|
||||
self.screen.current_model = model
|
||||
obj_id = self.screen.save_current()
|
||||
if obj_id:
|
||||
if not self.attrs.get('confirm', False) or \
|
||||
common.sur(self.attrs['confirm'], self.window):
|
||||
button_type = self.attrs.get('type', 'workflow')
|
||||
if button_type == 'workflow':
|
||||
args = ('object', 'exec_workflow', self.screen.name,
|
||||
self.attrs['name'], obj_id)
|
||||
try:
|
||||
rpc.execute(*args)
|
||||
except Exception, exception:
|
||||
common.process_exception(exception, self.window, *args)
|
||||
elif button_type == 'object':
|
||||
args = ('object', 'execute', self.screen.name,
|
||||
self.attrs['name'], [obj_id], model.context_get())
|
||||
try:
|
||||
rpc.execute(*args)
|
||||
except Exception, exception:
|
||||
common.process_exception(exception, self.window, *args)
|
||||
elif button_type == 'action':
|
||||
action_id = None
|
||||
args = ('object', 'execute', 'ir.action', 'get_action_id',
|
||||
int(self.attrs['name']), rpc.CONTEXT)
|
||||
try:
|
||||
action_id = rpc.execute(*args)
|
||||
except Exception, exception:
|
||||
action_id = common.process_exception(exception,
|
||||
self.window, *args)
|
||||
if action_id:
|
||||
Action.execute(action_id, {
|
||||
'model': self.screen.name,
|
||||
'id': obj_id,
|
||||
'ids': [obj_id],
|
||||
}, self.window)
|
||||
else:
|
||||
raise Exception('Unallowed button type')
|
||||
self.screen.reload()
|
||||
else:
|
||||
if self.screen.form:
|
||||
self.screen.form.message_info(
|
||||
_('Invalid Form, correct red fields!'))
|
||||
self.screen.display()
|
||||
|
||||
CELLTYPES = {
|
||||
'char': Char,
|
||||
'many2one': M2O,
|
||||
|
||||
@@ -61,6 +61,8 @@ class Parse(object):
|
||||
column.set_resizable(True)
|
||||
column.set_visible(not attrs.get('tree_invisible', False))
|
||||
self.tree.append_column(column)
|
||||
elif name == 'button':
|
||||
pass
|
||||
else:
|
||||
import logging
|
||||
log = logging.getLogger('view')
|
||||
|
||||
Reference in New Issue
Block a user