diff --git a/doc/usage.rst b/doc/usage.rst index 2caabd13bc..a4ee6ef68d 100644 --- a/doc/usage.rst +++ b/doc/usage.rst @@ -581,24 +581,6 @@ Tabs Position * Right * Bottom -.. _Menu-Options-File_Actions: - -File Actions...: - Opens a dialog to set up file types for print and open actions. - Use ``"%s"`` as a placeholder for the document name. - - * Provided file types: - - - ODT file: Open Office Writer Document - - PDF file: Adobes(TM) Portable Document Format - - PNG file: Portable Network Graphics format - - TXT file: Pure text file - - * Provided actions - - - Open: Setting up program system call which opens the specific file type. - - Print: Setting up program system call printing the specific file type. - .. _Menu-Options-Email: Email...: diff --git a/tryton/action/main.py b/tryton/action/main.py index cfbfa79919..aca6895e69 100644 --- a/tryton/action/main.py +++ b/tryton/action/main.py @@ -1,9 +1,7 @@ #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 time -import datetime import tryton.rpc as rpc -from tryton.common import message, error, selection, file_open, mailto +from tryton.common import message, selection, file_open, mailto from tryton.gui.window import Window from tryton.pyson import PYSONDecoder from tryton.exceptions import TrytonServerError @@ -15,6 +13,7 @@ import tryton.common as common _ = gettext.gettext + class Action(object): @staticmethod @@ -71,7 +70,7 @@ class Action(object): common.process_exception(exception) return if not res: - raise Exception, 'ActionNotFound' + raise Exception('ActionNotFound') action_type = res['type'] try: res = rpc.execute('model', action_type, 'search_read', @@ -117,7 +116,8 @@ class Action(object): domain_context = ctx.copy() domain_context['context'] = ctx domain_context['_user'] = rpc._USER - domain = PYSONDecoder(domain_context).decode(action['pyson_domain']) + domain = PYSONDecoder(domain_context).decode( + action['pyson_domain']) search_context = ctx.copy() search_context['context'] = ctx diff --git a/tryton/client.py b/tryton/client.py index 0d9a541345..aa79f2942f 100644 --- a/tryton/client.py +++ b/tryton/client.py @@ -22,21 +22,18 @@ import logging from urlparse import urlparse import threading -from tryton import version -from tryton import config import tryton.common as common -from tryton.config import CONFIG, CURRENT_DIR, PREFIX, PIXMAPS_DIR, \ - TRYTON_ICON, get_config_dir +from tryton.config import CONFIG, get_config_dir from tryton import translate from tryton import gui from tryton.ipc import Client as IPCClient -import traceback import time import signal if not hasattr(gtk.gdk, 'lock'): class _Lock(object): __enter__ = gtk.gdk.threads_enter + def __exit__(*ignored): gtk.gdk.threads_leave() @@ -44,11 +41,13 @@ if not hasattr(gtk.gdk, 'lock'): if sys.platform == 'win32': class Dialog(gtk.Dialog): + def run(self): with gtk.gdk.lock: return super(Dialog, self).run() gtk.Dialog = Dialog + class TrytonClient(object): "Tryton client" @@ -103,7 +102,8 @@ class TrytonClient(object): signal.signal(signal.SIGINT, lambda signum, frame: main.sig_quit()) signal.signal(signal.SIGTERM, lambda signum, frame: main.sig_quit()) if hasattr(signal, 'SIGQUIT'): - signal.signal(signal.SIGQUIT, lambda signum, frame: main.sig_quit()) + signal.signal(signal.SIGQUIT, + lambda signum, frame: main.sig_quit()) def excepthook(exctyp, exception, tb): import common @@ -135,7 +135,7 @@ class TrytonClient(object): if sys.platform == 'win32': while not self.quit_client.isSet(): with gtk.gdk.lock: - running = gtk.main_iteration(True) + gtk.main_iteration(True) else: gtk.main() except KeyboardInterrupt: diff --git a/tryton/common/button.py b/tryton/common/button.py index 75c40bffa6..b437058ad0 100644 --- a/tryton/common/button.py +++ b/tryton/common/button.py @@ -27,7 +27,8 @@ class Button(gtk.Button): def state_set(self, record): if record: - states = record.expr_eval(self.attrs.get('states', {}), check_load=False) + states = record.expr_eval(self.attrs.get('states', {}), + check_load=False) else: states = {} if states.get('invisible', False): diff --git a/tryton/common/cellrendererbinary.py b/tryton/common/cellrendererbinary.py index 0c7cc4b152..7bca98f24a 100644 --- a/tryton/common/cellrendererbinary.py +++ b/tryton/common/cellrendererbinary.py @@ -4,6 +4,9 @@ import gtk import gobject import pango +BUTTON_BORDER = 10 +BUTTON_SPACING = 2 + class CellRendererBinary(gtk.GenericCellRenderer): __gproperties__ = { @@ -48,7 +51,8 @@ class CellRendererBinary(gtk.GenericCellRenderer): 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) + height = img_sensitive.get_height() + self.images[key] = (img_sensitive, img_insensitive, width, height) def do_set_property(self, pspec, value): setattr(self, pspec.name, value) @@ -56,24 +60,31 @@ class CellRendererBinary(gtk.GenericCellRenderer): def do_get_property(self, pspec): return getattr(self, pspec.name) - def button_width(self, cell_area): - return ((cell_area.width / 2 - (len(self.buttons) + 1) * 2) - / len(self.buttons)) + def button_width(self): + return (sum(width for _, _, width, _ in self.images.itervalues()) + + (2 * (BUTTON_BORDER + BUTTON_SPACING) * len(self.buttons)) + - 2 * BUTTON_SPACING) 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) + 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) + if event is None: + return + button_width = self.button_width() for index, button_name in enumerate(self.buttons): - x_offset = button_width * index + 2 * (index + 1) - x_button = cell_area.x + cell_area.width / 2 + 5 + x_offset - if x_button < event.x < x_button + button_width: + _, _, pxbf_width, _ = self.images[button_name] + x_offset = (cell_area.width - button_width + + (pxbf_width + (2 * BUTTON_BORDER) + BUTTON_SPACING) * index) + x_button = cell_area.x + x_offset + if x_button < event.x < (x_button + pxbf_width + + (2 * BUTTON_BORDER)): break else: button_name = None @@ -83,9 +94,10 @@ class CellRendererBinary(gtk.GenericCellRenderer): return if not self.size and button_name == 'save': return - if event is None or event.type == gtk.gdk.BUTTON_PRESS: + if event.type == gtk.gdk.BUTTON_PRESS: self.clicking = button_name self.emit(button_name, path) + def timeout(self, widget): self.clicking = '' widget.queue_draw() @@ -99,24 +111,31 @@ class CellRendererBinary(gtk.GenericCellRenderer): if type(window) == gtk.gdk.Pixmap: return + button_width = self.button_width() + # display size layout = widget.create_pango_layout(self.size) layout.set_font_description(widget.style.font_desc) w, h = layout.get_size() - x = int(cell_area.x + (cell_area.width - w / pango.SCALE) * 0) + x = int(cell_area.x + cell_area.width - button_width - w / pango.SCALE + - BUTTON_SPACING) y = int(cell_area.y + (cell_area.height - h / pango.SCALE) / 2) + layout.set_width(((cell_area.width / 2) - 2) * pango.SCALE) state = gtk.STATE_NORMAL if flags & gtk.CELL_RENDERER_SELECTED: state = gtk.STATE_ACTIVE - window.draw_layout(widget.style.text_gc[state], x, y, layout) + if x >= cell_area.x: + widget.style.paint_layout(window, state, True, expose_area, + widget, "cellrendererbinary", x, y, layout) # display buttons - 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: + pxbf_sens, pxbf_insens, pxbf_width, pxbf_height = \ + self.images[button_name] + if (self.clicking == button_name + and flags & gtk.CELL_RENDERER_SELECTED): state = gtk.STATE_ACTIVE shadow = gtk.SHADOW_IN if (not self.editable and button_name in ('new', 'clear') @@ -125,14 +144,16 @@ class CellRendererBinary(gtk.GenericCellRenderer): pixbuf = pxbf_insens else: pixbuf = pxbf_sens - x_offset = (cell_area.width / 2 + 5 - + button_width * index + 2 * (index + 1)) - 1 + x_offset = (cell_area.width - button_width + + (pxbf_width + (2 * BUTTON_BORDER) + BUTTON_SPACING) * index) + if x_offset < 0: + continue widget.style.paint_box(window, state, shadow, None, widget, "button", cell_area.x + x_offset, cell_area.y, - button_width, cell_area.height) + pxbf_width + (2 * BUTTON_BORDER), 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) + cell_area.x + x_offset + BUTTON_BORDER, + cell_area.y + (cell_area.height - pxbf_height) / 2) gobject.type_register(CellRendererBinary) diff --git a/tryton/common/cellrendererbutton.py b/tryton/common/cellrendererbutton.py index f57f83b468..d32ac4c4b7 100644 --- a/tryton/common/cellrendererbutton.py +++ b/tryton/common/cellrendererbutton.py @@ -54,19 +54,29 @@ class CellRendererButton(gtk.GenericCellRenderer): 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) + widget.style.paint_layout(window, state, True, expose_area, widget, + "cellrendererbutton", x, y, layout) layout = widget.create_pango_layout(self.text) layout.set_font_description(widget.style.font_desc) + layout.set_ellipsize(pango.ELLIPSIZE_END) w, h = layout.get_size() - x = int(cell_area.x + (cell_area.width - w / pango.SCALE) / 2) + if cell_area.width < w / pango.SCALE: + x = cell_area.x + 2 / pango.SCALE + else: + x = int(cell_area.x + (cell_area.width - w / pango.SCALE) / 2) y = int(cell_area.y + (cell_area.height - h / pango.SCALE) / 2) - window.draw_layout(widget.style.text_gc[0], x, y, layout) + layout.set_width((cell_area.width - 4) * pango.SCALE) + layout.set_wrap(pango.WRAP_CHAR) + widget.style.paint_layout(window, state, True, expose_area, widget, + "cellrendererbutton", 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) + 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): @@ -80,6 +90,7 @@ class CellRendererButton(gtk.GenericCellRenderer): while gtk.events_pending(): gtk.main_iteration() self.emit("clicked", path) + def timeout(self, widget): self.clicking = False widget.queue_draw() diff --git a/tryton/common/cellrenderercombo.py b/tryton/common/cellrenderercombo.py index 374ade5bd2..b4d3c0dfa9 100644 --- a/tryton/common/cellrenderercombo.py +++ b/tryton/common/cellrenderercombo.py @@ -106,10 +106,13 @@ class CellRendererCombo(gtk.GenericCellRenderer): editable.modify_text(gtk.STATE_INSENSITIVE, fg_color) else: editable.modify_bg(gtk.STATE_ACTIVE, style.bg[gtk.STATE_ACTIVE]) - editable.modify_base(gtk.STATE_NORMAL, style.base[gtk.STATE_NORMAL]) + editable.modify_base(gtk.STATE_NORMAL, + style.base[gtk.STATE_NORMAL]) editable.modify_fg(gtk.STATE_NORMAL, style.fg[gtk.STATE_NORMAL]) - editable.modify_text(gtk.STATE_NORMAL, style.text[gtk.STATE_NORMAL]) - editable.modify_text(gtk.STATE_INSENSITIVE, style.text[gtk.STATE_INSENSITIVE]) + editable.modify_text(gtk.STATE_NORMAL, + style.text[gtk.STATE_NORMAL]) + editable.modify_text(gtk.STATE_INSENSITIVE, + style.text[gtk.STATE_INSENSITIVE]) return editable gobject.type_register(CellRendererCombo) diff --git a/tryton/common/cellrendererdate.py b/tryton/common/cellrendererdate.py index d7e199f4bc..d8afcbc80d 100644 --- a/tryton/common/cellrendererdate.py +++ b/tryton/common/cellrendererdate.py @@ -3,7 +3,7 @@ import gtk import gobject import pango -from date_widget import mapping, DateEntry, compute_date +from date_widget import DateEntry, compute_date class CellRendererDate(gtk.GenericCellRenderer): @@ -100,10 +100,13 @@ class CellRendererDate(gtk.GenericCellRenderer): editable.modify_text(gtk.STATE_INSENSITIVE, fg_color) else: editable.modify_bg(gtk.STATE_ACTIVE, style.bg[gtk.STATE_ACTIVE]) - editable.modify_base(gtk.STATE_NORMAL, style.base[gtk.STATE_NORMAL]) + editable.modify_base(gtk.STATE_NORMAL, + style.base[gtk.STATE_NORMAL]) editable.modify_fg(gtk.STATE_NORMAL, style.fg[gtk.STATE_NORMAL]) - editable.modify_text(gtk.STATE_NORMAL, style.text[gtk.STATE_NORMAL]) - editable.modify_text(gtk.STATE_INSENSITIVE, style.text[gtk.STATE_INSENSITIVE]) + editable.modify_text(gtk.STATE_NORMAL, + style.text[gtk.STATE_NORMAL]) + editable.modify_text(gtk.STATE_INSENSITIVE, + style.text[gtk.STATE_INSENSITIVE]) if self.text: editable.set_text(self.text) @@ -126,9 +129,10 @@ class CellRendererDate(gtk.GenericCellRenderer): if ok: self._date_cb(event) else: - if hasattr(event, 'keyval') and not event.keyval == gtk.keysyms.Escape: + if (hasattr(event, 'keyval') + and not event.keyval == gtk.keysyms.Escape): dt = widget.date_get() - res= compute_date(self.cmd, dt, widget.format) + res = compute_date(self.cmd, dt, widget.format) if res: widget.date_set(res) self.cmd = '' diff --git a/tryton/common/cellrendererinteger.py b/tryton/common/cellrendererinteger.py index aaeedf31a4..d2c85c383c 100644 --- a/tryton/common/cellrendererinteger.py +++ b/tryton/common/cellrendererinteger.py @@ -7,7 +7,6 @@ import locale class CellRendererInteger(CellRendererText): - def on_start_editing(self, event, widget, path, background_area, cell_area, flags): editable = super(CellRendererInteger, self).on_start_editing(event, diff --git a/tryton/common/cellrenderertext.py b/tryton/common/cellrenderertext.py index 4beded4d23..a704a5aab0 100644 --- a/tryton/common/cellrenderertext.py +++ b/tryton/common/cellrenderertext.py @@ -100,10 +100,13 @@ class CellRendererText(gtk.GenericCellRenderer): editable.modify_text(gtk.STATE_INSENSITIVE, fg_color) else: editable.modify_bg(gtk.STATE_ACTIVE, style.bg[gtk.STATE_ACTIVE]) - editable.modify_base(gtk.STATE_NORMAL, style.base[gtk.STATE_NORMAL]) + editable.modify_base(gtk.STATE_NORMAL, + style.base[gtk.STATE_NORMAL]) editable.modify_fg(gtk.STATE_NORMAL, style.fg[gtk.STATE_NORMAL]) - editable.modify_text(gtk.STATE_NORMAL, style.text[gtk.STATE_NORMAL]) - editable.modify_text(gtk.STATE_INSENSITIVE, style.text[gtk.STATE_INSENSITIVE]) + editable.modify_text(gtk.STATE_NORMAL, + style.text[gtk.STATE_NORMAL]) + editable.modify_text(gtk.STATE_INSENSITIVE, + style.text[gtk.STATE_INSENSITIVE]) editable.set_text(self.text) editable.grab_focus() diff --git a/tryton/common/cellrenderertoggle.py b/tryton/common/cellrenderertoggle.py index 2f4f4592dd..b9cafbc9be 100644 --- a/tryton/common/cellrenderertoggle.py +++ b/tryton/common/cellrenderertoggle.py @@ -2,7 +2,6 @@ #this repository contains the full copyright notices and license terms. import gtk import gobject -import pango class CellRendererToggle(gtk.GenericCellRenderer): diff --git a/tryton/common/common.py b/tryton/common/common.py index f38ce58ae4..2758f8ea44 100644 --- a/tryton/common/common.py +++ b/tryton/common/common.py @@ -11,7 +11,7 @@ import subprocess import re import logging from tryton.config import CONFIG -from tryton.config import TRYTON_ICON, PIXMAPS_DIR, DATA_DIR +from tryton.config import TRYTON_ICON, PIXMAPS_DIR import time import sys import xmlrpclib @@ -37,7 +37,7 @@ try: except ImportError: ssl = None import dis -from threading import Lock, Semaphore +from threading import Lock try: import pytz except ImportError: @@ -128,6 +128,7 @@ class TrytonIconFactory(gtk.IconFactory): ICONFACTORY = TrytonIconFactory() ICONFACTORY.add_default() + def find_in_path(name): if os.name == "nt": sep = ';' @@ -141,12 +142,14 @@ def find_in_path(name): return val return name + def test_server_version(host, port): version = rpc.server_version(host, port) if not version: return False return version.split('.')[:2] == VERSION.split('.')[:2] + def refresh_dblist(host, port): ''' Return the number of database available @@ -158,6 +161,7 @@ def refresh_dblist(host, port): return -1 return rpc.db_list(host, port) + def refresh_langlist(lang_widget, host, port): liststore = lang_widget.get_model() liststore.clear() @@ -174,17 +178,18 @@ def refresh_langlist(lang_widget, host, port): liststore.insert(i, (val, key)) if key == lang: index = i - if key == 'en_US' and index < 0 : + if key == 'en_US' and index < 0: index = i i += 1 lang_widget.set_active(index) return lang_list + def request_server(server_widget): result = False parent = get_toplevel_window() dialog = gtk.Dialog( - title= _('Tryton Connection'), + title=_('Tryton Connection'), parent=parent, flags=gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT | gtk.WIN_POS_CENTER_ON_PARENT | @@ -211,7 +216,7 @@ def request_server(server_widget): entry_server.set_text("localhost") entry_server.set_activates_default(True) entry_server.set_width_chars(16) - table.attach(entry_server, 1, 2, 0, 1,yoptions=False, + table.attach(entry_server, 1, 2, 0, 1, yoptions=False, xoptions=gtk.FILL | gtk.EXPAND) label_port = gtk.Label(_("Port:")) label_port.set_alignment(1, 0.5) @@ -242,6 +247,7 @@ def request_server(server_widget): dialog.destroy() return result + def get_toplevel_window(): windows = [x for x in gtk.window_list_toplevels() if x.window and x.props.visible] @@ -250,6 +256,7 @@ def get_toplevel_window(): return window return trans2windows[None] + def get_sensible_widget(window): from tryton.gui.main import Main main = Main.get_main() @@ -260,6 +267,7 @@ def get_sensible_widget(window): return page.widget return window + def center_window(window, parent, sensible): parent_x, parent_y = parent.window.get_origin() window_allocation = window.get_allocation() @@ -270,10 +278,11 @@ def center_window(window, parent, sensible): int((sensible_allocation.height - window_allocation.height) / 2)) window.move(x, y) + def selection(title, values, alwaysask=False): - if not values or len(values)==0: + if not values or len(values) == 0: return None - elif len(values)==1 and (not alwaysask): + elif len(values) == 1 and (not alwaysask): key = values.keys()[0] return (key, values[key]) @@ -331,13 +340,14 @@ def selection(title, values, alwaysask=False): dialog.destroy() return res + def file_selection(title, filename='', action=gtk.FILE_CHOOSER_ACTION_OPEN, preview=True, multi=False, filters=None): parent = get_toplevel_window() if action == gtk.FILE_CHOOSER_ACTION_OPEN: buttons = (gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL, - gtk.STOCK_OPEN,gtk.RESPONSE_OK) + gtk.STOCK_OPEN, gtk.RESPONSE_OK) else: buttons = (gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL, gtk.STOCK_SAVE, gtk.RESPONSE_OK) @@ -403,48 +413,9 @@ def file_selection(title, filename='', win.destroy() return filenames + def file_open(filename, type, print_p=False): - if os.name == 'nt': - operation = 'open' - if print_p: - operation = 'print' - try: - os.startfile(os.path.normpath(filename), operation) - except WindowsError: - save_name = file_selection(_('Save As...'), - action=gtk.FILE_CHOOSER_ACTION_SAVE) - if save_name: - file_p = open(filename, 'rb') - save_p = open(save_name, 'wb+') - save_p.write(file_p.read()) - save_p.close() - file_p.close() - return - elif sys.platform == 'darwin': - pid = os.fork() - if not pid: - pid = os.fork() - if not pid: - try: - os.execv('/usr/bin/open', ['/usr/bin/open', filename]) - except OSError: - sys.exit(0) - time.sleep(0.1) - sys.exit(0) - os.waitpid(pid, 0) - return - cmd = '' - if isinstance(CONFIG['client.actions'], basestring): - CONFIG['client.actions'] = safe_eval(CONFIG['client.actions']) - if type in CONFIG['client.actions']: - if print_p: - cmd = CONFIG['client.actions'][type][1] - else: - cmd = CONFIG['client.actions'][type][0] - if not cmd: - #TODO add dialog box - pass - if not cmd: + def save(): save_name = file_selection(_('Save As...'), action=gtk.FILE_CHOOSER_ACTION_SAVE) if save_name: @@ -453,25 +424,26 @@ def file_open(filename, type, print_p=False): save_p.write(file_p.read()) save_p.close() file_p.close() - return - cmd = cmd % filename - args = shlex.split(str(cmd)) - prog = find_in_path(args[0]) - args[0] = os.path.basename(args[0]) - if print_p: - os.spawnv(os.P_WAIT, prog, args) - return - pid = os.fork() - if not pid: - pid = os.fork() - if not pid: - try: - os.execv(prog, args) - except OSError: - sys.exit(0) - time.sleep(0.1) - sys.exit(0) - os.waitpid(pid, 0) + + if os.name == 'nt': + operation = 'open' + if print_p: + operation = 'print' + try: + os.startfile(os.path.normpath(filename), operation) + except WindowsError: + save() + elif sys.platform == 'darwin': + try: + subprocess.Popen(['/usr/bin/open', filename]) + except OSError: + save() + else: + try: + subprocess.Popen(['xdg-open', filename]) + except OSError: + save() + def mailto(to=None, cc=None, subject=None, body=None, attachment=None): if CONFIG['client.email']: @@ -485,6 +457,23 @@ def mailto(to=None, cc=None, subject=None, body=None, attachment=None): args = shlex.split(str(cmd)) subprocess.Popen(args) return + if os.name != 'nt' and sys.platform != 'darwin': + args = ['xdg-email', '--utf8'] + if cc: + args.extend(['--cc', cc]) + if subject: + args.extend(['--subject', subject]) + if body: + args.extend(['--body', body]) + if attachment: + args.extend(['--attach', attachment]) + if to: + args.append(to) + try: + subprocess.Popen(args) + return + except OSError: + pass #http://www.faqs.org/rfcs/rfc2368.html url = "mailto:" if to: @@ -540,7 +529,7 @@ class MessageDialog(UniqueDialog): def build_dialog(self, parent, message, msg_type): dialog = gtk.MessageDialog(parent, - gtk.DIALOG_MODAL|gtk.DIALOG_DESTROY_WITH_PARENT, msg_type, + gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT, msg_type, gtk.BUTTONS_OK, message) return dialog @@ -559,7 +548,8 @@ class WarningDialog(UniqueDialog): dialog.set_markup('%s' % (to_xml(title))) dialog.format_secondary_markup(to_xml(message)) else: - dialog.set_markup('%s\n%s' % (to_xml(title), to_xml(message))) + dialog.set_markup( + '%s\n%s' % (to_xml(title), to_xml(message))) return dialog warning = WarningDialog() @@ -659,7 +649,7 @@ class AskDialog(UniqueDialog): def build_dialog(self, parent, question, visibility): win = gtk.Dialog('Tryton', parent, - gtk.DIALOG_MODAL|gtk.DIALOG_DESTROY_WITH_PARENT, + gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT, (gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL, gtk.STOCK_OK, gtk.RESPONSE_OK)) win.set_has_separator(True) @@ -704,9 +694,9 @@ ask = AskDialog() class ConcurrencyDialog(UniqueDialog): def build_dialog(self, parent, resource, obj_id, context): - dialog = gtk.Dialog(_('Concurrency Exception'), parent, gtk.DIALOG_MODAL - | gtk.DIALOG_DESTROY_WITH_PARENT | gtk.WIN_POS_CENTER_ON_PARENT - | gtk.gdk.WINDOW_TYPE_HINT_DIALOG) + dialog = gtk.Dialog(_('Concurrency Exception'), parent, + gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT | + gtk.WIN_POS_CENTER_ON_PARENT | gtk.gdk.WINDOW_TYPE_HINT_DIALOG) dialog.set_has_separator(True) dialog.set_default_response(gtk.RESPONSE_CANCEL) hbox = gtk.HBox() @@ -830,15 +820,16 @@ class ErrorDialog(UniqueDialog): if title == details: title = '' log = logging.getLogger('common.message') - log.error(details) + log.error(details + '\n' + title) response = super(ErrorDialog, self).__call__(title, details) if response == gtk.RESPONSE_OK: - send_bugtracker(details) + send_bugtracker(title, details) error = ErrorDialog() -def send_bugtracker(msg): + +def send_bugtracker(title, msg): from tryton import rpc parent = get_toplevel_window() win = gtk.Dialog(_('Bug Tracker'), parent, @@ -897,21 +888,15 @@ def send_bugtracker(msg): protocol = 'http' if ssl or hasattr(socket, 'ssl'): protocol = 'https' - server = xmlrpclib.Server(('%s://%s:%s@' + CONFIG['roundup.xmlrpc']) - % (protocol, user, password), allow_none=True) + server = xmlrpclib.Server( + ('%s://%s:%s@' + CONFIG['roundup.xmlrpc']) + % (protocol, user, password), allow_none=True) if hashlib: - msg_md5 = hashlib.md5(msg).hexdigest() + msg_md5 = hashlib.md5(msg + '\n' + title).hexdigest() else: - msg_md5 = md5.new(msg).hexdigest() - # use the last line of the message as title - title = '[no title]' - for line in msg.splitlines(): - #don't use empty line nor ^ from sql error - if line and '^' != line.strip(): - if len(line) > 128: - title = line[:128] + '...' - else: - title = line + msg_md5 = md5.new(msg + '\n' + title).hexdigest() + if not title: + title = '[no title]' issue_id = None msg_ids = server.filter('msg', None, {'summary': str(msg_md5)}) if msg_ids: @@ -921,9 +906,10 @@ def send_bugtracker(msg): if issue_id: # issue to same message already exists, add user to nosy-list server.set('issue' + str(issue_id), *['nosy=+' + user]) - message(_('The same bug was already reported by another user.\n' \ - 'To keep you informed your username is added to the nosy-list of this issue') + \ - '%s' % issue_id) + message( + _('The same bug was already reported by another user.\n' + 'To keep you informed your username is added ' + 'to the nosy-list of this issue') + '%s' % issue_id) else: # create a new issue for this error-message # first create message @@ -934,23 +920,27 @@ def send_bugtracker(msg): 'nosy=' + user, 'title=' + title, 'priority=bug']) message(_('Created new bug with ID ') + \ 'issue%s' % issue_id) - webbrowser.open(CONFIG['roundup.url'] + 'issue%s' % issue_id, new=2) + webbrowser.open(CONFIG['roundup.url'] + 'issue%s' % issue_id, + new=2) except (socket.error, xmlrpclib.Fault), exception: if (isinstance(exception, xmlrpclib.Fault) and 'roundup.cgi.exceptions.Unauthorised' in exception.faultString): message(_('Connection error!\nBad username or password!')) - return send_bugtracker(msg, parent) + return send_bugtracker(title, msg) tb_s = reduce(lambda x, y: x + y, traceback.format_exception(sys.exc_type, sys.exc_value, sys.exc_traceback)) message(_('Exception:') + '\n' + tb_s, msg_type=gtk.MESSAGE_ERROR) + def to_xml(string): - return string.replace('&','&').replace('<','<').replace('>','>') + return string.replace('&', '&' + ).replace('<', '<').replace('>', '>') PLOCK = Lock() + def process_exception(exception, *args, **kwargs): if isinstance(exception, TrytonError): @@ -1049,6 +1039,7 @@ def process_exception(exception, *args, **kwargs): error(error_title, error_detail) return False + def node_attributes(node): result = {} attrs = node.attributes @@ -1058,6 +1049,7 @@ def node_attributes(node): result[str(attrs.item(i).localName)] = str(attrs.item(i).nodeValue) return result + def hex2rgb(hexstring, digits=2): """ Converts a hexstring color to a rgb tuple. @@ -1068,11 +1060,12 @@ def hex2rgb(hexstring, digits=2): if isinstance(hexstring, (tuple, list)): return hexstring top = float(int(digits * 'f', 16)) - r = int(hexstring[1:digits+1], 16) - g = int(hexstring[digits+1:digits*2+1], 16) - b = int(hexstring[digits*2+1:digits*3+1], 16) + r = int(hexstring[1:digits + 1], 16) + g = int(hexstring[digits + 1:digits * 2 + 1], 16) + b = int(hexstring[digits * 2 + 1:digits * 3 + 1], 16) return r / top, g / top, b / top + def clamp(minValue, maxValue, value): """Make sure value is between minValue and maxValue""" if value < minValue: @@ -1081,12 +1074,14 @@ def clamp(minValue, maxValue, value): return maxValue return value + def lighten(r, g, b, amount): """Return a lighter version of the color (r, g, b)""" return (clamp(0.0, 1.0, r + amount), clamp(0.0, 1.0, g + amount), clamp(0.0, 1.0, b + amount)) + def generateColorscheme(masterColor, keys, light=0.06): """ Generates a dictionary where the keys match the keys argument and @@ -1121,7 +1116,7 @@ class DBProgress(object): def update(self, combo, progressbar, callback, dbname=''): self.db_info = None - thread = threading.Thread(target=self.start).start() + threading.Thread(target=self.start).start() gobject.timeout_add(100, self.end, combo, progressbar, callback, dbname) @@ -1206,7 +1201,8 @@ class RPCProgress(object): hbox.pack_start(img, expand=True, fill=False) vbox2 = gtk.VBox(False, 0) label = gtk.Label() - label.set_markup(''+_('Operation in progress')+'') + label.set_markup( + '' + _('Operation in progress') + '') label.set_alignment(0.0, 0.5) vbox2.pack_start(label, expand=True, fill=False) vbox2.pack_start(gtk.HSeparator(), expand=True, fill=True) @@ -1272,8 +1268,8 @@ COLOR_SCHEMES = { } COLORS = { - 'invalid':'#ff6969', - 'required':'#d2d2ff', + 'invalid': '#ff6969', + 'required': '#d2d2ff', } DT_FORMAT = '%Y-%m-%d' @@ -1286,7 +1282,7 @@ FLOAT_TIME_CONV = { 'w': 168, 'd': 24, 'h': 1, - 'm': 1.0/60, + 'm': 1.0 / 60, } FLOAT_TIME_SEPS = { @@ -1298,6 +1294,7 @@ FLOAT_TIME_SEPS = { 'm': _('m'), } + def text_to_float_time(text, conv=None): try: try: @@ -1340,6 +1337,7 @@ def text_to_float_time(text, conv=None): except ValueError: return 0.0 + def float_time_to_text(val, conv=None): if conv: tmp_conv = FLOAT_TIME_CONV.copy() @@ -1362,7 +1360,7 @@ def float_time_to_text(val, conv=None): val = val - days * conv['d'] hours = int(val) val = val - hours - mins = int((val% 1 + 0.01) / conv['m']) + mins = int((val % 1 + 0.01) / conv['m']) if years: value += ' ' + locale.format('%d', years, True) + FLOAT_TIME_SEPS['Y'] if months: @@ -1376,6 +1374,7 @@ def float_time_to_text(val, conv=None): value = value.strip() return value + def filter_domain(domain): ''' Return the biggest subset of domain with only AND operator @@ -1394,23 +1393,23 @@ def filter_domain(domain): return res _ALLOWED_CODES = set(dis.opmap[x] for x in [ - 'POP_TOP','ROT_TWO','ROT_THREE','ROT_FOUR','DUP_TOP', - 'BUILD_LIST','BUILD_MAP','BUILD_TUPLE', - 'LOAD_CONST','RETURN_VALUE','STORE_SUBSCR', - 'UNARY_POSITIVE','UNARY_NEGATIVE','UNARY_NOT', - 'UNARY_INVERT','BINARY_POWER','BINARY_MULTIPLY', - 'BINARY_DIVIDE','BINARY_FLOOR_DIVIDE','BINARY_TRUE_DIVIDE', - 'BINARY_MODULO','BINARY_ADD','BINARY_SUBTRACT', - 'BINARY_LSHIFT','BINARY_RSHIFT','BINARY_AND','BINARY_XOR', 'BINARY_OR', - 'STORE_MAP', 'LOAD_NAME', 'CALL_FUNCTION', 'COMPARE_OP', 'LOAD_ATTR', - 'STORE_NAME', 'GET_ITER', 'FOR_ITER', 'LIST_APPEND', 'JUMP_ABSOLUTE', - 'DELETE_NAME', 'JUMP_IF_TRUE', 'JUMP_IF_FALSE', 'JUMP_IF_FALSE_OR_POP', - 'JUMP_IF_TRUE_OR_POP', 'POP_JUMP_IF_FALSE', 'POP_JUMP_IF_TRUE', - 'BINARY_SUBSCR', - ] if x in dis.opmap) + 'POP_TOP', 'ROT_TWO', 'ROT_THREE', 'ROT_FOUR', 'DUP_TOP', 'BUILD_LIST', + 'BUILD_MAP', 'BUILD_TUPLE', 'LOAD_CONST', 'RETURN_VALUE', + 'STORE_SUBSCR', 'UNARY_POSITIVE', 'UNARY_NEGATIVE', 'UNARY_NOT', + 'UNARY_INVERT', 'BINARY_POWER', 'BINARY_MULTIPLY', 'BINARY_DIVIDE', + 'BINARY_FLOOR_DIVIDE', 'BINARY_TRUE_DIVIDE', 'BINARY_MODULO', + 'BINARY_ADD', 'BINARY_SUBTRACT', 'BINARY_LSHIFT', 'BINARY_RSHIFT', + 'BINARY_AND', 'BINARY_XOR', 'BINARY_OR', 'STORE_MAP', 'LOAD_NAME', + 'CALL_FUNCTION', 'COMPARE_OP', 'LOAD_ATTR', 'STORE_NAME', 'GET_ITER', + 'FOR_ITER', 'LIST_APPEND', 'JUMP_ABSOLUTE', 'DELETE_NAME', + 'JUMP_IF_TRUE', 'JUMP_IF_FALSE', 'JUMP_IF_FALSE_OR_POP', + 'JUMP_IF_TRUE_OR_POP', 'POP_JUMP_IF_FALSE', 'POP_JUMP_IF_TRUE', + 'BINARY_SUBSCR', + ] if x in dis.opmap) _SAFE_EVAL_CACHE = {} + def safe_eval(source, data=None): if '__subclasses__' in source: raise ValueError('__subclasses__ not allowed') @@ -1447,6 +1446,7 @@ def safe_eval(source, data=None): 'dict': dict, }}, data) + def timezoned_date(date): if pytz and rpc.CONTEXT.get('timezone'): lzone = pytz.timezone(rpc.CONTEXT['timezone']) @@ -1456,6 +1456,7 @@ def timezoned_date(date): date = ldt return date + def humanize(size): for x in ('bytes', 'KB', 'MB', 'GB', 'TB', 'PB'): if size < 1000: diff --git a/tryton/common/date_widget.py b/tryton/common/date_widget.py index f6162a3810..a11edd1fa9 100644 --- a/tryton/common/date_widget.py +++ b/tryton/common/date_widget.py @@ -24,6 +24,7 @@ mapping = { '%p': ('__', '([_ AP][_ M])'), } + class DateEntry(gtk.Entry): def __init__(self, format, callback=None, callback_process=None): @@ -68,7 +69,8 @@ class DateEntry(gtk.Entry): return if self.mode_cmd: - if self.callback: self.callback(value) + if self.callback: + self.callback(value) self.stop_emission('insert-text') return @@ -110,7 +112,8 @@ class DateEntry(gtk.Entry): end = len(self.initial_value) if end < 0: end = 0 - while (start > 0) and (self.initial_value[start] not in ['_', ' ','0','X']): + while (start > 0 + and self.initial_value[start] not in ['_', ' ', '0', 'X']): start -= 1 text = self.get_text() text = text[:start] + self.initial_value[start:end] + text[end:] @@ -179,15 +182,16 @@ class DateEntry(gtk.Entry): for a in range(len(self.initial_value)): if self.initial_value[a] == text[a]: - text = text[:a] + default[a] + text[a+1:] + text = text[:a] + default[a] + text[a + 1:] return text def test_date(self, text): default = datetime_strftime(datetime.datetime(2000, 1, 1), self.format) try: - time.strptime(self.compute_date(text, default=default, year='2000'), - self.format) + time.strptime( + self.compute_date(text, default=default, year='2000'), + self.format) except ValueError: return False return True @@ -287,7 +291,8 @@ class ComplexEntry(gtk.HBox): self.widget_cmd.show() self._date_cb(event) else: - if hasattr(event, 'keyval') and not event.keyval == gtk.keysyms.Escape: + if (hasattr(event, 'keyval') + and not event.keyval == gtk.keysyms.Escape): cmd = self.widget_cmd.get_text() dt = self.widget.date_get() or datetime.datetime.now() res = compute_date(cmd, dt, self.widget.format) @@ -296,6 +301,7 @@ class ComplexEntry(gtk.HBox): self.widget_cmd.set_text('') self.widget_cmd.hide() + def compute_date(cmd, dt, format): lst = { '^=(\d+)d$': lambda dt, r: dt + \ @@ -320,8 +326,8 @@ def compute_date(cmd, dt, format): relativedelta(months=int(r.group(1))), '^([\\+-]\d+)y$': lambda dt, r: dt + \ relativedelta(years=int(r.group(1))), - '^=$': lambda dt,r: datetime.datetime.now(), - '^-$': lambda dt,r: False + '^=$': lambda dt, r: datetime.datetime.now(), + '^-$': lambda dt, r: False } for r, f in lst.items(): groups = re.match(r, cmd) @@ -336,6 +342,7 @@ def compute_date(cmd, dt, format): if __name__ == '__main__': win = gtk.Window() win.set_title('gtk.Entry subclass') + def cb(window, event): gtk.main_quit() win.connect('delete-event', cb) diff --git a/tryton/common/datetime_strftime.py b/tryton/common/datetime_strftime.py index d125d8d204..2420eeeeea 100644 --- a/tryton/common/datetime_strftime.py +++ b/tryton/common/datetime_strftime.py @@ -3,6 +3,7 @@ #Copyright (c) 2002-2007 John D. Hunter; All Rights Reserved import time + def datetime_strftime(dt, fmt): ''' Allow datetime strftime formatting for years before 1900. @@ -46,5 +47,5 @@ def datetime_strftime(dt, fmt): s = s1 syear = "%04d" % (dt.year,) for site in sites: - s = s[:site] + syear + s[site+4:] + s = s[:site] + syear + s[site + 4:] return s diff --git a/tryton/common/domain_inversion.py b/tryton/common/domain_inversion.py index 8da0a6aa2a..5b7a125077 100644 --- a/tryton/common/domain_inversion.py +++ b/tryton/common/domain_inversion.py @@ -4,6 +4,7 @@ import operator import types + def in_(a, b): if isinstance(a, (list, tuple)): return any(operator.contains(b, x) for x in a) @@ -28,6 +29,7 @@ OPERATORS = { 'not child_of': lambda a, b: True, } + def locale_part(expression, field_name): if expression == field_name: return 'id' @@ -36,12 +38,14 @@ def locale_part(expression, field_name): return local return expression + def is_leaf(expression): return (isinstance(expression, (list, tuple)) and len(expression) > 2 and isinstance(expression[1], basestring) and expression[1] in OPERATORS) + def eval_leaf(part, context, boolop=operator.and_): field, operand, value = part[:3] if '.' in field: @@ -54,6 +58,7 @@ def eval_leaf(part, context, boolop=operator.and_): return True return OPERATORS[operand](context[field], value) + def inverse_leaf(domain): if domain in ('AND', 'OR'): return domain @@ -67,6 +72,7 @@ def inverse_leaf(domain): else: return map(inverse_leaf, domain) + def eval_domain(domain, context, boolop=operator.and_): "compute domain boolean value according to the context" if is_leaf(domain): @@ -83,6 +89,7 @@ def eval_domain(domain, context, boolop=operator.and_): return boolop(eval_domain(domain[0], context), eval_domain(domain[1:], context, boolop)) + def localize_domain(domain, field_name=None): "returns only locale part of domain. eg: langage.code -> code" if domain in ('AND', 'OR', True, False): @@ -97,6 +104,7 @@ def localize_domain(domain, field_name=None): else: return [localize_domain(part, field_name) for part in domain] + def unlocalize_domain(domain, fieldname): if domain in ('AND', 'OR', True, False): return domain @@ -105,6 +113,7 @@ def unlocalize_domain(domain, fieldname): else: return [unlocalize_domain(part, fieldname) for part in domain] + def simplify(domain): "remove unused domain delimiter" if is_leaf(domain): @@ -120,6 +129,7 @@ def simplify(domain): else: return [simplify(branch) for branch in domain] + def merge(domain, domoperator=None): if not domain or domain in ('AND', 'OR'): return [] @@ -146,6 +156,7 @@ def parse(domain): else: return And(domain[1:] if domain[0] == 'AND' else domain) + def domain_inversion(domain, symbol, context=None): """compute an inversion of the domain eventually the context is used to simplify the expression""" @@ -169,7 +180,10 @@ class And(object): self.variables |= expression.variables def base(self, expression): - return expression if '.' not in expression else expression.split('.')[0] + if '.' not in expression: + return expression + else: + return expression.split('.')[0] def inverse(self, symbol, context): result = [] @@ -209,8 +223,8 @@ class Or(And): if (symbol not in self.variables and not known_variables >= self.variables): # In this case we don't know anything about this OR part, we - # consider it to be True (because people will have the constraint on - # this part later). + # consider it to be True (because people will have the constraint + # on this part later). return True for part in self.branches: if isinstance(part, And): @@ -244,6 +258,7 @@ class Or(And): else: return simplify(['OR'] + result) + # Test stuffs def test_simple_inversion(): domain = [['x', '=', 3]] @@ -258,6 +273,7 @@ def test_simple_inversion(): domain = [['x.id', '>', 5]] assert domain_inversion(domain, 'x') == [['x.id', '>', 5]] + def test_and_inversion(): domain = [['x', '=', 3], ['y', '>', 5]] assert domain_inversion(domain, 'x') == [['x', '=', 3]] @@ -274,11 +290,13 @@ def test_and_inversion(): assert domain_inversion(domain, 'y', {'x': 3}) == [['y', '<', 3]] assert domain_inversion(domain, 'x') == [['x.id', '>', 5]] + def test_or_inversion(): domain = ['OR', ['x', '=', 3], ['y', '>', 5], ['z', '=', 'abc']] assert domain_inversion(domain, 'x') == [['x', '=', 3]] assert domain_inversion(domain, 'x', {'y': 4}) == [['x', '=', 3]] - assert domain_inversion(domain, 'x', {'y': 4, 'z': 'ab'}) == [['x', '=', 3]] + assert domain_inversion(domain, 'x', {'y': 4, 'z': 'ab'}) ==\ + [['x', '=', 3]] assert domain_inversion(domain, 'x', {'y': 7}) == True assert domain_inversion(domain, 'x', {'y': 7, 'z': 'b'}) == True assert domain_inversion(domain, 'x', {'z': 'abc'}) == True @@ -299,6 +317,7 @@ def test_or_inversion(): assert domain_inversion(domain, 'length', {'length': 0, 'name': 'n'}) ==\ [['length', '>', 5]] + def test_orand_inversion(): domain = ['OR', [['x', '=', 3], ['y', '>', 5], ['z', '=', 'abc']], [['x', '=', 4]], [['y', '>', 6]]] @@ -308,6 +327,7 @@ def test_orand_inversion(): assert domain_inversion(domain, 'x', {'y': 7}) == True assert domain_inversion(domain, 'x', {'z': 'ab'}) == True + def test_andor_inversion(): domain = [['OR', ['x', '=', 4], ['y', '>', 6]], ['z', '=', 3]] assert domain_inversion(domain, 'z') == [['z', '=', 3]] @@ -315,6 +335,7 @@ def test_andor_inversion(): assert domain_inversion(domain, 'z', {'x': 5, 'y': 5}) == False assert domain_inversion(domain, 'z', {'x': 5, 'y': 7}) == [['z', '=', 3]] + def test_andand_inversion(): domain = [[['x', '=', 4], ['y', '>', 6]], ['z', '=', 3]] assert domain_inversion(domain, 'z') == [['z', '=', 3]] @@ -325,6 +346,7 @@ def test_andand_inversion(): domain = [[['x', '=', 4], ['y', '>', 6], ['z', '=', 2]], [['w', '=', 2]]] assert domain_inversion(domain, 'z', {'x': 4}) == [['z', '=', 2]] + def test_oror_inversion(): domain = ['OR', ['OR', ['x', '=', 3], ['y', '>', 5]], ['OR', ['x', '=', 2], ['z', '=', 'abc']], @@ -342,6 +364,7 @@ def test_oror_inversion(): assert domain_inversion(domain, 'x', {'y': 4, 'z': 'b'}) == \ ['OR', [['x', '=', 3]], [['x', '=', 2]]] + def test_parse(): domain = parse([['x', '=', 5]]) assert domain.variables == set('x') @@ -352,6 +375,7 @@ def test_parse(): domain = parse([[['x', '=', 4], ['y', '>', 6]], ['z', '=', 3]]) assert domain.variables == set('xyz') + def test_simplify(): domain = [['x', '=', 3]] assert simplify(domain) == [['x', '=', 3]] @@ -364,6 +388,7 @@ def test_simplify(): domain = ['OR', ['x', '=', 3], ['AND', ['y', '=', 5]]] assert simplify(domain) == ['OR', ['x', '=', 3], [['y', '=', 5]]] + def test_merge(): domain = [['x', '=', 6], ['y', '=', 7]] assert merge(domain) == ['AND', ['x', '=', 6], ['y', '=', 7]] @@ -391,6 +416,7 @@ def test_merge(): ['OR', ['c', '=', 3], ['AND', ['d', '=', 4], ['d2', '=', 6]]], ['d', '=', 5], ['e', '=', 6], ['f', '=', 7]] + def test_evaldomain(): domain = [['x', '>', 5]] assert eval_domain(domain, {'x': 6}) @@ -423,6 +449,7 @@ def test_evaldomain(): assert not eval_domain(domain, {'x': 5}) assert not eval_domain(domain, {'x': 11}) + def test_localize(): domain = [['x', '=', 5]] assert localize_domain(domain) == [['x', '=', 5]] diff --git a/tryton/common/environment.py b/tryton/common/environment.py index 84a29dec40..3f34580f50 100644 --- a/tryton/common/environment.py +++ b/tryton/common/environment.py @@ -20,8 +20,8 @@ class EvalEnvironment(dict): if self.eval_type == 'eval': return self.parent.get_eval(check_load=self.check_load)[item] else: - return self.parent.group.fields[item].get_on_change_value(self.parent, - check_load=self.check_load) + return self.parent.group.fields[item].get_on_change_value( + self.parent, check_load=self.check_load) def __getattr__(self, item): try: diff --git a/tryton/common/tdp.py b/tryton/common/tdp.py index 9b7f372bd1..1363b85840 100644 --- a/tryton/common/tdp.py +++ b/tryton/common/tdp.py @@ -32,6 +32,7 @@ OPERATORS = set(( 'ilike', 'not ilike')) + def operator(field): type_ = field['type'] if field else '' if type_ in ('char', 'text', 'many2one') or not field: @@ -68,7 +69,7 @@ def cast(field, value): return key return value elif type_ == 'datetime': - value = value.replace(' : ', ':') # Parser add spaces arround : + value = value.replace(' : ', ':') # Parser add spaces arround : try: value = datetime.datetime(*time.strptime(value, date_format() + ' ' + HM_FORMAT)[:6]) @@ -87,6 +88,7 @@ def cast(field, value): else: return value + def quote(value): for test in (':', ' '): if test in value: @@ -127,15 +129,16 @@ class Base(object): right = property(_get_right, _set_right) def domain(self, parent_field=None): - raise NotImplementedError("domain method is missing on %s" % \ - self.__class__) + raise NotImplementedError("domain method is missing on %s" + % self.__class__) def complete_fmt(self, left, value, right): return (self.fmt % (left, value, right)).strip() def complete(self, parent_field=None): left = self.left and tuple(self.left.complete()) or ('',) - right = self.right and tuple(self.right.complete(parent_field)) or ('',) + right = (self.right and tuple(self.right.complete(parent_field)) + or ('',)) for lvalue in left: for rvalue in right: @@ -144,15 +147,15 @@ class Base(object): def split(self, words=""): field, value = None, ' '.join(words) for i in xrange(len(words)): - candidate = ' '.join(words[-i-1:]) + candidate = ' '.join(words[-i - 1:]) if candidate.lower() in self.parser.dom_fields: field = self.parser.dom_fields[candidate.lower()] - value = ' '.join(words[:-i-1]) + value = ' '.join(words[:-i - 1]) return field, value def __str__(self, prefix=''): - res = '%s[%s] %s'% (prefix, self.pos or 'root', self.value) + res = '%s[%s] %s' % (prefix, self.pos or 'root', self.value) res = res.ljust(30) + str(type(self)) if self.left: res += "\n" + self.left.__str__(' ' + prefix) @@ -202,8 +205,8 @@ class Literal(Base): candidate = word + candidate for field in suggestions: if field.lower().startswith(candidate.lower()): - if words[pos+1:]: - new_item = ' '.join(reversed(words[pos+1:])) + if words[pos + 1:]: + new_item = ' '.join(reversed(words[pos + 1:])) new_item += ' ' + field else: new_item = field @@ -221,7 +224,7 @@ class Literal(Base): if field.lower().startswith(candidate.lower()): new_item = quote(field) - if (i-len(words) < 0) and words[i-len(words):]: + if (i - len(words) < 0) and words[i - len(words):]: find = False for item in self.suggest(words[i - len(words):], self.parser.sugg_fields): @@ -230,7 +233,7 @@ class Literal(Base): find = True if find: break - new_item += ' ' + ' '.join(words[i-len(words):]) + new_item += ' ' + ' '.join(words[i - len(words):]) yield new_item break @@ -246,7 +249,8 @@ class Literal(Base): if parent_field: if parent_field['type'] in ('selection', 'reference', 'boolean'): if parent_field['type'] in ('selection', 'reference'): - suggestions = tuple(x[1] for x in parent_field['selection']) + suggestions = tuple(x[1] + for x in parent_field['selection']) else: suggestions = (_('Y'), _('Yes'), _('True'), '1', _('N'), _('No'), _('False'), '0') @@ -369,12 +373,13 @@ class Colon(Base, InfixMixin): if field['type'] in ('char', 'text', 'many2one'): value += '%' - domain.append((field['name'] , operator(field), value)) + domain.append((field['name'], operator(field), value)) else: domain.extend(self.right.domain(field)) return domain + class DoubleDot(Base, InfixMixin): value = '..' lbp = 70 @@ -436,7 +441,7 @@ class Comma(Base, InfixMixin): node = node.left walk(self.left, values) - return [(field_name, 'in' , list(reversed(values)))] + return [(field_name, 'in', list(reversed(values)))] class Comparator(Base, InfixMixin): @@ -464,15 +469,19 @@ class Comparator(Base, InfixMixin): res.append((field_name, self.value, value)) return res + class LessThan(Comparator): value = '<' + class LessThanOrEqual(Comparator): value = '<=' + class BiggerThan(Comparator): value = '>' + class BiggerThanOrEqual(Comparator): value = '>=' @@ -519,6 +528,7 @@ class Not(Base, InfixMixin): res.append((field_name, oper, value)) return res + class NotEqual(Equal): value = '!=' fmt = '%s%s%s' @@ -574,6 +584,7 @@ class CloseParenthesis(Base): return self.left.domain() return [] + class OpenParenthesis(Base): value = '(' lbp = 10 @@ -701,7 +712,7 @@ class DomainParser: return left def next_token(self): - try : + try: new_tk = self.token_flow.next() except StopIteration: return End(self) @@ -808,6 +819,7 @@ class DomainParser: domain = domain[1:] else: nary = ' ' + def format(expression): if (isinstance(expression, (list, tuple)) and len(expression) > 2 @@ -892,6 +904,7 @@ def test_parser(): } return DomainParser(fields) + def test_selection_complete(): parser = test_parser() assert list(parser.parse('S').complete()) == ['Selection:'] @@ -912,6 +925,7 @@ def test_selection_complete(): assert list(parser.parse('Selection: Ham foo').complete()) == [ 'Selection: Ham foo'] + def test_selection_domain(): parser = test_parser() assert parser.parse('S').domain() == [('rec_name', 'ilike', 'S%')] @@ -923,6 +937,7 @@ def test_selection_domain(): assert parser.parse('Selection: Ham; Spam').domain() == [ ('selection', 'in', ['ham', 'spam'])] + def test_selection_string(): parser = test_parser() assert parser.string([]) == '' @@ -933,6 +948,7 @@ def test_selection_string(): assert parser.string([('selection', 'in', ['ham', 'spam'])]) == \ 'Selection: Ham; Spam' + def test_boolean_complete(): parser = test_parser() assert list(parser.parse('b').complete()) == ['Boolean:'] @@ -943,13 +959,15 @@ def test_boolean_complete(): assert list(parser.parse('boolean: y').complete()) == ['Boolean: Y', 'Boolean: Yes'] assert list(parser.parse('boolean: 1').complete()) == ['Boolean: 1'] - assert list(parser.parse('boolean: false').complete()) == ['Boolean: False'] + assert list(parser.parse('boolean: false').complete()) ==\ + ['Boolean: False'] assert list(parser.parse('boolean: f').complete()) == ['Boolean: False'] assert list(parser.parse('boolean: n').complete()) == ['Boolean: N', 'Boolean: No'] assert list(parser.parse('boolean: 0').complete()) == ['Boolean: 0'] assert list(parser.parse('boolean: =1').complete()) == ['Boolean: =1'] + def test_boolean_domain(): parser = test_parser() assert parser.parse('B').domain() == [('rec_name', 'ilike', 'B%')] @@ -961,6 +979,7 @@ def test_boolean_domain(): assert parser.parse('Boolean: true; false').domain() == [ ('boolean', 'in', [True, False])] + def test_boolean_string(): parser = test_parser() assert parser.string([('boolean', '=', True)]) == 'Boolean: True' @@ -968,6 +987,7 @@ def test_boolean_string(): assert parser.string([('boolean', 'in', [True, False])]) == \ 'Boolean: True; False' + def test_char_complete(): parser = test_parser() assert list(parser.parse('c').complete()) == ['Char:'] @@ -977,6 +997,7 @@ def test_char_complete(): 'Char: "foo bar"'] assert list(parser.parse('char: =foo').complete()) == ['Char: =foo'] + def test_char_domain(): parser = test_parser() assert parser.parse('c').domain() == [('rec_name', 'ilike', 'c%')] @@ -989,7 +1010,9 @@ def test_char_domain(): assert parser.parse('Char: !=foo').domain() == [('char', '!=', 'foo')] assert parser.parse('Char: != foo').domain() == [('char', '!=', 'foo')] assert parser.parse('Char: 2; 3').domain() == [('char', 'in', ['2', '3'])] - assert parser.parse('Char:! 2; 3').domain() == [('char', 'not in', ['2', '3'])] + assert parser.parse('Char:! 2; 3').domain() == [ + ('char', 'not in', ['2', '3'])] + def test_char_string(): parser = test_parser() @@ -1007,6 +1030,7 @@ def test_numeric_complete(): assert list(parser.parse('numeric: 100').complete()) == [ 'Numeric: 100'] + def test_numeric_domain(): parser = test_parser() assert parser.parse('Numeric: >100').domain() == [ @@ -1022,17 +1046,20 @@ def test_numeric_domain(): assert parser.parse('Numeric: 2; 3').domain() == [ ('numeric', 'in', [Decimal(2), Decimal(3)])] + def test_numeric_string(): parser = test_parser() assert parser.string([('numeric', '=', Decimal(100))]) == 'Numeric: 100.00' assert parser.string([('numeric', 'in', [Decimal(2), Decimal(3)])]) == \ 'Numeric: 2.00; 3.00' + def test_integer_complete(): parser = test_parser() assert list(parser.parse('integer: 42').complete()) == ['Integer: 42'] assert list(parser.parse('integer: 2;3').complete()) == ['Integer: 2; 3'] + def test_integer_domain(): parser = test_parser() assert parser.parse('Integer: >42').domain() == [ @@ -1050,6 +1077,7 @@ def test_integer_domain(): assert parser.parse('Integer: 2; 3').domain() == [ ('integer', 'in', [2, 3])] + def test_integer_string(): parser = test_parser() assert parser.string([('integer', '=', 42)]) == 'Integer: 42' @@ -1061,6 +1089,7 @@ def test_float_complete(): parser = test_parser() assert list(parser.parse('float: 3.14').complete()) == ['Float: 3.14'] + def test_float_domain(): parser = test_parser() assert parser.parse('Float: >3.14').domain() == [ @@ -1076,6 +1105,7 @@ def test_float_domain(): assert parser.parse('Float: foo').domain() == [ ('float', '=', False)] + def test_float_string(): parser = test_parser() assert parser.string([('float', '=', 3.14)]) == 'Float: 3.14' @@ -1084,6 +1114,7 @@ def test_float_string(): assert parser.string([('float', 'not in', [3.14, 42])]) == \ 'Float: !3.14; 42.00' + def test_date_complete(): today = datetime.date.today() today_str = datetime_strftime(today, date_format()) @@ -1113,6 +1144,7 @@ def test_date_complete(): 'Date: 12/04/2002', ] + def test_date_domain(): today = datetime.date.today() today_str = datetime_strftime(today, date_format()) @@ -1127,7 +1159,9 @@ def test_date_domain(): assert parser.parse('Date: 12/4/2002').domain() == [ ('date', '=', datetime.date(2002, 12, 4))] assert parser.parse('Date: 12/4/2002; 1/1/1970').domain() == [ - ('date', 'in', [datetime.date(2002, 12, 4), datetime.date(1970, 1, 1)])] + ('date', 'in', [datetime.date(2002, 12, 4), + datetime.date(1970, 1, 1)])] + def test_date_string(): parser = test_parser() @@ -1138,6 +1172,7 @@ def test_date_string(): datetime.date(1970, 1, 1)])]) == \ 'Date: 12/04/2002; 01/01/1970' + def test_datetime_complete(): today = datetime.date.today() today_str = datetime_strftime(today, date_format()) @@ -1149,6 +1184,7 @@ def test_datetime_complete(): assert list(parser.parse('Date Time: ' + today_str + ' 12:30:00' ).complete()) == ['Date Time: "' + today_str + ' 12:30:00"'] + def test_datetime_domain(): today = datetime.date.today() today_str = datetime_strftime(today, date_format()) @@ -1170,6 +1206,7 @@ def test_datetime_domain(): datetime.datetime.combine(datetime.date(1970, 1, 1), datetime.time.min)])] + def test_datetime_string(): parser = test_parser() assert parser.string([('datetime', '=', False)]) == 'Date Time: =' @@ -1184,6 +1221,7 @@ def test_datetime_string(): datetime.time.min)])]) == \ 'Date Time: 12/04/2002; 01/01/1970' + def test_composite_complete(): today = datetime.date.today() today_str = datetime_strftime(today, date_format()) @@ -1230,6 +1268,7 @@ def test_composite_complete(): 'Selection: Ham or Selection: Spamham', ] + def test_composite_domain(): parser = test_parser() assert parser.parse('char: foo boolean: false').domain() == [ @@ -1250,9 +1289,9 @@ def test_composite_domain(): assert parser.parse('char: foo or char: bar or boolean: 0').domain() == [ 'OR', ('char', 'ilike', 'foo%'), ('char', 'ilike', 'bar%'), ('boolean', '=', False)] - assert parser.parse('(char: foo or char: bar) and boolean: 1').domain() == [ - ['OR', ('char', 'ilike', 'foo%'), ('char', 'ilike', 'bar%')], - ('boolean', '=', True)] + assert parser.parse('(char: foo or char: bar) and boolean: 1').domain() ==\ + [['OR', ('char', 'ilike', 'foo%'), ('char', 'ilike', 'bar%')], + ('boolean', '=', True)] assert parser.parse('(char: foo or char: bar) boolean: 1').domain() == [ ['OR', ('char', 'ilike', 'foo%'), ('char', 'ilike', 'bar%')], ('boolean', '=', True)] @@ -1260,15 +1299,18 @@ def test_composite_domain(): ).domain() == [ ['OR', ('char', 'ilike', 'foo%'), ('char', 'ilike', 'bar%')], ('datetime', '=', datetime.datetime(2002, 12, 4, 0, 0))] - assert parser.parse('(char: foo or char: bar) Date Time: 12/4/2002').domain() == [ - ['OR', ('char', 'ilike', 'foo%'), ('char', 'ilike', 'bar%')], - ('datetime', '=', datetime.datetime(2002, 12, 4, 0, 0))] - assert parser.parse('char: foo or (char: bar and boolean: 1)').domain() == [ - 'OR', ('char', 'ilike', 'foo%'), [ - ('char', 'ilike', 'bar%'), ('boolean', '=', True)]] - assert parser.parse('char: foo and (char: bar or boolean: 0)').domain() == [ - ('char', 'ilike', 'foo%'), - ['OR', ('char', 'ilike', 'bar%'), ('boolean', '=', False)]] + assert parser.parse( + '(char: foo or char: bar) Date Time: 12/4/2002').domain() == [ + ['OR', ('char', 'ilike', 'foo%'), ('char', 'ilike', 'bar%')], + ('datetime', '=', datetime.datetime(2002, 12, 4, 0, 0))] + assert parser.parse( + 'char: foo or (char: bar and boolean: 1)').domain() == [ + 'OR', ('char', 'ilike', 'foo%'), [ + ('char', 'ilike', 'bar%'), ('boolean', '=', True)]] + assert parser.parse( + 'char: foo and (char: bar or boolean: 0)').domain() == [ + ('char', 'ilike', 'foo%'), + ['OR', ('char', 'ilike', 'bar%'), ('boolean', '=', False)]] assert parser.parse('char: foo (char: bar or boolean: 0)').domain() == [ ('char', 'ilike', 'foo%'), ['OR', ('char', 'ilike', 'bar%'), ('boolean', '=', False)]] @@ -1338,6 +1380,7 @@ def test_composite_string(): ['OR', ('char', 'ilike', 'bar%'), ('boolean', '=', False)]]) == \ 'Char: foo (Char: bar or Boolean: False)' + def test_quote_complete(): parser = test_parser() assert list(parser.parse('"char"').complete()) == ['Char:'] @@ -1348,12 +1391,14 @@ def test_quote_complete(): assert list(parser.parse('Char: "Boolean: false"').complete()) == [ 'Char: "Boolean: false"'] + def test_quote_domain(): parser = test_parser() assert parser.parse('"char"').domain() == [('rec_name', 'ilike', 'char%')] assert parser.parse('char: "foo bar"').domain() == [ ('char', 'ilike', 'foo bar%')] + def test_quote_string(): parser = test_parser() assert parser.string([('rec_name', 'ilike', 'char:%')]) == '"char:"' @@ -1361,16 +1406,19 @@ def test_quote_string(): assert parser.string([('char', 'ilike', 'Boolean: false%')]) == \ 'Char: "Boolean: false"' + def test_column(): parser = test_parser() assert parser.parse(':').domain() == [] assert parser.parse('::').domain() == [] assert parser.parse(': foo').domain() == [('rec_name', 'ilike', 'foo%')] assert parser.parse('foo :').domain() == [('rec_name', 'ilike', 'foo%')] - assert parser.parse(': foo b').domain() == [('rec_name', 'ilike', 'foo b%')] + assert parser.parse(': foo b').domain() == [ + ('rec_name', 'ilike', 'foo b%')] assert parser.parse('": foo b"').domain() == [ ('rec_name', 'ilike', ': foo b%')] + def test_double_dot(): parser = test_parser() assert parser.parse('Integer: 0..42').domain() == [ @@ -1384,6 +1432,7 @@ def test_double_dot(): assert parser.parse('Integer: 0..42 Char: foo').domain() == [ ('integer', '>=', 0), ('integer', '<', 42), ('char', 'ilike', 'foo%')] + def test_comma(): parser = test_parser() assert parser.parse('Char: foo; bar').domain() == [ @@ -1409,6 +1458,7 @@ def test_comma(): assert parser.parse('Integer: 0; 1;; 2; 3').domain() == [ ('integer', 'in', [0, 1, 0, 2, 3])] + def test_comparator(): parser = test_parser() assert parser.parse('< foo').domain() == [ @@ -1430,6 +1480,7 @@ def test_comparator(): assert parser.parse('foo <').domain() == [ ('rec_name', 'ilike', 'foo%'), ('rec_name', '<', '')] + def test_str(): parser = test_parser() assert str(parser.parse('foo bar spam ham =')) == '''\ diff --git a/tryton/config.py b/tryton/config.py index 4683034d29..d98e3cd18d 100644 --- a/tryton/config.py +++ b/tryton/config.py @@ -15,11 +15,13 @@ from tryton.exceptions import TrytonError _ = gettext.gettext + def get_home_dir(): if os.name == 'nt': return os.path.join(os.environ['HOMEDRIVE'], os.environ['HOMEPATH']) return os.environ['HOME'] + def get_config_dir(): if os.name == 'nt': return os.path.join(os.environ['APPDATA'], '.config', 'tryton', @@ -29,20 +31,6 @@ def get_config_dir(): if not os.path.isdir(get_config_dir()): os.makedirs(get_config_dir(), 0700) -def find_path(progs, args): - if os.name == 'nt': - return '' - if sys.platform == 'darwin': - return '' - paths = [x for x in os.environ['PATH'].split(':') - if os.path.isdir(x)] - for dir in paths: - for prog in progs: - val = os.path.join(dir, prog) - if os.path.isfile(val) or os.path.islink(val): - return val + ' ' + args - return '' - class ConfigManager(object): "Config manager" @@ -78,17 +66,6 @@ class ConfigManager(object): 'client.default_path': get_home_dir(), 'client.lang': locale.getdefaultlocale()[0], 'client.language_direction': 'ltr', - 'client.actions': { - 'odt': {0: find_path(['ooffice', 'ooffice2', 'libreoffice'], '"%s"'), - 1: find_path(['ooffice', 'ooffice2', 'libreoffice'], '-p "%s"')}, - 'txt': {0: find_path(['ooffice', 'ooffice2', 'libreoffice'], '"%s"'), - 1: find_path(['ooffice', 'ooffice2', 'libreoffice'], '-p "%s"')}, - 'pdf': {0: find_path(['evince', 'xpdf', 'gpdf', - 'kpdf', 'epdfview', 'acroread'], '"%s"'), 1: ''}, - 'png': {0: find_path(['feh', 'display', 'qiv', 'eye'], '"%s"'), 1: ''}, - 'csv': {0: find_path(['ooffice', 'ooffice2', 'libreoffice'], '"%s"'), - 1: find_path(['ooffice', 'ooffice2', 'libreoffice'], '-p "%s"')}, - }, 'client.email': '', 'client.can_change_accelerators': False, 'client.limit': 1000, @@ -128,18 +105,19 @@ class ConfigManager(object): if opt.config and not os.path.isfile(opt.config): raise TrytonError(_('File "%s" not found') % (opt.config,)) - self.rcfile = opt.config or os.path.join(get_config_dir(), 'tryton.conf') + self.rcfile = opt.config or os.path.join( + get_config_dir(), 'tryton.conf') self.load() for arg in ('log_level', 'log_logger'): if getattr(opt, arg): - self.options['logging.'+arg[4:]] = getattr(opt, arg) + self.options['logging.' + arg[4:]] = getattr(opt, arg) if opt.verbose: self.options['logging.default'] = 'INFO' for arg in ('login', 'port', 'server'): if getattr(opt, arg): - self.options['login.'+arg] = getattr(opt, arg) + self.options['login.' + arg] = getattr(opt, arg) def save(self): try: @@ -204,6 +182,7 @@ if not os.path.isdir(PIXMAPS_DIR): TRYTON_ICON = gtk.gdk.pixbuf_new_from_file( os.path.join(PIXMAPS_DIR, 'tryton-icon.png').encode('utf-8')) + def _data_dir(): data_dir = os.path.join(CURRENT_DIR, 'share', 'tryton') if not os.path.isdir(data_dir): diff --git a/tryton/fingerprints.py b/tryton/fingerprints.py index 8c7f8069bd..101feda004 100644 --- a/tryton/fingerprints.py +++ b/tryton/fingerprints.py @@ -25,7 +25,6 @@ class Fingerprints(dict): self[host] = sha1 def save(self): - lines = [] with open(KNOWN_HOSTS_PATH, 'w') as known_hosts: known_hosts.writelines('%s %s' % (host, sha1) + os.linesep for host, sha1 in self.iteritems()) @@ -33,7 +32,7 @@ class Fingerprints(dict): def __setitem__(self, key, value): assert isinstance(key, basestring) if value: - assert len(value) == 59 # len of formated sha1 + assert len(value) == 59 # len of formated sha1 else: value = '' super(Fingerprints, self).__setitem__(key, value) diff --git a/tryton/gui/main.py b/tryton/gui/main.py index e50b6c48a7..7a2cd441e2 100644 --- a/tryton/gui/main.py +++ b/tryton/gui/main.py @@ -15,15 +15,13 @@ except ImportError: import json import webbrowser import tryton.rpc as rpc -from tryton.config import CONFIG, TRYTON_ICON, PIXMAPS_DIR, DATA_DIR, \ - get_config_dir +from tryton.config import CONFIG, TRYTON_ICON, get_config_dir import tryton.common as common from tryton.action import Action from tryton.exceptions import TrytonServerError, TrytonError from tryton.gui.window import Window from tryton.gui.window.preference import Preference from tryton.gui.window import Limit -from tryton.gui.window import FileActions from tryton.gui.window import Email from tryton.gui.window.dblogin import DBLogin from tryton.gui.window.dbcreate import DBCreate @@ -32,12 +30,10 @@ from tryton.gui.window.tips import Tips from tryton.gui.window.about import About from tryton.gui.window.shortcuts import Shortcuts from tryton.gui.window.dbrestore import DBRestore -import re import tryton.translate as translate import tryton.plugins import pango import time -import threading try: import gtk_osxapplication except ImportError: @@ -82,7 +78,8 @@ class Main(object): self.macapp = None if gtk_osxapplication is not None: self.macapp = gtk_osxapplication.OSXApplication() - self.macapp.connect("NSApplicationBlockTermination", self.sig_close) + self.macapp.connect("NSApplicationBlockTermination", + self.sig_close) gtk.accel_map_add_entry('/File/Connect', gtk.keysyms.O, gtk.gdk.CONTROL_MASK) @@ -101,7 +98,7 @@ class Main(object): gtk.accel_map_add_entry('/Form/Save', gtk.keysyms.S, gtk.gdk.CONTROL_MASK) gtk.accel_map_add_entry('/Form/Duplicate', gtk.keysyms.D, - gtk.gdk.CONTROL_MASK|gtk.gdk.SHIFT_MASK) + gtk.gdk.CONTROL_MASK | gtk.gdk.SHIFT_MASK) gtk.accel_map_add_entry('/Form/Delete', gtk.keysyms.D, gtk.gdk.CONTROL_MASK) gtk.accel_map_add_entry('/Form/Next', gtk.keysyms.Page_Down, @@ -112,10 +109,10 @@ class Main(object): gtk.gdk.CONTROL_MASK) gtk.accel_map_add_entry('/Form/Close', gtk.keysyms.W, gtk.gdk.CONTROL_MASK) - gtk.accel_map_add_entry('/Form/Previous Tab', gtk.keysyms.Page_Up, - gtk.gdk.CONTROL_MASK) - gtk.accel_map_add_entry('/Form/Next Tab', gtk.keysyms.Page_Down, - gtk.gdk.CONTROL_MASK) + gtk.accel_map_add_entry('/Form/Previous Tab', + gtk.keysyms.Page_Up, gtk.gdk.CONTROL_MASK) + gtk.accel_map_add_entry('/Form/Next Tab', + gtk.keysyms.Page_Down, gtk.gdk.CONTROL_MASK) gtk.accel_map_add_entry('/Form/Goto', gtk.keysyms.G, gtk.gdk.CONTROL_MASK) gtk.accel_map_add_entry('/Form/Reload', gtk.keysyms.R, @@ -189,11 +186,6 @@ class Main(object): self.sig_statusbar_show() - if os.name == 'nt' or sys.platform == 'darwin': - # Disable actions, on win32 we use os.startfile - # and on mac we use /usr/bin/open - self.menuitem_actions.set_sensitive(False) - # Adding a timer the check to requests gobject.timeout_add(5 * 60 * 1000, self.request_set) _MAIN.append(self) @@ -259,6 +251,7 @@ class Main(object): self.menuitem_shortcut = menuitem_shortcut menubar.add(menuitem_shortcut) menuitem_shortcut.set_accel_path('/Shortcuts') + def shortcut_activate(widget): if (not menuitem_shortcut.get_submenu() or not menuitem_shortcut.get_submenu().get_children()): @@ -276,7 +269,7 @@ class Main(object): if self.macapp is not None: self.menubar.set_no_show_all(True) self.macapp.set_menu_bar(self.menubar) - self.macapp.insert_app_menu_item(self.aboutitem,0) + self.macapp.insert_app_menu_item(self.aboutitem, 0) menuitem_file.show_all() menuitem_user.show_all() menuitem_options.show_all() @@ -296,7 +289,8 @@ class Main(object): if not update: self.sb_username = gtk.Label() self.sb_username.set_alignment(0.0, 0.5) - self.status_hbox.pack_start(self.sb_username, True, True, padding=5) + self.status_hbox.pack_start(self.sb_username, True, True, + padding=5) self.sb_requests = gtk.Label() self.sb_requests.set_alignment(0.5, 0.5) @@ -310,14 +304,16 @@ class Main(object): self.secure_img = gtk.Image() self.secure_img.set_from_stock('tryton-lock', gtk.ICON_SIZE_MENU) - self.status_hbox.pack_start(self.secure_img, False, True, padding=2) + self.status_hbox.pack_start(self.secure_img, False, True, + padding=2) self.status_hbox.show_all() def _set_menu_file(self): menu_file = gtk.Menu() - imagemenuitem_connect = gtk.ImageMenuItem(_('_Connect...'), self.accel_group) + imagemenuitem_connect = gtk.ImageMenuItem(_('_Connect...'), + self.accel_group) image = gtk.Image() image.set_from_stock('tryton-connect', gtk.ICON_SIZE_MENU) imagemenuitem_connect.set_image(image) @@ -351,7 +347,8 @@ class Main(object): image.set_from_stock('tryton-folder-new', gtk.ICON_SIZE_MENU) imagemenuitem_db_new.set_image(image) imagemenuitem_db_new.connect('activate', self.sig_db_new) - imagemenuitem_db_new.set_accel_path('/File/Database/New Database') + imagemenuitem_db_new.set_accel_path( + '/File/Database/New Database') menu_database.add(imagemenuitem_db_new) imagemenuitem_db_restore = gtk.ImageMenuItem(_('_Restore Database...')) @@ -359,7 +356,8 @@ class Main(object): image.set_from_stock('tryton-folder-saved-search', gtk.ICON_SIZE_MENU) imagemenuitem_db_restore.set_image(image) imagemenuitem_db_restore.connect('activate', self.sig_db_restore) - imagemenuitem_db_restore.set_accel_path('/File/Database/Restore Database') + imagemenuitem_db_restore.set_accel_path( + '/File/Database/Restore Database') menu_database.add(imagemenuitem_db_restore) imagemenuitem_db_dump = gtk.ImageMenuItem(_('_Backup Database...')) @@ -367,7 +365,8 @@ class Main(object): image.set_from_stock('tryton-save-as', gtk.ICON_SIZE_MENU) imagemenuitem_db_dump.set_image(image) imagemenuitem_db_dump.connect('activate', self.sig_db_dump) - imagemenuitem_db_dump.set_accel_path('/File/Database/Backup Database') + imagemenuitem_db_dump.set_accel_path( + '/File/Database/Backup Database') menu_database.add(imagemenuitem_db_dump) imagemenuitem_db_drop = gtk.ImageMenuItem(_('Dro_p Database...')) @@ -375,11 +374,12 @@ class Main(object): image.set_from_stock('tryton-delete', gtk.ICON_SIZE_MENU) imagemenuitem_db_drop.set_image(image) imagemenuitem_db_drop.connect('activate', self.sig_db_drop) - imagemenuitem_db_drop.set_accel_path('/File/Database/Drop Database') + imagemenuitem_db_drop.set_accel_path( + '/File/Database/Drop Database') menu_database.add(imagemenuitem_db_drop) - - imagemenuitem_close = gtk.ImageMenuItem(_('_Quit...'), self.accel_group) + imagemenuitem_close = gtk.ImageMenuItem(_('_Quit...'), + self.accel_group) image = gtk.Image() image.set_from_stock('tryton-log-out', gtk.ICON_SIZE_MENU) imagemenuitem_close.set_image(image) @@ -404,7 +404,8 @@ class Main(object): menu_user.add(gtk.SeparatorMenuItem()) - imagemenuitem_menu = gtk.ImageMenuItem(_('_Menu Reload'), self.accel_group) + imagemenuitem_menu = gtk.ImageMenuItem(_('_Menu Reload'), + self.accel_group) image = gtk.Image() image.set_from_stock('tryton-start-here', gtk.ICON_SIZE_MENU) imagemenuitem_menu.set_image(image) @@ -414,11 +415,11 @@ class Main(object): imagemenuitem_menu_toggle = gtk.ImageMenuItem(_('_Menu Toggle'), self.accel_group) - imagemenuitem_menu_toggle.connect('activate', lambda *a: self.menu_toggle()) + imagemenuitem_menu_toggle.connect('activate', + lambda *a: self.menu_toggle()) imagemenuitem_menu_toggle.set_accel_path('/User/Menu Toggle') menu_user.add(imagemenuitem_menu_toggle) - imagemenuitem_home = gtk.ImageMenuItem(_('_Home'), self.accel_group) image = gtk.Image() image.set_from_stock('tryton-go-home', gtk.ICON_SIZE_MENU) @@ -434,7 +435,8 @@ class Main(object): image.set_from_stock('tryton-mail-message-new', gtk.ICON_SIZE_MENU) imagemenuitem_send_request.set_image(image) imagemenuitem_send_request.connect('activate', self.sig_request_new) - imagemenuitem_send_request.set_accel_path('/User/Send a Request') + imagemenuitem_send_request.set_accel_path( + '/User/Send a Request') menu_user.add(imagemenuitem_send_request) imagemenuitem_open_request = gtk.ImageMenuItem(_('_Read my Requests')) @@ -442,7 +444,8 @@ class Main(object): image.set_from_stock('tryton-mail-message', gtk.ICON_SIZE_MENU) imagemenuitem_open_request.set_image(image) imagemenuitem_open_request.connect('activate', self.sig_request_open) - imagemenuitem_open_request.set_accel_path('/User/Read my Requests') + imagemenuitem_open_request.set_accel_path( + '/User/Read my Requests') menu_user.add(imagemenuitem_open_request) return menu_user @@ -460,7 +463,8 @@ class Main(object): radiomenuitem_default = gtk.RadioMenuItem(label=_('_Default')) radiomenuitem_default.connect('activate', lambda x: self.sig_toolbar('default')) - radiomenuitem_default.set_accel_path('/Options/Toolbar/Default') + radiomenuitem_default.set_accel_path( + '/Options/Toolbar/Default') menu_toolbar.add(radiomenuitem_default) if (CONFIG['client.toolbar'] or 'both') == 'default': radiomenuitem_default.set_active(True) @@ -543,18 +547,20 @@ class Main(object): checkmenuitem_statusbar = gtk.CheckMenuItem(_('Statusbar')) checkmenuitem_statusbar.connect('activate', - lambda menuitem: self.sig_statusbar_change(menuitem.get_active())) - checkmenuitem_statusbar.set_accel_path('/Options/Form/Statusbar') + lambda menuitem: self.sig_statusbar_change(menuitem.get_active())) + checkmenuitem_statusbar.set_accel_path( + '/Options/Form/Statusbar') menu_form.add(checkmenuitem_statusbar) if CONFIG['form.statusbar']: checkmenuitem_statusbar.set_active(True) - checkmenuitem_save_width_height = gtk.CheckMenuItem(_('Save Width/Height')) + checkmenuitem_save_width_height = gtk.CheckMenuItem( + _('Save Width/Height')) checkmenuitem_save_width_height.connect('activate', - lambda menuitem: CONFIG.__setitem__('client.save_width_height', - menuitem.get_active())) + lambda menuitem: CONFIG.__setitem__('client.save_width_height', + menuitem.get_active())) checkmenuitem_save_width_height.set_accel_path( - '/Options/Form/Save Width Height') + '/Options/Form/Save Width Height') menu_form.add(checkmenuitem_save_width_height) if CONFIG['client.save_width_height']: checkmenuitem_save_width_height.set_active(True) @@ -602,7 +608,8 @@ class Main(object): label=_('Left')) radiomenuitem_left.connect('activate', lambda x: CONFIG.__setitem__('client.form_tab', 'left')) - radiomenuitem_left.set_accel_path('/Options/Tabs Position/Left') + radiomenuitem_left.set_accel_path( + '/Options/Tabs Position/Left') menu_tab.add(radiomenuitem_left) if (CONFIG['client.form_tab'] or 'left') == 'left': radiomenuitem_left.set_active(True) @@ -611,7 +618,8 @@ class Main(object): label=_('Right')) radiomenuitem_right.connect('activate', lambda x: CONFIG.__setitem__('client.form_tab', 'right')) - radiomenuitem_right.set_accel_path('/Options/Tabs Position/Right') + radiomenuitem_right.set_accel_path( + '/Options/Tabs Position/Right') menu_tab.add(radiomenuitem_right) if (CONFIG['client.form_tab'] or 'left') == 'right': radiomenuitem_right.set_active(True) @@ -620,7 +628,8 @@ class Main(object): label=_('Bottom')) radiomenuitem_bottom.connect('activate', lambda x: CONFIG.__setitem__('client.form_tab', 'bottom')) - radiomenuitem_bottom.set_accel_path('/Options/Tabs Position/Bottom') + radiomenuitem_bottom.set_accel_path( + '/Options/Tabs Position/Bottom') menu_tab.add(radiomenuitem_bottom) if (CONFIG['client.form_tab'] or 'left') == 'bottom': radiomenuitem_bottom.set_active(True) @@ -631,12 +640,6 @@ class Main(object): menuitem_limit.set_accel_path('/Options/Search Limit') menu_options.add(menuitem_limit) - menuitem_actions = gtk.MenuItem(_('File _Actions...')) - self.menuitem_actions = menuitem_actions - menuitem_actions.connect('activate', self.sig_file_actions) - menuitem_actions.set_accel_path('/Options/File Actions') - menu_options.add(menuitem_actions) - menuitem_email = gtk.MenuItem(_('_Email...')) self.menuitem_email = menuitem_email menuitem_email.connect('activate', self.sig_email) @@ -657,13 +660,15 @@ class Main(object): def _set_menu_plugins(self): menu_plugins = gtk.Menu() - imagemenuitem_plugin_execute = gtk.ImageMenuItem(_('_Execute a Plugin')) + imagemenuitem_plugin_execute = gtk.ImageMenuItem( + _('_Execute a Plugin')) image = gtk.Image() image.set_from_stock('tryton-executable', gtk.ICON_SIZE_MENU) imagemenuitem_plugin_execute.set_image(image) - imagemenuitem_plugin_execute.connect('activate', self.sig_plugin_execute) + imagemenuitem_plugin_execute.connect('activate', + self.sig_plugin_execute) imagemenuitem_plugin_execute.set_accel_path( - '/Plugins/Execute a Plugin') + '/Plugins/Execute a Plugin') menu_plugins.add(imagemenuitem_plugin_execute) return menu_plugins @@ -678,15 +683,16 @@ class Main(object): imagemenuitem_tips.set_accel_path('/Help/Tips') menu_help.add(imagemenuitem_tips) - imagemenuitem_shortcuts = gtk.ImageMenuItem(_('_Keyboard Shortcuts...')) + imagemenuitem_shortcuts = gtk.ImageMenuItem( + _('_Keyboard Shortcuts...')) image = gtk.Image() image.set_from_stock('tryton-help', gtk.ICON_SIZE_MENU) imagemenuitem_shortcuts.set_image(image) imagemenuitem_shortcuts.connect('activate', self.sig_shortcuts) - imagemenuitem_shortcuts.set_accel_path('/Help/Keyboard Shortcuts') + imagemenuitem_shortcuts.set_accel_path( + '/Help/Keyboard Shortcuts') menu_help.add(imagemenuitem_shortcuts) - imagemenuitem_about = gtk.ImageMenuItem(_('_About...')) image = gtk.Image() image.set_from_stock('gtk-about', gtk.ICON_SIZE_MENU) @@ -817,9 +823,6 @@ class Main(object): def sig_limit(self, widget): Limit().run() - def sig_file_actions(self, widget): - FileActions().run() - def sig_email(self, widget): Email().run() @@ -843,7 +846,8 @@ class Main(object): 'get_preferences', False, rpc.CONTEXT) if prefs and 'language_direction' in prefs: translate.set_language_direction(prefs['language_direction']) - CONFIG['client.language_direction'] = prefs['language_direction'] + CONFIG['client.language_direction'] = \ + prefs['language_direction'] self.sb_username.set_text(prefs.get('status_bar', '')) if prefs and 'language' in prefs: translate.setlang(prefs['language'], prefs.get('locale')) @@ -866,8 +870,8 @@ class Main(object): ctx = {} ctx.update(rpc.CONTEXT) ctx['active_test'] = False - return Window.create(None, 'res.request', False, [ ], - mode=['form', 'tree'], context=ctx) + return Window.create(None, 'res.request', False, [], + mode=['form', 'tree'], context=ctx) def sig_request_open(self, widget): ctx = {} @@ -881,8 +885,8 @@ class Main(object): else: raise ids = ids1 + ids2 - return Window.create(False, 'res.request', ids, [ ], - mode=['tree', 'form'], context=ctx) + return Window.create(False, 'res.request', ids, [], + mode=['tree', 'form'], context=ctx) def request_set(self, exception=False): try: @@ -897,7 +901,6 @@ class Main(object): else: ids, ids2 = rpc.execute('model', 'res.request', 'request_get', rpc.CONTEXT) - label = _('Requests (%s/%s)') % (len(ids), len(ids2)) message = _('Waiting requests: %s received - %s sent') % (len(ids), len(ids2)) self.sb_requests.set_text(message) @@ -935,7 +938,8 @@ class Main(object): common.ICONFACTORY.load_icons() if prefs and 'language_direction' in prefs: translate.set_language_direction(prefs['language_direction']) - CONFIG['client.language_direction'] = prefs['language_direction'] + CONFIG['client.language_direction'] = \ + prefs['language_direction'] menu_id = self.sig_win_menu(quiet=False, prefs=prefs) if menu_id: self.sig_home_new(quiet=True, except_id=menu_id, prefs=prefs) @@ -1026,7 +1030,8 @@ class Main(object): if (self.menu_screen and self.menu_screen.current_view.view_type == 'tree'): try: - has_focus = self.menu_screen.current_view.widget_tree.has_focus() + has_focus = \ + self.menu_screen.current_view.widget_tree.has_focus() except AttributeError: has_focus = (self.menu_screen.current_view.widget_tree.flags() & gtk.HAS_FOCUS) @@ -1114,7 +1119,7 @@ class Main(object): def sig_configure(self, widget, event): if hasattr(event, 'width') \ and hasattr(event, 'height'): - self._width = int(event.width) + self._width = int(event.width) self._height = int(event.height) return False @@ -1336,7 +1341,7 @@ class Main(object): if dbname: with open(filename, 'rb') as file_p: data = file_p.read() - host, port = url.rsplit(':' , 1) + host, port = url.rsplit(':', 1) rpcprogress = common.RPCProgress('db_exec', (host, int(port), 'restore', dbname, passwd, buffer(data), update)) try: @@ -1497,7 +1502,6 @@ class Main(object): direct_print = json.loads(params.get('direct_print', 'false')) email_print = json.loads(params.get('email_print', 'false')) email = json.loads(params.get('email', 'null')) - name = json.loads(params.get('name', 'false')) context = json.loads(params.get('context', '{}')) except ValueError: return diff --git a/tryton/gui/window/__init__.py b/tryton/gui/window/__init__.py index 3558718664..d0d616fc01 100644 --- a/tryton/gui/window/__init__.py +++ b/tryton/gui/window/__init__.py @@ -1,6 +1,5 @@ #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 window import * -from fileactions import * from email import * from limit import * diff --git a/tryton/gui/window/about.py b/tryton/gui/window/about.py index 84d3ecaa03..8757d71d04 100644 --- a/tryton/gui/window/about.py +++ b/tryton/gui/window/about.py @@ -3,9 +3,8 @@ #this repository contains the full copyright notices and license terms. import gtk import gettext -import os import webbrowser -from tryton.config import TRYTON_ICON, PIXMAPS_DIR, DATA_DIR +from tryton.config import TRYTON_ICON from tryton.version import VERSION, WEBSITE from tryton.common import get_toplevel_window diff --git a/tryton/gui/window/attachment.py b/tryton/gui/window/attachment.py index 4c83734452..daafd69d77 100644 --- a/tryton/gui/window/attachment.py +++ b/tryton/gui/window/attachment.py @@ -5,20 +5,27 @@ from tryton.gui.window.view_form.screen import Screen from tryton.gui.window.win_form import WinForm -class Attachment(object): +class Attachment(WinForm): "Attachment window" - def __init__(self, model_name, record_id): + def __init__(self, model_name, record_id, callback=None): self.resource = '%s,%s' % (model_name, record_id) - - def run(self): + self.attachment_callback = callback screen = Screen('ir.attachment', domain=[ ('resource', '=', self.resource), ], mode=['tree', 'form'], context={ 'resource': self.resource, }, exclude_field='resource') screen.search_filter() - def callback(result): - if result: - screen.group.save() - WinForm(screen, callback, view_type='tree') + super(Attachment, self).__init__(screen, self.callback, + view_type='tree') + + def destroy(self): + self.prev_view.save_width_height() + super(Attachment, self).destroy() + + def callback(self, result): + if result: + self.screen.group.save() + if self.attachment_callback: + self.attachment_callback() diff --git a/tryton/gui/window/board.py b/tryton/gui/window/board.py index 697d887250..2e9d80b016 100644 --- a/tryton/gui/window/board.py +++ b/tryton/gui/window/board.py @@ -2,8 +2,6 @@ #this repository contains the full copyright notices and license terms. "Board" import gettext -import gtk -from tryton.config import CONFIG from tryton.signal_event import SignalEvent from tryton.gui import Main import tryton.rpc as rpc diff --git a/tryton/gui/window/dbcreate.py b/tryton/gui/window/dbcreate.py index e59463baa9..817f7592a7 100644 --- a/tryton/gui/window/dbcreate.py +++ b/tryton/gui/window/dbcreate.py @@ -5,7 +5,7 @@ import gobject import gettext import re import tryton.common as common -from tryton.config import CONFIG, TRYTON_ICON, PIXMAPS_DIR +from tryton.config import CONFIG, TRYTON_ICON from tryton.exceptions import TrytonServerError import tryton.rpc as rpc @@ -28,10 +28,11 @@ class DBCreate(object): self.entry_adminpasswd2.set_sensitive(True) self.entry_server_connection.modify_text(gtk.STATE_INSENSITIVE, \ gtk.gdk.color_parse(common.COLOR_SCHEMES["black"])) - self.tooltips.set_tip(self.entry_server_connection,_("This is the URL of " \ - "the Tryton server. Use server 'localhost' and port '8000' if " \ - "the server is installed on this computer. Click on 'Change' to " \ - "change the address.")) + self.tooltips.set_tip(self.entry_server_connection, + _("This is the URL of the Tryton server. Use server " + "'localhost' and port '8000' if the server is installed " + "on this computer. Click on 'Change' to change the " + "address.")) else: self.entry_serverpasswd.set_sensitive(False) self.entry_dbname.set_sensitive(False) @@ -89,12 +90,12 @@ class DBCreate(object): must be filled, then the Create button is set to sensitive. This event method doesn't check the valid of single entrys. """ - if self.entry_server_connection.get_text() != "" \ - and self.entry_serverpasswd.get_text() != "" \ - and self.entry_dbname.get_text() != "" \ - and self.combo_language.get_active() != -1 \ - and self.entry_adminpasswd.get_text() != "" \ - and self.entry_adminpasswd2.get_text() != "": + if (self.entry_server_connection.get_text() != "" + and self.entry_serverpasswd.get_text() != "" + and self.entry_dbname.get_text() != "" + and self.combo_language.get_active() != -1 + and self.entry_adminpasswd.get_text() != "" + and self.entry_adminpasswd2.get_text() != ""): widget.unset_flags(gtk.HAS_DEFAULT) self.button_create.set_sensitive(True) self.button_create.set_flags(gtk.CAN_DEFAULT) @@ -114,7 +115,7 @@ class DBCreate(object): - First character must be a letter """ - if (new_text.isalnum() or new_text == '_' ): + if new_text.isalnum() or new_text == '_': _hid = entry.get_data('handlerid') entry.handler_block(_hid) _pos = entry.get_position() @@ -133,11 +134,9 @@ class DBCreate(object): self.port = port # GTK Stuffs - self.dialog = gtk.Dialog( - title= _("Create new database"), - flags=gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT - | gtk.WIN_POS_CENTER_ON_PARENT, - ) + self.dialog = gtk.Dialog(title=_("Create new database"), + flags=gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT | + gtk.WIN_POS_CENTER_ON_PARENT) self.dialog.set_has_separator(True) self.dialog.set_icon(TRYTON_ICON) # This event is needed for controlling the button_create @@ -152,7 +151,8 @@ class DBCreate(object): img_connect = gtk.Image() img_connect.set_from_stock('tryton-new', gtk.ICON_SIZE_BUTTON) self.button_create.set_image(img_connect) - self.tooltips.set_tip(self.button_create, _('Create the new database.')) + self.tooltips.set_tip(self.button_create, + _('Create the new database.')) self.dialog.add_action_widget(self.button_create, gtk.RESPONSE_OK) self.dialog.set_default_response(gtk.RESPONSE_OK) @@ -163,10 +163,10 @@ class DBCreate(object): table.set_col_spacings(3) self.label_server_setup = gtk.Label() - self.label_server_setup.set_markup(""+ _("Server Setup:")+ "") + self.label_server_setup.set_markup("" + _("Server Setup:") + "") self.label_server_setup.set_justify(gtk.JUSTIFY_LEFT) self.label_server_setup.set_alignment(0, 1) - self.label_server_setup.set_padding( 9, 5) + self.label_server_setup.set_padding(9, 5) table.attach(self.label_server_setup, 0, 3, 0, 1, xoptions=gtk.FILL) self.label_server = gtk.Label(_("Server connection:")) self.label_server.set_alignment(1, 0.5) @@ -176,25 +176,26 @@ class DBCreate(object): self.entry_server_connection.set_sensitive(False) self.entry_server_connection.unset_flags(gtk.CAN_FOCUS) self.entry_server_connection.set_editable(False) - self.tooltips.set_tip(self.entry_server_connection, _("This is the URL of " \ - "the server. Use server 'localhost' and port '8000' if " \ - "the server is installed on this computer. Click on 'Change' to " \ - "change the address.")) + self.tooltips.set_tip(self.entry_server_connection, + _("This is the URL of the server. Use server 'localhost' and port " + "'8000' if the server is installed on this computer. Click on " + "'Change' to change the address.")) self.button_server_change = gtk.Button(_("C_hange"), stock=None, use_underline=True) img_button_server_change = gtk.Image() - img_button_server_change.set_from_stock('tryton-preferences-system', \ + img_button_server_change.set_from_stock('tryton-preferences-system', gtk.ICON_SIZE_BUTTON) self.button_server_change.set_image(img_button_server_change) - table.attach(self.button_server_change, 2, 3, 1, 2, yoptions=False, xoptions=gtk.FILL) - self.tooltips.set_tip(self.button_server_change, _("Setup the " \ - "server connection...")) + table.attach(self.button_server_change, 2, 3, 1, 2, yoptions=False, + xoptions=gtk.FILL) + self.tooltips.set_tip(self.button_server_change, + _("Setup the server connection...")) table.attach(self.entry_server_connection, 1, 2, 1, 2) self.label_serverpasswd = gtk.Label(_("Tryton Server Password:")) self.label_serverpasswd.set_justify(gtk.JUSTIFY_RIGHT) self.label_serverpasswd.set_alignment(1, 0.5) - self.label_serverpasswd.set_padding( 3, 3) + self.label_serverpasswd.set_padding(3, 3) table.attach(self.label_serverpasswd, 0, 1, 2, 3, xoptions=gtk.FILL, yoptions=gtk.FILL) self.entry_serverpasswd = gtk.Entry() @@ -212,15 +213,15 @@ class DBCreate(object): table.attach(self.hseparator, 0, 3, 3, 4, yoptions=gtk.FILL) label_dbname = gtk.Label() - label_dbname.set_markup("" + _("New database setup:") + "") + label_dbname.set_markup("" + _("New database setup:") + "") label_dbname.set_justify(gtk.JUSTIFY_LEFT) label_dbname.set_alignment(0, 1) - label_dbname.set_padding( 9, 5) + label_dbname.set_padding(9, 5) table.attach(label_dbname, 0, 3, 4, 5, xoptions=gtk.FILL, yoptions=gtk.FILL) label_dbname = gtk.Label(_("Database name:")) label_dbname.set_justify(gtk.JUSTIFY_RIGHT) - label_dbname.set_padding( 3, 3) + label_dbname.set_padding(3, 3) label_dbname.set_alignment(1, 0.5) table.attach(label_dbname, 0, 1, 5, 6, xoptions=gtk.FILL, yoptions=gtk.FILL) @@ -229,18 +230,18 @@ class DBCreate(object): self.entry_dbname.set_width_chars(16) self.entry_dbname.set_activates_default(True) table.attach(self.entry_dbname, 1, 3, 5, 6, yoptions=gtk.FILL) - self.tooltips.set_tip(self.entry_dbname, _("Choose the name of the new " \ - "database.\n" \ - "Allowed characters are alphanumerical or _ (underscore)\n" \ - "You need to avoid all accents, space or special characters! " \ - "Example: tryton")) - handlerid = self.entry_dbname.connect("insert-text", \ + self.tooltips.set_tip(self.entry_dbname, + _("Choose the name of the new database.\n" + "Allowed characters are alphanumerical or _ (underscore)\n" + "You need to avoid all accents, space or special characters! " + "Example: tryton")) + handlerid = self.entry_dbname.connect("insert-text", self.entry_insert_text) self.entry_dbname.set_data('handlerid', handlerid) label_language = gtk.Label(_("Default language:")) label_language.set_justify(gtk.JUSTIFY_RIGHT) label_language.set_alignment(1, 0.5) - label_language.set_padding( 3, 3) + label_language.set_padding(3, 3) table.attach(label_language, 0, 1, 6, 7, xoptions=gtk.FILL, yoptions=gtk.FILL) eventbox_language = gtk.EventBox() @@ -253,24 +254,25 @@ class DBCreate(object): "the administration menu.")) label_adminpasswd = gtk.Label(_("Admin password:")) label_adminpasswd.set_justify(gtk.JUSTIFY_RIGHT) - label_adminpasswd.set_padding( 3, 3) + label_adminpasswd.set_padding(3, 3) label_adminpasswd.set_alignment(1, 0.5) table.attach(label_adminpasswd, 0, 1, 7, 8, xoptions=gtk.FILL, yoptions=gtk.FILL) self.entry_adminpasswd = gtk.Entry() self.entry_adminpasswd.set_visibility(False) self.entry_adminpasswd.set_activates_default(True) - self.tooltips.set_tip(self.entry_adminpasswd, _("Choose a password for " \ - "the admin user of the new database. With these credentials you " \ - "will be later able to login into the database:\n" \ - "User name: admin\n" \ - "Password: ")) + self.tooltips.set_tip(self.entry_adminpasswd, + _("Choose a password for the admin user of the new database. " + "With these credentials you will be later able to login into " + "the database:\n" + "User name: admin\n" + "Password: ")) table.attach(self.entry_adminpasswd, 1, 3, 7, 8, yoptions=gtk.FILL) self.entry_adminpasswd.connect("key-press-event", \ self.event_passwd_clear) label_adminpasswd2 = gtk.Label(_("Confirm admin password:")) label_adminpasswd2.set_justify(gtk.JUSTIFY_RIGHT) - label_adminpasswd2.set_padding( 3, 3) + label_adminpasswd2.set_padding(3, 3) label_adminpasswd2.set_alignment(1, 0.5) table.attach(label_adminpasswd2, 0, 1, 8, 9, xoptions=gtk.FILL, yoptions=gtk.FILL) @@ -355,14 +357,14 @@ class DBCreate(object): common.process_exception(exception) continue if exist: - common.warning(_("A database with the same name " \ - "already exists.\n" \ - "Try another database name."), - _("This database name already exist!")) - self.entry_dbname.set_text("") - self.entry_dbname.grab_focus() - continue - else: # Everything runs fine, break the block here + common.warning(_("A database with the same name " + "already exists.\n" + "Try another database name."), + _("This database name already exist!")) + self.entry_dbname.set_text("") + self.entry_dbname.grab_focus() + continue + else: # Everything runs fine, break the block here host = url_m.group(1) port = url_m.group(2) try: @@ -378,13 +380,13 @@ class DBCreate(object): self.entry_serverpasswd.set_text("") self.entry_serverpasswd.grab_focus() continue - else: # Unclassified error - common.warning(_("Can't create the " \ - "database, caused by an unknown reason.\n" \ - "If there is a database created, it could " \ - "be broken. Maybe drop this database! " \ - "Please check the error message for " \ - "possible informations.\n" \ + else: # Unclassified error + common.warning(_("Can't create the " + "database, caused by an unknown reason.\n" + "If there is a database created, it could " + "be broken. Maybe drop this database! " + "Please check the error message for " + "possible informations.\n" "Error message:\n") + str(exception.faultCode), _("Error creating database!")) @@ -410,4 +412,3 @@ class DBCreate(object): parent.present() self.dialog.destroy() return dbname - diff --git a/tryton/gui/window/dbdumpdrop.py b/tryton/gui/window/dbdumpdrop.py index 08cfe1aea6..6be380e745 100644 --- a/tryton/gui/window/dbdumpdrop.py +++ b/tryton/gui/window/dbdumpdrop.py @@ -1,7 +1,5 @@ # 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 threading - import gtk import gobject import gettext @@ -11,6 +9,7 @@ import tryton.rpc as rpc _ = gettext.gettext + class DBBackupDrop(object): """ Widget for database backup and drop. @@ -20,14 +19,16 @@ class DBBackupDrop(object): db_widget.hide() label.hide() dbprogress = common.DBProgress(host, port) + def callback(dbs, createdb): if dbs is None or dbs == -1: if dbs is None: - label.set_label('' + \ - _('Could not connect to server!') + '') + label.set_label('' + + _('Could not connect to server!') + '') else: - label.set_label('' + \ - _('This client version is not compatible with the server!') + label.set_label('' + + _('This client version is not compatible ' + 'with the server!') + '') db_widget.hide() label.show() @@ -58,9 +59,9 @@ class DBBackupDrop(object): must be filled, then the Create button is set to sensitive. This event method doesn't check the valid of single entrys. """ - if self.entry_server_connection.get_text() != "" \ - and self.combo_database.get_active_text() != "" \ - and self.entry_serverpasswd.get_text() != "": + if (self.entry_server_connection.get_text() != "" + and self.combo_database.get_active_text() != "" + and self.entry_serverpasswd.get_text() != ""): widget.unset_flags(gtk.HAS_DEFAULT) self.button_ok.set_sensitive(True) self.button_ok.set_flags(gtk.CAN_DEFAULT) @@ -73,7 +74,7 @@ class DBBackupDrop(object): def __init__(self, function=None): # This widget is used for creating and droping a database! - if function =="backup": + if function == "backup": dialog_title = _("Backup a database") button_ok_text = _("Backup") button_ok_tooltip = _("Backup the choosen database.") @@ -114,14 +115,15 @@ class DBBackupDrop(object): table.set_border_width(10) table.set_row_spacings(3) table.set_col_spacings(3) - self.dialog_vbox.pack_start(table, True, False,0) + self.dialog_vbox.pack_start(table, True, False, 0) label_subtitle = gtk.Label() - label_subtitle.set_markup(""+ label_subtitle_text + "") + label_subtitle.set_markup("" + label_subtitle_text + "") label_subtitle.set_justify(gtk.JUSTIFY_LEFT) label_subtitle.set_alignment(0, 1) - label_subtitle.set_padding( 9, 5) - table.attach(label_subtitle, 0, 3, 0, 1, yoptions=False, xoptions=gtk.FILL) + label_subtitle.set_padding(9, 5) + table.attach(label_subtitle, 0, 3, 0, 1, yoptions=False, + xoptions=gtk.FILL) hseparator = gtk.HSeparator() table.attach(hseparator, 0, 3, 1, 2, yoptions=False) @@ -183,7 +185,7 @@ class DBBackupDrop(object): self.label_serverpasswd = gtk.Label(_("Tryton Server Password:")) self.label_serverpasswd.set_justify(gtk.JUSTIFY_RIGHT) self.label_serverpasswd.set_alignment(1, 0.5) - self.label_serverpasswd.set_padding( 3, 3) + self.label_serverpasswd.set_padding(3, 3) table.attach(self.label_serverpasswd, 0, 1, 4, 5, yoptions=False, xoptions=gtk.FILL) @@ -234,4 +236,3 @@ class DBBackupDrop(object): self.dialog.destroy() return (url, database, passwd) - diff --git a/tryton/gui/window/dblogin.py b/tryton/gui/window/dblogin.py index 4e28d7c2bb..73024dc0af 100644 --- a/tryton/gui/window/dblogin.py +++ b/tryton/gui/window/dblogin.py @@ -5,10 +5,7 @@ import ConfigParser import gtk import gobject import os -import re import gettext -import threading -import time from tryton.version import VERSION import tryton.common as common @@ -31,8 +28,9 @@ class DBListEditor(object): # GTK Stuffs self.parent = parent self.dialog = gtk.Dialog(title=_(u'Profile Editor'), parent=parent, - flags=gtk.DIALOG_MODAL|gtk.DIALOG_DESTROY_WITH_PARENT) - self.ok_button = self.dialog.add_button(gtk.STOCK_OK, gtk.RESPONSE_ACCEPT) + flags=gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT) + self.ok_button = self.dialog.add_button(gtk.STOCK_OK, + gtk.RESPONSE_ACCEPT) self.dialog.set_position(gtk.WIN_POS_CENTER_ON_PARENT) self.dialog.set_has_separator(True) self.dialog.set_icon(TRYTON_ICON) @@ -94,7 +92,8 @@ class DBListEditor(object): database.set_padding(3, 3) self.database_entry = gtk.Entry() self.database_entry.connect('changed', self.dbentry_changed) - self.database_entry.connect('changed', self.update_profiles, 'database') + self.database_entry.connect('changed', self.update_profiles, + 'database') self.database_entry.set_activates_default(True) self.database_label = gtk.Label() self.database_label.set_use_markup(True) @@ -108,7 +107,7 @@ class DBListEditor(object): self.database_combo.connect('changed', self.dbcombo_changed) self.database_button = gtk.Button(_(u'Create')) self.database_button.connect('clicked', self.db_create) - self.database_progressbar= gtk.ProgressBar() + self.database_progressbar = gtk.ProgressBar() self.database_progressbar.set_text(_(u'Fetching databases list')) image = gtk.Image() image.set_from_stock('tryton-new', gtk.ICON_SIZE_BUTTON) @@ -131,7 +130,8 @@ class DBListEditor(object): username.set_alignment(1, 0.5) username.set_padding(3, 3) self.username_entry = gtk.Entry() - self.username_entry.connect('changed', self.update_profiles, 'username') + self.username_entry.connect('changed', self.update_profiles, + 'username') self.username_entry.set_activates_default(True) table.attach(username, 0, 1, 4, 5, yoptions=False, xoptions=gtk.FILL) table.attach(self.username_entry, 1, 2, 4, 5, yoptions=False) @@ -193,10 +193,10 @@ class DBListEditor(object): def profile_create(self, button): self.clear_entries() model = self.profile_tree.get_model() - selection = self.profile_tree.get_selection() model.append(['', False]) column = self.profile_tree.get_column(0) - self.profile_tree.set_cursor(len(model)-1, column, start_editing=True) + self.profile_tree.set_cursor(len(model) - 1, column, + start_editing=True) def profile_delete(self, button): self.clear_entries() @@ -375,7 +375,7 @@ class DBLogin(object): # GTK Stuffs self.parent = common.get_toplevel_window() self.dialog = gtk.Dialog(title=_('Login'), parent=self.parent, - flags=gtk.DIALOG_MODAL|gtk.DIALOG_DESTROY_WITH_PARENT) + flags=gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT) self.dialog.set_position(gtk.WIN_POS_CENTER_ON_PARENT) self.dialog.set_has_separator(True) self.dialog.set_icon(TRYTON_ICON) @@ -444,7 +444,8 @@ class DBLogin(object): self.label_host.set_alignment(1, 0.5) self.label_host.set_padding(3, 3) self.entry_host = gtk.Entry() - self.entry_host.connect_after('focus-out-event', self.clear_profile_combo) + self.entry_host.connect_after('focus-out-event', + self.clear_profile_combo) self.entry_host.set_activates_default(True) self.table_main.attach(self.label_host, 0, 1, 4, 5, xoptions=gtk.FILL) self.table_main.attach(self.entry_host, 1, 3, 4, 5) @@ -453,7 +454,8 @@ class DBLogin(object): self.label_database.set_alignment(1, 0.5) self.label_database.set_padding(3, 3) self.entry_database = gtk.Entry() - self.entry_database.connect_after('focus-out-event', self.clear_profile_combo) + self.entry_database.connect_after('focus-out-event', + self.clear_profile_combo) self.entry_database.set_activates_default(True) self.table_main.attach(self.label_database, 0, 1, 5, 6, xoptions=gtk.FILL) @@ -465,12 +467,12 @@ class DBLogin(object): self.entry_login = gtk.Entry() self.entry_login.set_activates_default(True) self.table_main.attach(self.entry_login, 1, 3, 6, 7) - label_password = gtk.Label(str = _("Password:")) + label_password = gtk.Label(str=_("Password:")) label_password.set_justify(gtk.JUSTIFY_RIGHT) label_password.set_alignment(1, 0.5) label_password.set_padding(3, 3) self.table_main.attach(label_password, 0, 1, 7, 8, xoptions=gtk.FILL) - label_username = gtk.Label(str = _("User name:")) + label_username = gtk.Label(str=_("User name:")) label_username.set_alignment(1, 0.5) label_username.set_padding(3, 3) self.table_main.attach(label_username, 0, 1, 6, 7, xoptions=gtk.FILL) @@ -631,13 +633,10 @@ class DBLogin(object): port = self.get_port(netloc) except ValueError: continue - if ':' in host: - hostname = '[%s]' % host - else: - hostname = host try: if not common.test_server_version(host, port): - common.warning('', _(u'Incompatible version of the server')) + common.warning('', + _(u'Incompatible version of the server')) continue except Exception, exception: common.process_exception(exception) @@ -660,4 +659,3 @@ class DBLogin(object): Main.get_main().refresh_ssl() raise TrytonError('QueryCanceled') return result - diff --git a/tryton/gui/window/dbrestore.py b/tryton/gui/window/dbrestore.py index 6be7386542..8f52fc7e9e 100644 --- a/tryton/gui/window/dbrestore.py +++ b/tryton/gui/window/dbrestore.py @@ -5,7 +5,7 @@ import gtk import gobject import gettext import tryton.common as common -from tryton.config import CONFIG, TRYTON_ICON +from tryton.config import CONFIG import tryton.rpc as rpc _ = gettext.gettext @@ -19,10 +19,10 @@ class DBRestore(object): must be filled, then the restore button is set to sensitive. This event method doesn't check the valid of single entrys. """ - if self.entry_server_url.get_text() != "" \ - and self.entry_server_password.get_text() != "" \ - and self.entry_server_url.get_text() != "" \ - and self.entry_db_name.get_text() != "": + if (self.entry_server_url.get_text() != "" + and self.entry_server_password.get_text() != "" + and self.entry_server_url.get_text() != "" + and self.entry_db_name.get_text() != ""): widget.unset_flags(gtk.HAS_DEFAULT) self.button_restore.set_sensitive(True) self.button_restore.set_flags(gtk.CAN_DEFAULT) @@ -40,7 +40,7 @@ class DBRestore(object): - Allowed characters are alpha-nummeric [A-Za-z0-9] and underscore (_) - First character must be a letter """ - if (new_text.isalnum() or new_text == '_' ): + if new_text.isalnum() or new_text == '_': _hid = entry.get_data('handlerid') entry.handler_block(_hid) _pos = entry.get_position() @@ -48,6 +48,7 @@ class DBRestore(object): new_text = "" _pos = entry.insert_text(new_text, _pos) entry.handler_unblock(_hid) + def _move_cursor(): with gtk.gdk.lock: entry.set_position(_pos) @@ -158,7 +159,8 @@ class DBRestore(object): img_restore.set_from_stock('tryton-folder-saved-search', \ gtk.ICON_SIZE_BUTTON) self.button_restore.set_image(img_restore) - self.tooltips.set_tip(self.button_restore, _('Restore the database from file.')) + self.tooltips.set_tip(self.button_restore, + _('Restore the database from file.')) self.dialog.add_action_widget(self.button_restore, gtk.RESPONSE_OK) self.dialog.set_default_response(gtk.RESPONSE_OK) diff --git a/tryton/gui/window/email.py b/tryton/gui/window/email.py index 4112050f92..d9e6d1d443 100644 --- a/tryton/gui/window/email.py +++ b/tryton/gui/window/email.py @@ -14,9 +14,9 @@ class Email(object): def __init__(self): self.parent = get_toplevel_window() self.win = gtk.Dialog(_('Email'), self.parent, - gtk.DIALOG_MODAL|gtk.DIALOG_DESTROY_WITH_PARENT, - (gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL, - gtk.STOCK_OK, gtk.RESPONSE_OK)) + gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT, + (gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL, gtk.STOCK_OK, + gtk.RESPONSE_OK)) self.win.set_default_response(gtk.RESPONSE_OK) self.win.set_icon(TRYTON_ICON) self.win.set_has_separator(True) @@ -84,7 +84,6 @@ class Email(object): self.win.vbox.pack_start(hbox, expand=True, fill=True) - self.win.show_all() def run(self): diff --git a/tryton/gui/window/fileactions.py b/tryton/gui/window/fileactions.py deleted file mode 100644 index 403365662a..0000000000 --- a/tryton/gui/window/fileactions.py +++ /dev/null @@ -1,88 +0,0 @@ -#This file is part of Tryton. The COPYRIGHT file at the top level of -#this repository contains the full copyright notices and license terms. -"File actions" -import gtk -import gettext -from tryton.config import TRYTON_ICON, CONFIG -from tryton.common import safe_eval, get_toplevel_window - -_ = gettext.gettext - - -class FileActions(object): - "File actions window" - - def __init__(self): - self.parent= get_toplevel_window() - self.win = gtk.Dialog(_('File Actions'), self.parent, - gtk.DIALOG_MODAL|gtk.DIALOG_DESTROY_WITH_PARENT, - (gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL, - gtk.STOCK_OK, gtk.RESPONSE_OK)) - self.win.set_default_response(gtk.RESPONSE_OK) - self.win.set_icon(TRYTON_ICON) - self.win.set_has_separator(True) - self.win.vbox.pack_start(gtk.Label( - _('Edit Files Actions')), expand=False, fill=True) - self.win.vbox.pack_start(gtk.HSeparator()) - self.treeview = gtk.TreeView() - - self.model = gtk.ListStore(str, str, str, str) - self.treeview.set_model(self.model) - - for index, text in enumerate((_('File Type'), _('Open'), _('Print'))): - renderer = gtk.CellRendererText() - if index != 0: - renderer.set_property('editable', True) - renderer.connect('edited', self._sig_edited) - column = gtk.TreeViewColumn(text, renderer, text=index + 1) - column.set_resizable(True) - self.treeview.append_column(column) - - i = 1 - if isinstance(CONFIG['client.actions'], basestring): - CONFIG['client.actions'] = safe_eval(CONFIG['client.actions']) - extensions = CONFIG['client.actions'].keys() - extensions.sort() - for extension in extensions: - iter = self.model.append() - self.model.set(iter, 0, extension, - 1, _('%s file') % extension.upper(), - 2, CONFIG['client.actions'][extension][0], - 3, CONFIG['client.actions'][extension][1]) - - scroll = gtk.ScrolledWindow() - scroll.add(self.treeview) - scroll.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC) - viewport= gtk.Viewport() - viewport.set_shadow_type(gtk.SHADOW_ETCHED_IN) - viewport.set_size_request(400, 200) - viewport.add(scroll) - self.win.vbox.pack_start(viewport, expand=True, fill=True) - - label = gtk.Label(_('Use "%s" as a placeholder for the file name')) - label.set_alignment(0.0, 0.5) - label.set_padding(0, 10) - self.win.vbox.pack_start(label, expand=False, fill=True) - self.win.show_all() - - def run(self): - "Run the window" - res = self.win.run() - if res == gtk.RESPONSE_OK: - config = {} - for extension, _, cmd_open, cmd_print in self.model: - config[extension] = { - 0: cmd_open, - 1: cmd_print, - } - CONFIG['client.actions'] = config - CONFIG.save() - self.parent.present() - self.win.destroy() - return res - - def _sig_edited(self, cell, path, new_text): - iter = self.model.get_iter_from_string(path) - (path, column) = self.treeview.get_cursor() - column_id = self.treeview.get_columns().index(column) - self.model.set(iter, column_id + 1, new_text) diff --git a/tryton/gui/window/form.py b/tryton/gui/window/form.py index ddde3c2bba..66b3852fe8 100644 --- a/tryton/gui/window/form.py +++ b/tryton/gui/window/form.py @@ -8,10 +8,8 @@ import locale import tryton.rpc as rpc from tryton.gui.window.view_form.screen import Screen from tryton.action import Action -from tryton.config import CONFIG from tryton.gui import Main from tryton.gui.window import Window -from tryton.gui.window.preference import Preference from tryton.gui.window.win_export import WinExport from tryton.gui.window.win_import import WinImport from tryton.gui.window.attachment import Attachment @@ -21,7 +19,7 @@ from tryton.common import (TRYTON_ICON, message, sur, sur_3b, COLOR_SCHEMES, from tryton.exceptions import TrytonServerError import tryton.common as common from tryton.translate import date_format -from tryton.common import DT_FORMAT, DHM_FORMAT, HM_FORMAT +from tryton.common import HM_FORMAT from tryton.pyson import PYSONEncoder from tabcontent import TabContent @@ -183,9 +181,9 @@ class Form(SignalEvent, TabContent): return parent = common.get_toplevel_window() win = gtk.Dialog(_('Go to ID'), parent, - gtk.DIALOG_MODAL|gtk.DIALOG_DESTROY_WITH_PARENT, - (gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL, - gtk.STOCK_OK, gtk.RESPONSE_OK)) + gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT, + (gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL, gtk.STOCK_OK, + gtk.RESPONSE_OK)) win.set_icon(TRYTON_ICON) win.set_has_separator(True) win.set_default_response(gtk.RESPONSE_OK) @@ -200,6 +198,7 @@ class Form(SignalEvent, TabContent): entry.set_property('activates_default', True) entry.set_max_length(0) entry.set_alignment(1.0) + def sig_insert_text(widget, new_text, new_text_length, position): value = widget.get_text() position = widget.get_position() @@ -240,7 +239,9 @@ class Form(SignalEvent, TabContent): def sig_attach(self, widget=None): obj_id = self.id_get() if obj_id >= 0 and obj_id is not False: - Attachment(self.model, obj_id).run() + def callback(): + self.update_attachment_count(reload=True) + Attachment(self.model, obj_id, callback) else: self.message_info(_('No record selected!')) self.update_attachment_count(reload=True) @@ -300,7 +301,7 @@ class Form(SignalEvent, TabContent): display_format = date_format() + ' ' + HM_FORMAT date = timezoned_date(line[key]) value = common.datetime_strftime(date, display_format) - message_str += val + ' ' + value +'\n' + message_str += val + ' ' + value + '\n' message_str += _('Model:') + ' ' + self.model message(message_str) return True @@ -482,6 +483,7 @@ class Form(SignalEvent, TabContent): self.activate_save() def modified_save(self, reload=True): + self.screen.current_view.set_value() if self.screen.modified(): value = sur_3b( _('This record has been modified\n' \ diff --git a/tryton/gui/window/limit.py b/tryton/gui/window/limit.py index bac2ce6a58..b0501e8131 100644 --- a/tryton/gui/window/limit.py +++ b/tryton/gui/window/limit.py @@ -15,9 +15,9 @@ class Limit(object): def __init__(self): self.parent = get_toplevel_window() self.win = gtk.Dialog(_('Limit'), self.parent, - gtk.DIALOG_MODAL|gtk.DIALOG_DESTROY_WITH_PARENT, - (gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL, - gtk.STOCK_OK, gtk.RESPONSE_OK)) + gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT, + (gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL, gtk.STOCK_OK, + gtk.RESPONSE_OK)) self.win.set_default_response(gtk.RESPONSE_OK) self.win.set_icon(TRYTON_ICON) self.win.set_has_separator(True) @@ -29,8 +29,9 @@ class Limit(object): hbox.pack_start(gtk.Label(_('Limit:')), expand=True, fill=True) self.spin_limit = gtk.SpinButton(climb_rate=1, digits=0) self.spin_limit.set_numeric(False) - self.spin_limit.set_adjustment(gtk.Adjustment(value=CONFIG['client.limit'], - lower=1, upper=sys.maxint, step_incr=10, page_incr=100)) + self.spin_limit.set_adjustment(gtk.Adjustment( + value=CONFIG['client.limit'], lower=1, upper=sys.maxint, + step_incr=10, page_incr=100)) hbox.pack_start(self.spin_limit, expand=True, fill=True) self.win.vbox.pack_start(hbox, expand=True, fill=True) diff --git a/tryton/gui/window/preference.py b/tryton/gui/window/preference.py index 3f0359675c..69f04c38eb 100644 --- a/tryton/gui/window/preference.py +++ b/tryton/gui/window/preference.py @@ -19,7 +19,7 @@ class Preference(object): def __init__(self, user): self.parent = common.get_toplevel_window() self.win = gtk.Dialog(_('Preferences'), self.parent, - gtk.DIALOG_MODAL|gtk.DIALOG_DESTROY_WITH_PARENT) + gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT) self.win.set_position(gtk.WIN_POS_CENTER_ON_PARENT) self.win.set_has_separator(False) self.win.set_icon(TRYTON_ICON) diff --git a/tryton/gui/window/shortcuts.py b/tryton/gui/window/shortcuts.py index 2d6bc3df01..b1a3733aec 100644 --- a/tryton/gui/window/shortcuts.py +++ b/tryton/gui/window/shortcuts.py @@ -91,7 +91,7 @@ Examples: label.set_alignment(0, 0.5) table.attach(label, 1, 2, i, i + 1, yoptions=False, xoptions=gtk.FILL) - i +=1 + i += 1 return table def run(self): diff --git a/tryton/gui/window/tips.py b/tryton/gui/window/tips.py index a5348abd3c..e6528fa0e5 100644 --- a/tryton/gui/window/tips.py +++ b/tryton/gui/window/tips.py @@ -18,7 +18,8 @@ class Tips(object): '''), - _(u'''Do you know Triton, one of the namesakes for our project? + _( +u'''Do you know Triton, one of the namesakes for our project? Triton (pronounced /ˈtraɪtən/ TRYE-tən, or as in Greek Τρίτων) is the largest moon of the planet Neptune, discovered on October 10, 1846 @@ -41,7 +42,6 @@ You can save any graphs in PNG file with right-click on it. '''), ] - parent = get_toplevel_window() self.win = gtk.Dialog(_('Tips'), parent, gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT) @@ -118,5 +118,3 @@ You can save any graphs in PNG file with right-click on it. def tip_previous(self, widget): self.number -= 1 self.tip_set() - - diff --git a/tryton/gui/window/view_board/action.py b/tryton/gui/window/view_board/action.py index a88223182d..64859add15 100644 --- a/tryton/gui/window/view_board/action.py +++ b/tryton/gui/window/view_board/action.py @@ -4,14 +4,9 @@ import gtk from tryton.gui.window.view_form.screen import Screen import tryton.rpc as rpc -import time -import datetime -from tryton.gui.window.win_search import WinSearch -from tryton.action import Action as Action2 import tryton.common as common from tryton.pyson import PYSONDecoder import gettext -from tryton.config import CONFIG from tryton.signal_event import SignalEvent from tryton.exceptions import TrytonServerError from tryton.gui.window.win_form import WinForm @@ -89,7 +84,7 @@ class Action(SignalEvent): else: self.title.set_text(name) - self.widget.set_size_request(int(attrs.get('width',-1)), + self.widget.set_size_request(int(attrs.get('width', -1)), int(attrs.get('height', -1))) self.screen.search_filter() @@ -97,6 +92,7 @@ class Action(SignalEvent): def row_activate(self): if not self.screen.current_record: pass + def callback(result): if result: self.screen.current_record.save() @@ -133,5 +129,5 @@ class Action(SignalEvent): return del self.domain[:] self.domain.extend(new_domain) - if hasattr(self, 'screen'): # Catch early update + if hasattr(self, 'screen'): # Catch early update self.display() diff --git a/tryton/gui/window/view_board/parser.py b/tryton/gui/window/view_board/parser.py index 7aa0abedd0..e22021cf80 100644 --- a/tryton/gui/window/view_board/parser.py +++ b/tryton/gui/window/view_board/parser.py @@ -2,10 +2,13 @@ #this repository contains the full copyright notices and license terms. 'Parser' import gtk -from tryton.gui.window.view_form.view.form_gtk.parser import _container +import gettext +from tryton.gui.window.view_form.view.form_gtk.parser import _container, VBox import tryton.common as common from action import Action -from tryton.config import CONFIG, TRYTON_ICON +from tryton.config import CONFIG + +_ = gettext.gettext class ParserBoard(object): @@ -47,13 +50,6 @@ class ParserBoard(object): xexpand=xexpand, xfill=xfill) elif node.localName == 'separator': text = attrs.get('string', '') - if 'string' in attrs or 'name' in attrs: - if not text: - if 'name' in attrs and attrs['name'] in fields: - if 'states' in fields[attrs['name']]: - attrs['states'] = \ - fields[attrs['name']]['states'] - text = fields[attrs['name']]['string'] vbox = VBox(attrs=attrs) if text: label = gtk.Label(text) @@ -68,22 +64,6 @@ class ParserBoard(object): xexpand=xexpand, xfill=xfill) elif node.localName == 'label': text = attrs.get('string', '') - if not text: - if 'name' in attrs and attrs['name'] in fields: - if 'states' in fields[attrs['name']]: - attrs['states'] = fields[attrs['name']]['states'] - if gtk.widget_get_default_direction() == gtk.TEXT_DIR_RTL: - text = _(':') + fields[attrs['name']]['string'] - else: - text = fields[attrs['name']]['string'] + _(':') - if 'align' not in attrs: - attrs['align'] = 1.0 - else: - for node in node.childNodes: - if node.nodeType == node.TEXT_NODE: - text += node.data - else: - text += node.toxml() if not text: container.empty_add(int(attrs.get('colspan', 1))) continue @@ -115,7 +95,8 @@ class ParserBoard(object): container.wid_add(notebook, colspan=int(attrs.get('colspan', 4)), yexpand=True, yfill=True) - widget, new_widgets = self.parse(node, notebook, tooltips=tooltips) + widget, new_widgets = self.parse(node, notebook, + tooltips=tooltips) widgets += new_widgets elif node.localName == 'page': if CONFIG['client.form_tab'] == 'left': @@ -124,9 +105,10 @@ class ParserBoard(object): angle = -90 else: angle = 0 - label = gtk.Label(attrs.get('string','No String Attr.')) + label = gtk.Label(attrs.get('string', _('No String Attr.'))) label.set_angle(angle) - widget, new_widgets = self.parse(node, notebook, tooltips=tooltips) + widget, new_widgets = self.parse(node, notebook, + tooltips=tooltips) widgets += new_widgets notebook.append_page(widget, label) elif node.localName == 'group': @@ -145,7 +127,8 @@ class ParserBoard(object): hpaned = gtk.HPaned() container.wid_add(hpaned, colspan=int(attrs.get('colspan', 4)), yexpand=True, yfill=True) - widget, new_widgets = self.parse(node, paned=hpaned, tooltips=tooltips) + widget, new_widgets = self.parse(node, paned=hpaned, + tooltips=tooltips) widgets += new_widgets if 'position' in attrs: hpaned.set_position(int(attrs['position'])) @@ -153,19 +136,20 @@ class ParserBoard(object): vpaned = gtk.VPaned() container.wid_add(vpaned, colspan=int(attrs.get('colspan', 4)), yexpand=True, yfill=True) - widget, new_widgets = self.parse(node, paned=vpaned, tooltips=tooltips) + widget, new_widgets = self.parse(node, paned=vpaned, + tooltips=tooltips) widgets += new_widgets if 'position' in attrs: vpaned.set_position(int(attrs['position'])) elif node.localName == 'child': - widget, new_widgets = self.parse(node, paned=paned, tooltips=tooltips) + widget, new_widgets = self.parse(node, paned=paned, + tooltips=tooltips) widgets += new_widgets if not paned.get_child1(): paned.pack1(widget, resize=True, shrink=True) elif not paned.get_child2(): paned.pack2(widget, resize=True, shrink=True) elif node.localName == 'action': - name = str(attrs['name']) widget_act = Action(attrs, self.context) widgets.append(widget_act) yexpand = bool(attrs.get('yexpand', 1)) diff --git a/tryton/gui/window/view_board/view_board.py b/tryton/gui/window/view_board/view_board.py index fde66aec38..688e0cff2b 100644 --- a/tryton/gui/window/view_board/view_board.py +++ b/tryton/gui/window/view_board/view_board.py @@ -6,6 +6,7 @@ import xml.dom.minidom from parser import ParserBoard from tryton.gui.window.view_board.action import Action + class ViewBoard(object): 'View board' diff --git a/tryton/gui/window/view_form/model/field.py b/tryton/gui/window/view_form/model/field.py index d0f469e853..903c6de2c2 100644 --- a/tryton/gui/window/view_form/model/field.py +++ b/tryton/gui/window/view_form/model/field.py @@ -3,14 +3,13 @@ import os import tempfile import tryton.rpc as rpc -from tryton.common import DT_FORMAT, DHM_FORMAT, HM_FORMAT, datetime_strftime, \ +from tryton.common import DT_FORMAT, DHM_FORMAT, datetime_strftime, \ domain_inversion, eval_domain, localize_domain, unlocalize_domain, \ merge, inverse_leaf, EvalEnvironment, RPCProgress import tryton.common as common import time import datetime from decimal import Decimal -import logging from tryton.exceptions import TrytonServerError @@ -60,8 +59,8 @@ class CharField(object): def validation_domains(self, record): screen_domain, attr_domain = self.domains_get(record) if attr_domain: - return screen_domain, screen_domain + unlocalize_domain(attr_domain, - self.name) + return (screen_domain, screen_domain + + unlocalize_domain(attr_domain, self.name)) else: return screen_domain, screen_domain @@ -91,12 +90,13 @@ class CharField(object): elif domain == [('id', '=', False)]: res = False else: - if (isinstance(inverted_domain, list) \ - and len(inverted_domain) == 1 and inverted_domain[0][1] == '='): - # If the inverted domain is so constraint that only one value is - # possible we should use it. But we must also pay attention to - # the fact that the original domain might be a 'OR' domain and - # thus not preventing the modification of fields. + if (isinstance(inverted_domain, list) + and len(inverted_domain) == 1 + and inverted_domain[0][1] == '='): + # If the inverted domain is so constraint that only one value + # is possible we should use it. But we must also pay attention + # to the fact that the original domain might be a 'OR' domain + # and thus not preventing the modification of fields. leftpart, _, value = inverted_domain[0][:3] setdefault = True if '.' in leftpart: @@ -135,9 +135,9 @@ class CharField(object): def set_client(self, record, value, force_change=False): internal = record.value.get(self.name, False) - prev_modified_fields = record.modified_fields.copy() self.set(record, value) - if (internal or False) != (record.value.get(self.name, False) or False): + if ((internal or False) + != (record.value.get(self.name, False) or False)): record.modified_fields.setdefault(self.name) record.signal('record-modified') self.sig_changed(record) @@ -230,11 +230,10 @@ class FloatField(CharField): def set_client(self, record, value, force_change=False): internal = record.value.get(self.name) - prev_modified_fields = record.modified_fields.copy() self.set(record, value) digits = record.expr_eval(self.attrs.get('digits', (16, 2))) - if abs(float(internal or 0.0) - float(record.value[self.name] or 0.0)) \ - >= (10.0**(-int(digits[1]))): + if (abs(float(internal or 0.0) - float(record.value[self.name] or 0.0)) + >= (10.0 ** (-int(digits[1])))): if not self.get_state_attrs(record).get('readonly', False): record.modified_fields.setdefault(self.name) record.signal('record-modified') @@ -248,12 +247,11 @@ class NumericField(CharField): def set_client(self, record, value, force_change=False): value = Decimal(str(value)) internal = record.value.get(self.name) - prev_modified_fields = record.modified_fields.copy() self.set(record, value) digits = record.expr_eval(self.attrs.get('digits', (16, 2))) - if abs((internal or Decimal('0.0')) - \ - (record.value[self.name] or Decimal('0.0'))) \ - >= Decimal(str(10.0**(-int(digits[1])))): + if (abs((internal or Decimal('0.0')) + - (record.value[self.name] or Decimal('0.0'))) + >= Decimal(str(10.0 ** (-int(digits[1]))))): if not self.get_state_attrs(record).get('readonly', False): record.modified_fields.setdefault(self.name) record.signal('record-modified') @@ -270,12 +268,12 @@ class IntegerField(CharField): def get_client(self, record): return record.value.get(self.name) or 0 + class BooleanField(CharField): def set_client(self, record, value, force_change=False): value = bool(value) internal = bool(record.value.get(self.name, False)) - prev_modified_fields = record.modified_fields.copy() self.set(record, value) if internal != bool(record.value.get(self.name, False)): record.modified_fields.setdefault(self.name) @@ -367,7 +365,6 @@ class M2OField(CharField): def set_client(self, record, value, force_change=False): internal = record.value.get(self.name) or (False, '') - prev_modified_fields = record.modified_fields.copy() self.set(record, value) if (internal[0] or False) != (record.value[self.name][0] or False): record.modified_fields.setdefault(self.name) @@ -394,7 +391,8 @@ class M2OField(CharField): def domain_get(self, record): screen_domain, attr_domain = self.domains_get(record) - return localize_domain(inverse_leaf(screen_domain), self.name) + attr_domain + return (localize_domain(inverse_leaf(screen_domain), self.name) + + attr_domain) def get_state_attrs(self, record): result = super(M2OField, self).get_state_attrs(record) @@ -404,6 +402,7 @@ class M2OField(CharField): result['readonly'] = True return result + class O2OField(M2OField): pass @@ -453,7 +452,8 @@ class O2MField(CharField): if record.model_name == self.attrs['relation']: group.fields = record.group.fields group.signal_connect(group, 'group-changed', self._group_changed) - group.signal_connect(group, 'group-list-changed', self._group_list_changed) + group.signal_connect(group, 'group-list-changed', + self._group_list_changed) group.signal_connect(group, 'group-cleared', self._group_cleared) record.value[self.name] = group @@ -493,10 +493,10 @@ class O2MField(CharField): if record.value.get(self.name) is None: return {} result = {} - for record2 in (record.value[self.name] \ - + record.value[self.name].record_removed \ + for record2 in (record.value[self.name] + + record.value[self.name].record_removed + record.value[self.name].record_deleted): - result.update(record2.get_timestamp()) + result.update(record2.get_timestamp()) return result def get_eval(self, record, check_load=True): @@ -530,7 +530,8 @@ class O2MField(CharField): record.value[self.name] = group group.load(value, display=False) group.signal_connect(group, 'group-changed', self._group_changed) - group.signal_connect(group, 'group-list-changed', self._group_list_changed) + group.signal_connect(group, 'group-list-changed', + self._group_list_changed) group.signal_connect(group, 'group-cleared', self._group_cleared) if modified: record.modified_fields.setdefault(self.name) @@ -591,7 +592,8 @@ class O2MField(CharField): new_record.set_default(vals, modified=modified) group.add(new_record) group.signal_connect(group, 'group-changed', self._group_changed) - group.signal_connect(group, 'group-list-changed', self._group_list_changed) + group.signal_connect(group, 'group-list-changed', + self._group_list_changed) group.signal_connect(group, 'group-cleared', self._group_cleared) return True @@ -717,7 +719,8 @@ class M2MField(O2MField): group.fields = fields group.load(value, display=False) group.signal_connect(group, 'group-changed', self._group_changed) - group.signal_connect(group, 'group-list-changed', self._group_list_changed) + group.signal_connect(group, 'group-list-changed', + self._group_list_changed) group.signal_connect(group, 'group-cleared', self._group_cleared) if modified: record.modified_fields.setdefault(self.name) @@ -744,7 +747,6 @@ class ReferenceField(CharField): def set_client(self, record, value, force_change=False): internal = record.value.get(self.name) - prev_modified_fields = record.modified_fields.copy() self.set(record, value) if (internal or False) != (record.value[self.name] or False): record.modified_fields.setdefault(self.name) @@ -792,6 +794,7 @@ class ReferenceField(CharField): record.modified_fields.setdefault(self.name) record.signal('record-modified') + class BinaryField(CharField): def get(self, record, check_load=True, readonly=True, modified=False): @@ -849,14 +852,14 @@ TYPES = { 'char': CharField, 'sha': CharField, 'float_time': FloatField, - 'integer' : IntegerField, - 'biginteger' : IntegerField, - 'float' : FloatField, - 'numeric' : NumericField, - 'many2one' : M2OField, - 'many2many' : M2MField, - 'one2many' : O2MField, - 'reference' : ReferenceField, + 'integer': IntegerField, + 'biginteger': IntegerField, + 'float': FloatField, + 'numeric': NumericField, + 'many2one': M2OField, + 'many2many': M2MField, + 'one2many': O2MField, + 'reference': ReferenceField, 'selection': SelectionField, 'boolean': BooleanField, 'datetime': DateTimeField, diff --git a/tryton/gui/window/view_form/model/group.py b/tryton/gui/window/view_form/model/group.py index 338cf67462..a32dab1b48 100644 --- a/tryton/gui/window/view_form/model/group.py +++ b/tryton/gui/window/view_form/model/group.py @@ -1,6 +1,5 @@ #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 copy import tryton.rpc as rpc from record import Record from field import Field, O2MField @@ -236,8 +235,8 @@ class Group(SignalEvent, list): ctx = rpc.CONTEXT.copy() ctx.update(self._context) if self.parent_datetime_field: - ctx['_datetime'] = self.parent.get_eval(check_load=False)\ - [self.parent_datetime_field] + ctx['_datetime'] = self.parent.get_eval(check_load=False + )[self.parent_datetime_field] return ctx context = property(_get_context) @@ -247,7 +246,8 @@ class Group(SignalEvent, list): record.signal_unconnect(record.group) record.group = self record.signal_connect(self, 'record-changed', self._record_changed) - record.signal_connect(self, 'record-modified', self._record_modified) + record.signal_connect(self, 'record-modified', + self._record_modified) if position == -1: self.append(record) else: @@ -373,7 +373,8 @@ class Group(SignalEvent, list): if len(new) and len(to_add): ctx.update(self.context) - args = ('model', self.model_name, 'default_get', to_add.keys(), ctx) + args = ('model', self.model_name, 'default_get', to_add.keys(), + ctx) try: values = rpc.execute(*args) except TrytonServerError, exception: diff --git a/tryton/gui/window/view_form/model/record.py b/tryton/gui/window/view_form/model/record.py index 9cc919927c..6d882e6336 100644 --- a/tryton/gui/window/view_form/model/record.py +++ b/tryton/gui/window/view_form/model/record.py @@ -4,10 +4,7 @@ import tryton.rpc as rpc from tryton.signal_event import SignalEvent import tryton.common as common from tryton.pyson import PYSONDecoder -import field -import datetime -import logging -import time +import field as fields from functools import reduce from tryton.exceptions import TrytonServerError @@ -33,14 +30,14 @@ class Record(SignalEvent): self.modified_fields = {} self._timestamp = None self.attachment_count = -1 - self.next = {} # Used in Group list + self.next = {} # Used in Group list self.value = {} self.autocompletion = {} self.exception = False def __getitem__(self, name, raise_exception=False): if name not in self._loaded and self.id >= 0: - ids = [self.id] + ids = [self.id] if name == '*': loading = reduce( lambda x, y: 'eager' if x == y == 'eager' else 'lazy', @@ -65,21 +62,22 @@ class Record(SignalEvent): ids.append(record.id) n += 1 if loading == 'eager': - fields = [fname for fname, field in self.group.fields.iteritems() - if field.attrs.get('loading', 'eager') == 'eager'] + fnames = [fname + for fname, field in self.group.fields.iteritems() + if field.attrs.get('loading', 'eager') == 'eager'] else: - fields = self.group.fields.keys() - fields = [fname for fname in fields if fname not in self._loaded] - fields.extend(('%s.rec_name' % fname for fname in fields[:] + fnames = self.group.fields.keys() + fnames = [fname for fname in fnames if fname not in self._loaded] + fnames.extend(('%s.rec_name' % fname for fname in fnames[:] if self.group.fields[fname].attrs['type'] in ('many2one', 'one2one', 'reference'))) - fields.append('_timestamp') + fnames.append('_timestamp') ctx = rpc.CONTEXT.copy() ctx.update(self.context_get()) ctx.update(dict(('%s.%s' % (self.model_name, fname), 'size') for fname, field in self.group.fields.iteritems() if field.attrs['type'] == 'binary')) - args = ('model', self.model_name, 'read', ids, fields, ctx) + args = ('model', self.model_name, 'read', ids, fnames, ctx) exception = None try: values = rpc.execute(*args) @@ -89,7 +87,7 @@ class Record(SignalEvent): values = common.process_exception(exception, *args) if not values: values = [{'id': x} for x in ids] - default_values = dict((f, False) for f in fields) + default_values = dict((f, False) for f in fnames) for value in values: value.update(default_values) self.exception = True @@ -391,10 +389,11 @@ class Record(SignalEvent): for fieldname, value in val.items(): if fieldname not in self.group.fields: continue - if isinstance(self.group.fields[fieldname], field.M2OField): + if isinstance(self.group.fields[fieldname], fields.M2OField): if fieldname + '.rec_name' in val: value = (value, val[fieldname + '.rec_name']) - elif isinstance(self.group.fields[fieldname], field.ReferenceField): + elif isinstance(self.group.fields[fieldname], + fields.ReferenceField): if value: ref_model, ref_id = value.split(',', 1) if fieldname + '.rec_name' in val: @@ -417,13 +416,14 @@ class Record(SignalEvent): continue if fieldname not in self.group.fields: continue - if isinstance(self.group.fields[fieldname], field.O2MField): + if isinstance(self.group.fields[fieldname], fields.O2MField): later[fieldname] = value continue - if isinstance(self.group.fields[fieldname], field.M2OField): + if isinstance(self.group.fields[fieldname], fields.M2OField): if fieldname + '.rec_name' in val: value = (value, val[fieldname + '.rec_name']) - elif isinstance(self.group.fields[fieldname], field.ReferenceField): + elif isinstance(self.group.fields[fieldname], + fields.ReferenceField): if value: ref_model, ref_id = value.split(',', 1) if fieldname + '.rec_name' in val: @@ -501,14 +501,14 @@ class Record(SignalEvent): for fieldname, value in res.items(): if fieldname not in self.group.fields: continue - if isinstance(self.group.fields[fieldname], field.O2MField): + if isinstance(self.group.fields[fieldname], fields.O2MField): later[fieldname] = value continue - if isinstance(self.group.fields[fieldname], field.M2OField): + if isinstance(self.group.fields[fieldname], fields.M2OField): if fieldname + '.rec_name' in res: value = (value, res[fieldname + '.rec_name']) elif isinstance(self.group.fields[fieldname], - field.ReferenceField): + fields.ReferenceField): if value: ref_model, ref_id = value.split(',', 1) if fieldname + '.rec_name' in res: @@ -602,5 +602,8 @@ class Record(SignalEvent): def destroy(self): super(Record, self).destroy() self.group = None + for v in self.value.itervalues(): + if hasattr(v, 'destroy'): + v.destroy() self.value = None self.next = None diff --git a/tryton/gui/window/view_form/screen/screen.py b/tryton/gui/window/view_form/screen/screen.py index fc383cd701..31559c45d5 100644 --- a/tryton/gui/window/view_form/screen/screen.py +++ b/tryton/gui/window/view_form/screen/screen.py @@ -6,7 +6,6 @@ try: import simplejson as json except ImportError: import json -import copy import collections import xml.dom.minidom import tryton.rpc as rpc @@ -14,7 +13,6 @@ from tryton.gui.window.view_form.model.group import Group from tryton.gui.window.view_form.model.record import Record from tryton.gui.window.view_form.view.screen_container import ScreenContainer from tryton.signal_event import SignalEvent -from tryton.common import node_attributes from tryton.config import CONFIG import tryton.common as common from tryton.exceptions import TrytonServerError, TrytonServerUnavailable @@ -368,13 +366,18 @@ class Screen(SignalEvent): self.fields_view_tree = view break + # Ensure that loading is always eager for fields on tree view + # and always lazy for fields only on form view if node.localName == 'tree': loading = 'eager' else: loading = 'lazy' for field in fields: - if field not in self.group.fields: + if field not in self.group.fields or loading == 'eager': fields[field]['loading'] = loading + else: + fields[field]['loading'] = \ + self.group.fields[field].attrs['loading'] children_field = view.get('field_childs') @@ -436,9 +439,6 @@ class Screen(SignalEvent): record = group.new(default, self.domain, ctx) group.add(record, self.new_model_position()) self.current_record = record - fields = None - if self.current_view: - fields = self.current_view.get_fields() self.display() self.set_cursor(new=True) self.request_set() @@ -505,7 +505,8 @@ class Screen(SignalEvent): elif current_view.view_type == 'tree' and not self.current_record: # The widget might have been destroyed if self.screen_container: - self.screen_container.set_cursor(new=new, reset_view=reset_view) + self.screen_container.set_cursor(new=new, + reset_view=reset_view) elif current_view.view_type in ('tree', 'form'): current_view.set_cursor(new=new, reset_view=reset_view) @@ -528,7 +529,8 @@ class Screen(SignalEvent): res = False if self.current_view.view_type != 'tree': if self.current_record: - res = self.current_record.modified or self.current_record.id < 0 + res = (self.current_record.modified + or self.current_record.id < 0) else: for record in self.group: if record.modified or record.id < 0: diff --git a/tryton/gui/window/view_form/view/form.py b/tryton/gui/window/view_form/view/form.py index 8c72e4dbc8..a26677a336 100644 --- a/tryton/gui/window/view_form/view/form.py +++ b/tryton/gui/window/view_form/view/form.py @@ -4,11 +4,9 @@ import operator from functools import reduce import gtk import gettext -from tryton.common import message, TRYTON_ICON import tryton.rpc as rpc import tryton.common as common from interface import ParserView -from tryton.config import CONFIG from tryton.exceptions import TrytonServerError from tryton.action import Action @@ -196,4 +194,3 @@ class ViewForm(ParserView): self.screen.reload(written=True) else: self.screen.display() - diff --git a/tryton/gui/window/view_form/view/form_gtk/binary.py b/tryton/gui/window/view_form/view/form_gtk/binary.py index 982ab1d572..44127283ac 100644 --- a/tryton/gui/window/view_form/view/form_gtk/binary.py +++ b/tryton/gui/window/view_form/view/form_gtk/binary.py @@ -5,7 +5,7 @@ import gettext import os import tempfile from tryton.common import common -from tryton.common import file_selection, message, warning, Tooltips, file_open +from tryton.common import file_selection, Tooltips, file_open from interface import WidgetInterface _ = gettext.gettext @@ -24,12 +24,15 @@ class Binary(WidgetInterface): self.widget = gtk.HBox(spacing=0) self.wid_size = gtk.Entry() self.wid_size.set_width_chars(10) + self.wid_size.set_alignment(1.0) self.wid_size.props.sensitive = False if self.filename and attrs.get('filename_visible'): self.wid_text = gtk.Entry() self.wid_text.set_property('activates_default', True) - self.wid_text.connect('focus-in-event', lambda x, y: self._focus_in()) - self.wid_text.connect('focus-out-event', lambda x, y: self._focus_out()) + self.wid_text.connect('focus-in-event', + lambda x, y: self._focus_in()) + self.wid_text.connect('focus-out-event', + lambda x, y: self._focus_out()) self.wid_text.connect_after('key_press_event', self.sig_key_press) self.widget.pack_start(self.wid_text, expand=True, fill=True) else: @@ -136,7 +139,7 @@ class Binary(WidgetInterface): filename = file_selection(_('Save As...'), filename=filename, action=gtk.FILE_CHOOSER_ACTION_SAVE) if filename: - with open(filename,'wb') as fp: + with open(filename, 'wb') as fp: fp.write(self.field.get_data(self.record)) def sig_remove(self, widget=None): diff --git a/tryton/gui/window/view_form/view/form_gtk/calendar.py b/tryton/gui/window/view_form/view/form_gtk/calendar.py index 0966ee1d28..8408719b5a 100644 --- a/tryton/gui/window/view_form/view/form_gtk/calendar.py +++ b/tryton/gui/window/view_form/view/form_gtk/calendar.py @@ -4,10 +4,8 @@ import time import datetime import gtk import gettext -import locale from interface import WidgetInterface -import tryton.rpc as rpc -from tryton.common import DT_FORMAT, DHM_FORMAT, HM_FORMAT, message, \ +from tryton.common import DT_FORMAT, DHM_FORMAT, HM_FORMAT, \ TRYTON_ICON, timezoned_date from tryton.common import date_widget, Tooltips, datetime_strftime, \ get_toplevel_window @@ -89,7 +87,7 @@ class Calendar(WidgetInterface): if not value: self.entry.clear() else: - if len(value)>10: + if len(value) > 10: value = value[:10] date = datetime.date(*time.strptime(value, DT_FORMAT)[:3]) value = datetime_strftime(date, self.format) @@ -101,9 +99,9 @@ class Calendar(WidgetInterface): def cal_open(self, widget): parent = get_toplevel_window() win = gtk.Dialog(_('Date Selection'), parent, - gtk.DIALOG_MODAL|gtk.DIALOG_DESTROY_WITH_PARENT, - (gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL, - gtk.STOCK_OK, gtk.RESPONSE_OK)) + gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT, + (gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL, gtk.STOCK_OK, + gtk.RESPONSE_OK)) win.set_has_separator(True) win.set_icon(TRYTON_ICON) @@ -120,7 +118,7 @@ class Calendar(WidgetInterface): try: val = self.get_value(self.record) if val: - cal.select_month(int(val[5:7])-1, int(val[0:4])) + cal.select_month(int(val[5:7]) - 1, int(val[0:4])) cal.select_day(int(val[8:10])) except ValueError: pass @@ -220,9 +218,9 @@ class DateTime(WidgetInterface): def cal_open(self, widget): parent = get_toplevel_window() win = gtk.Dialog(_('Date Time Selection'), parent, - gtk.DIALOG_MODAL|gtk.DIALOG_DESTROY_WITH_PARENT, - (gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL, - gtk.STOCK_OK, gtk.RESPONSE_OK)) + gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT, + (gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL, gtk.STOCK_OK, + gtk.RESPONSE_OK)) win.set_has_separator(True) win.set_icon(TRYTON_ICON) win.vbox.set_spacing(2) @@ -252,7 +250,7 @@ class DateTime(WidgetInterface): if val: widget_hour.set_value(int(val[11:13])) widget_minute.set_value(int(val[-5:-3])) - cal.select_month(int(val[5:7])-1, int(val[0:4])) + cal.select_month(int(val[5:7]) - 1, int(val[0:4])) cal.select_day(int(val[8:10])) else: widget_hour.set_value(time.localtime()[3]) diff --git a/tryton/gui/window/view_form/view/form_gtk/checkbox.py b/tryton/gui/window/view_form/view/form_gtk/checkbox.py index 1bdca3f739..2f994125f7 100644 --- a/tryton/gui/window/view_form/view/form_gtk/checkbox.py +++ b/tryton/gui/window/view_form/view/form_gtk/checkbox.py @@ -6,6 +6,7 @@ import gettext _ = gettext.gettext + class CheckBox(WidgetInterface): def __init__(self, field_name, model_name, attrs=None): diff --git a/tryton/gui/window/view_form/view/form_gtk/float.py b/tryton/gui/window/view_form/view/form_gtk/float.py index 26de08b29d..73a294cb27 100644 --- a/tryton/gui/window/view_form/view/form_gtk/float.py +++ b/tryton/gui/window/view_form/view/form_gtk/float.py @@ -67,4 +67,3 @@ class Float(Integer): if len(new_int) > digits[0] \ or len(new_decimal) > digits[1]: entry.stop_emission('insert-text') - diff --git a/tryton/gui/window/view_form/view/form_gtk/float_time.py b/tryton/gui/window/view_form/view/form_gtk/float_time.py index 1644babecf..86c2d497eb 100644 --- a/tryton/gui/window/view_form/view/form_gtk/float_time.py +++ b/tryton/gui/window/view_form/view/form_gtk/float_time.py @@ -35,8 +35,9 @@ class FloatTime(WidgetInterface): value = self.entry.get_text() if not value: return field.set_client(record, 0.0) + digits = record.expr_eval(field.attrs.get('digits', (16, 2))) return field.set_client(record, - common.text_to_float_time(value, self.conv)) + round(common.text_to_float_time(value, self.conv), digits[1])) def display(self, record, field): super(FloatTime, self).display(record, field) diff --git a/tryton/gui/window/view_form/view/form_gtk/image.py b/tryton/gui/window/view_form/view/form_gtk/image.py index 3422406ae5..49cd276aa3 100644 --- a/tryton/gui/window/view_form/view/form_gtk/image.py +++ b/tryton/gui/window/view_form/view/form_gtk/image.py @@ -54,7 +54,8 @@ class Image(WidgetInterface): if self.filename: self.but_open = gtk.Button() img_open = gtk.Image() - img_open.set_from_stock('tryton-open', gtk.ICON_SIZE_SMALL_TOOLBAR) + img_open.set_from_stock('tryton-open', + gtk.ICON_SIZE_SMALL_TOOLBAR) self.but_open.set_image(img_open) self.but_open.set_relief(gtk.RELIEF_NONE) self.but_open.connect('clicked', self.sig_open) @@ -65,7 +66,8 @@ class Image(WidgetInterface): self.but_save_as = gtk.Button() img_save_as = gtk.Image() - img_save_as.set_from_stock('tryton-save', gtk.ICON_SIZE_SMALL_TOOLBAR) + img_save_as.set_from_stock('tryton-save', + gtk.ICON_SIZE_SMALL_TOOLBAR) self.but_save_as.set_image(img_save_as) self.but_save_as.set_relief(gtk.RELIEF_NONE) self.but_save_as.connect('clicked', self.sig_save_as) @@ -74,7 +76,8 @@ class Image(WidgetInterface): self.but_remove = gtk.Button() img_remove = gtk.Image() - img_remove.set_from_stock('tryton-clear', gtk.ICON_SIZE_SMALL_TOOLBAR) + img_remove.set_from_stock('tryton-clear', + gtk.ICON_SIZE_SMALL_TOOLBAR) self.but_remove.set_image(img_remove) self.but_remove.set_relief(gtk.RELIEF_NONE) self.but_remove.connect('clicked', self.sig_remove) @@ -193,7 +196,7 @@ class Image(WidgetInterface): if self.field: value = self.field.get_client(self.record) if isinstance(value, (int, long)): - if value > 10**6: + if value > 10 ** 6: value = False else: value = self.field.get_data(self.record) diff --git a/tryton/gui/window/view_form/view/form_gtk/interface.py b/tryton/gui/window/view_form/view/form_gtk/interface.py index 9010889807..4924e6cc8b 100644 --- a/tryton/gui/window/view_form/view/form_gtk/interface.py +++ b/tryton/gui/window/view_form/view/form_gtk/interface.py @@ -9,7 +9,7 @@ class WidgetInterface(object): def __init__(self, field_name, model_name, attrs=None): self.field_name = field_name self.model_name = model_name - self.view = None # Filled by ViewForm + self.view = None # Filled by ViewForm self.attrs = attrs or {} for attr_name in ('readonly', 'invisible'): if attr_name in self.attrs: diff --git a/tryton/gui/window/view_form/view/form_gtk/many2many.py b/tryton/gui/window/view_form/view/form_gtk/many2many.py index 3465071e5f..878c684db0 100644 --- a/tryton/gui/window/view_form/view/form_gtk/many2many.py +++ b/tryton/gui/window/view_form/view/form_gtk/many2many.py @@ -50,7 +50,6 @@ class Many2Many(WidgetInterface): self.but_add.set_relief(gtk.RELIEF_NONE) hbox.pack_start(self.but_add, expand=False, fill=False) - self.but_remove = gtk.Button() tooltips.set_tip(self.but_remove, _('Remove')) self.but_remove.connect('clicked', self._sig_remove) @@ -130,7 +129,7 @@ class Many2Many(WidgetInterface): else: dom = domain ids = rpc.execute('model', self.attrs['relation'], 'search', - dom , 0, CONFIG['client.limit'], None, context) + dom, 0, CONFIG['client.limit'], None, context) except TrytonServerError, exception: common.process_exception(exception) return False diff --git a/tryton/gui/window/view_form/view/form_gtk/many2one.py b/tryton/gui/window/view_form/view/form_gtk/many2one.py index 81d8bf5d85..f6b11d9b9f 100644 --- a/tryton/gui/window/view_form/view/form_gtk/many2one.py +++ b/tryton/gui/window/view_form/view/form_gtk/many2one.py @@ -1,10 +1,8 @@ #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 gobject import gtk import gettext from interface import WidgetInterface -from tryton.common import TRYTON_ICON, COLOR_SCHEMES import tryton.common as common from tryton.gui.window.view_form.screen import Screen from tryton.gui.window.win_search import WinSearch @@ -14,7 +12,6 @@ from tryton.action import Action from tryton.config import CONFIG from tryton.pyson import PYSONEncoder from tryton.exceptions import TrytonServerError -import pango _ = gettext.gettext @@ -33,7 +30,8 @@ class Many2One(WidgetInterface): self.wid_text.connect_after('key_press_event', self.sig_key_press) self.wid_text.connect('populate-popup', self._populate_popup) self.wid_text.connect('focus-in-event', lambda x, y: self._focus_in()) - self.wid_text.connect('focus-out-event', lambda x, y: self._focus_out()) + self.wid_text.connect('focus-out-event', + lambda x, y: self._focus_out()) self.wid_text.connect_after('changed', self.sig_changed) self.changed = True self.wid_text.connect('activate', self.sig_activate) @@ -118,12 +116,13 @@ class Many2One(WidgetInterface): common.process_exception(exception) self.changed = True return - if len(ids)==1: + if len(ids) == 1: self.field.set_client(self.record, ids[0], force_change=True) self.focus_out = True self.display(self.record, self.field) return + def callback(ids): if ids: self.field.set_client(self.record, ids[0], @@ -150,6 +149,7 @@ class Many2One(WidgetInterface): def sig_new(self, *args): self.focus_out = False screen = self.get_screen() + def callback(result): if result and screen.save_current(): value = (screen.current_record.id, @@ -165,6 +165,7 @@ class Many2One(WidgetInterface): if value: screen = self.get_screen() screen.load([self.field.get(self.record)]) + def callback(result): if result and screen.save_current(): value = (screen.current_record.id, @@ -200,7 +201,7 @@ class Many2One(WidgetInterface): common.process_exception(exception) self.changed = True return False - if ids and len(ids)==1: + if ids and len(ids) == 1: self.field.set_client(self.record, ids[0], force_change=True) self.focus_out = True @@ -230,7 +231,8 @@ class Many2One(WidgetInterface): elif event.keyval == gtk.keysyms.F2: self.sig_edit(widget) return True - elif event.keyval in (gtk.keysyms.Tab, gtk.keysyms.Return) and editable: + elif (event.keyval in (gtk.keysyms.Tab, gtk.keysyms.Return) + and editable): self.sig_activate(widget, event, key_press=True) return False @@ -243,7 +245,7 @@ class Many2One(WidgetInterface): return False def set_value(self, record, field): - pass # No update of the model, the model is updated in real time ! + pass # No update of the model, the model is updated in real time ! def display(self, record, field): self.changed = False @@ -280,9 +282,9 @@ class Many2One(WidgetInterface): menu_entries.append((None, None, None)) menu_entries.append((None, None, None)) menu_entries.append((_('Actions'), - lambda x: self.click_and_action('form_action'),0)) + lambda x: self.click_and_action('form_action'), 0)) menu_entries.append((_('Reports'), - lambda x: self.click_and_action('form_print'),0)) + lambda x: self.click_and_action('form_print'), 0)) menu_entries.append((None, None, None)) for relate in relates: relate['string'] = relate['name'] diff --git a/tryton/gui/window/view_form/view/form_gtk/one2many.py b/tryton/gui/window/view_form/view/form_gtk/one2many.py index 0862b8f2df..ee89d1a666 100644 --- a/tryton/gui/window/view_form/view/form_gtk/one2many.py +++ b/tryton/gui/window/view_form/view/form_gtk/one2many.py @@ -2,7 +2,6 @@ #this repository contains the full copyright notices and license terms. import gtk import gettext -from tryton.common import TRYTON_ICON, COLOR_SCHEMES from interface import WidgetInterface from tryton.gui.window.view_form.screen import Screen from tryton.gui.window.win_search import WinSearch @@ -11,7 +10,6 @@ from tryton.config import CONFIG from tryton.exceptions import TrytonServerError import tryton.common as common import tryton.rpc as rpc -import pango _ = gettext.gettext @@ -47,7 +45,8 @@ class One2Many(WidgetInterface): tooltips.set_tip(self.but_add, _('Add')) self.but_add.connect('clicked', self._sig_add) img_add = gtk.Image() - img_add.set_from_stock('tryton-list-add', gtk.ICON_SIZE_SMALL_TOOLBAR) + img_add.set_from_stock('tryton-list-add', + gtk.ICON_SIZE_SMALL_TOOLBAR) img_add.set_alignment(0.5, 0.5) self.but_add.add(img_add) self.but_add.set_relief(gtk.RELIEF_NONE) @@ -57,7 +56,8 @@ class One2Many(WidgetInterface): tooltips.set_tip(self.but_remove, _('Remove')) self.but_remove.connect('clicked', self._sig_remove, True) img_remove = gtk.Image() - img_remove.set_from_stock('tryton-list-remove', gtk.ICON_SIZE_SMALL_TOOLBAR) + img_remove.set_from_stock('tryton-list-remove', + gtk.ICON_SIZE_SMALL_TOOLBAR) img_remove.set_alignment(0.5, 0.5) self.but_remove.add(img_remove) self.but_remove.set_relief(gtk.RELIEF_NONE) @@ -111,7 +111,8 @@ class One2Many(WidgetInterface): tooltips.set_tip(self.but_pre, _('Previous')) self.but_pre.connect('clicked', self._sig_previous) img_pre = gtk.Image() - img_pre.set_from_stock('tryton-go-previous', gtk.ICON_SIZE_SMALL_TOOLBAR) + img_pre.set_from_stock('tryton-go-previous', + gtk.ICON_SIZE_SMALL_TOOLBAR) img_pre.set_alignment(0.5, 0.5) self.but_pre.add(img_pre) self.but_pre.set_relief(gtk.RELIEF_NONE) @@ -136,7 +137,8 @@ class One2Many(WidgetInterface): tooltips.set_tip(but_switch, _('Switch')) but_switch.connect('clicked', self.switch_view) img_switch = gtk.Image() - img_switch.set_from_stock('tryton-fullscreen', gtk.ICON_SIZE_SMALL_TOOLBAR) + img_switch.set_from_stock('tryton-fullscreen', + gtk.ICON_SIZE_SMALL_TOOLBAR) img_switch.set_alignment(0.5, 0.5) but_switch.add(img_switch) but_switch.set_relief(gtk.RELIEF_NONE) @@ -304,7 +306,8 @@ class One2Many(WidgetInterface): try: if self.wid_text.get_text(): - dom = [('rec_name', 'ilike', '%' + self.wid_text.get_text() + '%'), + dom = [('rec_name', 'ilike', + '%' + self.wid_text.get_text() + '%'), ['OR', domain, ('id', 'in', removed_ids)]] else: dom = ['OR', domain, ('id', 'in', removed_ids)] @@ -313,6 +316,7 @@ class One2Many(WidgetInterface): except TrytonServerError, exception: common.process_exception(exception) return False + def callback(ids): res_id = None if ids: @@ -328,7 +332,6 @@ class One2Many(WidgetInterface): else: callback(ids) - def _sig_label(self, screen, signal_data): name = '_' if signal_data[0] >= 1: @@ -386,7 +389,7 @@ class One2Many(WidgetInterface): def set_value(self, record, field): self.screen.save_tree_state() self.screen.current_view.set_value() - if self.screen.modified(): # TODO check if required + if self.screen.modified(): # TODO check if required record.modified_fields.setdefault(field.name) record.signal('record-modified') return True diff --git a/tryton/gui/window/view_form/view/form_gtk/parser.py b/tryton/gui/window/view_form/view/form_gtk/parser.py index 6e21691340..cd08b607fc 100644 --- a/tryton/gui/window/view_form/view/form_gtk/parser.py +++ b/tryton/gui/window/view_form/view/form_gtk/parser.py @@ -72,7 +72,7 @@ class Image(gtk.Image): class Frame(gtk.Frame): def __init__(self, label=None, attrs=None): - if not label: # label must be None to have no label widget + if not label: # label must be None to have no label widget label = None super(Frame, self).__init__(label=label) self.attrs = attrs or {} @@ -137,8 +137,8 @@ class _container(object): table.set_col_spacings(0) table.set_row_spacings(0) table.set_border_width(0) - self.cont.append( (table, 0, 0) ) - self.col.append( col ) + self.cont.append((table, 0, 0)) + self.col.append(col) def get(self): return self.cont[-1][0] @@ -155,8 +155,8 @@ class _container(object): table.resize(height + 1, self.col[-1]) def wid_add(self, widget, name='', yexpand=False, ypadding=2, rowspan=1, - colspan=1, translate=False, fname=None, help_tip=False, yfill=False, - xexpand=True, xfill=True, xpadding=3): + colspan=1, translate=False, fname=None, help_tip=False, + yfill=False, xexpand=True, xfill=True, xpadding=3): (table, width, height) = self.cont[-1] if colspan > self.col[-1]: colspan = self.col[-1] @@ -182,7 +182,8 @@ class _container(object): img.set_from_stock('tryton-locale', gtk.ICON_SIZE_SMALL_TOOLBAR) button.set_image(img) button.set_relief(gtk.RELIEF_NONE) - self.trans_box.append((button, name, fname, widget.get_children()[0])) + self.trans_box.append((button, name, fname, + widget.get_children()[0])) widget.get_child().pack_start(button, fill=False, expand=False) widget.show_all() table.attach(widget, width, width + colspan, @@ -355,9 +356,9 @@ class ParserForm(ParserInterface): colspan=colspan, yexpand=yexpand, yfill=yfill, xexpand=xexpand, xfill=xfill) - widget, widgets, buttons, spam, notebook_list2, cursor_widget2 = \ - self.parse(model_name, node, fields, notebook, - tooltips=tooltips) + widget, widgets, buttons, spam, notebook_list2, cursor_widget2\ + = self.parse(model_name, node, fields, notebook, + tooltips=tooltips) if not cursor_widget: cursor_widget = cursor_widget2 notebook_list.extend(notebook_list2) @@ -369,7 +370,7 @@ class ParserForm(ParserInterface): elif node.localName == 'page': if CONFIG['client.form_tab'] == 'left': angle = 90 - tab_box = gtk.VBox(spacing=3) + tab_box = gtk.VBox(spacing=3) image_pos, image_rotate = ('end', gtk.gdk.PIXBUF_ROTATE_COUNTERCLOCKWISE) elif CONFIG['client.form_tab'] == 'right': @@ -412,9 +413,9 @@ class ParserForm(ParserInterface): else: tab_box.pack_start(icon) tab_box.show_all() - widget, widgets, buttons, spam, notebook_list2, cursor_widget2 = \ - self.parse(model_name, node, fields, notebook, - tooltips=tooltips) + widget, widgets, buttons, spam, notebook_list2, cursor_widget2\ + = self.parse(model_name, node, fields, notebook, + tooltips=tooltips) if not cursor_widget: cursor_widget = cursor_widget2 notebook_list.extend(notebook_list2) @@ -482,8 +483,8 @@ class ParserForm(ParserInterface): xexpand=xexpand, xfill=xfill) elif node.localName == 'group': - widget, widgets, buttons, spam, notebook_list2, cursor_widget2 = \ - self.parse(model_name, node, fields, tooltips=tooltips) + widget, widgets, buttons, spam, notebook_list2, cursor_widget2\ + = self.parse(model_name, node, fields, tooltips=tooltips) if not cursor_widget: cursor_widget = cursor_widget2 notebook_list.extend(notebook_list2) @@ -515,9 +516,9 @@ class ParserForm(ParserInterface): hpaned = gtk.HPaned() container.wid_add(hpaned, colspan=int(attrs.get('colspan', 4)), yexpand=True, yfill=True) - widget, widgets, buttons, spam, notebook_list2, cursor_widget2 = \ - self.parse(model_name, node, fields, paned=hpaned, - tooltips=tooltips) + widget, widgets, buttons, spam, notebook_list2, cursor_widget2\ + = self.parse(model_name, node, fields, paned=hpaned, + tooltips=tooltips) if not cursor_widget: cursor_widget = cursor_widget2 notebook_list.extend(notebook_list2) @@ -531,9 +532,9 @@ class ParserForm(ParserInterface): vpaned = gtk.VPaned() container.wid_add(vpaned, colspan=int(attrs.get('colspan', 4)), yexpand=True, yfill=True) - widget, widgets, buttons, spam, notebook_list, cursor_widget2 = \ - self.parse(model_name, node, fields, paned=vpaned, - tooltips=tooltips) + widget, widgets, buttons, spam, notebook_list, cursor_widget2\ + = self.parse(model_name, node, fields, paned=vpaned, + tooltips=tooltips) if not cursor_widget: cursor_widget = cursor_widget2 notebook_list.extend(notebook_list2) @@ -544,9 +545,9 @@ class ParserForm(ParserInterface): if 'position' in attrs: vpaned.set_position(int(attrs['position'])) elif node.localName == 'child': - widget, widgets, buttons, spam, notebook_list2, cursor_widget2 = \ - self.parse(model_name, node, fields, paned=paned, - tooltips=tooltips) + widget, widgets, buttons, spam, notebook_list2, cursor_widget2\ + = self.parse(model_name, node, fields, paned=paned, + tooltips=tooltips) if not cursor_widget: cursor_widget = cursor_widget2 notebook_list.extend(notebook_list2) @@ -568,7 +569,7 @@ class ParserForm(ParserInterface): obj_id = self.screen.current_record.id if obj_id < 0: common.message( - _('You need to save the record before adding translations!')) + _('You need to save the record before adding translations!')) return False obj_id = self.screen.current_record.save(force_reload=False) @@ -599,6 +600,7 @@ class ParserForm(ParserInterface): widget_entry = widget_entry.get_children()[0] if isinstance(widget_entry, gtk.ScrolledWindow): widget_entry = widget_entry.get_child() + #widget accessor functions def value_get(widget): if isinstance(widget, gtk.Entry): @@ -643,10 +645,9 @@ class ParserForm(ParserInterface): else: return None, False - parent = common.get_toplevel_window() - win = gtk.Dialog(_('Add Translation'),parent, - gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT) + win = gtk.Dialog(_('Add Translation'), parent, + gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT) win.set_has_separator(True) win.vbox.set_spacing(5) win.set_property('default-width', 600) @@ -657,7 +658,7 @@ class ParserForm(ParserInterface): accel_group = gtk.AccelGroup() win.add_accel_group(accel_group) - but_cancel = win.add_button(gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL) + win.add_button(gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL) but_ok = win.add_button(gtk.STOCK_OK, gtk.RESPONSE_OK) but_ok.add_accelerator('clicked', accel_group, gtk.keysyms.Return, @@ -689,17 +690,16 @@ class ParserForm(ParserInterface): label.set_alignment(1.0, 0.5) (entry, yoptions) = widget_duplicate(widget_entry) - hbox = gtk.HBox(homogeneous=False) if code == lang['code']: value_set(entry, value_get(widget_entry)) else: value_set(entry, val[name]) entries_list.append((val['id'], lang['code'], entry)) - table.attach(label, 0, 1, i, i+1, yoptions=False, xoptions=gtk.FILL, - ypadding=2, xpadding=3) - table.attach(entry, 1, 2, i, i+1, yoptions=yoptions, - ypadding=2, xpadding=3) + table.attach(label, 0, 1, i, i + 1, yoptions=False, + xoptions=gtk.FILL, ypadding=2, xpadding=3) + table.attach(entry, 1, 2, i, i + 1, yoptions=yoptions, + ypadding=2, xpadding=3) i += 1 vbox.pack_start(table) @@ -714,7 +714,6 @@ class ParserForm(ParserInterface): win.vbox.add(scrolledwindow) win.show_all() - data = [] response = win.run() if response == gtk.RESPONSE_OK: to_save = [(x[0], x[1], value_get(x[2])) for x in entries_list] @@ -776,11 +775,11 @@ WIDGETS_TYPE = { 'one2many': (One2Many, 1, True, True), 'many2many': (Many2Many, 1, True, True), 'many2one': (Many2One, 1, False, False), - 'email' : (Email, 1, False, False), - 'url' : (URL, 1, False, False), - 'callto' : (CallTo, 1, False, False), - 'sip' : (SIP, 1, False, False), - 'image' : (Image2, 1, False, False), + 'email': (Email, 1, False, False), + 'url': (URL, 1, False, False), + 'callto': (CallTo, 1, False, False), + 'sip': (SIP, 1, False, False), + 'image': (Image2, 1, False, False), 'progressbar': (ProgressBar, 1, False, False), 'one2one': (One2One, 1, False, False), } diff --git a/tryton/gui/window/view_form/view/form_gtk/reference.py b/tryton/gui/window/view_form/view/form_gtk/reference.py index b84f82ca85..e652bdf642 100644 --- a/tryton/gui/window/view_form/view/form_gtk/reference.py +++ b/tryton/gui/window/view_form/view/form_gtk/reference.py @@ -88,7 +88,7 @@ class Reference(WidgetInterface): if selection: pop = sorted((len(x) for x in selection), reverse=True) average = sum(pop) / len(pop) - deviation = int(math.sqrt(sum((x - average)**2 for x in pop) / + deviation = int(math.sqrt(sum((x - average) ** 2 for x in pop) / len(pop))) width = max(next((x for x in pop if x < (deviation * 4)), 10), 10) else: @@ -149,7 +149,6 @@ class Reference(WidgetInterface): def sig_focus_out(self, widget, event, leave=False): if not self.focus_out: return - child = self.widget_combo.get_child() self.changed = False value = self.field.get_client(self.record) @@ -166,6 +165,7 @@ class Reference(WidgetInterface): if not leave: screen = Screen(model, mode=['form']) screen.load([obj_id]) + def callback(result): if result and screen.save_current(): value = (screen.current_record.id, @@ -178,7 +178,7 @@ class Reference(WidgetInterface): WinForm(screen, callback) return elif model: - if not self._readonly and ( self.wid_text.get_text() or not leave): + if not self._readonly and (self.wid_text.get_text() or not leave): domain = self.field.domain_get(self.record) context = self.field.context_get(self.record) @@ -205,7 +205,8 @@ class Reference(WidgetInterface): def callback(ids): if ids: - self.field.set_client(self.record, (model, (ids[0], ''))) + self.field.set_client(self.record, + (model, (ids[0], ''))) self.focus_out = True self.changed = True self.display(self.record, self.field) @@ -223,6 +224,7 @@ class Reference(WidgetInterface): if not model: return screen = Screen(model, mode=['form']) + def callback(result): if result and screen.save_current(): value = (screen.current_record.id, @@ -238,7 +240,8 @@ class Reference(WidgetInterface): elif event.keyval == gtk.keysyms.F2: self.sig_focus_out(widget, event) return True - elif event.keyval in (gtk.keysyms.Tab, gtk.keysyms.Return) and editable: + elif (event.keyval in (gtk.keysyms.Tab, gtk.keysyms.Return) + and editable): if self.field.get(self.record) or \ not self.wid_text.get_text(): return False @@ -272,7 +275,7 @@ class Reference(WidgetInterface): if not field: child.set_text('') child.set_position(0) - self.changed =True + self.changed = True return False super(Reference, self).display(record, field) value = field.get_client(record) @@ -306,8 +309,8 @@ class Reference(WidgetInterface): if self.last_key[0] == key: self.last_key[1] += 1 else: - self.last_key = [ key, 1 ] - if not self.key_catalog.has_key(key): + self.last_key = [key, 1] + if key not in self.key_catalog: return self.widget_combo.set_active_iter( self.key_catalog[key][self.last_key[1] \ diff --git a/tryton/gui/window/view_form/view/form_gtk/selection.py b/tryton/gui/window/view_form/view/form_gtk/selection.py index 95ede546e9..d606d01973 100644 --- a/tryton/gui/window/view_form/view/form_gtk/selection.py +++ b/tryton/gui/window/view_form/view/form_gtk/selection.py @@ -7,7 +7,6 @@ import math from interface import WidgetInterface import tryton.rpc as rpc import tryton.common as common -from tryton.pyson import PYSONDecoder from tryton.exceptions import TrytonServerError @@ -61,8 +60,8 @@ class Selection(WidgetInterface): if domain == self._last_domain: return - args = ('model', self.attrs['relation'], 'search_read', domain, 0, None, - None, ['rec_name'], rpc.CONTEXT) + args = ('model', self.attrs['relation'], 'search_read', domain, 0, + None, None, ['rec_name'], rpc.CONTEXT) try: result = rpc.execute(*args) except TrytonServerError, exception: @@ -101,14 +100,15 @@ class Selection(WidgetInterface): if self._selection: pop = sorted((len(x) for x in self._selection), reverse=True) average = sum(pop) / len(pop) - deviation = int(math.sqrt(sum((x - average)**2 for x in pop) / + deviation = int(math.sqrt(sum((x - average) ** 2 for x in pop) / len(pop))) width = max(next((x for x in pop if x < (deviation * 4)), 10), 10) else: width = 10 self.entry.child.set_width_chars(width) if self._selection: - self.entry.child.set_max_length(max(len(x) for x in self._selection)) + self.entry.child.set_max_length( + max(len(x) for x in self._selection)) completion.set_text_column(0) return lst diff --git a/tryton/gui/window/view_form/view/form_gtk/textbox.py b/tryton/gui/window/view_form/view/form_gtk/textbox.py index ce4a3ede0b..acbc85422c 100644 --- a/tryton/gui/window/view_form/view/form_gtk/textbox.py +++ b/tryton/gui/window/view_form/view/form_gtk/textbox.py @@ -2,7 +2,6 @@ #this repository contains the full copyright notices and license terms. import gtk from interface import WidgetInterface -import tryton.rpc as rpc from tryton.config import CONFIG try: @@ -28,7 +27,8 @@ class TextBox(WidgetInterface): #TODO better tab solution self.textview.set_accepts_tab(False) self.textview.connect('focus-in-event', lambda x, y: self._focus_in()) - self.textview.connect('focus-out-event', lambda x, y: self._focus_out()) + self.textview.connect('focus-out-event', + lambda x, y: self._focus_out()) self.scrolledwindow.add(self.textview) self.scrolledwindow.show_all() diff --git a/tryton/gui/window/view_form/view/form_gtk/url.py b/tryton/gui/window/view_form/view/form_gtk/url.py index 13be7537a8..98cf521c1c 100644 --- a/tryton/gui/window/view_form/view/form_gtk/url.py +++ b/tryton/gui/window/view_form/view/form_gtk/url.py @@ -1,6 +1,5 @@ #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 gtk from char import Char import webbrowser @@ -104,4 +103,3 @@ class SIP(URL): else: self.tooltips.set_tip(self.button, '') self.tooltips.disable() - diff --git a/tryton/gui/window/view_form/view/graph_gtk/bar.py b/tryton/gui/window/view_form/view/graph_gtk/bar.py index 73b248a003..493b65c594 100644 --- a/tryton/gui/window/view_form/view/graph_gtk/bar.py +++ b/tryton/gui/window/view_form/view/graph_gtk/bar.py @@ -1,8 +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. -#This code is inspired by the pycha project (http://www.lorenzogil.com/projects/pycha/) +#This code is inspired by the pycha project +#(http://www.lorenzogil.com/projects/pycha/) from graph import Graph -from tryton.common import hex2rgb, lighten, float_time_to_text +from tryton.common import float_time_to_text import locale import math import cairo @@ -21,8 +22,8 @@ class Bar(Graph): w = self.area.w * bar.w h = self.area.h * bar.h - if w < 1 or h <1: - return # don't draw too small + if w < 1 or h < 1: + return # don't draw too small cr.set_source_rgba(0, 0, 0, 0.15) rectangle = self._getShadowRectangle(x, y, w, h) @@ -52,7 +53,8 @@ class Bar(Graph): def sourceRectangle(self, x, y, w, h, r, g, b): linear = cairo.LinearGradient((x + w) / 2, y, (x + w) / 2, y + h) - linear.add_color_stop_rgb(0, 3.5 * r / 5.0, 3.5 * g / 5.0, 3.5 * b / 5.0) + linear.add_color_stop_rgb(0, 3.5 * r / 5.0, 3.5 * g / 5.0, + 3.5 * b / 5.0) linear.add_color_stop_rgb(1, r, g, b) return linear @@ -71,8 +73,9 @@ class Bar(Graph): highlight = False draw_bars = [] - yfields_float_time = dict([(x.get('key', x['name']), x.get('float_time')) - for x in self.yfields if x.get('widget')]) + yfields_float_time = dict( + (x.get('key', x['name']), x.get('float_time')) + for x in self.yfields if x.get('widget')) for bar in self.bars: if intersect(bar, event): if not bar.highlight: @@ -179,7 +182,7 @@ class VerticalBar(Bar): return ylabels def _getShadowRectangle(self, x, y, w, h): - return (x-2, y-2, w+4, h+2) + return (x - 2, y - 2, w + 4, h + 2) class HorizontalBar(Bar): @@ -236,7 +239,7 @@ class HorizontalBar(Bar): return [(x[0], x[1]) for x in ylabels] def _getShadowRectangle(self, x, y, w, h): - return (x, y-2, w+2, h+4) + return (x, y - 2, w + 2, h + 4) def _getLegendPosition(self, width, height): return self.area.x + self.area.w * 0.95 - width, \ diff --git a/tryton/gui/window/view_form/view/graph_gtk/graph.py b/tryton/gui/window/view_form/view/graph_gtk/graph.py index 854c1007be..260adac1be 100644 --- a/tryton/gui/window/view_form/view/graph_gtk/graph.py +++ b/tryton/gui/window/view_form/view/graph_gtk/graph.py @@ -1,20 +1,19 @@ #This file is part of Tryton. The COPYRIGHT file at the top level of #this repository contains the full copyright notices and license terms. -#This code is inspired by the pycha project (http://www.lorenzogil.com/projects/pycha/) +#This code is inspired by the pycha project +#(http://www.lorenzogil.com/projects/pycha/) import gtk from functools import reduce from tryton.common import hex2rgb, generateColorscheme, DT_FORMAT, \ - DHM_FORMAT, COLOR_SCHEMES, datetime_strftime + COLOR_SCHEMES, datetime_strftime from tryton.pyson import PYSONDecoder import locale import math import datetime -import time from dateutil.relativedelta import relativedelta import tryton.rpc as rpc import cairo from tryton.action import Action -from tryton.translate import date_format from tryton.gui.window import Window @@ -65,10 +64,11 @@ class Popup(object): def enter(self, widget, event): self.win.hide() + class Graph(gtk.DrawingArea): 'Graph' - __gsignals__ = { "expose-event": "override" } + __gsignals__ = {"expose-event": "override"} def __init__(self, xfield, yfields, attrs, model): super(Graph, self).__init__() @@ -167,13 +167,12 @@ class Graph(gtk.DrawingArea): def drawGraph(self, cr, width, height): pass - def YLabels(self): ylabels = [] if self.yrange == 0.0: base = 1 else: - base = 10**int(math.log(self.yrange, 10)) + base = 10 ** int(math.log(self.yrange, 10)) for i in xrange(int(self.yrange / base) + 1): val = int(self.minyval / base) * base + i * base h = (val - self.minyval) * self.yscale @@ -356,7 +355,6 @@ class Graph(gtk.DrawingArea): self.ids[x].append(model.id) self.datas.setdefault(x, {}) for yfield in self.yfields: - name = yfield['name'] key = yfield.get('key', yfield['name']) self.datas[x].setdefault(key, 0.0) if yfield.get('domain'): @@ -411,7 +409,8 @@ class Graph(gtk.DrawingArea): yLabelWidth = 0 width = width - self.leftPadding - yLabelWidth - self.rightPadding height = height - self.topPadding - self.bottomPadding - xLabelHeight - self.area = Area(self.leftPadding + yLabelWidth, self.topPadding, width, height) + self.area = Area(self.leftPadding + yLabelWidth, self.topPadding, + width, height) def updateXY(self): self.maxxval = len(self.datas) @@ -458,6 +457,7 @@ class Graph(gtk.DrawingArea): def _getDatasKeys(self): return [x.get('key', x['name']) for x in self.yfields] + class Area(object): def __init__(self, x, y, w, h): diff --git a/tryton/gui/window/view_form/view/graph_gtk/line.py b/tryton/gui/window/view_form/view/graph_gtk/line.py index d4b1694059..e843f01ddb 100644 --- a/tryton/gui/window/view_form/view/graph_gtk/line.py +++ b/tryton/gui/window/view_form/view/graph_gtk/line.py @@ -1,6 +1,7 @@ #This file is part of Tryton. The COPYRIGHT file at the top level of #this repository contains the full copyright notices and license terms. -#This code is inspired by the pycha project (http://www.lorenzogil.com/projects/pycha/) +#This code is inspired by the pycha project +#(http://www.lorenzogil.com/projects/pycha/) from graph import Graph from tryton.common import hex2rgb, float_time_to_text, safe_eval import locale @@ -33,8 +34,8 @@ class Line(Graph): if self.xrange == 0: x = 1.0 - if not bool(safe_eval(yfield2attrs[yfield].get('empty', '1'))) \ - and yval == 0: + if (not bool(safe_eval(yfield2attrs[yfield].get('empty', '1'))) + and yval == 0): continue point = Point(x, y, xval, yval, xfield, yfield) @@ -140,8 +141,9 @@ class Line(Graph): highlight = False draw_points = [] - yfields_float_time = dict([(x.get('key', x['name']), x.get('float_time')) - for x in self.yfields if x.get('widget')]) + yfields_float_time = dict( + (x.get('key', x['name']), x.get('float_time')) + for x in self.yfields if x.get('widget')) for point in self.points: if point == nearest[0] and nearest[1] < dia / 100: if not point.highlight: diff --git a/tryton/gui/window/view_form/view/graph_gtk/parser.py b/tryton/gui/window/view_form/view/graph_gtk/parser.py index 1311fb5bce..4f175cfbe3 100644 --- a/tryton/gui/window/view_form/view/graph_gtk/parser.py +++ b/tryton/gui/window/view_form/view/graph_gtk/parser.py @@ -3,12 +3,12 @@ from tryton.gui.window.view_form.view.interface import ParserInterface import tryton.common as common import gtk -from graph import Graph from bar import VerticalBar, HorizontalBar from line import Line from pie import Pie from tryton.config import TRYTON_ICON, CONFIG -import sys, os +import sys +import os import gettext _ = gettext.gettext @@ -20,12 +20,12 @@ GRAPH_TYPE = { 'pie': Pie, } + def save(widget, graph): parent = common.get_toplevel_window() dia = gtk.Dialog(_('Save As'), parent, - gtk.DIALOG_MODAL|gtk.DIALOG_DESTROY_WITH_PARENT, - (gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL, - gtk.STOCK_OK, gtk.RESPONSE_OK)) + gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT, + (gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL, gtk.STOCK_OK, gtk.RESPONSE_OK)) dia.set_icon(TRYTON_ICON) dia.set_has_separator(True) dia.set_default_response(gtk.RESPONSE_OK) @@ -98,6 +98,7 @@ def save(widget, graph): dia.destroy() return + def button_press(widget, event, graph): if event.button == 3: menu = gtk.Menu() @@ -132,7 +133,8 @@ class ParserGraph(ParserInterface): continue xfield = common.node_attributes(child) if not xfield.get('string'): - xfield['string'] = fields[xfield['name']].attrs['string'] + xfield['string'] = fields[xfield['name'] + ].attrs['string'] break elif node.localName == 'y': for child in node.childNodes: @@ -140,10 +142,12 @@ class ParserGraph(ParserInterface): continue yattrs = common.node_attributes(child) if not yattrs.get('string') and yattrs['name'] != '#': - yattrs['string'] = fields[yattrs['name']].attrs['string'] + yattrs['string'] = fields[yattrs['name'] + ].attrs['string'] yfields.append(yattrs) - widget = GRAPH_TYPE[attrs.get('type', 'vbar')](xfield, yfields, attrs, model) + widget = GRAPH_TYPE[attrs.get('type', 'vbar') + ](xfield, yfields, attrs, model) event = gtk.EventBox() event.add(widget) event.connect('button-press-event', button_press, widget) diff --git a/tryton/gui/window/view_form/view/graph_gtk/pie.py b/tryton/gui/window/view_form/view/graph_gtk/pie.py index feb0e46da7..0ba4287c2d 100644 --- a/tryton/gui/window/view_form/view/graph_gtk/pie.py +++ b/tryton/gui/window/view_form/view/graph_gtk/pie.py @@ -1,6 +1,7 @@ #This file is part of Tryton. The COPYRIGHT file at the top level of #this repository contains the full copyright notices and license terms. -#This code is inspired by the pycha project (http://www.lorenzogil.com/projects/pycha/) +#This code is inspired by the pycha project +#(http://www.lorenzogil.com/projects/pycha/) from graph import Graph, Area import math import cairo @@ -97,7 +98,8 @@ class Pie(Graph): cr.set_source_rgba(*color) slice.draw(cr, self.centerx, self.centery, self.radius) cr.fill() - cr.set_source_rgb(*hex2rgb(self.attrs.get('background', '#f5f5f5'))) + cr.set_source_rgb(*hex2rgb( + self.attrs.get('background', '#f5f5f5'))) slice.draw(cr, self.centerx, self.centery, self.radius) cr.set_line_width(2) cr.stroke() @@ -120,7 +122,8 @@ class Pie(Graph): if event.y == self.centery: angle = math.pi / 2 else: - angle = math.atan((event.x - self.centerx)/(self.centery - event.y)) + angle = math.atan((event.x - self.centerx) + / (self.centery - event.y)) if event.x >= self.centerx: if event.y <= self.centery: pass @@ -139,12 +142,14 @@ class Pie(Graph): if self.yfields[0].get('widget') == 'float_time': conv = None if self.yfields[0].get('float_time'): - conv = rpc.CONTEXT.get(self.yfields[0]['float_time']) + conv = rpc.CONTEXT.get( + self.yfields[0]['float_time']) value = float_time_to_text(slice.fraction * self.sum, conv) sum = float_time_to_text(self.sum, conv) else: - value = locale.format('%.2f', slice.fraction * self.sum) + value = locale.format('%.2f', + slice.fraction * self.sum) sum = locale.format('%.2f', self.sum) label = '%s (%s%%)\n%s/%s' % (self.labels[slice.xname], locale.format('%.2f', slice.fraction * 100), @@ -181,8 +186,8 @@ class Slice(object): cr.new_path() cr.move_to(centerx, centery) cr.arc(centerx, centery, radius, - self.startAngle - (math.pi/2), - self.endAngle - (math.pi/2)) + self.startAngle - (math.pi / 2), + self.endAngle - (math.pi / 2)) cr.line_to(centerx, centery) cr.close_path() diff --git a/tryton/gui/window/view_form/view/list.py b/tryton/gui/window/view_form/view/list.py index 30b4dee97e..37da0e8777 100644 --- a/tryton/gui/window/view_form/view/list.py +++ b/tryton/gui/window/view_form/view/list.py @@ -21,7 +21,6 @@ from tryton.common.cellrendererbinary import CellRendererBinary from tryton.pyson import PYSONEncoder from tryton.gui.window import Window from tryton.exceptions import TrytonServerError -import os _ = gettext.gettext @@ -34,7 +33,8 @@ def path_convert_id2pos(model, id_path): current_id = id_path.pop(0) try: record = group.get(current_id) - group = record.children_group(model.children_field, check_load=True) + group = record.children_group(model.children_field, + check_load=True) except (KeyError, AttributeError): return None return model.on_get_path(record) @@ -49,7 +49,7 @@ class AdaptModelGroup(gtk.GenericTreeModel): self.sort_asc = True self.set_property('leak_references', False) self.children_field = children_field - self.__removed = None # XXX dirty hack to allow update of has_child + self.__removed = None # XXX dirty hack to allow update of has_child def added(self, group, record): if (group is self.group @@ -80,7 +80,7 @@ class AdaptModelGroup(gtk.GenericTreeModel): len(record.children_group(self.children_field)) <= 1): path = self.on_get_path(record.parent) iter_ = self.get_iter(path) - self.__removed = record # XXX check for thread + self.__removed = record # XXX check for thread self.row_has_child_toggled(path, iter_) self.__removed = None @@ -313,30 +313,34 @@ class ViewList(ParserView): if screen.readonly: dnd = False if dnd: - self.widget_tree.drag_source_set(gtk.gdk.BUTTON1_MASK | gtk.gdk.BUTTON3_MASK, - [('MY_TREE_MODEL_ROW', gtk.TARGET_SAME_WIDGET, 0),], - gtk.gdk.ACTION_MOVE) + self.widget_tree.drag_source_set( + gtk.gdk.BUTTON1_MASK | gtk.gdk.BUTTON3_MASK, + [('MY_TREE_MODEL_ROW', gtk.TARGET_SAME_WIDGET, 0)], + gtk.gdk.ACTION_MOVE) self.widget_tree.drag_dest_set(gtk.DEST_DEFAULT_ALL, - [('MY_TREE_MODEL_ROW', gtk.TARGET_SAME_WIDGET, 0),], - gtk.gdk.ACTION_MOVE) + [('MY_TREE_MODEL_ROW', gtk.TARGET_SAME_WIDGET, 0)], + gtk.gdk.ACTION_MOVE) self.widget_tree.connect('drag-begin', self.drag_begin) self.widget_tree.connect('drag-motion', self.drag_motion) self.widget_tree.connect('drag-drop', self.drag_drop) self.widget_tree.connect("drag-data-get", self.drag_data_get) - self.widget_tree.connect('drag-data-received', self.drag_data_received) + self.widget_tree.connect('drag-data-received', + self.drag_data_received) self.widget_tree.connect('drag-data-delete', self.drag_data_delete) self.widget_tree.connect('key_press_event', self.on_keypress) if self.children_field: self.widget_tree.connect('test-expand-row', self.test_expand_row) - self.widget_tree.set_expander_column(self.widget_tree.get_column(0)) + self.widget_tree.set_expander_column( + self.widget_tree.get_column(0)) def get_fields(self): return [col.name for col in self.widget_tree.get_columns() if col.name] def on_keypress(self, widget, event): - if event.keyval == gtk.keysyms.c and event.state & gtk.gdk.CONTROL_MASK: + if (event.keyval == gtk.keysyms.c + and event.state & gtk.gdk.CONTROL_MASK): self.on_copy() return False if event.keyval in (gtk.keysyms.Down, gtk.keysyms.Up): @@ -347,7 +351,7 @@ class ViewList(ParserView): if event.keyval == gtk.keysyms.Down: test = True for i in xrange(len(path)): - iter_ = model.get_iter(path[0:i+1]) + iter_ = model.get_iter(path[0:i + 1]) if model.iter_next(iter_): test = False if test: @@ -390,7 +394,7 @@ class ViewList(ParserView): try: for field in fields: record.__getitem__(field, True) - except TrytonServerError, exception: + except TrytonServerError: return True iter_ = model.iter_next(iter_) return False @@ -419,7 +423,7 @@ class ViewList(ParserView): clipboard.set_with_data(targets, self.copy_get_func, self.copy_clear_func, selection) - def copy_foreach(self, treemodel, path,iter, data): + def copy_foreach(self, treemodel, path, iter, data): record = treemodel.get_value(iter, 0) values = [] for col in self.widget_tree.get_columns(): @@ -465,6 +469,7 @@ class ViewList(ParserView): def drag_data_get(self, treeview, context, selection, target_id, etime): treeview.emit_stop_by_name('drag-data-get') + def _func_sel_get(store, path, iter_, data): value = store.get_value(iter_, 0) data.append(json.dumps(value.get_path(store.group))) @@ -496,6 +501,7 @@ class ViewList(ParserView): record = store.group.get_by_path(data) record_path = store.on_get_path(record) drop_info = treeview.get_dest_row_at_pos(x, y) + def check_recursion(from_, to): if not from_ or not to: return True @@ -508,7 +514,8 @@ class ViewList(ParserView): if drop_info: path, position = drop_info check_path = path - if position in (gtk.TREE_VIEW_DROP_BEFORE, gtk.TREE_VIEW_DROP_AFTER): + if position in (gtk.TREE_VIEW_DROP_BEFORE, + gtk.TREE_VIEW_DROP_AFTER): check_path = path[:-1] if not check_recursion(record_path, check_path): return @@ -634,28 +641,32 @@ class ViewList(ParserView): def __getitem__(self, name): return None - def destroy(self): - if CONFIG['client.save_width_height']: - fields = {} - last_col = None - for col in self.widget_tree.get_columns(): - if col.get_visible(): - last_col = col - if not hasattr(col, 'name') or not hasattr(col, 'width'): - continue - if col.get_width() != col.width and col.get_visible(): - fields[col.name] = col.get_width() - #Don't set width for last visible columns - #as it depends of the screen size - if last_col and last_col.name in fields: - del fields[last_col.name] + def save_width_height(self): + if not CONFIG['client.save_width_height']: + return + fields = {} + last_col = None + for col in self.widget_tree.get_columns(): + if col.get_visible(): + last_col = col + if not hasattr(col, 'name') or not hasattr(col, 'width'): + continue + if col.get_width() != col.width and col.get_visible(): + fields[col.name] = col.get_width() + #Don't set width for last visible columns + #as it depends of the screen size + if last_col and last_col.name in fields: + del fields[last_col.name] - if fields and any(fields.itervalues()): - try: - rpc.execute('model', 'ir.ui.view_tree_width', 'set_width', - self.screen.model_name, fields, rpc.CONTEXT) - except TrytonServerError: - pass + if fields and any(fields.itervalues()): + try: + rpc.execute('model', 'ir.ui.view_tree_width', 'set_width', + self.screen.model_name, fields, rpc.CONTEXT) + except TrytonServerError: + pass + + def destroy(self): + self.save_width_height() self.widget_tree.destroy() self.screen = None self.widget_tree = None @@ -710,7 +721,6 @@ class ViewList(ParserView): return True self.update_children() - def set_value(self): if hasattr(self.widget_tree, 'editable') \ and self.widget_tree.editable: @@ -773,11 +783,12 @@ class ViewList(ParserView): value += field_value if loaded: - label_str = locale.format('%.' + str(self.children[child][3]) + 'f', - value_selected, True) + label_str = locale.format( + '%.' + str(self.children[child][3]) + 'f', value_selected, + True) label_str += ' / ' - label_str += locale.format('%.' + str(self.children[child][3]) + 'f', - value, True) + label_str += locale.format( + '%.' + str(self.children[child][3]) + 'f', value, True) else: label_str = '-' self.children[child][2].set_text(label_str) @@ -807,7 +818,8 @@ class ViewList(ParserView): break if path[:-1]: self.widget_tree.expand_to_path(path[:-1]) - self.widget_tree.scroll_to_cell(path, focus_column, use_align=False) + self.widget_tree.scroll_to_cell(path, focus_column, + use_align=False) self.widget_tree.set_cursor(path, focus_column, new) def sel_ids_get(self): diff --git a/tryton/gui/window/view_form/view/list_gtk/editabletree.py b/tryton/gui/window/view_form/view/list_gtk/editabletree.py index d96c1bc1d4..00ed147198 100644 --- a/tryton/gui/window/view_form/view/list_gtk/editabletree.py +++ b/tryton/gui/window/view_form/view/list_gtk/editabletree.py @@ -38,7 +38,6 @@ class EditableTreeView(gtk.TreeView): def on_open_remote(self, current_record, fieldname, create, value, entry=None, callback=None): - field = current_record[fieldname] cell = self.cells[fieldname] if value != cell.get_textual_value(current_record) or not value: changed = True @@ -151,6 +150,7 @@ class EditableTreeView(gtk.TreeView): else: txt = entry.get_active_text() entry.handler_block(entry.editing_done_id) + def callback(): entry.handler_unblock(entry.editing_done_id) self.set_cursor(path, column, True) @@ -201,9 +201,9 @@ class EditableTreeView(gtk.TreeView): break entry.handler_block(entry.editing_done_id) if self.editable == 'top': - new_path = self._key_up(path, model, col) + self._key_up(path, model, col) else: - new_path = self._key_down(path, model, column) + self._key_down(path, model, column) entry.handler_unblock(entry.editing_done_id) elif event.keyval in (gtk.keysyms.F3, gtk.keysyms.F2): if isinstance(entry, gtk.Entry): @@ -211,6 +211,7 @@ class EditableTreeView(gtk.TreeView): else: value = entry.get_active_text() entry.handler_block(entry.editing_done_id) + def callback(): cell = self.cells[column.name] value = cell.get_textual_value(record) @@ -221,13 +222,14 @@ class EditableTreeView(gtk.TreeView): entry.handler_unblock(entry.editing_done_id) self.set_cursor(path, column, True) self.on_open_remote(record, column.name, - create=(event.keyval==gtk.keysyms.F3), value=value, + create=(event.keyval == gtk.keysyms.F3), value=value, callback=callback) else: field = record[column.name] if isinstance(entry, gtk.Entry): entry.set_max_length(int(field.attrs.get('size', 0))) - # store in the record the entry widget to get the value in set_value + # store in the record the entry widget to get the value in + # set_value field.editabletree_entry = entry record.modified_fields.setdefault(column.name) return False diff --git a/tryton/gui/window/view_form/view/list_gtk/parser.py b/tryton/gui/window/view_form/view/list_gtk/parser.py index 9085e39fec..084e8e653d 100644 --- a/tryton/gui/window/view_form/view/list_gtk/parser.py +++ b/tryton/gui/window/view_form/view/list_gtk/parser.py @@ -12,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, file_selection, file_open + HM_FORMAT, file_selection, file_open import tryton.common as common from tryton.exceptions import TrytonError, TrytonServerError from tryton.common.cellrendererbutton import CellRendererButton @@ -25,7 +25,6 @@ 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 import gtk import locale import datetime @@ -35,6 +34,7 @@ import operator _ = gettext.gettext + def send_keys(renderer, editable, position, treeview): editable.connect('key_press_event', treeview.on_keypressed) editable.editing_done_id = editable.connect('editing_done', @@ -42,6 +42,7 @@ def send_keys(renderer, editable, position, treeview): if isinstance(editable, (gtk.ComboBoxEntry, gtk.ComboBox)): editable.connect('changed', treeview.on_editing_done) + def sort_model(column, treeview, screen): for col in treeview.get_columns(): if col != column: @@ -71,6 +72,7 @@ def sort_model(column, treeview, screen): for record in unsaved_records: store.group.append(record) + class ParserTree(ParserInterface): def __init__(self, parent=None, attrs=None, screen=None, @@ -142,6 +144,7 @@ class ParserTree(ParserInterface): render_pixbuf = gtk.CellRendererPixbuf() col.pack_start(render_pixbuf, expand=False) icon = node_attrs['icon'] + def setter(column, cell, store, iter): record = store.get_value(iter, 0) value = record[icon].get_client(record) or '' @@ -242,6 +245,7 @@ class ParserTree(ParserInterface): col.set_widget(label) col._type = 'button' + col.set_cell_data_func(renderer, cell.setter) if 'width' in node_attrs: width = int(node_attrs['width']) else: @@ -328,7 +332,8 @@ class Char(object): bg_color = 'white' if not field.get_state_attrs(record).get('valid', True): bg_color = COLORS.get('invalid', 'white') - elif bool(int(field.get_state_attrs(record).get('required', 0))): + elif bool(int( + field.get_state_attrs(record).get('required', 0))): bg_color = COLORS.get('required', 'white') cell.set_property('background', bg_color) if bg_color == 'white': @@ -366,6 +371,7 @@ class Char(object): if callback: callback() + class Int(Char): def __init__(self, field_name, model_name, treeview, attrs=None): @@ -383,6 +389,7 @@ class Int(Char): return locale.format('%d', record[self.field_name].get_client(record) or 0, True) + class Boolean(Int): def __init__(self, field_name, model_name, treeview, attrs=None): @@ -484,7 +491,7 @@ class Float(Char): def get_textual_value(self, record): field = record[self.field_name] digit = record.expr_eval(field.attrs.get('digits', (16, 2)))[1] - return locale.format('%.'+str(digit)+'f', + return locale.format('%.' + str(digit) + 'f', record[self.field_name].get_client(record) or 0.0, True) def value_from_text(self, record, text, callback=None): @@ -513,7 +520,9 @@ class FloatTime(Char): def value_from_text(self, record, text, callback=None): field = record[self.field_name] - field.set_client(record, common.text_to_float_time(text, self.conv)) + digits = record.expr_eval(field.attrs.get('digits', (16, 2))) + field.set_client(record, + round(common.text_to_float_time(text, self.conv), digits[1])) if callback: callback() @@ -582,7 +591,7 @@ class Binary(Char): filename = file_selection(_('Save As...'), filename=filename, action=gtk.FILE_CHOOSER_ACTION_SAVE) if filename: - with open(filename,'wb') as fp: + with open(filename, 'wb') as fp: fp.write(field.get_data(record)) def clear_binary(self, renderer, path): @@ -681,6 +690,7 @@ class M2O(Char): def search_remote(self, record, relation, ids=None, domain=None, context=None, callback=None): field = record.group.fields[self.field_name] + def search_callback(found): value = None if found: @@ -733,6 +743,7 @@ class O2M(Char): screen = Screen(relation, mode=['tree', 'form'], exclude_field=field.attrs.get('relation_field')) screen.group = group + def open_callback(result): if callback: callback() @@ -781,6 +792,7 @@ class M2M(Char): return if not callback: return + def winsearch_callback(result): field.set_client(record, result or []) if callback: @@ -807,20 +819,21 @@ class M2M(Char): field.set_client(record, False) if callback: callback() - if ids and len(ids)==1: + if ids and len(ids) == 1: field.set_client(record, ids) if callback: callback() return else: ids = [x.id for x in field.get_client(record)] + def open_callback(result): if result: field.set_client(record, result) if callback: callback() - WinSearch(relation, open_callback, sel_multi=True, ids=ids, context=context, - domain=domain) + WinSearch(relation, open_callback, sel_multi=True, ids=ids, + context=context, domain=domain) class Selection(Char): @@ -1002,6 +1015,15 @@ class Button(object): self.renderer.connect('clicked', self.button_clicked) + def setter(self, column, cell, store, iter): + record = store.get_value(iter, 0) + states = record.expr_eval(self.attrs.get('states', {}), + check_load=False) + invisible = states.get('invisible', False) + cell.set_property('visible', not invisible) + # TODO readonly + # TODO icon + def button_clicked(self, widget, path): if not path: return True diff --git a/tryton/gui/window/view_form/view/screen_container.py b/tryton/gui/window/view_form/view/screen_container.py index bdb8bd4da1..77a38b0e9d 100644 --- a/tryton/gui/window/view_form/view/screen_container.py +++ b/tryton/gui/window/view_form/view/screen_container.py @@ -6,6 +6,7 @@ import tryton.common as common _ = gettext.gettext + class ScreenContainer(object): def __init__(self): @@ -139,7 +140,7 @@ class ScreenContainer(object): model.append([r.strip()]) def clear(self, widget=None): - self.search_entry.set_text(''); + self.search_entry.set_text('') def get_text(self): return self.search_entry.get_text().strip().decode('utf-8') diff --git a/tryton/gui/window/win_export.py b/tryton/gui/window/win_export.py index 94499aa958..06a1f70521 100644 --- a/tryton/gui/window/win_export.py +++ b/tryton/gui/window/win_export.py @@ -20,11 +20,9 @@ class WinExport(object): def __init__(self, model, ids, context=None): self.parent = common.get_toplevel_window() - self.dialog = gtk.Dialog( - title= _("Export to CSV"), - parent=self.parent, - flags=gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT - | gtk.WIN_POS_CENTER_ON_PARENT) + self.dialog = gtk.Dialog(title=_("Export to CSV"), parent=self.parent, + flags=gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT | + gtk.WIN_POS_CENTER_ON_PARENT) self.dialog.set_icon(TRYTON_ICON) vbox = gtk.VBox() @@ -327,7 +325,7 @@ class WinExport(object): try: new_id = rpc.execute(*args) except TrytonServerError, exception: - new_ids = common.process_exception(exception, self.dialog, *args) + new_id = common.process_exception(exception, self.dialog, *args) if not new_id: return self.predef_model.append(( @@ -419,7 +417,7 @@ class WinExport(object): row = [] for val in data: if type(val) == types.StringType: - row.append(val.replace('\n',' ').replace('\t',' ')) + row.append(val.replace('\n', ' ').replace('\t', ' ')) else: row.append(val) writer.writerow(row) diff --git a/tryton/gui/window/win_form.py b/tryton/gui/window/win_form.py index bac42f0489..78f2b57fff 100644 --- a/tryton/gui/window/win_form.py +++ b/tryton/gui/window/win_form.py @@ -1,6 +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 tryton.common import TRYTON_ICON +from tryton.common import TRYTON_ICON, COLOR_SCHEMES import tryton.common as common from tryton.config import CONFIG import gtk @@ -8,6 +8,7 @@ import pango import gettext from tryton.exceptions import TrytonServerError from tryton.gui.window.nomodal import NoModal +import tryton.rpc as rpc _ = gettext.gettext @@ -56,7 +57,7 @@ class WinForm(NoModal): if new and many: self.but_ok.add_accelerator('clicked', self.accel_group, gtk.keysyms.Return, - gtk.gdk.CONTROL_MASK|gtk.gdk.SHIFT_MASK, + gtk.gdk.CONTROL_MASK | gtk.gdk.SHIFT_MASK, gtk.ACCEL_VISIBLE) self.but_new = self.win.add_button(gtk.STOCK_NEW, @@ -130,7 +131,8 @@ class WinForm(NoModal): tooltips.set_tip(self.but_del, _('Delete selected record')) self.but_del.connect('clicked', self._sig_remove) img_del = gtk.Image() - img_del.set_from_stock('tryton-delete', gtk.ICON_SIZE_SMALL_TOOLBAR) + img_del.set_from_stock('tryton-delete', + gtk.ICON_SIZE_SMALL_TOOLBAR) img_del.set_alignment(0.5, 0.5) self.but_del.add(img_del) self.but_del.set_relief(gtk.RELIEF_NONE) @@ -142,7 +144,8 @@ class WinForm(NoModal): tooltips.set_tip(but_pre, _('Previous')) but_pre.connect('clicked', self._sig_previous) img_pre = gtk.Image() - img_pre.set_from_stock('tryton-go-previous', gtk.ICON_SIZE_SMALL_TOOLBAR) + img_pre.set_from_stock('tryton-go-previous', + gtk.ICON_SIZE_SMALL_TOOLBAR) img_pre.set_alignment(0.5, 0.5) but_pre.add(img_pre) but_pre.set_relief(gtk.RELIEF_NONE) @@ -155,7 +158,8 @@ class WinForm(NoModal): tooltips.set_tip(but_next, _('Next')) but_next.connect('clicked', self._sig_next) img_next = gtk.Image() - img_next.set_from_stock('tryton-go-next', gtk.ICON_SIZE_SMALL_TOOLBAR) + img_next.set_from_stock('tryton-go-next', + gtk.ICON_SIZE_SMALL_TOOLBAR) img_next.set_alignment(0.5, 0.5) but_next.add(img_next) but_next.set_relief(gtk.RELIEF_NONE) @@ -167,7 +171,8 @@ class WinForm(NoModal): tooltips.set_tip(but_switch, _('Switch')) but_switch.connect('clicked', self.switch_view) img_switch = gtk.Image() - img_switch.set_from_stock('tryton-fullscreen', gtk.ICON_SIZE_SMALL_TOOLBAR) + img_switch.set_from_stock('tryton-fullscreen', + gtk.ICON_SIZE_SMALL_TOOLBAR) img_switch.set_alignment(0.5, 0.5) but_switch.add(img_switch) but_switch.set_relief(gtk.RELIEF_NONE) @@ -251,6 +256,7 @@ class WinForm(NoModal): from tryton.gui.window.win_search import WinSearch domain = [] context = rpc.CONTEXT.copy() + model_name = self.screen.model_name try: if self.wid_text.get_text(): @@ -258,7 +264,7 @@ class WinForm(NoModal): '%' + self.wid_text.get_text() + '%'), domain] else: dom = domain - ids = rpc.execute('model', self.attrs['relation'], 'search', dom, + ids = rpc.execute('model', model_name, 'search', dom, 0, CONFIG['client.limit'], None, context) except TrytonServerError, exception: common.process_exception(exception) @@ -274,9 +280,8 @@ class WinForm(NoModal): self.wid_text.set_text('') if len(ids) != 1: - WinSearch(self.attrs['relation'], callback, sel_multi=True, - ids=ids, context=context, domain=domain, - views_preload=self.attrs.get('views', {})) + WinSearch(model_name, callback, sel_multi=True, + ids=ids, context=context, domain=domain) else: callback(ids) diff --git a/tryton/gui/window/win_import.py b/tryton/gui/window/win_import.py index e9c9b3797a..80e8eb22f1 100644 --- a/tryton/gui/window/win_import.py +++ b/tryton/gui/window/win_import.py @@ -45,7 +45,7 @@ class WinImport(object): hbox_mapping.pack_start(vbox_buttons, False, True, 0) button_add = gtk.Button(_("_Add"), stock=None, use_underline=True) - button_add.set_alignment(0.0,0.0) + button_add.set_alignment(0.0, 0.0) img_button = gtk.Image() img_button.set_from_stock('tryton-list-add', gtk.ICON_SIZE_BUTTON) button_add.set_image(img_button) @@ -54,7 +54,7 @@ class WinImport(object): button_remove = gtk.Button(_("_Remove"), stock=None, use_underline=True) - button_remove.set_alignment(0.0,0.0) + button_remove.set_alignment(0.0, 0.0) img_button = gtk.Image() img_button.set_from_stock('tryton-list-remove', gtk.ICON_SIZE_BUTTON) button_remove.set_image(img_button) @@ -63,7 +63,7 @@ class WinImport(object): button_remove_all = gtk.Button(_("Clear"), stock=None, use_underline=True) - button_remove_all.set_alignment(0.0,0.0) + button_remove_all.set_alignment(0.0, 0.0) img_button = gtk.Image() img_button.set_from_stock('tryton-clear', gtk.ICON_SIZE_BUTTON) button_remove_all.set_image(img_button) @@ -75,7 +75,7 @@ class WinImport(object): button_autodetect = gtk.Button(_("Auto-Detect"), stock=None, use_underline=True) - button_autodetect.set_alignment(0.0,0.0) + button_autodetect.set_alignment(0.0, 0.0) img_button = gtk.Image() img_button.set_from_stock('tryton-find', gtk.ICON_SIZE_BUTTON) button_autodetect.set_image(img_button) @@ -132,15 +132,15 @@ class WinImport(object): table.attach(self.import_csv_sep, 1, 2, 0, 1) label_import_csv_del = gtk.Label(_("Text Delimiter:")) - label_import_csv_del.set_alignment( 1, 0.5) + label_import_csv_del.set_alignment(1, 0.5) table.attach(label_import_csv_del, 2, 3, 0, 1) self.import_csv_del = gtk.Entry() - self.import_csv_del.set_text( "\"") - self.import_csv_del.set_width_chars( 1) + self.import_csv_del.set_text("\"") + self.import_csv_del.set_width_chars(1) table.attach(self.import_csv_del, 3, 4, 0, 1) label_import_csv_enc = gtk.Label(_("Encoding:")) - label_import_csv_enc.set_alignment( 1, 0.5) + label_import_csv_enc.set_alignment(1, 0.5) table.attach(label_import_csv_enc, 0, 1, 1, 2) self.import_csv_enc = gtk.combo_box_new_text() self.import_csv_enc.append_text("UTF-8") @@ -148,7 +148,7 @@ class WinImport(object): table.attach(self.import_csv_enc, 1, 2, 1, 2) label_import_csv_skip = gtk.Label(_("Lines to Skip:")) - label_import_csv_skip.set_alignment( 1, 0.5) + label_import_csv_skip.set_alignment(1, 0.5) table.attach(label_import_csv_skip, 2, 3, 1, 2) self.import_csv_skip_adj = gtk.Adjustment(0, 0, 100, 1, 10) @@ -266,7 +266,6 @@ class WinImport(object): if word not in self.fields_invert and word not in self.fields: iter = self.model1.get_iter_first() prefix = '' - prefix_name = '' for parent in word.split('/')[:-1]: while iter: if self.model1.get_value(iter, 0) == parent or \ @@ -300,7 +299,7 @@ class WinImport(object): def _sig_sel_add(self, store, path, iter): num = self.model2.append() name = self.fields[store.get_value(iter, 1)][0] - self.model2.set(num, 0, name, 1, store.get_value(iter,1)) + self.model2.set(num, 0, name, 1, store.get_value(iter, 1)) def sig_unsel(self, widget=None): store, paths = self.view2.get_selection().get_selected_rows() diff --git a/tryton/gui/window/win_search.py b/tryton/gui/window/win_search.py index 4712a6c75b..87ef2c4ddf 100644 --- a/tryton/gui/window/win_search.py +++ b/tryton/gui/window/win_search.py @@ -3,7 +3,6 @@ import gtk import gettext import tryton.common as common -import tryton.rpc as rpc from tryton.gui.window.view_form.screen import Screen from tryton.config import TRYTON_ICON from tryton.gui.window.win_form import WinForm @@ -34,7 +33,8 @@ class WinSearch(NoModal): self.accel_group = gtk.AccelGroup() self.win.add_accel_group(self.accel_group) - self.but_cancel = self.win.add_button(gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL) + self.but_cancel = self.win.add_button(gtk.STOCK_CANCEL, + gtk.RESPONSE_CANCEL) self.but_find = self.win.add_button(gtk.STOCK_FIND, gtk.RESPONSE_APPLY) self.but_ok = self.win.add_button(gtk.STOCK_OK, gtk.RESPONSE_OK) self.but_ok.add_accelerator('clicked', self.accel_group, @@ -118,6 +118,7 @@ class WinSearch(NoModal): elif response_id == gtk.RESPONSE_ACCEPT: screen = Screen(self.model_name, domain=self.domain, context=self.context, mode=['form']) + def callback(result): if result and screen.save_current(): res = [screen.current_record.id] diff --git a/tryton/gui/window/window.py b/tryton/gui/window/window.py index 4070cccb56..6d2f16162e 100644 --- a/tryton/gui/window/window.py +++ b/tryton/gui/window/window.py @@ -1,7 +1,5 @@ #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 tryton.rpc as rpc -from preference import * class Window(object): diff --git a/tryton/gui/window/wizard.py b/tryton/gui/window/wizard.py index 46b34325f6..99dc116ea5 100644 --- a/tryton/gui/window/wizard.py +++ b/tryton/gui/window/wizard.py @@ -9,7 +9,6 @@ import tryton.common as common from tryton.gui.window.view_form.screen import Screen from tryton.gui import Main from tryton.exceptions import TrytonServerError -from tryton.config import CONFIG from tryton.gui.window.nomodal import NoModal from tryton.common.button import Button _ = gettext.gettext @@ -74,7 +73,9 @@ class Wizard(object): ctx['active_ids'] = self.ids ctx['active_model'] = self.model if self.screen: - data = {self.screen_state: self.screen.get_on_change_value()} + data = { + self.screen_state: self.screen.get_on_change_value(), + } else: data = {} rpcprogress = common.RPCProgress('execute', ('wizard', @@ -230,7 +231,7 @@ class Wizard(object): self.screen.set_cursor() -class WizardForm(Wizard,SignalEvent): +class WizardForm(Wizard, SignalEvent): "Wizard" def __init__(self, name=False): diff --git a/tryton/ipc.py b/tryton/ipc.py index ea7e70e45e..1c0d6fb87b 100644 --- a/tryton/ipc.py +++ b/tryton/ipc.py @@ -12,6 +12,7 @@ from tryton.config import get_config_dir __all__ = ['Server', 'Client'] + class IPCServer(object): thread = None @@ -112,7 +113,7 @@ class FIFOServer(IPCServer): pass def _read(self): - fifo = os.fdopen(os.open(self.filename, os.O_RDONLY|os.O_NONBLOCK)) + fifo = os.fdopen(os.open(self.filename, os.O_RDONLY | os.O_NONBLOCK)) data = '' while self.running: try: diff --git a/tryton/jsonrpc.py b/tryton/jsonrpc.py index a38f4a97c0..d853a925dc 100644 --- a/tryton/jsonrpc.py +++ b/tryton/jsonrpc.py @@ -29,13 +29,14 @@ class ResponseError(xmlrpclib.ResponseError): class Fault(xmlrpclib.Fault): def __init__(self, faultCode, faultString='', **extra): - super(Fault, self).__init__(faultCode, str(faultString), **extra) + super(Fault, self).__init__(faultCode, faultString, **extra) self.args = faultString class ProtocolError(xmlrpclib.ProtocolError): pass + def object_hook(dct): if '__class__' in dct: if dct['__class__'] == 'datetime': @@ -109,7 +110,7 @@ class JSONUnmarshaller(object): class Transport(xmlrpclib.Transport, xmlrpclib.SafeTransport): accept_gzip_encoding = True - encode_threshold = 1400 # common MTU + encode_threshold = 1400 # common MTU def __init__(self, fingerprints=None, ca_certs=None): xmlrpclib.Transport.__init__(self) @@ -123,7 +124,8 @@ class Transport(xmlrpclib.Transport, xmlrpclib.SafeTransport): return parser, target def get_host_info(self, host): - host, extra_headers, x509 = xmlrpclib.Transport.get_host_info(self, host) + host, extra_headers, x509 = xmlrpclib.Transport.get_host_info( + self, host) if extra_headers is None: extra_headers = [] extra_headers.append(('Connection', 'keep-alive')) @@ -151,11 +153,11 @@ class Transport(xmlrpclib.Transport, xmlrpclib.SafeTransport): return self._connection[1] host, extra_headers, x509 = self.get_host_info(host) - ca_certs = self.__ca_certs + ca_certs = self.__ca_certs cert_reqs = ssl.CERT_REQUIRED if ca_certs else ssl.CERT_NONE - class HTTPSConnection(httplib.HTTPSConnection): + def connect(self): sock = socket.create_connection((self.host, self.port), self.timeout) @@ -180,12 +182,13 @@ class Transport(xmlrpclib.Transport, xmlrpclib.SafeTransport): peercert = sock.getpeercert(True) except socket.error: peercert = None + def format_hash(value): return reduce(lambda x, y: x + y[1].upper() + - ((y[0] % 2 and y[0] + 1 < len(value)) and ':' or ''), - enumerate(value), '') + ((y[0] % 2 and y[0] + 1 < len(value)) and ':' or ''), + enumerate(value), '') return format_hash(hashlib.sha1(peercert).hexdigest()) - except ssl.SSLError, e: + except ssl.SSLError: http_connection() fingerprint = '' diff --git a/tryton/plugins/__init__.py b/tryton/plugins/__init__.py index 119eca5e7b..492786bb6b 100644 --- a/tryton/plugins/__init__.py +++ b/tryton/plugins/__init__.py @@ -21,11 +21,13 @@ if os.path.isdir(PLUGINS_PATH): continue module = os.path.splitext(plugin)[0] try: - module = imp.load_module(module, *imp.find_module(module, [PLUGINS_PATH])) + module = imp.load_module(module, *imp.find_module(module, + [PLUGINS_PATH])) MODULES.append(module) except ImportError, exception: continue + def execute(datas): result = {} diff --git a/tryton/plugins/translation/__init__.py b/tryton/plugins/translation/__init__.py index b21b318577..d88cf6e0b3 100644 --- a/tryton/plugins/translation/__init__.py +++ b/tryton/plugins/translation/__init__.py @@ -5,12 +5,14 @@ import gettext _ = gettext.gettext + def translate_view(datas): model = datas['model'] Window.create(False, 'ir.translation', res_id=False, domain=[('model', '=', model)], mode=['tree', 'form']) + def get_plugins(model): return [ (_('Translate view'), translate_view), diff --git a/tryton/plugins/workflow/__init__.py b/tryton/plugins/workflow/__init__.py index 502e5d4c16..db0660d763 100644 --- a/tryton/plugins/workflow/__init__.py +++ b/tryton/plugins/workflow/__init__.py @@ -5,18 +5,21 @@ import gettext _ = gettext.gettext + def workflow_print(datas): datas = datas.copy() datas['nested'] = False Action.exec_report('workflow.instance.graph', datas) return True + def workflow_print_complex(datas): datas = datas.copy() datas['nested'] = True Action.exec_report('workflow.instance.graph', datas) return True + def get_plugins(model): return [ (_('Print Workflow'), workflow_print), diff --git a/tryton/pyson.py b/tryton/pyson.py index 9c7dde7e93..1e66d7f275 100644 --- a/tryton/pyson.py +++ b/tryton/pyson.py @@ -1,6 +1,5 @@ #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 sys try: import simplejson as json except ImportError: @@ -22,7 +21,7 @@ class PYSON(object): raise NotImplementedError def __invert__(self): - if self.types()!= set([bool]): + if self.types() != set([bool]): return Not(Bool(self)) else: return Not(self) @@ -307,7 +306,8 @@ class If(PYSON): def __init__(self, condition, then_statement, else_statement=None): super(If, self).__init__() if isinstance(condition, PYSON): - assert condition.types() == set([bool]), 'condition must be boolean' + assert condition.types() == set([bool]), \ + 'condition must be boolean' else: assert isinstance(condition, bool), 'condition must be boolean' if isinstance(then_statement, PYSON): diff --git a/tryton/rpc.py b/tryton/rpc.py index 01635ba4cb..32ec540dad 100644 --- a/tryton/rpc.py +++ b/tryton/rpc.py @@ -30,7 +30,9 @@ if not os.path.isfile(_CA_CERTS): _CA_CERTS = None _FINGERPRINTS = Fingerprints() -ServerProxy = partial(ServerProxy, fingerprints=_FINGERPRINTS, ca_certs=_CA_CERTS) +ServerProxy = partial(ServerProxy, fingerprints=_FINGERPRINTS, + ca_certs=_CA_CERTS) + def db_list(host, port): try: @@ -46,6 +48,7 @@ def db_list(host, port): logging.getLogger('rpc.result').debug(repr(None)) return None + def db_exec(host, port, method, *args): connection = ServerProxy(host, port) logging.getLogger('rpc.request').info('common.db.%s(None, None, %s)' % @@ -54,6 +57,7 @@ def db_exec(host, port, method, *args): logging.getLogger('rpc.result').debug(repr(result)) return result + def server_version(host, port): try: connection = ServerProxy(host, port) @@ -65,9 +69,10 @@ def server_version(host, port): except (Fault, socket.error): raise + def login(username, password, host, port, database): - global CONNECTION, _USER, _USERNAME, _SESSION, _HOST, _PORT, _DATABASE, _VIEW_CACHE - global _TOOLBAR_CACHE + global CONNECTION, _USER, _USERNAME, _SESSION, _HOST, _PORT, _DATABASE + global _VIEW_CACHE, _TOOLBAR_CACHE _VIEW_CACHE = {} _TOOLBAR_CACHE = {} try: @@ -99,9 +104,10 @@ def login(username, password, host, port, database): IPCServer(host, port, database).run() return 1 + def logout(): - global CONNECTION, _USER, _USERNAME, _SESSION, _HOST, _PORT, _DATABASE, _VIEW_CACHE - global _TOOLBAR_CACHE + global CONNECTION, _USER, _USERNAME, _SESSION, _HOST, _PORT, _DATABASE + global _VIEW_CACHE, _TOOLBAR_CACHE if IPCServer.instance: IPCServer.instance.stop() if CONNECTION is not None: @@ -125,6 +131,7 @@ def logout(): _VIEW_CACHE = {} _TOOLBAR_CACHE = {} + def context_reload(): global CONTEXT, TIMEZONE, _HOST, _PORT try: @@ -142,6 +149,7 @@ def context_reload(): except Fault: pass + def _execute(blocking, *args): global CONNECTION, _USER, _SESSION if CONNECTION is None: @@ -186,8 +194,10 @@ def _execute(blocking, *args): logging.getLogger('rpc.result').debug(repr(result)) return result + def execute(*args): return _execute(True, *args) + def execute_nonblocking(*args): return _execute(False, *args) diff --git a/tryton/translate.py b/tryton/translate.py index ac7971f577..583e65c5b2 100644 --- a/tryton/translate.py +++ b/tryton/translate.py @@ -5,7 +5,7 @@ import os import locale import gettext from version import PACKAGE -from tryton.client import CURRENT_DIR, PREFIX +from tryton.config import CURRENT_DIR, PREFIX import logging import gtk import sys @@ -197,12 +197,14 @@ def setlang(lang=None, locale_dict=None): conv[field] = locale_dict[field] locale.localeconv = lambda: conv + def set_language_direction(direction): if direction == 'rtl': gtk.widget_set_default_direction(gtk.TEXT_DIR_RTL) else: gtk.widget_set_default_direction(gtk.TEXT_DIR_LTR) + def date_format(): ''' Return the locale date format diff --git a/tryton/version.py b/tryton/version.py index 06169802f1..ebed2fb2b1 100644 --- a/tryton/version.py +++ b/tryton/version.py @@ -4,4 +4,3 @@ PACKAGE = "tryton" VERSION = "2.3.0" LICENSE = "GPL-3" WEBSITE = "http://www.tryton.org/" -