Add notification message
issue11065 review367951004
This commit is contained in:
1 parent
5ade55babe
commit
985e2f1928
12 files changed
+121
-68
No files matched your search
@@ -1,3 +1,4 @@
|
||||
* Support notification message
|
||||
* Add option to define logging output location
|
||||
* Remove TreeViewControl
|
||||
* Manage optional column
|
||||
|
||||
+23
-23
@@ -2,16 +2,16 @@
|
||||
# this repository contains the full copyright notices and license terms.
|
||||
from . import timedelta
|
||||
from .common import (
|
||||
COLOR_SCHEMES, MODELACCESS, MODELHISTORY, MODELNAME, TRYTON_ICON,
|
||||
VIEW_SEARCH, IconFactory, Login, Logout, RPCContextReload, RPCException,
|
||||
RPCExecute, RPCProgress, Tooltips, apply_label_attributes, ask,
|
||||
check_version, concurrency, data2pixbuf, date_format, ellipsize, error,
|
||||
file_open, file_selection, file_write, filter_domain, generateColorscheme,
|
||||
get_align, get_hostname, get_port, get_sensible_widget,
|
||||
get_toplevel_window, hex2rgb, highlight_rgb, humanize, idle_add, mailto,
|
||||
message, node_attributes, process_exception, resize_pixbuf, selection,
|
||||
setup_window, slugify, sur, sur_3b, timezoned_date, to_xml,
|
||||
untimezoned_date, userwarning, warning)
|
||||
COLOR_SCHEMES, MODELACCESS, MODELHISTORY, MODELNAME, MODELNOTIFICATION,
|
||||
TRYTON_ICON, VIEW_SEARCH, IconFactory, Login, Logout, RPCContextReload,
|
||||
RPCException, RPCExecute, RPCProgress, Tooltips, apply_label_attributes,
|
||||
ask, check_version, concurrency, data2pixbuf, date_format, ellipsize,
|
||||
error, file_open, file_selection, file_write, filter_domain,
|
||||
generateColorscheme, get_align, get_hostname, get_port,
|
||||
get_sensible_widget, get_toplevel_window, hex2rgb, highlight_rgb, humanize,
|
||||
idle_add, mailto, message, node_attributes, process_exception,
|
||||
resize_pixbuf, selection, setup_window, slugify, sur, sur_3b,
|
||||
timezoned_date, to_xml, untimezoned_date, userwarning, warning)
|
||||
from .domain_inversion import (
|
||||
concat, domain_inversion, eval_domain, extract_reference_models,
|
||||
filter_leaf, inverse_leaf, localize_domain, merge,
|
||||
@@ -19,16 +19,16 @@ from .domain_inversion import (
|
||||
from .environment import EvalEnvironment
|
||||
|
||||
__all__ = [
|
||||
IconFactory, MODELACCESS, MODELHISTORY, MODELNAME, VIEW_SEARCH,
|
||||
get_toplevel_window, get_sensible_widget, selection, file_selection,
|
||||
slugify, file_write, file_open, mailto, message, warning, userwarning, sur,
|
||||
sur_3b, ask, concurrency, error, to_xml, process_exception, Login, Logout,
|
||||
node_attributes, hex2rgb, highlight_rgb, generateColorscheme, RPCException,
|
||||
RPCProgress, RPCExecute, RPCContextReload, Tooltips, COLOR_SCHEMES,
|
||||
filter_domain, timezoned_date, untimezoned_date, humanize, get_hostname,
|
||||
get_port, resize_pixbuf, data2pixbuf, apply_label_attributes, ellipsize,
|
||||
get_align, date_format, idle_add, domain_inversion, eval_domain,
|
||||
localize_domain, merge, inverse_leaf, filter_leaf,
|
||||
prepare_reference_domain, extract_reference_models, concat, simplify,
|
||||
unique_value, EvalEnvironment, timedelta, check_version, TRYTON_ICON,
|
||||
setup_window]
|
||||
IconFactory, MODELACCESS, MODELHISTORY, MODELNAME, MODELNOTIFICATION,
|
||||
VIEW_SEARCH, get_toplevel_window, get_sensible_widget, selection,
|
||||
file_selection, slugify, file_write, file_open, mailto, message, warning,
|
||||
userwarning, sur, sur_3b, ask, concurrency, error, to_xml,
|
||||
process_exception, Login, Logout, node_attributes, hex2rgb, highlight_rgb,
|
||||
generateColorscheme, RPCException, RPCProgress, RPCExecute,
|
||||
RPCContextReload, Tooltips, COLOR_SCHEMES, filter_domain, timezoned_date,
|
||||
untimezoned_date, humanize, get_hostname, get_port, resize_pixbuf,
|
||||
data2pixbuf, apply_label_attributes, ellipsize, get_align, date_format,
|
||||
idle_add, domain_inversion, eval_domain, localize_domain, merge,
|
||||
inverse_leaf, filter_leaf, prepare_reference_domain,
|
||||
extract_reference_models, concat, simplify, unique_value, EvalEnvironment,
|
||||
timedelta, check_version, TRYTON_ICON, setup_window]
|
||||
@@ -286,6 +286,25 @@ class ModelName:
|
||||
MODELNAME = ModelName()
|
||||
|
||||
|
||||
class ModelNotification:
|
||||
_depends = {}
|
||||
|
||||
def load_names(self):
|
||||
try:
|
||||
self._depends = rpc.execute(
|
||||
'model', 'ir.model', 'get_notification', rpc.CONTEXT)
|
||||
except TrytonServerError:
|
||||
pass
|
||||
|
||||
def get(self, model):
|
||||
if not self._depends:
|
||||
self.load_names()
|
||||
return self._depends.get(model, [])
|
||||
|
||||
|
||||
MODELNOTIFICATION = ModelNotification()
|
||||
|
||||
|
||||
class ViewSearch(object):
|
||||
searches = {}
|
||||
|
||||
|
||||
@@ -518,6 +518,7 @@ class Main(Gtk.Application):
|
||||
common.IconFactory.load_icons,
|
||||
common.MODELACCESS.load_models,
|
||||
common.MODELHISTORY.load_history,
|
||||
common.MODELNOTIFICATION.load_names,
|
||||
common.VIEW_SEARCH.load_searches,
|
||||
):
|
||||
t = threading.Thread(target=target)
|
||||
|
||||
+12
-11
@@ -293,7 +293,7 @@ class Form(TabContent):
|
||||
def sig_logs(self, widget=None):
|
||||
current_record = self.screen.current_record
|
||||
if not current_record or current_record.id < 0:
|
||||
self.message_info(
|
||||
self.info_bar_add(
|
||||
_('You have to select one record.'), Gtk.MessageType.INFO)
|
||||
return False
|
||||
|
||||
@@ -407,10 +407,10 @@ class Form(TabContent):
|
||||
msg = _('Are you sure to remove those records?')
|
||||
if sur(msg):
|
||||
if not self.screen.remove(delete=True, force_remove=True):
|
||||
self.message_info(
|
||||
self.info_bar_add(
|
||||
_('Records not removed.'), Gtk.MessageType.ERROR)
|
||||
else:
|
||||
self.message_info(_('Records removed.'), Gtk.MessageType.INFO)
|
||||
self.info_bar_add(_('Records removed.'), Gtk.MessageType.INFO)
|
||||
self.screen.count_tab_domain(True)
|
||||
|
||||
def sig_import(self, widget=None):
|
||||
@@ -467,7 +467,7 @@ class Form(TabContent):
|
||||
if not self.modified_save():
|
||||
return
|
||||
self.screen.new()
|
||||
self.message_info()
|
||||
self.info_bar_clear()
|
||||
self.activate_save()
|
||||
|
||||
def sig_copy(self, widget=None):
|
||||
@@ -476,7 +476,8 @@ class Form(TabContent):
|
||||
if not self.modified_save():
|
||||
return
|
||||
if self.screen.copy():
|
||||
self.message_info(_('Working now on the duplicated record(s).'),
|
||||
self.info_bar_add(
|
||||
_('Working now on the duplicated record(s).'),
|
||||
Gtk.MessageType.INFO)
|
||||
self.screen.count_tab_domain(True)
|
||||
|
||||
@@ -489,11 +490,11 @@ class Form(TabContent):
|
||||
or self.screen.writable):
|
||||
return
|
||||
if self.screen.save_current():
|
||||
self.message_info(_('Record saved.'), Gtk.MessageType.INFO)
|
||||
self.info_bar_add(_('Record saved.'), Gtk.MessageType.INFO)
|
||||
self.screen.count_tab_domain(True)
|
||||
return True
|
||||
else:
|
||||
self.message_info(
|
||||
self.info_bar_add(
|
||||
self.screen.invalid_message(), Gtk.MessageType.ERROR)
|
||||
return False
|
||||
|
||||
@@ -501,14 +502,14 @@ class Form(TabContent):
|
||||
if not self.modified_save():
|
||||
return
|
||||
self.screen.display_prev()
|
||||
self.message_info()
|
||||
self.info_bar_clear()
|
||||
self.activate_save()
|
||||
|
||||
def sig_next(self, widget=None):
|
||||
if not self.modified_save():
|
||||
return
|
||||
self.screen.display_next()
|
||||
self.message_info()
|
||||
self.info_bar_clear()
|
||||
self.activate_save()
|
||||
|
||||
def sig_reload(self, test_modified=True):
|
||||
@@ -529,7 +530,7 @@ class Form(TabContent):
|
||||
set_cursor = True
|
||||
break
|
||||
self.screen.display(set_cursor=set_cursor)
|
||||
self.message_info()
|
||||
self.info_bar_clear()
|
||||
self.set_buttons_sensitive()
|
||||
self.activate_save()
|
||||
self.screen.count_tab_domain()
|
||||
@@ -628,7 +629,7 @@ class Form(TabContent):
|
||||
else:
|
||||
msg = "%s/%s" % (name, common.humanize(size))
|
||||
self.status_label.set_text(msg)
|
||||
self.message_info()
|
||||
self.info_bar_clear()
|
||||
self.activate_save()
|
||||
self.refresh_attachment_preview()
|
||||
|
||||
|
||||
@@ -9,27 +9,31 @@ class InfoBar(object):
|
||||
toolbar = None
|
||||
|
||||
def create_info_bar(self):
|
||||
self.info_label = Gtk.Label()
|
||||
self.__box = Gtk.VBox()
|
||||
self.__box.show()
|
||||
self.__messages = set()
|
||||
return self.__box
|
||||
|
||||
self.info_bar = Gtk.InfoBar()
|
||||
self.info_bar.get_content_area().pack_start(
|
||||
self.info_label, False, False, 0)
|
||||
self.info_bar.set_show_close_button(True)
|
||||
self.info_bar.connect('response', lambda i, r: i.hide())
|
||||
def info_bar_add(self, message, type_=Gtk.MessageType.ERROR):
|
||||
key = (message, type_)
|
||||
if key not in self.__messages:
|
||||
info_bar = Gtk.InfoBar()
|
||||
self.__box.pack_start(info_bar, False, False, 0)
|
||||
area = info_bar.get_content_area()
|
||||
area.add(Gtk.Label(label=message))
|
||||
info_bar.set_show_close_button(True)
|
||||
info_bar.connect('response', self.__response, key)
|
||||
info_bar.set_message_type(type_)
|
||||
info_bar.show_all()
|
||||
|
||||
def response(self, bar, response):
|
||||
if response == Gtk.ResponseType.CLOSE:
|
||||
bar.hide()
|
||||
def __response(self, widget, response, key):
|
||||
self.__messages.add(key)
|
||||
self.__box.remove(widget)
|
||||
|
||||
def message_info(self, message=None, type_=Gtk.MessageType.ERROR):
|
||||
if message:
|
||||
# Work around https://bugzilla.gnome.org/show_bug.cgi?id=710888
|
||||
parent = self.info_bar.get_parent()
|
||||
self.info_bar.unparent()
|
||||
self.info_bar.set_parent(parent)
|
||||
def info_bar_refresh(self):
|
||||
for child in self.__box.get_children():
|
||||
self.__box.remove(child)
|
||||
|
||||
self.info_label.set_label(message)
|
||||
self.info_bar.set_message_type(type_)
|
||||
self.info_bar.show_all()
|
||||
else:
|
||||
self.info_bar.hide()
|
||||
def info_bar_clear(self):
|
||||
self.info_bar_refresh()
|
||||
self.__messages.clear()
|
||||
@@ -203,9 +203,8 @@ class TabContent(InfoBar):
|
||||
self.scrolledwindow.show()
|
||||
self.main.pack1(self.scrolledwindow, resize=True, shrink=False)
|
||||
|
||||
self.create_info_bar()
|
||||
self.widget.pack_start(
|
||||
self.info_bar, expand=False, fill=True, padding=0)
|
||||
self.create_info_bar(), expand=False, fill=True, padding=0)
|
||||
|
||||
def make_title_bar(self):
|
||||
tooltips = common.Tooltips()
|
||||
|
||||
@@ -524,3 +524,7 @@ class Group(list):
|
||||
self.parent.group.fields[self.child_name].sig_changed(self.parent)
|
||||
self.parent.validate(softvalidation=True)
|
||||
self.parent.group.record_modified()
|
||||
|
||||
def record_notify(self, notifications):
|
||||
for screen in self.screens:
|
||||
screen.record_notify(notifications)
|
||||
@@ -566,9 +566,22 @@ class Record:
|
||||
'model', self.model_name, 'on_change',
|
||||
values, fieldnames, context=self.get_context())
|
||||
except RPCException:
|
||||
return
|
||||
for change in changes:
|
||||
self.set_on_change(change)
|
||||
pass
|
||||
else:
|
||||
for change in changes:
|
||||
self.set_on_change(change)
|
||||
|
||||
notification_fields = common.MODELNOTIFICATION.get(self.model_name)
|
||||
if set(fieldnames) & set(notification_fields):
|
||||
values = self._get_on_change_args(notification_fields)
|
||||
try:
|
||||
notifications = RPCExecute(
|
||||
'model', self.model_name, 'on_change_notify', values,
|
||||
context=self.get_context())
|
||||
except RPCException:
|
||||
pass
|
||||
else:
|
||||
self.group.record_notify(notifications)
|
||||
|
||||
def on_change_with(self, field_names):
|
||||
field_names = set(field_names)
|
||||
|
||||
@@ -20,6 +20,7 @@ from tryton.common import (
|
||||
sur, warning)
|
||||
from tryton.common.domain_parser import DomainParser
|
||||
from tryton.config import CONFIG
|
||||
from tryton.gui.window.infobar import InfoBar
|
||||
from tryton.gui.window.view_form.model.group import Group
|
||||
from tryton.gui.window.view_form.view import View
|
||||
from tryton.gui.window.view_form.view.screen_container import ScreenContainer
|
||||
@@ -447,6 +448,18 @@ class Screen:
|
||||
if display:
|
||||
self.display()
|
||||
|
||||
def record_notify(self, notifications):
|
||||
for window in self.windows:
|
||||
if isinstance(window, InfoBar):
|
||||
window.info_bar_refresh()
|
||||
for type_, message in notifications:
|
||||
type_ = {
|
||||
'info': Gtk.MessageType.INFO,
|
||||
'warning': Gtk.MessageType.WARNING,
|
||||
'error': Gtk.MessageType.ERROR,
|
||||
}.get(type_, Gtk.MessageType.WARNING)
|
||||
window.info_bar_add(message, type_)
|
||||
|
||||
def record_message(self, position, size, max_size, record_id):
|
||||
for window in self.windows:
|
||||
if hasattr(window, 'record_message'):
|
||||
|
||||
@@ -274,9 +274,8 @@ class WinForm(NoModal, InfoBar):
|
||||
|
||||
scroll.add(self.screen.screen_container.alternate_viewport)
|
||||
|
||||
self.create_info_bar()
|
||||
self.win.vbox.pack_start(
|
||||
self.info_bar, expand=False, fill=True, padding=0)
|
||||
self.create_info_bar(), expand=False, fill=True, padding=0)
|
||||
|
||||
self.screen.windows.append(self)
|
||||
if view_type == 'tree':
|
||||
@@ -422,12 +421,12 @@ class WinForm(NoModal, InfoBar):
|
||||
if record:
|
||||
validate = record.pre_validate()
|
||||
if not validate:
|
||||
self.message_info(self.screen.invalid_message(),
|
||||
Gtk.MessageType.ERROR)
|
||||
self.info_bar_add(
|
||||
self.screen.invalid_message(), Gtk.MessageType.ERROR)
|
||||
self.screen.set_cursor()
|
||||
self.screen.display()
|
||||
return
|
||||
self.message_info()
|
||||
self.info_bar_clear()
|
||||
if response_id == Gtk.ResponseType.ACCEPT:
|
||||
self.new()
|
||||
return
|
||||
|
||||
@@ -171,10 +171,10 @@ class Wizard(InfoBar):
|
||||
if (button_attrs.get('validate', True)
|
||||
and not self.screen.current_record.validate()):
|
||||
self.screen.display(set_cursor=True)
|
||||
self.message_info(
|
||||
self.info_bar_add(
|
||||
self.screen.invalid_message(), Gtk.MessageType.ERROR)
|
||||
return
|
||||
self.message_info()
|
||||
self.info_bar_clear()
|
||||
self.state = state
|
||||
self.process()
|
||||
|
||||
@@ -242,9 +242,8 @@ class Wizard(InfoBar):
|
||||
self.widget.pack_start(
|
||||
self.scrolledwindow, expand=True, fill=True, padding=0)
|
||||
|
||||
self.create_info_bar()
|
||||
self.widget.pack_start(
|
||||
self.info_bar, expand=False, fill=True, padding=0)
|
||||
self.create_info_bar(), expand=False, fill=True, padding=0)
|
||||
|
||||
|
||||
class WizardForm(Wizard, TabContent):
|
||||
|
||||
Reference in new issue
Block a user