Remove database management

issue5384
review30261003
This commit is contained in:
Sergi Almacellas Abellana
2016-07-07 16:06:30 +02:00
parent 6ddb79e169
commit 2af733f5ce
9 changed files with 104 additions and 1316 deletions
+1
View File
@@ -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
+11 -130
View File
@@ -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.
-91
View File
@@ -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):
+18 -194
View File
@@ -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('<tryton>/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('<tryton>/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('<tryton>/File/Connect')
menu_file.add(imagemenuitem_connect)
imagemenuitem_connect.set_accel_path('<tryton>/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('<tryton>/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('<tryton>/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(
'<tryton>/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(
'<tryton>/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(
'<tryton>/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(
'<tryton>/File/Database/Drop Database')
menu_database.add(imagemenuitem_db_drop)
imagemenuitem_disconnect.set_accel_path(
'<tryton>/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('<tryton>/File/Quit')
imagemenuitem_close.set_accel_path('<tryton>/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':
-392
View File
@@ -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("<b>" + _("Server Setup:") + "</b>")
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("<b>" + _("New database setup:") + "</b>")
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: <The password you set here>"))
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
-240
View File
@@ -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('<b>' +
_('Could not connect to server!') + '</b>')
self.combo_database_label.show()
elif dbs == -1:
self.combo_database_label.set_label('<b>' +
_('This client version is not compatible '
'with the server!')
+ '</b>')
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('<b>'
+ _('No database found, you must create one!') + '</b>')
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("<b>" + label_subtitle_text + "</b>")
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)
+72 -52
View File
@@ -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('<b>%s</b>' % 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('<b>%s</b>' % 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
-207
View File
@@ -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("<tt>" + filename + "</tt>")
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
+2 -10
View File
@@ -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)