merge.
This commit is contained in:
commit
c58f00cfe4
3 files changed
+202
-4
No files matched your search
@@ -0,0 +1,122 @@
|
||||
#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
|
||||
|
||||
|
||||
class CellRendererBinary(gtk.GenericCellRenderer):
|
||||
__gproperties__ = {
|
||||
'visible': (gobject.TYPE_INT, 'Visible', 'Visible', 0, 10, 0,
|
||||
gobject.PARAM_READWRITE),
|
||||
'editable': (gobject.TYPE_INT, 'Editable', 'Editable', 0, 10, 0,
|
||||
gobject.PARAM_READWRITE),
|
||||
'content': (gobject.TYPE_INT, 'Content', 'Content', 0, 10, 0,
|
||||
gobject.PARAM_READWRITE),
|
||||
}
|
||||
__gsignals__ = {
|
||||
'new': (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE,
|
||||
(gobject.TYPE_STRING,)),
|
||||
'open': (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE,
|
||||
(gobject.TYPE_STRING,)),
|
||||
'save': (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE,
|
||||
(gobject.TYPE_STRING,)),
|
||||
'clear': (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE,
|
||||
(gobject.TYPE_STRING,)),
|
||||
}
|
||||
|
||||
def __init__(self, use_filename):
|
||||
self.__gobject_init__()
|
||||
self.visible = True
|
||||
self.set_property('mode', gtk.CELL_RENDERER_MODE_EDITABLE)
|
||||
self.use_filename = use_filename
|
||||
if use_filename:
|
||||
self.buttons = ('new', 'open', 'save', 'clear')
|
||||
else:
|
||||
self.buttons = ('new', 'save', 'clear')
|
||||
self.clicking = ''
|
||||
self.images = {}
|
||||
widget = gtk.Button()
|
||||
for key, stock_name in (
|
||||
('new', 'tryton-find'),
|
||||
('open', 'tryton-open'),
|
||||
('save', 'tryton-save-as'),
|
||||
('clear', 'tryton-clear')):
|
||||
# hack to get gtk.gdk.Image from stock icon
|
||||
img_sensitive = widget.render_icon(stock_name,
|
||||
gtk.ICON_SIZE_SMALL_TOOLBAR)
|
||||
img_insensitive = img_sensitive.copy()
|
||||
img_sensitive.saturate_and_pixelate(img_insensitive, 0, False)
|
||||
width = img_sensitive.get_width()
|
||||
self.images[key] = (img_sensitive, img_insensitive, width)
|
||||
|
||||
def do_set_property(self, pspec, value):
|
||||
setattr(self, pspec.name, value)
|
||||
|
||||
def do_get_property(self, pspec):
|
||||
return getattr(self, pspec.name)
|
||||
|
||||
def button_width(self, cell_area):
|
||||
return ((cell_area.width - (len(self.buttons) + 1) * 2)
|
||||
/ len(self.buttons))
|
||||
|
||||
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):
|
||||
button_width = self.button_width(cell_area)
|
||||
for index, button_name in enumerate(self.buttons):
|
||||
x_offset = button_width * index + 2 * (index + 1)
|
||||
x_button = cell_area.x + x_offset
|
||||
if x_button < event.x < x_button + button_width:
|
||||
break
|
||||
else:
|
||||
button_name = None
|
||||
if not self.visible or not button_name:
|
||||
return
|
||||
if not self.editable and button_name in ('new', 'clear'):
|
||||
return
|
||||
if not self.content and button_name == 'save':
|
||||
return
|
||||
if event is None or event.type == gtk.gdk.BUTTON_PRESS:
|
||||
self.clicking = button_name
|
||||
self.emit(button_name, path)
|
||||
def timeout(self, widget):
|
||||
self.clicking = ''
|
||||
widget.queue_draw()
|
||||
gobject.timeout_add(60, timeout, self, widget)
|
||||
|
||||
def on_render(self, window, widget, background_area, cell_area,
|
||||
expose_area, flags):
|
||||
if not self.visible:
|
||||
return
|
||||
# Handle Pixmap window as pygtk failed
|
||||
if type(window) == gtk.gdk.Pixmap:
|
||||
return
|
||||
button_width = self.button_width(cell_area)
|
||||
for index, button_name in enumerate(self.buttons):
|
||||
state = gtk.STATE_NORMAL
|
||||
shadow = gtk.SHADOW_OUT
|
||||
pxbf_sens, pxbf_insens, pxbf_width = self.images[button_name]
|
||||
if self.clicking and flags & gtk.CELL_RENDERER_SELECTED:
|
||||
state = gtk.STATE_ACTIVE
|
||||
shadow = gtk.SHADOW_IN
|
||||
if (not self.editable and button_name in ('new', 'clear')
|
||||
or not self.content and button_name in ('open', 'save')):
|
||||
state = gtk.STATE_INSENSITIVE
|
||||
pixbuf = pxbf_insens
|
||||
else:
|
||||
pixbuf = pxbf_sens
|
||||
x_offset = button_width * index + 2 * (index + 1)
|
||||
widget.style.paint_box(window, state, shadow,
|
||||
None, widget, "button", cell_area.x + x_offset, cell_area.y,
|
||||
button_width, cell_area.height)
|
||||
window.draw_pixbuf(widget.style.black_gc,
|
||||
pixbuf, 0, 0,
|
||||
cell_area.x + x_offset + button_width / 2 - pxbf_width / 2,
|
||||
cell_area.y)
|
||||
|
||||
gobject.type_register(CellRendererBinary)
|
||||
@@ -17,6 +17,7 @@ import tryton.common as common
|
||||
from tryton.config import CONFIG
|
||||
from tryton.common.cellrendererbutton import CellRendererButton
|
||||
from tryton.common.cellrenderertoggle import CellRendererToggle
|
||||
from tryton.common.cellrendererbinary import CellRendererBinary
|
||||
from tryton.pyson import PYSONEncoder
|
||||
from tryton.gui.window import Window
|
||||
from tryton.exceptions import TrytonServerError
|
||||
@@ -797,7 +798,7 @@ class ViewList(ParserView):
|
||||
editable = renderer.get_property('activatable')
|
||||
elif isinstance(renderer,
|
||||
(gtk.CellRendererProgress, CellRendererButton,
|
||||
gtk.CellRendererPixbuf)):
|
||||
gtk.CellRendererPixbuf, CellRendererBinary)):
|
||||
editable = False
|
||||
else:
|
||||
editable = renderer.get_property('editable')
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
#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 os
|
||||
import gobject
|
||||
import tempfile
|
||||
from editabletree import EditableTreeView
|
||||
from tryton.gui.window.view_form.view.interface import ParserInterface
|
||||
from tryton.gui.window.win_search import WinSearch
|
||||
@@ -10,7 +12,7 @@ from tryton.gui.window.view_form.screen import Screen
|
||||
from tryton.config import CONFIG
|
||||
import tryton.rpc as rpc
|
||||
from tryton.common import DT_FORMAT, DHM_FORMAT, COLORS, node_attributes, \
|
||||
TRYTON_ICON, HM_FORMAT
|
||||
TRYTON_ICON, HM_FORMAT, file_selection, file_open
|
||||
import tryton.common as common
|
||||
from tryton.exceptions import TrytonError, TrytonServerError
|
||||
from tryton.common.cellrendererbutton import CellRendererButton
|
||||
@@ -20,6 +22,7 @@ from tryton.common.cellrenderertoggle import CellRendererToggle
|
||||
from tryton.common.cellrenderercombo import CellRendererCombo
|
||||
from tryton.common.cellrendererinteger import CellRendererInteger
|
||||
from tryton.common.cellrendererfloat import CellRendererFloat
|
||||
from tryton.common.cellrendererbinary import CellRendererBinary
|
||||
from tryton.action import Action
|
||||
from tryton.translate import date_format
|
||||
from tryton.pyson import PYSONDecoder
|
||||
@@ -108,7 +111,7 @@ class ParserTree(ParserInterface):
|
||||
continue
|
||||
for attr_name in ('relation', 'domain', 'selection',
|
||||
'relation_field', 'string', 'views', 'invisible',
|
||||
'add_remove', 'sort', 'context'):
|
||||
'add_remove', 'sort', 'context', 'filename'):
|
||||
if attr_name in fields[fname].attrs and \
|
||||
not attr_name in node_attrs:
|
||||
node_attrs[attr_name] = fields[fname].attrs[attr_name]
|
||||
@@ -127,7 +130,8 @@ class ParserTree(ParserInterface):
|
||||
pass
|
||||
else:
|
||||
renderer.set_property('editable', not readonly)
|
||||
if not readonly:
|
||||
if (not readonly
|
||||
and not isinstance(renderer, CellRendererBinary)):
|
||||
renderer.connect_after('editing-started', send_keys,
|
||||
treeview)
|
||||
|
||||
@@ -505,6 +509,76 @@ class FloatTime(Char):
|
||||
if callback:
|
||||
callback()
|
||||
|
||||
|
||||
class Binary(Char):
|
||||
|
||||
def __init__(self, field_name, model_name, treeview, attrs=None):
|
||||
super(Binary, self).__init__(field_name, model_name, treeview,
|
||||
attrs=attrs)
|
||||
self.filename = attrs.get('filename')
|
||||
self.renderer = CellRendererBinary(bool(self.filename))
|
||||
self.renderer.connect('new', self.new_binary)
|
||||
self.renderer.connect('open', self.open_binary)
|
||||
self.renderer.connect('save', self.save_binary)
|
||||
self.renderer.connect('clear', self.clear_binary)
|
||||
|
||||
def get_textual_value(self, record):
|
||||
pass
|
||||
|
||||
def value_from_text(self, record, text, callback=None):
|
||||
if callback:
|
||||
callback()
|
||||
|
||||
def setter(self, column, cell, store, iter):
|
||||
record = store.get_value(iter, 0)
|
||||
size = record[self.field_name].get_size(record)
|
||||
cell.set_property('content', bool(size))
|
||||
|
||||
def _get_record_field(self, path):
|
||||
store = self.treeview.get_model()
|
||||
record = store.get_value(store.get_iter(path), 0)
|
||||
field = record.group.fields[self.field_name]
|
||||
return record, field
|
||||
|
||||
def new_binary(self, renderer, path):
|
||||
filename = file_selection(_('Open...'))
|
||||
record, field = self._get_record_field(path)
|
||||
if filename:
|
||||
field.set_client(record, open(filename, 'rb').read())
|
||||
|
||||
def open_binary(self, renderer, path):
|
||||
if not self.filename:
|
||||
return
|
||||
dtemp = tempfile.mkdtemp(prefix='tryton_')
|
||||
record, field = self._get_record_field(path)
|
||||
filename_field = record.group.fields.get(self.filename)
|
||||
filename = filename_field.get(record).replace(
|
||||
os.sep, '_').replace(os.altsep or os.sep, '_')
|
||||
file_path = os.path.join(dtemp, filename)
|
||||
with open(file_path, 'wb') as fp:
|
||||
fp.write(field.get_data(record))
|
||||
root, type_ = os.path.splitext(filename)
|
||||
if type_:
|
||||
type_ = type_[1:]
|
||||
file_open(file_path, type_)
|
||||
|
||||
def save_binary(self, renderer, path):
|
||||
filename = ''
|
||||
record, field = self._get_record_field(path)
|
||||
if self.filename:
|
||||
filename_field = record.group.fields.get(self.filename)
|
||||
filename = filename_field.get(record)
|
||||
filename = file_selection(_('Save As...'), filename=filename,
|
||||
action=gtk.FILE_CHOOSER_ACTION_SAVE)
|
||||
if filename:
|
||||
with open(filename,'wb') as fp:
|
||||
fp.write(field.get_data(record))
|
||||
|
||||
def clear_binary(self, renderer, path):
|
||||
record, field = self._get_record_field(path)
|
||||
field.set_client(record, False)
|
||||
|
||||
|
||||
class M2O(Char):
|
||||
|
||||
def value_from_text(self, record, text, callback=None):
|
||||
@@ -994,4 +1068,5 @@ CELLTYPES = {
|
||||
'progressbar': ProgressBar,
|
||||
'reference': Reference,
|
||||
'one2one': O2O,
|
||||
'binary': Binary,
|
||||
}
|
||||
Reference in new issue
Block a user