Use dropdown for attachments
issue7659 review50551002
This commit is contained in:
1 parent
3978849e3a
commit
f717b64540
7 files changed
+119
-35
No files matched your search
@@ -1,3 +1,4 @@
|
||||
* Use dropdown for attachment
|
||||
* Apply factor on domain parser
|
||||
* Use tab name in CSV Export/Import
|
||||
* Add bus management
|
||||
|
||||
+3
-11
@@ -1,13 +1,11 @@
|
||||
# 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 gettext
|
||||
import tempfile
|
||||
import os
|
||||
import webbrowser
|
||||
|
||||
import tryton.rpc as rpc
|
||||
from tryton.common import RPCProgress, RPCExecute, RPCException, slugify
|
||||
from tryton.common import message, selection, file_open, mailto
|
||||
from tryton.common import RPCProgress, RPCExecute, RPCException
|
||||
from tryton.common import message, selection, file_write, file_open, mailto
|
||||
from tryton.config import CONFIG
|
||||
from tryton.pyson import PYSONDecoder
|
||||
|
||||
@@ -39,14 +37,8 @@ class Action(object):
|
||||
(type, data, print_p, name) = res
|
||||
if not print_p and direct_print:
|
||||
print_p = True
|
||||
dtemp = tempfile.mkdtemp(prefix='tryton_')
|
||||
|
||||
fp_name = os.path.join(dtemp,
|
||||
slugify(name) + os.extsep + slugify(type))
|
||||
if isinstance(data, str):
|
||||
data = data.encode('utf-8')
|
||||
with open(fp_name, 'wb') as file_d:
|
||||
file_d.write(data)
|
||||
fp_name = file_write((name, type), data)
|
||||
if email_print:
|
||||
mailto(to=email.get('to'), cc=email.get('cc'),
|
||||
subject=email.get('subject'), body=email.get('body'),
|
||||
|
||||
+17
-1
@@ -8,6 +8,7 @@ import pango
|
||||
import gettext
|
||||
import os
|
||||
import subprocess
|
||||
import tempfile
|
||||
import re
|
||||
import logging
|
||||
import unicodedata
|
||||
@@ -426,7 +427,22 @@ def slugify(value):
|
||||
return _slugify_hyphenate_re.sub('-', value)
|
||||
|
||||
|
||||
def file_open(filename, type, print_p=False):
|
||||
def file_write(filename, data):
|
||||
if isinstance(data, str):
|
||||
data = data.encode('utf-8')
|
||||
dtemp = tempfile.mkdtemp(prefix='tryton_')
|
||||
if not isinstance(filename, str):
|
||||
name, ext = filename
|
||||
else:
|
||||
name, ext = os.path.splitext(filename)
|
||||
filename = ''.join([slugify(name), os.extsep, slugify(ext)])
|
||||
filepath = os.path.join(dtemp, filename)
|
||||
with open(filepath, 'wb') as fp:
|
||||
fp.write(data)
|
||||
return filepath
|
||||
|
||||
|
||||
def file_open(filename, type=None, print_p=False):
|
||||
def save():
|
||||
save_name = file_selection(_('Save As...'),
|
||||
action=gtk.FILE_CHOOSER_ACTION_SAVE)
|
||||
|
||||
@@ -5,7 +5,10 @@ import os
|
||||
from urllib.request import urlopen
|
||||
from urllib.parse import urlparse, unquote
|
||||
import gettext
|
||||
import webbrowser
|
||||
from functools import partial
|
||||
|
||||
from tryton.common import RPCExecute, RPCException, file_write, file_open
|
||||
from tryton.gui.window.view_form.screen import Screen
|
||||
from tryton.gui.window.win_form import WinForm
|
||||
|
||||
@@ -46,3 +49,43 @@ class Attachment(WinForm):
|
||||
name_field.set_client(new_record, file_name)
|
||||
data_field.set_client(new_record, urlopen(uri).read())
|
||||
self.screen.display()
|
||||
|
||||
def add_file(self, filename):
|
||||
self.add_uri('file:///' + filename)
|
||||
|
||||
@staticmethod
|
||||
def get_attachments(record):
|
||||
attachments = []
|
||||
context = {}
|
||||
if record and record.id >= 0:
|
||||
context = record.get_context()
|
||||
try:
|
||||
attachments = RPCExecute('model', 'ir.attachment',
|
||||
'search_read', [
|
||||
('resource', '=', '%s,%s' % (
|
||||
record.model_name, record.id)),
|
||||
], 0, 20, None, ['rec_name', 'name', 'type', 'link'],
|
||||
context=context)
|
||||
except RPCException:
|
||||
pass
|
||||
for attachment in attachments:
|
||||
name = attachment['rec_name']
|
||||
callback = getattr(
|
||||
Attachment, 'open_' + attachment['type'], Attachment.open_data)
|
||||
yield name, partial(
|
||||
callback, attachment=attachment, context=context)
|
||||
|
||||
@staticmethod
|
||||
def open_link(attachment, context):
|
||||
if attachment['link']:
|
||||
webbrowser.open(attachment['link'], new=2)
|
||||
|
||||
@staticmethod
|
||||
def open_data(attachment, context):
|
||||
try:
|
||||
value, = RPCExecute('model', 'ir.attachment', 'read',
|
||||
[attachment['id']], ['data'], context=context)
|
||||
except RPCException:
|
||||
return
|
||||
filepath = file_write(attachment['name'], value['data'])
|
||||
file_open(filepath)
|
||||
@@ -106,11 +106,42 @@ class Form(SignalEvent, TabContent):
|
||||
self.screen.destroy()
|
||||
|
||||
def sig_attach(self, widget=None):
|
||||
record = self.screen.current_record
|
||||
if not record or record.id < 0:
|
||||
def window(widget):
|
||||
return Attachment(
|
||||
record, lambda: self.update_attachment_count(reload=True))
|
||||
|
||||
def add_file(widget):
|
||||
filename = common.file_selection(_("Select"))
|
||||
if filename:
|
||||
window(widget).add_file(filename)
|
||||
|
||||
def activate(widget, callback):
|
||||
callback()
|
||||
|
||||
button = self.buttons['attach']
|
||||
if widget != button:
|
||||
if button.props.sensitive:
|
||||
button.props.active = True
|
||||
return
|
||||
Attachment(record,
|
||||
lambda: self.update_attachment_count(reload=True))
|
||||
record = self.screen.current_record
|
||||
menu = button._menu = Gtk.Menu()
|
||||
for name, callback in Attachment.get_attachments(record):
|
||||
item = Gtk.MenuItem()
|
||||
item.set_label(name)
|
||||
item.connect('activate', activate, callback)
|
||||
menu.add(item)
|
||||
menu.add(Gtk.SeparatorMenuItem())
|
||||
add_item = Gtk.MenuItem()
|
||||
add_item.set_label(_("Add..."))
|
||||
add_item.connect('activate', add_file)
|
||||
menu.add(add_item)
|
||||
manage_item = Gtk.MenuItem()
|
||||
manage_item.set_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 update_attachment_count(self, reload=False):
|
||||
record = self.screen.current_record
|
||||
|
||||
@@ -16,12 +16,13 @@ _ = gettext.gettext
|
||||
|
||||
class ToolbarItem(object):
|
||||
def __init__(self, id, label,
|
||||
tooltip=None, icon_name=None, accel_path=None):
|
||||
tooltip=None, icon_name=None, accel_path=None, toggle=False):
|
||||
self.id = id
|
||||
self.label = label
|
||||
self.tooltip = tooltip
|
||||
self.icon_name = icon_name
|
||||
self.accel_path = accel_path
|
||||
self.toggle = toggle
|
||||
|
||||
@property
|
||||
def menu(self):
|
||||
@@ -104,7 +105,8 @@ class TabContent(InfoBar):
|
||||
label=_("A_ttachments..."),
|
||||
tooltip=_("Add an attachment to the record"),
|
||||
icon_name='tryton-attach',
|
||||
accel_path='<tryton>/Form/Attachments'),
|
||||
accel_path='<tryton>/Form/Attachments',
|
||||
toggle=True),
|
||||
ToolbarItem(
|
||||
id='note',
|
||||
label=_("_Notes..."),
|
||||
@@ -248,13 +250,17 @@ class TabContent(InfoBar):
|
||||
callback = getattr(self, 'sig_%s' % item.id, None)
|
||||
if not callback:
|
||||
continue
|
||||
toolitem = gtk.ToolButton()
|
||||
if item.toggle:
|
||||
toolitem = gtk.ToggleToolButton()
|
||||
toolitem.connect('toggled', callback)
|
||||
else:
|
||||
toolitem = gtk.ToolButton()
|
||||
toolitem.connect('clicked', callback)
|
||||
toolitem.set_icon_widget(
|
||||
common.IconFactory.get_image(
|
||||
item.icon_name, gtk.ICON_SIZE_LARGE_TOOLBAR))
|
||||
toolitem.set_label(item.label)
|
||||
toolitem.set_use_underline(True)
|
||||
toolitem.connect('clicked', callback)
|
||||
self.tooltips.set_tip(toolitem, item.tooltip)
|
||||
self.buttons[item.id] = toolitem
|
||||
elif not item and previous:
|
||||
|
||||
@@ -3,9 +3,8 @@
|
||||
import gtk
|
||||
import gettext
|
||||
import os
|
||||
import tempfile
|
||||
from tryton.common import common
|
||||
from tryton.common import file_selection, Tooltips, file_open, slugify
|
||||
from tryton.common import file_selection, Tooltips, file_open, file_write
|
||||
from tryton.common.entry_position import reset_position
|
||||
from tryton.config import CONFIG
|
||||
from .widget import Widget
|
||||
@@ -89,21 +88,20 @@ class BinaryMixin(Widget):
|
||||
self.filename_field.set_client(self.record,
|
||||
os.path.basename(filename))
|
||||
|
||||
def get_data(self):
|
||||
if hasattr(self.field, 'get_data'):
|
||||
data = self.field.get_data(self.record)
|
||||
else:
|
||||
data = self.field.get(self.record)
|
||||
return data
|
||||
|
||||
def open_(self, widget=None):
|
||||
if not self.filename_field:
|
||||
return
|
||||
filename = self.filename_field.get(self.record)
|
||||
if not filename:
|
||||
return
|
||||
dtemp = tempfile.mkdtemp(prefix='tryton_')
|
||||
root, ext = os.path.splitext(filename)
|
||||
filename = ''.join([slugify(root), os.extsep, slugify(ext)])
|
||||
file_path = os.path.join(dtemp, filename)
|
||||
with open(file_path, 'wb') as fp:
|
||||
if hasattr(self.field, 'get_data'):
|
||||
fp.write(self.field.get_data(self.record))
|
||||
else:
|
||||
fp.write(self.field.get(self.record))
|
||||
file_path = file_write(filename, self.get_data())
|
||||
root, type_ = os.path.splitext(filename)
|
||||
if type_:
|
||||
type_ = type_[1:]
|
||||
@@ -117,10 +115,7 @@ class BinaryMixin(Widget):
|
||||
action=gtk.FILE_CHOOSER_ACTION_SAVE)
|
||||
if filename:
|
||||
with open(filename, 'wb') as fp:
|
||||
if hasattr(self.field, 'get_data'):
|
||||
fp.write(self.field.get_data(self.record))
|
||||
else:
|
||||
fp.write(self.field.get(self.record))
|
||||
fp.write(self.get_data())
|
||||
|
||||
def clear(self, widget=None):
|
||||
if self.filename_field:
|
||||
|
||||
Reference in new issue
Block a user