diff --git a/CHANGELOG b/CHANGELOG index decf5c00dd..578f625f1d 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,4 @@ +* Remove database management * Limit readonly state for xxx2Many * Show records names in relate window title * Add support for count on Action Window Domains diff --git a/doc/usage.rst b/doc/usage.rst index f3799c7b9f..cb2da40dbc 100644 --- a/doc/usage.rst +++ b/doc/usage.rst @@ -22,7 +22,7 @@ Synopsis After startup, there raises the `login dialog`__ and optionally a `tips dialog`__. -__ Menu-File-Connect_ +__ Menu-Connection_ __ Menu-Help-Tips_ @@ -89,7 +89,7 @@ Figure: Tryton client application:: Client Window ________________________________________________________________ | Tryton _ o x| |----------------------------------------------------------------| - Menu bar | File User Options Favorites Help | + Menu bar | Connection User Options Favorites Help | |________________________________________________________________| | | ______ | Tabs | Menu | [Tab1] |[Tab2]| [Tab3]... | @@ -202,12 +202,12 @@ menu action. Most dialogs provide a *Cancel* button, used to stop the complete dialog process. -File -^^^^ -The file menu level provides functions about Tryton server login, -Database maintenance and closing the client application. +Connection +^^^^^^^^^^ +The connection menu level provides functions about Tryton server login, +logout and closing the client application. -.. _Menu-File-Connect: +.. _Menu-Connection: Connect... By choosing this menu entry the client will be connected to an available @@ -226,138 +226,19 @@ Connect... user may be logged out of the current session, and need to login again. Default timeout for inactivity logout is six minutes. -__ File-Server-Connection_ +__ Connection-Server-Connection_ -.. _Menu-File-Disconnect: +.. _Menu-Connection-Disconnect: Disconnect... Disconnects the client from an active server connection. In case of unsaved changes in an open tab, the Tryton client will request for saving the changes. -Database -++++++++ -This menu level provides tools to maintain Tryton databases. -For all database operations the user needs to know the Tryton server password. +__ Connection-Server-Connection_ -.. warning:: Consider not to use this server-site maintaining functions, - if there are security concerns. Since there are always security - concerns in a multiuser environment, better disclaim to provide - these functions on database level. - -.. note:: Database names are restricted by some rules: - - * Allowed characters are alpha-nummeric [A-Za-z0-9] and - underscore (_). - * First character must be an alphabetic letter. - * The maximum length of a database name is 64 characters. - - Tryton automatically checks if the given database name follows - the rules. - -.. _Menu-File-New_Database: - -New Database - Opens a :term:`dialog` for creating a new Tryton database with an initial - user called *admin*. - - * Server Setup: - - - `Server Connection`__ - - Tryton Server Password: The password given in the Tryton server - configuration. - - * New Database Setup: - - - Database Name: The name of the new database. - - Default Language: The default language of the new database. - - Admin Password: The *admin*-user password of the new database. - - Confirm Admin Password: Repeat the password of the new 'admin' user. - - * Actions: - - - Create: Creates the new database with initial user *admin* and the - provided password. - - Cancel - -__ File-Server-Connection_ - -.. note:: The appropriate Tryton database user (defined in the Tryton server - configuration) needs to be authorized to create databases for this step. - -.. _Menu-File-Restore_Database: - -Restore Database - Opens a :term:`dialog` to restore a previously created database backup - file. - - * File choose menu dialog - - - Choose a database backup file in the file system to be restored. - - Actions: - - + Open: Open the chosen backup file. - + Cancel - - * Restore Database dialog: - - - `Server Connection`__ - - Tryton Server Password: The password given in the Tryton server - configuration. - - File to Restore: Show filename and path. - - New Database Name: Enter a new name for the database to be restored - - Actions: - - + Restore: Proceed database restore. - + Cancel - -__ File-Server-Connection_ - -.. _Menu-File-Backup_Database: - -Backup Database - Open a :term:`dialog` to backup an existing database and save it as a file. - - * `Backup a Database` dialog - - - `Server connection`__ - - Database: Choose the Tryton database to backup. - - Tryton Server Password: The password given in the Tryton server - configuration. - - Actions: - - + Backup: Proceed database backup. - + Cancel - - * `Save Backup File` dialog - - - Choose a filename and location for the created backup file. - - Save the backup file. - -__ File-Server-Connection_ - -.. _Menu-File-Drop_Database: - -Drop Database - Open a :term:`dialog` to delete an existing Tryton database. - - * `Delete a Database` dialog - - - `Server Connection`__ - - Database: Choose a database to delete. - - Tryton Server Password: The password given in the Tryton server - configuration. - - * Confirmation Dialog - - - Yes: Drop the database - - No: Do not drop the database - - Cancel - -__ File-Server-Connection_ - -.. _File-Server-Connection: +.. _Connection-Server-Connection: Server (connection) dialog: This :term:`dialog` is widely used to setup a Tryton server connection. diff --git a/tryton/common/common.py b/tryton/common/common.py index cde806af64..943754f91c 100644 --- a/tryton/common/common.py +++ b/tryton/common/common.py @@ -24,11 +24,8 @@ except ImportError: import md5 import webbrowser import traceback -import threading import tryton.rpc as rpc -import locale import socket -from tryton import __version__ import thread import urllib from string import Template @@ -227,46 +224,6 @@ def find_in_path(name): 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 - or None if it is impossible to connect - or -1 if the server version doesn't match the client version - ''' - rpc.logout() - if not test_server_version(host, port): - return -1 - return rpc.db_list(host, port) - - -def refresh_langlist(lang_widget, host, port): - liststore = lang_widget.get_model() - liststore.clear() - try: - lang_list = rpc.db_exec(host, port, 'list_lang') - except socket.error: - return [] - index = -1 - i = 0 - lang = locale.getdefaultlocale()[0] - for key, val in lang_list: - liststore.insert(i, (val, key)) - if key == lang: - index = i - 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() @@ -1192,54 +1149,6 @@ def generateColorscheme(masterColor, keys, light=0.1): s, (v + light * i) % 1) for i, key in enumerate(keys)} -class DBProgress(object): - - def __init__(self, host, port): - self.dbs = None, None - self.host, self.port = host, port - self.updated = threading.Event() - - def start(self): - dbs = None - try: - dbs = refresh_dblist(self.host, self.port) - except Exception: - pass - finally: - self.dbs = dbs - self.updated.set() - - def update(self, combo, progressbar, callback, dbname=''): - self.db_info = None - threading.Thread(target=self.start).start() - gobject.timeout_add(100, self.end, combo, progressbar, callback, - dbname) - - def end(self, combo, progressbar, callback, dbname): - if not self.updated.isSet(): - progressbar.show() - progressbar.pulse() - return True - progressbar.hide() - dbs = self.dbs - - if dbs is not None and dbs not in (-1, -2): - liststore = combo.get_model() - liststore.clear() - index = -1 - for db_num, db_name in enumerate(dbs): - liststore.append([db_name]) - if db_name == dbname: - index = db_num - if index == -1: - index = 0 - combo.set_active(index) - dbs = len(dbs) - - callback(dbs) - return False - - class RPCException(Exception): def __init__(self, exception): diff --git a/tryton/gui/main.py b/tryton/gui/main.py index 8e72521373..39c051e5e1 100644 --- a/tryton/gui/main.py +++ b/tryton/gui/main.py @@ -29,19 +29,15 @@ from tryton.gui.window.preference import Preference from tryton.gui.window import Limit from tryton.gui.window import Email from tryton.gui.window.dblogin import DBLogin -from tryton.gui.window.dbcreate import DBCreate -from tryton.gui.window.dbdumpdrop import DBBackupDrop 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 from tryton.common.cellrendererclickablepixbuf import \ CellRendererClickablePixbuf import tryton.translate as translate import tryton.plugins from tryton.common.placeholder_entry import PlaceholderEntry import pango -import time if os.environ.get('GTKOSXAPPLICATION'): import gtkosx_application else: @@ -215,13 +211,13 @@ class Main(object): self.vbox.pack_start(menubar, False, True) self.vbox.reorder_child(menubar, 0) - menuitem_file = gtk.MenuItem(_('_File')) - menubar.add(menuitem_file) + menuitem_connection = gtk.MenuItem(_('_Connection')) + menubar.add(menuitem_connection) - menu_file = self._set_menu_file() - menuitem_file.set_submenu(menu_file) - menu_file.set_accel_group(self.accel_group) - menu_file.set_accel_path('/File') + menu_connection = self._set_menu_connection() + menuitem_connection.set_submenu(menu_connection) + menu_connection.set_accel_group(self.accel_group) + menu_connection.set_accel_path('/Connection') menuitem_user = gtk.MenuItem(_('_User')) if self.menuitem_user: @@ -273,7 +269,7 @@ class Main(object): self.menubar.set_no_show_all(True) self.macapp.set_menu_bar(self.menubar) self.macapp.insert_app_menu_item(self.aboutitem, 0) - menuitem_file.show_all() + menuitem_connection.show_all() menuitem_user.show_all() menuitem_options.show_all() menuitem_favorite.show_all() @@ -389,8 +385,8 @@ class Main(object): title += ' - ' + value self.window.set_title(title) - def _set_menu_file(self): - menu_file = gtk.Menu() + def _set_menu_connection(self): + menu_connection = gtk.Menu() imagemenuitem_connect = gtk.ImageMenuItem(_('_Connect...'), self.accel_group) @@ -398,65 +394,17 @@ class Main(object): image.set_from_stock('tryton-connect', gtk.ICON_SIZE_MENU) imagemenuitem_connect.set_image(image) imagemenuitem_connect.connect('activate', self.sig_login) - imagemenuitem_connect.set_accel_path('/File/Connect') - menu_file.add(imagemenuitem_connect) + imagemenuitem_connect.set_accel_path('/Connection/Connect') + menu_connection.add(imagemenuitem_connect) imagemenuitem_disconnect = gtk.ImageMenuItem(_('_Disconnect')) image = gtk.Image() image.set_from_stock('tryton-disconnect', gtk.ICON_SIZE_MENU) imagemenuitem_disconnect.set_image(image) imagemenuitem_disconnect.connect('activate', self.sig_logout) - imagemenuitem_disconnect.set_accel_path('/File/Disconnect') - menu_file.add(imagemenuitem_disconnect) - - menu_file.add(gtk.SeparatorMenuItem()) - - imagemenuitem_database = gtk.ImageMenuItem(_('Data_base')) - image = gtk.Image() - image.set_from_stock('tryton-system-file-manager', gtk.ICON_SIZE_MENU) - imagemenuitem_database.set_image(image) - menu_file.add(imagemenuitem_database) - - menu_database = gtk.Menu() - menu_database.set_accel_group(self.accel_group) - menu_database.set_accel_path('/File/Database') - imagemenuitem_database.set_submenu(menu_database) - - imagemenuitem_db_new = gtk.ImageMenuItem(_('_New Database...')) - image = gtk.Image() - 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') - menu_database.add(imagemenuitem_db_new) - - imagemenuitem_db_restore = gtk.ImageMenuItem(_('_Restore Database...')) - image = gtk.Image() - 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') - menu_database.add(imagemenuitem_db_restore) - - imagemenuitem_db_dump = gtk.ImageMenuItem(_('_Backup Database...')) - image = gtk.Image() - 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') - menu_database.add(imagemenuitem_db_dump) - - imagemenuitem_db_drop = gtk.ImageMenuItem(_('Dro_p Database...')) - image = gtk.Image() - 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') - menu_database.add(imagemenuitem_db_drop) + imagemenuitem_disconnect.set_accel_path( + '/Connection/Disconnect') + menu_connection.add(imagemenuitem_disconnect) imagemenuitem_close = gtk.ImageMenuItem(_('_Quit...'), self.accel_group) @@ -464,11 +412,11 @@ class Main(object): image.set_from_stock('tryton-log-out', gtk.ICON_SIZE_MENU) imagemenuitem_close.set_image(image) imagemenuitem_close.connect('activate', self.sig_close) - imagemenuitem_close.set_accel_path('/File/Quit') + imagemenuitem_close.set_accel_path('/Connection/Quit') if self.macapp is None: - menu_file.add(gtk.SeparatorMenuItem()) - menu_file.add(imagemenuitem_close) - return menu_file + menu_connection.add(gtk.SeparatorMenuItem()) + menu_connection.add(imagemenuitem_close) + return menu_connection def _set_menu_user(self): menu_user = gtk.Menu() @@ -1270,130 +1218,6 @@ class Main(object): for dialog in current_form.dialogs: dialog.show() - def sig_db_new(self, widget): - if not self.sig_logout(widget): - return False - dia = DBCreate(CONFIG['login.server'], int(CONFIG['login.port']), - sig_login=self.sig_login) - res = dia.run() - if res: - CONFIG.save() - return res - - def sig_db_drop(self, widget=None): - if not self.sig_logout(widget): - return False - url, dbname, passwd = DBBackupDrop(function='drop').run() - if not dbname: - rpc.logout() - return - - host, port = url.rsplit(':', 1) - sure = common.sur_3b(_("You are going to delete a Tryton " - "database.\nAre you really sure to proceed?")) - if sure == "ko" or sure == "cancel": - return - rpcprogress = common.RPCProgress('db_exec', (host, int(port), 'drop', - dbname, passwd)) - try: - rpcprogress.run(False) - except TrytonServerError, exception: - if exception.faultCode == "AccessDenied": - common.warning(_("Wrong Tryton Server Password\n" - "Please try again."), - _('Access denied!')) - self.sig_db_drop() - else: - common.warning(_('Database drop failed with error message:\n') - + str(exception.faultCode), _('Database drop failed!')) - return - common.message(_("Database dropped successfully!")) - - def sig_db_restore(self, widget=None): - if not self.sig_logout(widget): - return False - filename = common.file_selection(_('Open Backup File to Restore...'), - preview=False) - if not filename: - return - dialog = DBRestore(filename=filename) - url, dbname, passwd, update = dialog.run() - if dbname: - with open(filename, 'rb') as file_p: - data = file_p.read() - host, port = url.rsplit(':', 1) - cast = bytearray if bytes == str else bytes - rpcprogress = common.RPCProgress('db_exec', (host, int(port), - 'restore', dbname, passwd, cast(data), update)) - try: - res = rpcprogress.run(False) - except TrytonServerError, exception: - if exception.faultCode == \ - "Couldn't restore database with password": - common.warning(_("It is not possible to restore a " - "password protected database.\n" - "Backup and restore needed to be proceed " - "manual."), - _('Database is password protected!')) - elif exception.faultCode == "AccessDenied": - common.warning(_("Wrong Tryton Server Password.\n" - "Please try again."), - _('Access denied!')) - self.sig_db_restore() - else: - common.warning(_('Database restore failed with ' - 'error message:\n') + str(exception.faultCode), - _('Database restore failed!')) - return - if res: - common.message(_("Database restored successfully!")) - else: - common.message(_('Database restore failed!')) - - def sig_db_dump(self, widget=None): - if not self.sig_logout(widget): - return False - dialog = DBBackupDrop(function='backup') - url, dbname, passwd = dialog.run() - - if not (dbname and url and passwd): - rpc.logout() - return - - host, port = url.rsplit(':', 1) - rpcprogress = common.RPCProgress('db_exec', (host, int(port), 'dump', - dbname, passwd)) - try: - dump = rpcprogress.run(False) - except TrytonServerError, exception: - if exception.faultCode == "Couldn't dump database with password": - common.warning(_("It is not possible to dump a password " - "protected Database.\nBackup and restore " - "needed to be proceed manual."), - _('Database is password protected!')) - elif exception.faultCode == "AccessDenied": - common.warning(_("Wrong Tryton Server Password.\n" - "Please try again."), - _('Access denied!')) - self.sig_db_dump() - else: - common.warning(_('Database dump failed with ' - 'error message:\n') + str(exception.faultCode), - _('Database dump failed!')) - rpc.logout() - return - - filename = common.file_selection(_('Save As...'), - action=gtk.FILE_CHOOSER_ACTION_SAVE, preview=False, - filename=dbname + '-' + time.strftime('%Y%m%d%H%M') + '.dump') - - if filename: - with open(filename, 'wb') as file_: - file_.write(dump) - common.message(_("Database backuped successfully!")) - else: - rpc.logout() - def _open_url(self, url): urlp = urlparse(url) if not urlp.scheme == 'tryton': diff --git a/tryton/gui/window/dbcreate.py b/tryton/gui/window/dbcreate.py deleted file mode 100644 index 1f7617843e..0000000000 --- a/tryton/gui/window/dbcreate.py +++ /dev/null @@ -1,392 +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. -import gtk -import gobject -import gettext - -import tryton.common as common -from tryton.config import CONFIG, TRYTON_ICON -from tryton.exceptions import TrytonServerError -import tryton.rpc as rpc - -_ = gettext.gettext - - -class DBCreate(object): - def server_connection_state(self, state): - """ - Method to set the server connection information depending on the - connection state. If state is True, the connection string will shown. - Otherwise the wrong connection string will be shown plus an additional - errormessage. In this case, all entryboxes set insensitive - """ - if state: - self.entry_serverpasswd.set_sensitive(True) - self.entry_dbname.set_sensitive(True) - self.entry_adminpasswd.set_sensitive(True) - self.entry_adminpasswd2.set_sensitive(True) - 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) - self.entry_adminpasswd.set_sensitive(False) - self.entry_adminpasswd2.set_sensitive(False) - self.entry_server_connection.set_editable(False) - self.entry_server_connection.set_sensitive(False) - self.entry_server_connection.set_text( - self.entry_server_connection.get_text() - + " " + _("No connection!")) - self.tooltips.set_tip(self.entry_server_connection, _( - "Can not connect to the server!\n" - "1. Try to check if the server is running.\n" - "2. Find out on which address and port it is listening.\n" - "3. If there is a firewall between the server and this " - "client, make sure that the server address and port " - "(usually 8000) are not blocked.\n" - "Click on 'Change' to change the address.")) - return state - - def server_change(self, widget): - """ - This method checks the server connection via host and port. If the - connection is successfull, it query the language list and pass true - state to the GUI. Otherwise it pass false state to the GUI. - """ - res = common.request_server(self.entry_server_connection) - if not res: - return False - host, port = res - try: - if self.combo_language and host and port: - common.refresh_langlist(self.combo_language, host, port) - self.server_connection_state(True) - except TrytonServerError: - self.server_connection_state(False) - return False - return True - - def event_passwd_clear(self, widget, event, data=None): - """ - This event method clear the text in a widget if CTRL-u - is pressed. - """ - if ((event.keyval == gtk.keysyms.u) - and (event.state & gtk.gdk.CONTROL_MASK)): - widget.set_text("") - - def event_show_button_create(self, widget, event, data=None): - """ - This event method decide by rules if the Create button will be - sensitive or insensitive. The general rule is, all given fields - 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() != ""): - widget.unset_flags(gtk.HAS_DEFAULT) - self.button_create.set_sensitive(True) - self.button_create.set_flags(gtk.CAN_DEFAULT) - self.button_create.set_flags(gtk.HAS_DEFAULT) - self.button_create.set_flags(gtk.CAN_FOCUS) - self.button_create.set_flags(gtk.RECEIVES_DEFAULT) - self.button_create.grab_default() - - else: - self.button_create.set_sensitive(False) - - def entry_insert_text(self, entry, new_text, new_text_length, position): - """ - This event method checks each text input for the PostgreSQL - database name. It allows the following rules: - - Allowed characters are alpha-nummeric [A-Za-z0-9] and underscore (_) - - First character must be a letter - """ - - if new_text.isalnum() or new_text == '_': - _hid = entry.get_data('handlerid') - entry.handler_block(_hid) - _pos = entry.get_position() - _pos = entry.insert_text(new_text, _pos) - entry.handler_unblock(_hid) - - def _move_cursor(): - if not entry.props.window: - return - with gtk.gdk.lock: - entry.set_position(_pos) - return False - gobject.idle_add(_move_cursor) - entry.stop_emission("insert-text") - - def __init__(self, host=None, port=None, sig_login=None): - self.host = host - 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.set_has_separator(True) - self.dialog.set_icon(TRYTON_ICON) - # This event is needed for controlling the button_create - self.dialog.connect("key-press-event", self.event_show_button_create) - self.tooltips = common.Tooltips() - self.dialog.add_button("gtk-cancel", - gtk.RESPONSE_CANCEL) - self.button_create = gtk.Button(_('C_reate')) - self.button_create.set_flags(gtk.CAN_DEFAULT) - self.button_create.set_flags(gtk.HAS_DEFAULT) - self.button_create.set_sensitive(False) - 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.dialog.add_action_widget(self.button_create, gtk.RESPONSE_OK) - self.dialog.set_default_response(gtk.RESPONSE_OK) - - dialog_vbox = gtk.VBox() - table = gtk.Table(9, 3, False) - table.set_border_width(10) - table.set_row_spacings(3) - table.set_col_spacings(3) - - self.label_server_setup = gtk.Label() - 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) - 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) - self.label_server.set_padding(3, 3) - table.attach(self.label_server, 0, 1, 1, 2, xoptions=gtk.FILL) - self.entry_server_connection = gtk.Entry() - self.entry_server_connection.set_sensitive(False) - self.entry_server_connection.unset_flags(gtk.CAN_FOCUS) - self.entry_server_connection.set_editable(False) - self.label_server.set_mnemonic_widget(self.entry_server_connection) - 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', - 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.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) - table.attach(self.label_serverpasswd, 0, 1, 2, 3, xoptions=gtk.FILL, - yoptions=gtk.FILL) - self.entry_serverpasswd = gtk.Entry() - self.entry_serverpasswd.set_visibility(False) - self.entry_serverpasswd.set_activates_default(True) - self.label_serverpasswd.set_mnemonic_widget(self.entry_serverpasswd) - table.attach(self.entry_serverpasswd, 1, 3, 2, 3, yoptions=gtk.FILL) - self.tooltips.set_tip(self.entry_serverpasswd, _("This is the " - "password of the Tryton server. It doesn't belong to a " - "real user. This password is usually defined in the trytond " - "configuration.")) - self.entry_serverpasswd.connect("key-press-event", - self.event_passwd_clear) - - self.hseparator = gtk.HSeparator() - 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_justify(gtk.JUSTIFY_LEFT) - label_dbname.set_alignment(0, 1) - 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_alignment(1, 0.5) - table.attach(label_dbname, 0, 1, 5, 6, xoptions=gtk.FILL, - yoptions=gtk.FILL) - self.entry_dbname = gtk.Entry() - self.entry_dbname.set_max_length(63) - self.entry_dbname.set_width_chars(16) - self.entry_dbname.set_activates_default(True) - label_dbname.set_mnemonic_widget(self.entry_dbname) - 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.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) - table.attach(label_language, 0, 1, 6, 7, xoptions=gtk.FILL, - yoptions=gtk.FILL) - eventbox_language = gtk.EventBox() - self.combo_language = gtk.combo_box_new_text() - eventbox_language.add(self.combo_language) - table.attach(eventbox_language, 1, 3, 6, 7, yoptions=gtk.FILL) - self.tooltips.set_tip(eventbox_language, _("Choose the default " - "language that will be installed for this database. You will " - "be able to install new languages after installation through " - "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_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) - label_adminpasswd.set_mnemonic_widget(self.entry_adminpasswd) - 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_alignment(1, 0.5) - table.attach(label_adminpasswd2, 0, 1, 8, 9, xoptions=gtk.FILL, - yoptions=gtk.FILL) - self.entry_adminpasswd2 = gtk.Entry() - self.entry_adminpasswd2.set_visibility(False) - self.entry_adminpasswd2.set_activates_default(True) - label_adminpasswd2.set_mnemonic_widget(self.entry_adminpasswd2) - self.tooltips.set_tip(self.entry_adminpasswd2, _("Type the Admin " - "password again")) - table.attach(self.entry_adminpasswd2, 1, 3, 8, 9, yoptions=gtk.FILL) - self.entry_adminpasswd2.connect("key-press-event", - self.event_passwd_clear) - self.entry_serverpasswd.grab_focus() - dialog_vbox.pack_start(table) - self.dialog.vbox.pack_start(dialog_vbox) - self.sig_login = sig_login - - def run(self): - parent = common.get_toplevel_window() - self.dialog.set_default_response(gtk.RESPONSE_OK) - self.dialog.set_transient_for(parent) - self.dialog.show_all() - - pass_widget = self.entry_serverpasswd - change_button = self.button_server_change - admin_passwd = self.entry_adminpasswd - admin_passwd2 = self.entry_adminpasswd2 - change_button.connect_after('clicked', self.server_change) - - if self.host and self.port: - url = '%s:%d' % (self.host, self.port) - else: - url = '' - self.entry_server_connection.set_text(url) - - liststore = gtk.ListStore(str, str) - self.combo_language.set_model(liststore) - try: - common.refresh_langlist(self.combo_language, self.host, self.port) - except TrytonServerError: - self.button_create.set_sensitive(False) - - while True: - self.dialog.props.sensitive = True - res = self.dialog.run() - dbname = self.entry_dbname.get_text() - netloc = self.entry_server_connection.get_text() - host = common.get_hostname(netloc) - port = common.get_port(netloc) - langidx = self.combo_language.get_active_iter() - langreal = langidx \ - and self.combo_language.get_model().get_value(langidx, 1) - passwd = pass_widget.get_text() - if res == gtk.RESPONSE_OK: - if admin_passwd.get_text() != admin_passwd2.get_text(): - common.warning( - _("The new admin password " - "doesn't match the confirmation field.\n"), - _("Passwords doesn't match!")) - continue - try: - exist = rpc.db_exec(host, port, 'db_exist', dbname) - except TrytonServerError, exception: - 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 - self.dialog.props.sensitive = False - try: - rpcprogress = common.RPCProgress('db_exec', - (host, port, 'create', dbname, passwd, langreal, - admin_passwd.get_text())) - rpcprogress.run(False) - except TrytonServerError, exception: - if str(exception.faultCode) == "AccessDenied": - common.warning(_("Sorry, wrong password for " - "the Tryton server. " - "Please try again."), - _("Access denied!")) - 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" - "Error message:\n") - + str(exception.faultCode), - _("Error creating database!")) - parent.present() - self.dialog.destroy() - rpc.logout() - break - parent.present() - self.dialog.destroy() - if self.sig_login: - CONFIG['login.server'] = host - CONFIG['login.port'] = str(port) - CONFIG['login.db'] = dbname - CONFIG['login.login'] = 'admin' - self.sig_login() - break - break - parent.present() - self.dialog.destroy() - return dbname diff --git a/tryton/gui/window/dbdumpdrop.py b/tryton/gui/window/dbdumpdrop.py deleted file mode 100644 index 60a97484ce..0000000000 --- a/tryton/gui/window/dbdumpdrop.py +++ /dev/null @@ -1,240 +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. -import gtk -import gobject -import gettext -import tryton.common as common -from tryton.config import CONFIG, TRYTON_ICON -import tryton.rpc as rpc - -_ = gettext.gettext - - -class DBBackupDrop(object): - """ - Widget for database backup and drop. - """ - def refreshlist(self, host, port): - self.combo_database.hide() - self.combo_database_label.hide() - self.combo_database_entry.hide() - dbprogress = common.DBProgress(host, port) - - def callback(dbs): - if dbs is None: - self.combo_database_label.set_label('' + - _('Could not connect to server!') + '') - self.combo_database_label.show() - elif dbs == -1: - self.combo_database_label.set_label('' + - _('This client version is not compatible ' - 'with the server!') - + '') - self.combo_database_label.show() - elif dbs == -2: - self.combo_database_entry.show() - self.combo_database_entry.grab_focus() - elif dbs == 0: - self.combo_database_label.set_label('' - + _('No database found, you must create one!') + '') - self.combo_database_label.show() - else: - self.combo_database.show() - dbprogress.update(self.combo_database, self.db_progressbar, callback) - - def refreshlist_ask(self, widget=None): - res = common.request_server(self.entry_server_connection) - if not res: - return None - host, port = res - self.refreshlist(host, port) - return (host, port) - - def event_show_button_ok(self, widget, event, data=None): - """ - This event method decide by rules if the Create button will be - sensitive or insensitive. The general rule is, all given fields - 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() != "" - or self.combo_database_entry.get_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) - self.button_ok.set_flags(gtk.HAS_DEFAULT) - self.button_ok.set_flags(gtk.CAN_FOCUS) - self.button_ok.set_flags(gtk.RECEIVES_DEFAULT) - self.button_ok.grab_default() - else: - self.button_ok.set_sensitive(False) - - def __init__(self, function=None): - # This widget is used for creating and droping a database! - if function == "backup": - dialog_title = _("Backup a database") - button_ok_text = _("Backup") - button_ok_tooltip = _("Backup the choosen database.") - button_ok_icon = "tryton-save-as" - label_subtitle_text = _("Choose a Tryton database to backup:") - elif function == "drop": - dialog_title = _("Delete a database") - button_ok_text = _("Delete") - button_ok_tooltip = _("Delete the choosen database.") - button_ok_icon = "tryton-delete" - label_subtitle_text = _("Choose a Tryton database to delete:") - else: - return None - - self.parent = common.get_toplevel_window() - self.dialog = gtk.Dialog(title=dialog_title, parent=self.parent, - 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) - self.dialog.connect("key-press-event", self.event_show_button_ok) - self.tooltips = common.Tooltips() - self.dialog.add_button("gtk-cancel", - gtk.RESPONSE_CANCEL) - self.button_ok = gtk.Button(button_ok_text) - self.button_ok.set_flags(gtk.CAN_DEFAULT) - self.button_ok.set_flags(gtk.HAS_DEFAULT) - self.button_ok.set_sensitive(False) - img_connect = gtk.Image() - img_connect.set_from_stock(button_ok_icon, gtk.ICON_SIZE_BUTTON) - self.button_ok.set_image(img_connect) - self.tooltips.set_tip(self.button_ok, button_ok_tooltip) - self.dialog.add_action_widget(self.button_ok, gtk.RESPONSE_OK) - self.dialog.set_default_response(gtk.RESPONSE_OK) - self.dialog_vbox = gtk.VBox() - - table = gtk.Table(5, 3, False) - table.set_border_width(10) - table.set_row_spacings(3) - table.set_col_spacings(3) - self.dialog_vbox.pack_start(table, True, False, 0) - - label_subtitle = gtk.Label() - 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) - - hseparator = gtk.HSeparator() - table.attach(hseparator, 0, 3, 1, 2, yoptions=False) - - self.label_server = gtk.Label(_("Server Connection:")) - self.label_server.set_alignment(1, 0.5) - self.label_server.set_padding(3, 3) - table.attach(self.label_server, 0, 1, 2, 3, yoptions=False, - xoptions=gtk.FILL) - - self.entry_server_connection = gtk.Entry() - self.entry_server_connection.set_sensitive(False) - self.entry_server_connection.unset_flags(gtk.CAN_FOCUS) - self.entry_server_connection.set_editable(False) - self.label_server.set_mnemonic_widget(self.entry_server_connection) - 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.")) - table.attach(self.entry_server_connection, 1, 2, 2, 3, - yoptions=gtk.FILL) - - 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', - gtk.ICON_SIZE_BUTTON) - self.button_server_change.set_image(img_button_server_change) - table.attach(self.button_server_change, 2, 3, 2, 3, yoptions=False) - - self.label_database = gtk.Label() - self.label_database.set_text(_("Database:")) - self.label_database.set_alignment(1, 0.5) - self.label_database.set_padding(3, 3) - table.attach(self.label_database, 0, 1, 3, 4, yoptions=False, - xoptions=gtk.FILL) - - vbox_combo = gtk.VBox(homogeneous=True) - self.combo_database = gtk.ComboBox() - dbstore = gtk.ListStore(gobject.TYPE_STRING) - cell = gtk.CellRendererText() - self.combo_database.pack_start(cell, True) - self.combo_database.add_attribute(cell, 'text', 0) - self.combo_database.set_model(dbstore) - self.db_progressbar = gtk.ProgressBar() - self.combo_database_label = gtk.Label() - self.combo_database_label.set_use_markup(True) - self.combo_database_label.set_alignment(0, 1) - self.combo_database_entry = gtk.Entry() - vbox_combo.pack_start(self.combo_database) - vbox_combo.pack_start(self.combo_database_label) - vbox_combo.pack_start(self.db_progressbar) - vbox_combo.pack_start(self.combo_database_entry) - width, height = 0, 0 - # Compute size_request of box in order to prevent "form jumping" - for child in vbox_combo.get_children(): - cwidth, cheight = child.size_request() - width, height = max(width, cwidth), max(height, cheight) - vbox_combo.set_size_request(width, height) - table.attach(vbox_combo, 1, 3, 3, 4, yoptions=False) - - 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) - table.attach(self.label_serverpasswd, 0, 1, 4, 5, yoptions=False, - xoptions=gtk.FILL) - - self.entry_serverpasswd = gtk.Entry() - self.entry_serverpasswd.set_visibility(False) - self.entry_serverpasswd.set_activates_default(True) - self.label_serverpasswd.set_mnemonic_widget(self.entry_serverpasswd) - self.tooltips.set_tip(self.entry_serverpasswd, _("This is the " - "password of the Tryton server. It doesn't belong to a " - "real user. This password is usually defined in the trytond " - "configuration.")) - table.attach(self.entry_serverpasswd, 1, 3, 4, 5, yoptions=False) - - self.entry_serverpasswd.grab_focus() - self.dialog.vbox.pack_start(self.dialog_vbox) - - def run(self): - self.dialog.set_default_response(gtk.RESPONSE_OK) - self.dialog.show_all() - - self.entry_server_connection.set_text( - '%(login.server)s:%(login.port)s' % CONFIG) - self.refreshlist(CONFIG['login.server'], CONFIG['login.port']) - - self.button_server_change.connect_after('clicked', - self.refreshlist_ask) - - while True: - database = False - url = False - passwd = False - res = self.dialog.run() - if res == gtk.RESPONSE_OK: - if self.combo_database.get_visible(): - database = self.combo_database.get_active_text() - elif self.combo_database_entry.get_visible(): - database = self.combo_database_entry.get_text() - else: - continue - url = self.entry_server_connection.get_text() - passwd = self.entry_serverpasswd.get_text() - break - if res != gtk.RESPONSE_OK: - self.dialog.destroy() - rpc.logout() - break - self.parent.present() - self.dialog.destroy() - - return (url, database, passwd) diff --git a/tryton/gui/window/dblogin.py b/tryton/gui/window/dblogin.py index 349407ce23..b77e610e2f 100644 --- a/tryton/gui/window/dblogin.py +++ b/tryton/gui/window/dblogin.py @@ -6,12 +6,12 @@ import gtk import gobject import os import gettext +import threading from tryton import __version__ import tryton.common as common from tryton.config import CONFIG, TRYTON_ICON, PIXMAPS_DIR, get_config_dir import tryton.rpc as rpc -from tryton.gui.window.dbcreate import DBCreate from tryton.exceptions import TrytonError _ = gettext.gettext @@ -95,18 +95,14 @@ class DBListEditor(object): self.database_combo.add_attribute(cell, 'text', 0) self.database_combo.set_model(dbstore) 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.set_text(_(u'Fetching databases list')) image = gtk.Image() image.set_from_stock('tryton-new', gtk.ICON_SIZE_BUTTON) - self.database_button.set_image(image) db_box = gtk.VBox(homogeneous=True) db_box.pack_start(self.database_entry) db_box.pack_start(self.database_combo) db_box.pack_start(self.database_label) - db_box.pack_start(self.database_button) db_box.pack_start(self.database_progressbar) # Compute size_request of box in order to prevent "form jumping" width, height = 0, 0 @@ -177,7 +173,6 @@ class DBListEditor(object): self.database_entry.hide() self.database_combo.hide() self.database_label.hide() - self.database_button.hide() self.database_progressbar.hide() def profile_create(self, button): @@ -219,7 +214,7 @@ class DBListEditor(object): if field == 'database': self.current_database = entry_value - self.display_dbwidget(None, None, self.current_database) + self.display_dbwidget(None, None) def edit_started(self, renderer, editable, path): if isinstance(editable, gtk.Entry): @@ -266,7 +261,74 @@ class DBListEditor(object): for option in ('host', 'database')) model[selection][1] = active - def display_dbwidget(self, entry, event, dbname=None): + @classmethod + def test_server_version(cls, host, port): + ''' + Tests if the server version is compatible with the client version + ''' + version = rpc.server_version(host, port) + if not version: + return False + return version.split('.')[:2] == __version__.split('.')[:2] + + def refresh_databases(self, host, port): + self.dbs_updated = threading.Event() + threading.Thread(target=self.refresh_databases_start, + args=(host, port)).start() + gobject.timeout_add(100, self.refresh_databases_end, host, port) + + def refresh_databases_start(self, host, port): + dbs = None + try: + dbs = rpc.db_list(host, port) + except Exception: + pass + finally: + self.dbs = dbs + self.dbs_updated.set() + + def refresh_databases_end(self, host, port): + if not self.dbs_updated.isSet(): + self.database_progressbar.show() + self.database_progressbar.pulse() + return True + self.database_progressbar.hide() + dbs = self.dbs + + label = None + if not self.test_server_version(host, port): + label = _(u'Incompatible version of the server') + elif dbs is None: + label = _(u'Could not connect to the server') + if label: + self.database_label.set_label('%s' % label) + self.database_label.show() + else: + liststore = self.database_combo.get_model() + liststore.clear() + index = -1 + for db_num, db_name in enumerate(dbs): + liststore.append([db_name]) + if self.current_database and db_name == self.current_database: + index = db_num + if index == -1: + index = 0 + self.database_combo.set_active(index) + dbs = len(dbs) + self.database_entry.set_text(self.current_database + if self.current_database else '') + self.database_combo.show() + self.db_cache = (host, port, self.current_profile['name']) + + self.add_button.set_sensitive(True) + self.remove_button.set_sensitive(True) + self.ok_button.set_sensitive(True) + self.cell.set_property('editable', True) + self.host_entry.set_sensitive(True) + self.updating_db = False + return False + + def display_dbwidget(self, entry, event): netloc = self.host_entry.get_text() host = common.get_hostname(netloc) if not host: @@ -276,10 +338,7 @@ class DBListEditor(object): return if self.updating_db: return - if dbname is None: - dbname = self.current_database - dbprogress = common.DBProgress(host, port) self.hide_database_info() self.add_button.set_sensitive(False) self.remove_button.set_sensitive(False) @@ -287,46 +346,7 @@ class DBListEditor(object): self.cell.set_property('editable', False) self.host_entry.set_sensitive(False) self.updating_db = True - - def callback(dbs): - self.updating_db = False - self.db_cache = (host, port, self.current_profile['name']) - - if dbs is None or dbs == -1: - if dbs is None: - label = _(u'Could not connect to the server') - else: - label = _(u'Incompatible version of the server') - self.database_label.set_label('%s' % label) - self.database_label.show() - elif dbs == 0: - self.database_button.show() - elif dbs == -2: - self.database_entry.show() - else: - self.database_entry.set_text(dbname if dbname else '') - self.database_combo.show() - - self.add_button.set_sensitive(True) - self.remove_button.set_sensitive(True) - self.ok_button.set_sensitive(True) - self.cell.set_property('editable', True) - self.host_entry.set_sensitive(True) - - dbprogress.update(self.database_combo, - self.database_progressbar, callback, dbname) - - def db_create(self, button): - if not self.current_profile['name']: - return - netloc = self.host_entry.get_text() - host = common.get_hostname(netloc) - port = common.get_port(netloc) - dia = DBCreate(host, port) - dbname = dia.run() - self.db_cache = None - self.username_entry.set_text('admin') - self.display_dbwidget(None, None, dbname) + self.refresh_databases(host, port) def dbcombo_changed(self, combobox): dbname = combobox.get_active_text() @@ -583,7 +603,7 @@ class DBLogin(object): host = common.get_hostname(netloc) port = common.get_port(netloc) try: - if not common.test_server_version(host, port): + if not DBListEditor.test_server_version(host, port): common.warning('', _(u'Incompatible version of the server')) continue diff --git a/tryton/gui/window/dbrestore.py b/tryton/gui/window/dbrestore.py deleted file mode 100644 index 12fe330de4..0000000000 --- a/tryton/gui/window/dbrestore.py +++ /dev/null @@ -1,207 +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. - -import gtk -import gobject -import gettext -import tryton.common as common -from tryton.config import CONFIG -import tryton.rpc as rpc - -_ = gettext.gettext - - -class DBRestore(object): - def event_show_button_restore(self, widget, event, data=None): - """ - This event method decide by rules if the restore button will be - sensitive or insensitive. The general rule is, all given fields - 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() != ""): - widget.unset_flags(gtk.HAS_DEFAULT) - self.button_restore.set_sensitive(True) - self.button_restore.set_flags(gtk.CAN_DEFAULT) - self.button_restore.set_flags(gtk.HAS_DEFAULT) - self.button_restore.set_flags(gtk.CAN_FOCUS) - self.button_restore.set_flags(gtk.RECEIVES_DEFAULT) - self.button_restore.grab_default() - else: - self.button_restore.set_sensitive(False) - - def entry_insert_text(self, entry, new_text, new_text_length, position): - """ - This event method checks each text input for the PostgreSQL - database name. It allows the following rules: - - Allowed characters are alpha-nummeric [A-Za-z0-9] and underscore (_) - - First character must be a letter - """ - if new_text.isalnum() or new_text == '_': - _hid = entry.get_data('handlerid') - entry.handler_block(_hid) - _pos = entry.get_position() - if _pos == 0 and not new_text.isalpha(): - new_text = "" - _pos = entry.insert_text(new_text, _pos) - entry.handler_unblock(_hid) - - def _move_cursor(): - if not entry.props.window: - return - with gtk.gdk.lock: - entry.set_position(_pos) - return False - gobject.idle_add(_move_cursor) - entry.stop_emission("insert-text") - - def __init__(self, filename=None): - """ - Database restore widget - """ - self.parent = common.get_toplevel_window() - self.dialog = gtk.Dialog(title=_("Restore Database"), - parent=self.parent, flags=gtk.DIALOG_MODAL - | gtk.WIN_POS_CENTER_ON_PARENT) - vbox = gtk.VBox() - self.dialog.vbox.pack_start(vbox) - self.tooltips = common.Tooltips() - table = gtk.Table(6, 3, False) - table.set_border_width(9) - table.set_row_spacings(3) - table.set_col_spacings(3) - vbox.pack_start(table) - self.label_server_url = gtk.Label(_("Server Connection:")) - self.label_server_url.set_size_request(117, -1) - self.label_server_url.set_alignment(1, 0.5) - self.label_server_url.set_padding(3, 3) - table.attach(self.label_server_url, 0, 1, 0, 1, yoptions=gtk.FILL) - self.entry_server_url = gtk.Entry() - self.entry_server_url.set_sensitive(False) - self.entry_server_url.unset_flags(gtk.CAN_FOCUS) - self.entry_server_url.set_editable(False) - self.entry_server_url.set_activates_default(True) - self.entry_server_url.set_width_chars(16) - self.label_server_url.set_mnemonic_widget(self.entry_server_url) - self.tooltips.set_tip(self.entry_server_url, _("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.")) - table.attach(self.entry_server_url, 1, 2, 0, 1, yoptions=gtk.FILL) - 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', gtk.ICON_SIZE_BUTTON) - self.button_server_change.set_image(img_button_server_change) - self.tooltips.set_tip(self.button_server_change, _("Setup the " - "server connection...")) - table.attach(self.button_server_change, 2, 3, 0, 1, yoptions=gtk.FILL) - self.label_server_password = gtk.Label(_("Tryton Server Password:")) - self.label_server_password.set_justify(gtk.JUSTIFY_RIGHT) - self.label_server_password.set_alignment(1, 0.5) - self.label_server_password.set_padding(3, 3) - table.attach(self.label_server_password, 0, 1, 1, 2, yoptions=gtk.FILL) - self.entry_server_password = gtk.Entry() - self.entry_server_password.set_visibility(False) - self.entry_server_password.set_activates_default(True) - self.entry_server_password.set_width_chars(16) - self.label_server_password.set_mnemonic_widget( - self.entry_server_password) - self.tooltips.set_tip(self.entry_server_password, _("This is the " - "password of the Tryton server. It doesn't belong to a " - "real user. This password is usually defined in the trytond " - "configuration.")) - table.attach(self.entry_server_password, 1, 3, 1, 2, yoptions=gtk.FILL) - self.hseparator = gtk.HSeparator() - table.attach(self.hseparator, 0, 3, 2, 3, yoptions=gtk.FILL) - label_filename = gtk.Label() - label_filename.set_markup(_("File to Restore:")) - label_filename.set_alignment(1, 0.5) - table.attach(label_filename, 0, 1, 3, 4, yoptions=gtk.FILL) - entry_filename = gtk.Label() - entry_filename.set_markup("" + filename + "") - table.attach(entry_filename, 1, 3, 3, 4, yoptions=gtk.FILL) - self.entry_db_name = gtk.Entry() - self.entry_db_name.set_visibility(True) - self.entry_db_name.set_activates_default(True) - self.entry_db_name.set_width_chars(16) - self.entry_db_name.set_max_length(63) - handlerid = self.entry_db_name.connect("insert-text", - self.entry_insert_text) - self.entry_db_name.set_data('handlerid', handlerid) - self.tooltips.set_tip(self.entry_db_name, _("Choose the name of " - "the database to be restored.\n" - "Allowed characters are alphanumerical or _ (underscore)\n" - "You need to avoid all accents, space or special " - "characters! \nExample: tryton")) - table.attach(self.entry_db_name, 1, 3, 4, 5, yoptions=gtk.FILL) - label_db_name = gtk.Label(_("New Database Name:")) - label_db_name.set_alignment(1, 0.5) - label_db_name.set_mnemonic_widget(self.entry_db_name) - table.attach(label_db_name, 0, 1, 4, 5, yoptions=gtk.FILL) - label_db_update = gtk.Label(_('Update Database:')) - label_db_update.set_alignment(1, 0.5) - table.attach(label_db_update, 0, 1, 5, 6, yoptions=gtk.FILL) - self.check_update = gtk.CheckButton() - label_db_update.set_mnemonic_widget(self.check_update) - self.tooltips.set_tip(self.check_update, _('Check for an automatic ' - 'database update after restoring a database from a previous ' - 'Tryton version.')) - self.check_update.set_active(True) - table.attach(self.check_update, 1, 3, 5, 6, yoptions=gtk.FILL) - # Buttons and events - self.dialog.connect("key-press-event", - self.event_show_button_restore) - self.dialog.add_button("gtk-cancel", - gtk.RESPONSE_CANCEL) - self.button_restore = gtk.Button(_('Restore')) - self.button_restore.set_flags(gtk.CAN_DEFAULT) - self.button_restore.set_flags(gtk.HAS_DEFAULT) - self.button_restore.set_sensitive(False) - img_restore = gtk.Image() - 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.dialog.add_action_widget(self.button_restore, gtk.RESPONSE_OK) - self.dialog.set_default_response(gtk.RESPONSE_OK) - - self.entry_server_password.grab_focus() - - def run(self): - """ - Database Restore widget run part - """ - self.dialog.show_all() - - self.entry_server_url.set_text('%(login.server)s:%(login.port)s' % - CONFIG) - while True: - database = False - passwd = False - url = False - update = False - # TODO: This needs to be unified with the other widgets - self.button_server_change.connect_after('clicked', - lambda a, b: common.request_server(b), - self.entry_server_url) - res = self.dialog.run() - if res == gtk.RESPONSE_OK: - database = self.entry_db_name.get_text() - url = self.entry_server_url.get_text() - passwd = self.entry_server_password.get_text() - update = self.check_update.get_active() - break - else: - self.dialog.destroy() - rpc.logout() - break - self.parent.present() - self.dialog.destroy() - - return url, database, passwd, update diff --git a/tryton/rpc.py b/tryton/rpc.py index bf4c5f4a29..e7ee7a84a8 100644 --- a/tryton/rpc.py +++ b/tryton/rpc.py @@ -42,21 +42,13 @@ def db_list(host, port): return result except Fault, exception: if exception.faultCode == 'AccessDenied': - logging.getLogger(__name__).debug(-2) - return -2 + logging.getLogger(__name__).debug('AccessDenied') + return None else: logging.getLogger(__name__).debug(repr(None)) return None -def db_exec(host, port, method, database='', *args): - connection = ServerProxy(host, port, database=database) - logging.getLogger(__name__).info('common.db.%s(%s)' % (method, args)) - result = getattr(connection.common.db, method)(*args) - logging.getLogger(__name__).debug(repr(result)) - return result - - def server_version(host, port): try: connection = ServerProxy(host, port)