Added dbdumpdrop in pygtk, removed glade, modified main.py.

Catch some exceptions, tuned the user guidance more convenient.
Request if the user really want to delete a database.
This commit is contained in:
"Udo Spallek ext:(%22)
2008-10-16 20:18:19 +02:00
parent 10a2aa8769
commit ffa346470e
3 changed files with 269 additions and 300 deletions
-210
View File
@@ -1746,216 +1746,6 @@ Latin1</property>
</widget>
</child>
</widget>
<widget class="GtkDialog" id="win_db_select">
<property name="title" translatable="yes">Choose a Database...</property>
<property name="window_position">GTK_WIN_POS_CENTER_ON_PARENT</property>
<property name="type_hint">GDK_WINDOW_TYPE_HINT_DIALOG</property>
<child internal-child="vbox">
<widget class="GtkVBox" id="dialog-vbox24">
<property name="visible">True</property>
<child>
<widget class="GtkVBox" id="vbox48">
<property name="visible">True</property>
<property name="border_width">3</property>
<property name="spacing">3</property>
<child>
<widget class="GtkLabel" id="db_select_label">
<property name="visible">True</property>
<property name="xalign">0</property>
<property name="label" translatable="yes">&lt;b&gt;Backup a Database&lt;/b&gt;</property>
<property name="use_markup">True</property>
</widget>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
</packing>
</child>
<child>
<widget class="GtkHSeparator" id="hseparator30">
<property name="visible">True</property>
</widget>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">1</property>
</packing>
</child>
<child>
<widget class="GtkTable" id="table19">
<property name="visible">True</property>
<property name="border_width">2</property>
<property name="n_rows">3</property>
<property name="n_columns">3</property>
<property name="column_spacing">3</property>
<property name="row_spacing">3</property>
<child>
<widget class="GtkLabel" id="label286">
<property name="visible">True</property>
<property name="xalign">1</property>
<property name="xpad">3</property>
<property name="ypad">3</property>
<property name="label" translatable="yes">Tryton Server Password:</property>
<property name="justify">GTK_JUSTIFY_RIGHT</property>
</widget>
<packing>
<property name="top_attach">1</property>
<property name="bottom_attach">2</property>
<property name="x_options">GTK_FILL</property>
<property name="y_options"></property>
</packing>
</child>
<child>
<widget class="GtkLabel" id="label282">
<property name="visible">True</property>
<property name="xalign">1</property>
<property name="label" translatable="yes">Database:</property>
</widget>
<packing>
<property name="top_attach">2</property>
<property name="bottom_attach">3</property>
<property name="x_options">GTK_FILL</property>
<property name="y_options"></property>
</packing>
</child>
<child>
<widget class="GtkVBox" id="vbox58">
<property name="visible">True</property>
<child>
<widget class="GtkComboBox" id="combo_db_select">
<property name="visible">True</property>
</widget>
</child>
<child>
<widget class="GtkLabel" id="label_db_select">
<property name="visible">True</property>
<property name="xalign">0</property>
<property name="use_markup">True</property>
</widget>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">1</property>
</packing>
</child>
</widget>
<packing>
<property name="left_attach">1</property>
<property name="right_attach">3</property>
<property name="top_attach">2</property>
<property name="bottom_attach">3</property>
<property name="x_options">GTK_FILL</property>
<property name="y_options">GTK_FILL</property>
</packing>
</child>
<child>
<widget class="GtkEntry" id="ent_passwd_select">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="has_focus">True</property>
<property name="visibility">False</property>
<property name="activates_default">True</property>
<property name="width_chars">16</property>
</widget>
<packing>
<property name="left_attach">1</property>
<property name="right_attach">3</property>
<property name="top_attach">1</property>
<property name="bottom_attach">2</property>
<property name="y_options"></property>
</packing>
</child>
<child>
<widget class="GtkLabel" id="label285">
<property name="width_request">117</property>
<property name="visible">True</property>
<property name="xalign">1</property>
<property name="xpad">3</property>
<property name="ypad">3</property>
<property name="label" translatable="yes">Server:</property>
</widget>
<packing>
<property name="x_options">GTK_FILL</property>
<property name="y_options"></property>
</packing>
</child>
<child>
<widget class="GtkButton" id="but_server_select">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="label" translatable="yes">Change</property>
<property name="response_id">0</property>
<signal name="activate" handler="on_but_server_activate"/>
</widget>
<packing>
<property name="left_attach">2</property>
<property name="right_attach">3</property>
<property name="x_options">GTK_FILL</property>
<property name="y_options"></property>
</packing>
</child>
<child>
<widget class="GtkEntry" id="ent_server_select">
<property name="visible">True</property>
<property name="sensitive">False</property>
<property name="editable">False</property>
<property name="activates_default">True</property>
<property name="width_chars">16</property>
<property name="text">http://localhost:8069</property>
</widget>
<packing>
<property name="left_attach">1</property>
<property name="right_attach">2</property>
<property name="y_options"></property>
</packing>
</child>
</widget>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">2</property>
</packing>
</child>
</widget>
<packing>
<property name="position">2</property>
</packing>
</child>
<child internal-child="action_area">
<widget class="GtkHButtonBox" id="dialog-action_area27">
<property name="visible">True</property>
<property name="layout_style">GTK_BUTTONBOX_END</property>
<child>
<widget class="GtkButton" id="cancelbutton18">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="can_default">True</property>
<property name="label">gtk-cancel</property>
<property name="use_stock">True</property>
<property name="response_id">-6</property>
</widget>
</child>
<child>
<widget class="GtkButton" id="okbutton21">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="can_default">True</property>
<property name="label">gtk-ok</property>
<property name="use_stock">True</property>
<property name="response_id">-5</property>
</widget>
<packing>
<property name="position">1</property>
</packing>
</child>
</widget>
<packing>
<property name="expand">False</property>
<property name="pack_type">GTK_PACK_END</property>
</packing>
</child>
</widget>
</child>
</widget>
<widget class="GtkDialog" id="win_db_ent">
<property name="title" translatable="yes">Restore a Database</property>
<property name="window_position">GTK_WIN_POS_CENTER_ON_PARENT</property>
+44 -90
View File
@@ -14,6 +14,7 @@ from tryton.gui.window.preference import Preference
from tryton.gui.window import FilesActions
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
@@ -1273,24 +1274,35 @@ class Main(object):
def sig_db_drop(self, widget):
if not self.sig_logout(widget):
return False
url, dbname, passwd = self._choose_db_select(_('Delete a database'))
dialog = DBBackupDrop(self.window, function='drop')
url, dbname, passwd = dialog.run(self.window)
if not dbname:
rpc.logout()
Main.get_main().refresh_ssl()
return
host, port = url.rsplit(':', 1)
sure = common.sur_3b(_("You are going to delete a Tryton " \
"database.\nAre you really sure to proceed?"), self.window)
if sure == "ko" or sure == "cancel":
return
try:
rpc.db_exec(host, int(port), 'drop', passwd, dbname)
except Exception, exception:
self.refresh_ssl()
common.warning(_('Database drop failed with '\
'error message:\n') + str(exception[0]), self.window,
_('Database drop failed!'))
if exception[0] == "AccessDenied":
common.warning(_("The Tryton Server Password you provided " \
"is different to the stored password in the " \
"configuration.\n\nPlease try again."), \
self.window, _('Access denied!'))
self.sig_db_drop(self.window)
else:
common.warning(_('Database drop failed with ' \
'error message:\n') + str(exception[0]), \
self.window, _('Database drop failed!'))
return
self.refresh_ssl()
common.message(_("Database dropped successfully!"),
common.message(_("Database dropped successfully!"), \
parent=self.window)
def sig_db_restore(self, widget):
@@ -1374,8 +1386,10 @@ class Main(object):
win.destroy()
def sig_db_dump(self, widget):
url, dbname, passwd = self._choose_db_select(_('Backup a database'))
if not dbname:
dialog = DBBackupDrop(self.window, function='backup')
url, dbname, passwd = dialog.run(self.window)
if not (dbname and url and passwd):
rpc.logout()
Main.get_main().refresh_ssl()
return
@@ -1384,105 +1398,45 @@ class Main(object):
try:
dump_b64 = rpc.db_exec(host, int(port), 'dump', passwd, dbname)
except Exception, exception:
if exception[0] == "Couldn't dump database with password":
common.warning(_("It is impossible to dump a password " \
"protected Database.\nBackground: \n" \
"The Postgres database backup and restore " \
"functions 'pg_dump' and 'pg_restore' did not " \
"support passwords at all. Backup and restore " \
"needed to be proceed manual."), \
self.window, _('Database is password protected!'))
elif exception[0] == "AccessDenied":
common.warning(_("The Tryton Server Password you provided " \
"is different to the stored password in the " \
"configuration.\n\nPlease try again."), \
self.window, _('Access denied!'))
self.sig_db_dump(self.window)
else:
common.warning(_('Database dump failed with ' \
'error message:\n') + str(exception[0]), \
self.window, _('Database dump failed!'))
rpc.logout()
Main.get_main().refresh_ssl()
common.warning(_('Database dump failed with error message:\n') + \
str(exception[0]), self.window, _('Database dump failed!'))
return
self.refresh_ssl()
dump = base64.decodestring(dump_b64)
filename = common.file_selection(_('Save As...'),
action=gtk.FILE_CHOOSER_ACTION_SAVE, parent=self.window,
filename = common.file_selection(_('Save As...'), \
action=gtk.FILE_CHOOSER_ACTION_SAVE, parent=self.window, \
preview=False)
if filename:
file_ = file(filename, 'wb')
file_.write(dump)
file_.close()
common.message(_("Database backuped successfully!"),
common.message(_("Database backuped successfully!"), \
parent=self.window)
else:
rpc.logout()
Main.get_main().refresh_ssl()
def _choose_db_select(self, title=_("Backup a database")):
def refreshlist(widget, db_widget, label, host, port):
res = common.refresh_dblist(db_widget, host, port)
if res is None or res == -1:
if res is None:
label.set_label('<b>' + _('Could not connect to server!') +\
'</b>')
else:
label.set_label('<b>' + \
_('Incompatible version of the server!') + '</b>')
db_widget.hide()
label.show()
elif res == 0:
label.set_label('<b>' + \
_('No database found, you must create one!') + '</b>')
db_widget.hide()
label.show()
else:
label.hide()
db_widget.show()
return res
def refreshlist_ask(widget, server_widget, db_widget, label,
parent=None):
res = common.request_server(server_widget, parent)
if not res:
return None
host, port = res
refreshlist(widget, db_widget, label, host, port)
return (host, port)
dialog = glade.XML(GLADE, "win_db_select",
gettext.textdomain())
win = dialog.get_widget('win_db_select')
win.set_icon(TRYTON_ICON)
win.set_default_response(gtk.RESPONSE_OK)
win.set_transient_for(self.window)
win.show_all()
pass_widget = dialog.get_widget('ent_passwd_select')
server_widget = dialog.get_widget('ent_server_select')
db_widget = dialog.get_widget('combo_db_select')
label = dialog.get_widget('label_db_select')
dialog.get_widget('db_select_label').set_markup('<b>'+title+'</b>')
host = CONFIG['login.server']
port = int(CONFIG['login.port'])
url = '%s:%d' % (host, port)
server_widget.set_text(url)
liststore = gtk.ListStore(str)
db_widget.set_model(liststore)
refreshlist(None, db_widget, label, host, port)
change_button = dialog.get_widget('but_server_select')
change_button.connect_after('clicked', refreshlist_ask,
server_widget, db_widget, label, win)
cell = gtk.CellRendererText()
db_widget.pack_start(cell, True)
db_widget.add_attribute(cell, 'text', 0)
res = win.run()
database = False
url = False
passwd = False
if res == gtk.RESPONSE_OK:
database = db_widget.get_active_text()
url = server_widget.get_text()
passwd = pass_widget.get_text()
self.window.present()
win.destroy()
return (url, database, passwd)
def _choose_db_ent(self):
dialog = glade.XML(GLADE, "win_db_ent",
gettext.textdomain())
+225
View File
@@ -0,0 +1,225 @@
# 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 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.
"""
@staticmethod
def refreshlist(widget, db_widget, label, host, port):
res = common.refresh_dblist(db_widget, host, port)
if res is None or res == -1:
if res is None:
label.set_label('<b>' + \
_('Could not connect to server!') + '</b>')
else:
label.set_label('<b>' + \
_('Incompatible version of the server!') + '</b>')
db_widget.hide()
label.show()
elif res == 0:
label.set_label('<b>' + \
_('No database found, you must create one!') + '</b>')
db_widget.hide()
label.show()
else:
label.hide()
db_widget.show()
return res
@staticmethod
def refreshlist_ask(widget, server_widget, db_widget, label, parent=None):
res = common.request_server(server_widget, parent)
if not res:
return None
host, port = res
DBBackupDrop.refreshlist(widget, db_widget, label, 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() != -1 \
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, parent, 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.dialog = gtk.Dialog( \
title = dialog_title, \
parent = 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_size_request(500, 201)
self.dialog.set_icon(TRYTON_ICON)
self.dialog.connect("key-press-event", self.event_show_button_ok)
self.tooltips = gtk.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, True,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, xoptions=gtk.FILL)
hseparator = gtk.HSeparator()
table.attach(hseparator, 0, 3, 1, 2)
label_server = gtk.Label(_("Server Connection:"))
label_server.set_alignment(1, 0.5)
label_server.set_padding(3, 3)
table.attach(label_server, 0, 1, 2, 3, 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.entry_server_connection.set_text("http://localhost:8070")
self.tooltips.set_tip(self.entry_server_connection, _("This is the " \
"URL of the server. Use server 'localhost' and port '8070' " \
"if the server is installed on this computer. " \
"Click on 'Change' to change the address."), None)
table.attach(self.entry_server_connection, 1, 2, 2, 3)
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, \
xoptions=gtk.FILL)
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, xoptions=gtk.FILL)
vbox_combo = gtk.VBox()
self.combo_database = gtk.ComboBox()
self.combo_database_label = gtk.Label()
self.combo_database_label.set_use_markup(True)
self.combo_database_label.set_alignment(0, 1)
vbox_combo.pack_start(self.combo_database, True, True, 0)
vbox_combo.pack_start(self.combo_database_label, False, False, 0)
table.attach(vbox_combo, 1, 2, 3, 4)
label_serverpasswd = gtk.Label(_("Tryton Server Password:"))
label_serverpasswd.set_justify(gtk.JUSTIFY_RIGHT)
label_serverpasswd.set_alignment(1, 0.5)
label_serverpasswd.set_padding( 3, 3)
table.attach(label_serverpasswd, 0, 1, 4, 5, xoptions=gtk.FILL)
self.entry_serverpasswd = gtk.Entry()
self.entry_serverpasswd.set_visibility(False)
self.entry_serverpasswd.set_activates_default(True)
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."), None)
table.attach(self.entry_serverpasswd, 1, 2, 4, 5)
self.entry_serverpasswd.grab_focus()
self.dialog.vbox.pack_start(self.dialog_vbox)
def run(self, parent):
self.dialog.set_default_response(gtk.RESPONSE_OK)
self.dialog.set_transient_for(parent)
self.dialog.show_all()
pass_widget = self.entry_serverpasswd
server_widget = self.entry_server_connection
db_widget = self.combo_database
label = self.combo_database_label
host = CONFIG['login.server']
port = int(CONFIG['login.port'])
url = '%s:%d' % (host, port)
server_widget.set_text(url)
liststore = gtk.ListStore(str)
db_widget.set_model(liststore)
cell = gtk.CellRendererText()
db_widget.pack_start(cell, True)
db_widget.add_attribute(cell, 'text', 0)
res = self.refreshlist(None, db_widget, label, host, port)
change_button = self.button_server_change
change_button.connect_after('clicked', DBBackupDrop.refreshlist_ask, \
server_widget, db_widget, label, self.dialog)
while True:
database = False
url = False
passwd = False
res = self.dialog.run()
if res == gtk.RESPONSE_OK:
database = db_widget.get_active_text()
url = server_widget.get_text()
passwd = pass_widget.get_text()
break
if res != gtk.RESPONSE_OK:
self.dialog.destroy()
rpc.logout()
break
parent.present()
self.dialog.destroy()
return (url, database, passwd)