Use file from the Binary field to display document

On Windows the file used to create the Evince document must be kept after the
initialization.
Also reusing the file cache mechanism of the Binary field, prevents to create
temporary files on each call of display.
Evince document needs to have the proper extension to be sure to load the
proper backend. So the cache file must be retrieved with the requested
extension.
And finally we use Document.factory_get_document_full so if leading with the
filename extension does not work, it will try to guess from the data.

Closes #13307
(grafted from 34deeaf3c0215f793c3e673de3ee2e04971ebee4)

--HG--
branch : 7.0
This commit is contained in:
Cédric Krier
2024-06-07 20:42:40 +02:00
parent 595047abba
commit e2645f26c9
2 changed files with 57 additions and 28 deletions
@@ -9,6 +9,7 @@ import os
import tempfile
from decimal import Decimal
from itertools import chain
from pathlib import Path
import tryton.common as common
from tryton.common import (
@@ -1048,26 +1049,56 @@ class ReferenceField(Field):
class _FileCache(object):
def __init__(self, path):
self.path = path
def __init__(self, data=None):
_, filename = tempfile.mkstemp(prefix='tryton_')
self.path = Path(filename)
self.suffixes = {}
if data:
with open(self.path, 'wb') as fp:
fp.write(data)
@property
def data(self):
with open(self.path, 'rb') as fp:
return fp.read()
def __del__(self):
try:
os.remove(self.path)
except IOError:
pass
for path in self.suffixes.values():
try:
os.remove(path)
except IOError:
pass
def with_suffix(self, suffix):
if suffix in self.suffixes:
return self.suffixes[suffix]
_, filename = tempfile.mkstemp(prefix='tryton_', suffix=suffix)
self.suffixes[suffix] = path = Path(filename)
with open(path, 'wb') as fp:
fp.write(self.data)
return path
class BinaryField(Field):
_default = None
def _set_file_cache(self, record, data):
if isinstance(data, str):
data = data.encode('utf-8')
file_cache = _FileCache(data)
self.set(record, file_cache)
return file_cache
def get(self, record):
result = record.value.get(self.name, self._default)
if isinstance(result, _FileCache):
try:
with open(result.path, 'rb') as fp:
result = fp.read()
result = result.data
except IOError:
result = self.get_data(record)
return result
@@ -1076,13 +1107,7 @@ class BinaryField(Field):
return self.get(record)
def set_client(self, record, value, force_change=False):
_, filename = tempfile.mkstemp(prefix='tryton_')
data = value or b''
if isinstance(data, str):
data = data.encode('utf-8')
with open(filename, 'wb') as fp:
fp.write(data)
self.set(record, _FileCache(filename))
self._set_file_cache(record, value or b'')
self.sig_changed(record)
record.validate(softvalidation=True)
record.set_modified(self.name)
@@ -1106,15 +1131,20 @@ class BinaryField(Field):
[record.id], [self.name], context=context)
except RPCException:
return b''
_, filename = tempfile.mkstemp(prefix='tryton_')
data = values[self.name] or b''
if isinstance(data, str):
data = data.encode('utf-8')
with open(filename, 'wb') as fp:
fp.write(data)
self.set(record, _FileCache(filename))
self._set_file_cache(record, values[self.name] or b'')
return self.get(record)
def get_filename(self, record, suffix=None):
data = self.get_data(record)
file_cache = record.value.get(self.name)
if not isinstance(file_cache, _FileCache):
file_cache = self._set_file_cache(record, data)
if suffix:
filename = file_cache.with_suffix(suffix)
else:
filename = file_cache.path
return filename
class DictField(Field):
@@ -1,7 +1,6 @@
# This file is part of Tryton. The COPYRIGHT file at the top level of
# this repository contains the full copyright notices and license terms.
from pathlib import Path
from tempfile import NamedTemporaryFile
from gi.repository import Gdk, GLib, Gtk
@@ -76,17 +75,17 @@ class Document(BinaryMixin, Widget):
self.image.hide()
if self.evince_view:
self.evince_scroll.show()
suffix = None
if self.filename_field:
suffix = self.filename_field.get(self.record)
else:
suffix = None
filename = self.filename_field.get(self.record)
if filename:
suffix = Path(filename).suffix
filename = Path(self.field.get_filename(self.record, suffix))
try:
with NamedTemporaryFile(suffix=suffix) as fp:
fp.write(data)
path = Path(fp.name)
document = (
EvinceDocument.Document.factory_get_document(
path.as_uri()))
document = (
EvinceDocument.Document.factory_get_document_full(
filename.as_uri(),
EvinceDocument.DocumentLoadFlags.NONE))
model = EvinceView.DocumentModel()
model.set_document(document)
self.evince_view.set_model(model)