Added a connection manager like gajim

This commit is contained in:
Nicolas Évrard committed 2011-03-13 11:36:25 +01:00
1 parent 74c0af22a5
commit 90d7a32e66
8 files changed
+578 -240

No files matched your search

+1
View File
@@ -1,3 +1,4 @@
* Added a connection manager à la gajim
* Fix warning in wizards
* Added possibility to use server-side icons
* Added additional gtk.Entry for filename on BinaryField
+67 -18
View File
@@ -21,6 +21,7 @@ except ImportError:
import md5
import webbrowser
import traceback
import threading
import tryton.rpc as rpc
import locale
import socket
@@ -35,7 +36,7 @@ try:
except ImportError:
ssl = None
import dis
from threading import Lock
from threading import Lock, Semaphore
_ = gettext.gettext
@@ -126,7 +127,11 @@ def find_in_path(name):
return val
return name
def refresh_dblist(db_widget, host, port, dbtoload=None):
def false_call(function, *args):
function(*args)
return None
def refresh_dblist(host, port):
'''
Return the number of database available
or None if it is impossible to connect
@@ -137,22 +142,7 @@ def refresh_dblist(db_widget, host, port, dbtoload=None):
if hasattr(version, 'split'):
if version.split('.')[:2] != VERSION.split('.')[:2]:
return -1
if not dbtoload:
dbtoload = CONFIG['login.db']
index = 0
liststore = db_widget.get_model()
liststore.clear()
result = rpc.db_list(host, port)
from tryton.gui.main import Main
Main.get_main().refresh_ssl()
if result is None:
return None
for db_num, dbname in enumerate(result):
liststore.append([dbname])
if dbname == dbtoload:
index = db_num
db_widget.set_active(index)
return len(liststore)
return rpc.db_list(host, port)
def refresh_langlist(lang_widget, host, port):
liststore = lang_widget.get_model()
@@ -1030,6 +1020,65 @@ def generateColorscheme(masterColor, keys, light=0.06):
for i, key in enumerate(keys)])
class DBProgress(object):
def __init__(self, host, port):
self.dbs, self.createdb = None, None
self.host, self.port = host, port
self.updated = threading.Event()
self.db_info = None
def start(self):
key = (self.host, self.port)
try:
dbs = refresh_dblist(self.host, self.port)
createdb = True
except Exception, exception:
if exception[0] == 'AccessDenied':
dbs, createdb = [], False
else:
raise
self.db_info = (dbs, createdb)
self.updated.set()
def update(self, combo, progressbar, dbname=''):
key = (self.host, self.port)
self.db_info = None
thread = threading.Thread(target=self.start).start()
i = 0
while not self.updated.isSet():
i += 1
time.sleep(0.1)
if i >= 10:
progressbar.show()
progressbar.pulse()
while gtk.events_pending():
gtk.main_iteration()
progressbar.hide()
dbs, createdb = self.db_info
if dbs is None:
return None, False
elif dbs == -1:
return -1, False
from tryton.gui.main import Main
Main.get_main().refresh_ssl()
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)
return len(dbs), createdb
class RPCProgress(object):
def __init__(self, method, args, parent):
+3 -3
View File
@@ -1145,13 +1145,13 @@ class Main(object):
raise
return ([], [])
def sig_login(self, widget=None, dbname=False, res=None):
def sig_login(self, widget=None, profile_name=False, res=None):
if not self.sig_logout(widget, disconnect=False):
return
if not res:
try:
dblogin = DBLogin(self.window)
res = dblogin.run(dbname, self.window)
res = dblogin.run(profile_name, self.window)
except Exception, exception:
if exception.args == ('QueryCanceled',):
return False
@@ -1513,7 +1513,7 @@ class Main(object):
def sig_db_new(self, widget):
if not self.sig_logout(widget):
return False
dia = DBCreate(self.sig_login)
dia = DBCreate(sig_login=self.sig_login)
res = dia.run(self.window)
if res:
CONFIG.save()
+38 -27
View File
@@ -1,13 +1,14 @@
#This file is part of Tryton. The COPYRIGHT file at the top level of
#this repository contains the full copyright notices and license terms.
from __future__ import with_statement
import ConfigParser
import os
import gtk
import gobject
import gettext
import re
import tryton.common as common
from tryton.config import CONFIG, TRYTON_ICON, PIXMAPS_DIR
from tryton.config import CONFIG, TRYTON_ICON, PIXMAPS_DIR, get_config_dir
import tryton.rpc as rpc
_ = gettext.gettext
@@ -72,8 +73,6 @@ class DBCreate(object):
except Exception:
self.server_connection_state(False)
return False
CONFIG['login.server'] = host
CONFIG['login.port'] = port
return True
def event_passwd_clear(self, widget, event, data=None):
@@ -131,10 +130,11 @@ class DBCreate(object):
gobject.idle_add(_move_cursor)
entry.stop_emission("insert-text")
def __init__(self, sig_login=None):
"""
This method defines the complete GUI.
"""
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
@@ -178,7 +178,6 @@ class DBCreate(object):
self.entry_server_connection.set_sensitive(False)
self.entry_server_connection.unset_flags(gtk.CAN_FOCUS)
self.entry_server_connection.set_editable(False)
table.attach(self.entry_server_connection, 1, 2, 1, 2)
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 " \
@@ -192,6 +191,10 @@ class DBCreate(object):
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..."))
self.button_server_change.set_sensitive(not bool(self.host
and self.port))
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)
@@ -293,30 +296,22 @@ class DBCreate(object):
self.dialog.set_transient_for(parent)
self.dialog.show_all()
if not CONFIG['login.host']:
self.label_server_setup.hide()
self.label_server.hide()
self.entry_server_connection.hide()
self.button_server_change.hide()
self.label_serverpasswd.hide()
self.entry_serverpasswd.hide()
self.hseparator.hide()
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, self.dialog)
host = CONFIG['login.server']
port = int(CONFIG['login.port'])
url = '%s:%d' % (host, port)
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, host, port)
common.refresh_langlist(self.combo_language, self.host, self.port)
except Exception:
self.button_create.set_sensitive(False)
@@ -372,9 +367,8 @@ class DBCreate(object):
self.entry_dbname.grab_focus()
continue
else: # Everything runs fine, break the block here
CONFIG['login.server'] = host = url_m.group(1)
CONFIG['login.port'] = port = url_m.group(2)
CONFIG["login.login"] = "admin"
host = url_m.group(1)
port = url_m.group(2)
try:
rpcprogress = common.RPCProgress('db_exec',
(host, int(port), 'create', dbname, passwd,
@@ -409,10 +403,27 @@ class DBCreate(object):
parent.present()
self.dialog.destroy()
if self.sig_login:
self.sig_login(dbname=dbname)
profile_cfg = os.path.join(get_config_dir(),
'profiles.cfg')
profiles = ConfigParser.SafeConfigParser()
if os.path.exists(profile_cfg):
profiles.read(profile_cfg)
i, profile_name = 0, dbname
while profile_name in profiles.sections():
i += 1
profile_name = '%s_%s' % (dbname, i)
profiles.add_section(profile_name)
profiles.set(profile_name, 'host', host)
profiles.set(profile_name, 'port', port)
profiles.set(profile_name, 'database', dbname)
profiles.set(profile_name, 'username', '')
with open(profile_cfg, 'wb') as configfile:
profiles.write(configfile)
self.sig_login(profile_name=profile_name)
break
break
parent.present()
self.dialog.destroy()
return dbname
+30 -27
View File
@@ -1,5 +1,7 @@
# This file is part of Tryton. The COPYRIGHT file at the top level of this
# repository contains the full copyright notices and license terms.
import threading
import gtk
import gettext
import tryton.common as common
@@ -13,19 +15,22 @@ 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:
def refreshlist(widget, db_widget, label, db_progress, host, port):
db_widget.hide()
label.hide()
dbprogress = common.DBProgress(host, port)
dbs, createdb = dbprogress.update(db_widget, db_progress)
if dbs is None or dbs == -1:
if dbs is None:
label.set_label('<b>' + \
_('Could not connect to server!') + '</b>')
else:
label.set_label('<b>' + \
_('This client version is not compatible with the server!') +\
'</b>')
_('This client version is not compatible with the server!')
+ '</b>')
db_widget.hide()
label.show()
elif res == 0:
elif dbs == 0:
label.set_label('<b>' + \
_('No database found, you must create one!') + '</b>')
db_widget.hide()
@@ -33,17 +38,17 @@ class DBBackupDrop(object):
else:
label.hide()
db_widget.show()
return res
return dbs
@staticmethod
def refreshlist_ask(widget, server_widget, db_widget, label, parent=None):
def refreshlist_ask(widget, server_widget, db_widget, label, db_progress,
parent=None):
res = common.request_server(server_widget, parent)
if not res:
return None
host, port = res
if DBBackupDrop.refreshlist(widget, db_widget, label, host, port):
CONFIG['login.server'] = host
CONFIG['login.port'] = port
DBBackupDrop.refreshlist(widget, db_widget, label, db_progress, host,
port)
return (host, port)
def event_show_button_ok(self, widget, event, data=None):
@@ -157,11 +162,18 @@ class DBBackupDrop(object):
vbox_combo = gtk.VBox()
self.combo_database = gtk.ComboBox()
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)
vbox_combo.pack_start(self.combo_database, True, True, 0)
vbox_combo.pack_start(self.combo_database_label, False, False, 0)
vbox_combo.pack_start(self.combo_database, True, True)
vbox_combo.pack_start(self.combo_database_label, False, False)
vbox_combo.pack_start(self.db_progressbar, True, True)
width, height = 0, 0
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=gtk.FILL)
self.label_serverpasswd = gtk.Label(_("Tryton Server Password:"))
@@ -188,33 +200,24 @@ class DBBackupDrop(object):
self.dialog.set_transient_for(parent)
self.dialog.show_all()
if not CONFIG['login.host']:
self.label_server.hide()
self.entry_server_connection.hide()
self.button_server_change.hide()
self.label_serverpasswd.hide()
self.entry_serverpasswd.hide()
pass_widget = self.entry_serverpasswd
server_widget = self.entry_server_connection
db_widget = self.combo_database
db_progress = self.db_progressbar
label = self.combo_database_label
host = CONFIG['login.server']
port = int(CONFIG['login.port'])
url = '%s:%d' % (host, port)
server_widget.set_text(url)
server_widget.set_text('')
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)
res = self.refreshlist(None, db_widget, label, db_progress, '', '')
change_button = self.button_server_change
change_button.connect_after('clicked', DBBackupDrop.refreshlist_ask, \
server_widget, db_widget, label, self.dialog)
server_widget, db_widget, label, db_progress, self.dialog)
while True:
database = False
+432 -152
View File
@@ -1,19 +1,351 @@
#This file is part of Tryton. The COPYRIGHT file at the top level of
#this repository contains the full copyright notices and license terms.
from __future__ import with_statement
import ConfigParser
import gtk
import gobject
import os
import re
import gettext
import threading
import time
from tryton.version import VERSION
import tryton.common as common
from tryton.config import CONFIG, TRYTON_ICON, PIXMAPS_DIR
from tryton.config import CONFIG, TRYTON_ICON, PIXMAPS_DIR, get_config_dir
import tryton.rpc as rpc
from tryton.gui.window.dbcreate import DBCreate
_ = gettext.gettext
class DBListEditor(object):
def __init__(self, parent, profile_store, profiles):
self.profiles = profiles
self.current_database = None
self.old_profile, self.current_profile = None, None
self.updating_db = False
# GTK Stuffs
self.parent = parent
self.dialog = gtk.Dialog(title=_(u'Profile Editor'), parent=parent,
flags=gtk.DIALOG_MODAL|gtk.DIALOG_DESTROY_WITH_PARENT)
self.cancel_button = self.dialog.add_button(gtk.STOCK_CANCEL,
gtk.RESPONSE_CANCEL)
self.ok_button = self.dialog.add_button(gtk.STOCK_OK, gtk.RESPONSE_ACCEPT)
self.dialog.set_position(gtk.WIN_POS_CENTER_ON_PARENT)
self.dialog.set_has_separator(True)
self.dialog.set_icon(TRYTON_ICON)
hpaned = gtk.HPaned()
vbox_profiles = gtk.VBox(homogeneous=False, spacing=6)
self.cell = gtk.CellRendererText()
self.cell.set_property('editable', True)
self.cell.connect('edited', self.edit_profilename)
self.cell.connect('editing-started', self.edit_started)
self.cell.connect('editing-canceled', self.edit_canceled)
self.profile_tree = gtk.TreeView()
self.profile_tree.set_model(profile_store)
self.profile_tree.insert_column_with_attributes(-1, _(u'Profile'),
self.cell, text=0)
self.profile_tree.connect('cursor-changed', self.profile_selected)
scroll = gtk.ScrolledWindow()
scroll.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
scroll.add(self.profile_tree)
self.add_button = gtk.Button(_(u'_Add'))
self.add_button.connect('clicked', self.profile_create)
add_image = gtk.Image()
add_image.set_from_stock('gtk-add', gtk.ICON_SIZE_BUTTON)
self.add_button.set_image(add_image)
self.remove_button = gtk.Button(_(u'_Remove'))
self.remove_button.connect('clicked', self.profile_delete)
remove_image = gtk.Image()
remove_image.set_from_stock('gtk-remove', gtk.ICON_SIZE_BUTTON)
self.remove_button.set_image(remove_image)
vbox_profiles.pack_start(scroll, expand=True, fill=True)
vbox_profiles.pack_start(self.add_button, expand=False, fill=True)
vbox_profiles.pack_start(self.remove_button, expand=False, fill=True)
hpaned.add1(vbox_profiles)
table = gtk.Table(4, 2, homogeneous=False)
table.set_row_spacings(3)
table.set_col_spacings(3)
host = gtk.Label(_(u'Hostname:'))
host.set_alignment(1, 0.5)
host.set_padding(3, 3)
self.host_entry = gtk.Entry()
self.host_entry.connect('focus-out-event', self.display_dbwidget)
self.host_entry.connect('changed', self.update_profiles, 'host')
self.host_entry.set_activates_default(True)
table.attach(host, 0, 1, 1, 2, yoptions=False, xoptions=gtk.FILL)
table.attach(self.host_entry, 1, 2, 1, 2, yoptions=False)
port = gtk.Label(_(u'Port:'))
port.set_alignment(1, 0.5)
port.set_padding(3, 3)
self.port_entry = gtk.Entry()
self.port_entry.connect('focus-out-event', self.display_dbwidget)
self.port_entry.connect('changed', self.update_profiles, 'port')
self.port_entry.set_activates_default(True)
table.attach(port, 0, 1, 2, 3, yoptions=False, xoptions=gtk.FILL)
table.attach(self.port_entry, 1, 2, 2, 3, yoptions=False)
database = gtk.Label(_(u'Database:'))
database.set_alignment(1, 0.5)
database.set_padding(3, 3)
self.database_entry = gtk.Entry()
self.database_entry.connect('changed', self.dbentry_changed)
self.database_entry.connect('changed', self.update_profiles, 'database')
self.database_entry.set_activates_default(True)
self.database_label = gtk.Label()
self.database_label.set_use_markup(True)
self.database_label.set_alignment(0, 0.5)
self.database_combo = gtk.ComboBox()
dbstore = gtk.ListStore(gobject.TYPE_STRING)
cell = gtk.CellRendererText()
self.database_combo.pack_start(cell, True)
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
for child in db_box.get_children():
cwidth, cheight = child.size_request()
width, height = max(width, cwidth), max(height, cheight)
db_box.set_size_request(width, height)
table.attach(database, 0, 1, 3, 4, yoptions=False, xoptions=gtk.FILL)
table.attach(db_box, 1, 2, 3, 4, yoptions=False)
username = gtk.Label(_(u'Username:'))
username.set_alignment(1, 0.5)
username.set_padding(3, 3)
self.username_entry = gtk.Entry()
self.username_entry.connect('changed', self.update_profiles, 'username')
self.username_entry.set_activates_default(True)
table.attach(username, 0, 1, 4, 5, yoptions=False, xoptions=gtk.FILL)
table.attach(self.username_entry, 1, 2, 4, 5, yoptions=False)
hpaned.add2(table)
hpaned.set_position(250)
self.dialog.vbox.pack_start(hpaned)
self.dialog.set_default_size(640, 350)
self.dialog.set_default_response(gtk.RESPONSE_ACCEPT)
def run(self):
self.dialog.show_all()
self.clear_entries()
model = self.profile_tree.get_model()
if model:
self.profile_tree.get_selection().select_path((0,))
self.profile_selected(self.profile_tree)
self.dialog.run()
self.parent.present()
self.dialog.destroy()
def _current_profile(self):
model, selection = self.profile_tree.get_selection().get_selected()
if not selection:
return {'name': None, 'iter': None}
return {'name': model[selection][0], 'iter': selection}
def clear_entries(self):
for entryname in ('host', 'port', 'database', 'username'):
entry = getattr(self, '%s_entry' % entryname)
if entryname == 'port':
entry.set_text('8070')
else:
entry.set_text('')
self.current_database = None
self.database_combo.set_active(-1)
self.database_combo.get_model().clear()
self.hide_database_info()
def hide_database_info(self):
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):
self.clear_entries()
model = self.profile_tree.get_model()
selection = self.profile_tree.get_selection()
model.append(['', False])
column = self.profile_tree.get_column(0)
self.profile_tree.set_cursor(len(model)-1, column, start_editing=True)
def profile_delete(self, button):
self.clear_entries()
model, selection = self.profile_tree.get_selection().get_selected()
if not selection:
return
profile_name = model[selection][0]
self.profiles.remove_section(profile_name)
del model[selection]
def profile_selected(self, treeview):
self.old_profile = self.current_profile
self.current_profile = self._current_profile()
if not self.current_profile['name']:
return
if self.updating_db:
self.current_profile = self.old_profile
selection = treeview.get_selection()
selection.select_iter(self.old_profile['iter'])
return
self.clear_entries()
fields = ('host', 'port', 'database', 'username')
for field in fields:
entry = getattr(self, '%s_entry' % field)
try:
entry_value = self.profiles.get(self.current_profile['name'],
field)
entry.set_text(entry_value)
if field == 'database':
self.current_database = entry_value
except ConfigParser.NoOptionError:
pass
self.display_dbwidget(None, None, self.current_database)
def edit_canceled(self, renderer):
model = self.profile_tree.get_model()
for i, row in enumerate(list(model)):
if not row[0]:
del model[i]
def check_edit_cancel(self, editable, event, renderer, path):
renderer.emit('edited', path, editable.get_text())
def edit_started(self, renderer, editable, path):
if isinstance(editable, gtk.Entry):
editable.connect('focus-out-event', self.check_edit_cancel,
renderer, path)
def edit_profilename(self, renderer, path, newtext):
model = self.profile_tree.get_model()
oldname = model[path][0]
if oldname == newtext == '':
del model[path]
return
elif oldname == newtext or newtext == '':
return
if newtext in self.profiles.sections():
del model[path]
return
elif oldname in self.profiles.sections():
self.profiles.add_section(newtext)
for itemname, value in self.profiles.items(oldname):
self.profiles.set(newtext, itemname, value)
self.profiles.remove_section(oldname)
model[path][0] = newtext
else:
model[path][0] = newtext
self.profiles.add_section(newtext)
self.current_profile = self._current_profile()
self.host_entry.grab_focus()
def update_profiles(self, editable, entryname):
new_value = editable.get_text()
if not new_value:
return
section = self._current_profile()['name']
self.profiles.set(section, entryname, new_value)
self.validate_profile(section)
def validate_profile(self, profile_name):
model, selection = self.profile_tree.get_selection().get_selected()
if not selection:
return
active = all(self.profiles.has_option(profile_name, option)
for option in ('host', 'port', 'database'))
model[selection][1] = active
def display_dbwidget(self, entry, event, dbname=None):
host = self.host_entry.get_text()
port = self.port_entry.get_text()
if not (host and port):
return
if dbname is None:
dbname = self.current_database
dbprogress = common.DBProgress(host, int(port))
self.hide_database_info()
self.add_button.set_sensitive(False)
self.remove_button.set_sensitive(False)
self.ok_button.set_sensitive(False)
self.cancel_button.set_sensitive(False)
self.cell.set_property('editable', False)
self.updating_db = True
dbs, createdb = dbprogress.update(self.database_combo,
self.database_progressbar, dbname)
self.updating_db = False
if dbs is None and createdb is None:
pass
elif 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:
if createdb:
self.database_button.show()
else:
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.cancel_button.set_sensitive(True)
self.cell.set_property('editable', True)
def db_create(self, button):
if not self.current_profile['name']:
return
host = self.host_entry.get_text()
port = int(self.port_entry.get_text())
dia = DBCreate(host, port)
dbname = dia.run(self.dialog)
self.username_entry.set_text('admin')
self.display_dbwidget(None, None, dbname)
def dbcombo_changed(self, combobox):
dbname = combobox.get_active_text()
if dbname:
self.current_database = dbname
self.profiles.set(self.current_profile['name'], 'database', dbname)
self.validate_profile(self.current_profile['name'])
def dbentry_changed(self, entry):
dbname = entry.get_text()
if dbname:
self.current_database = dbname
self.profiles.set(self.current_profile['name'], 'database', dbname)
self.validate_profile(self.current_profile['name'])
class DBLogin(object):
def __init__(self, parent):
# GTK Stuffs
self.dialog = gtk.Dialog(title=_('Login'), parent=parent,
flags=gtk.DIALOG_MODAL|gtk.DIALOG_DESTROY_WITH_PARENT)
self.dialog.set_position(gtk.WIN_POS_CENTER_ON_PARENT)
@@ -25,7 +357,8 @@ class DBLogin(object):
img_cancel = gtk.Image()
img_cancel.set_from_stock('tryton-cancel', gtk.ICON_SIZE_BUTTON)
button_cancel.set_image(img_cancel)
tooltips.set_tip(button_cancel, _('Cancel connection to the Tryton server'))
tooltips.set_tip(button_cancel,
_('Cancel connection to the Tryton server'))
self.dialog.add_action_widget(button_cancel, gtk.RESPONSE_CANCEL)
self.button_connect = gtk.Button(_('C_onnect'))
img_connect = gtk.Image()
@@ -42,179 +375,126 @@ class DBLogin(object):
ebox.modify_bg(gtk.STATE_NORMAL, gtk.gdk.color_parse("#1b2019"))
ebox.add(image)
self.dialog.vbox.pack_start(ebox)
table_main = gtk.Table(4, 3, False)
table_main.set_border_width(10)
table_main.set_row_spacings(3)
table_main.set_col_spacings(3)
self.dialog.vbox.pack_start(table_main, True, True, 0)
vbox_combo = gtk.VBox()
self.hbox_combo = gtk.HBox()
self.combo_database = gtk.ComboBox()
self.combo_label = gtk.Label()
self.combo_label.set_use_markup(True)
self.combo_label.set_alignment(0, 0.5)
self.combo_button = gtk.Button(_('C_reate'))
self.combo_button.connect('clicked', self.db_create)
self.table_main = gtk.Table(3, 3, False)
self.table_main.set_border_width(10)
self.table_main.set_row_spacings(3)
self.table_main.set_col_spacings(3)
self.dialog.vbox.pack_start(self.table_main, True, True, 0)
self.profile_store = gtk.ListStore(gobject.TYPE_STRING,
gobject.TYPE_BOOLEAN)
self.combo_profile = gtk.ComboBox()
cell = gtk.CellRendererText()
self.combo_profile.pack_start(cell, True)
self.combo_profile.add_attribute(cell, 'text', 0)
self.combo_profile.add_attribute(cell, 'sensitive', 1)
self.combo_profile.set_model(self.profile_store)
self.combo_profile.connect('changed', self.profile_changed)
self.profile_label = gtk.Label(_(u'Profile:'))
self.profile_label.set_justify(gtk.JUSTIFY_RIGHT)
self.profile_label.set_alignment(1, 0.5)
self.profile_label.set_padding(3, 3)
self.profile_button = gtk.Button(_('_Manage profiles'))
self.profile_button.connect('clicked', self.profile_manage)
self.table_main.attach(self.profile_label, 0, 1, 0, 1,
xoptions=gtk.FILL)
self.table_main.attach(self.combo_profile, 1, 2, 0, 1)
self.table_main.attach(self.profile_button, 2, 3, 0, 1,
xoptions=gtk.FILL)
image = gtk.Image()
image.set_from_stock('tryton-new', gtk.ICON_SIZE_BUTTON)
self.combo_button.set_image(image)
vbox_combo.pack_start(self.combo_database, True, True, 0)
self.hbox_combo.pack_start(self.combo_label, True, True, 0)
self.hbox_combo.pack_start(self.combo_button, False, False, 0)
vbox_combo.pack_start(self.hbox_combo, True, True, 0)
table_main.attach(vbox_combo, 1, 3, 1, 2)
image.set_from_stock('gtk-edit', gtk.ICON_SIZE_BUTTON)
self.profile_button.set_image(image)
self.entry_password = gtk.Entry()
self.entry_password.set_visibility(False)
self.entry_password.set_activates_default(True)
table_main.attach(self.entry_password, 1, 3, 3, 4)
self.table_main.attach(self.entry_password, 1, 3, 3, 4)
self.entry_login = gtk.Entry()
self.entry_login.set_activates_default(True)
table_main.attach(self.entry_login, 1, 3, 2, 3)
self.label_server = gtk.Label()
self.label_server.set_text(_("Server:"))
self.label_server.set_alignment(1, 0.5)
self.label_server.set_padding(3, 3)
table_main.attach(self.label_server, 0, 1, 0, 1, xoptions=gtk.FILL)
label_database = gtk.Label()
label_database.set_text(_("Database:"))
label_database.set_alignment(1, 0.5)
label_database.set_padding(3, 3)
table_main.attach(label_database, 0, 1, 1, 2, xoptions=gtk.FILL)
self.entry_server = gtk.Entry()
table_main.attach(self.entry_server, 1, 2, 0, 1)
self.entry_server.set_sensitive(False)
self.entry_server.unset_flags(gtk.CAN_FOCUS)
self.entry_server.set_editable(False)
self.entry_server.set_text("localhost")
self.entry_server.set_activates_default(True)
self.entry_server.set_width_chars(16)
self.button_server = gtk.Button(label=_("C_hange"), stock=None,
use_underline=True)
tooltips.set_tip(self.button_server,
_('Configure the Tryton server connection'))
table_main.attach(self.button_server, 2, 3, 0, 1, xoptions=gtk.FILL)
self.table_main.attach(self.entry_login, 1, 3, 2, 3)
label_password = gtk.Label(str = _("Password:"))
label_password.set_justify(gtk.JUSTIFY_RIGHT)
label_password.set_alignment(1, 0.5)
label_password.set_padding(3, 3)
table_main.attach(label_password, 0, 1, 3, 4, xoptions=gtk.FILL)
self.table_main.attach(label_password, 0, 1, 3, 4, xoptions=gtk.FILL)
label_username = gtk.Label(str = _("User name:"))
label_username.set_alignment(1, 0.5)
label_username.set_padding(3, 3)
table_main.attach(label_username, 0, 1, 2, 3, xoptions=gtk.FILL)
self.table_main.attach(label_username, 0, 1, 2, 3, xoptions=gtk.FILL)
self.entry_password.grab_focus()
@staticmethod
def refreshlist(widget, db_widget, label, button, host, port,
butconnect=None):
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()
button.hide()
if butconnect:
butconnect.set_sensitive(False)
elif res == 0:
label.set_label('<b>' + \
_('No database found, you must create one!') + '</b>')
db_widget.hide()
label.show()
button.show()
if butconnect:
butconnect.set_sensitive(False)
# Profile informations
self.profile_cfg = os.path.join(get_config_dir(), 'profiles.cfg')
self.profiles = ConfigParser.SafeConfigParser({'port': '8070'})
if not os.path.exists(self.profile_cfg):
short_version = '.'.join(VERSION.split('.', 2)[:2])
name = 'demo%s.tryton.org' % short_version
self.profiles.add_section(name)
self.profiles.set(name, 'host', name)
self.profiles.set(name, 'port', '8070')
self.profiles.set(name, 'database', 'demo%s' % short_version)
self.profiles.set(name, 'username', 'demo')
else:
label.hide()
button.hide()
db_widget.show()
if butconnect:
butconnect.set_sensitive(True)
return res
self.profiles.read(self.profile_cfg)
for section in self.profiles.sections():
active = all(self.profiles.has_option(section, option)
for option in ('host', 'port', 'database'))
self.profile_store.append([section, active])
@staticmethod
def refreshlist_ask(widget, server_widget, db_widget, label, button,
butconnect=False, host=False, port=0, parent=None):
res = common.request_server(server_widget, parent) or (host, port)
if not res:
return False
host, port = res
res = DBLogin.refreshlist(widget, db_widget, label, button, host, port,
butconnect)
if res:
CONFIG['login.server'] = host
CONFIG['login.port'] = port
return res
def profile_manage(self, widget):
dia = DBListEditor(self.dialog, self.profile_store, self.profiles)
dia.run()
with open(self.profile_cfg, 'wb') as configfile:
self.profiles.write(configfile)
def db_create(self, widget):
dia = DBCreate()
dia.run(self.dialog)
host = CONFIG['login.server']
port = int(CONFIG['login.port'])
DBLogin.refreshlist(None, self.combo_database,
self.combo_label, self.combo_button, host, port,
self.button_connect)
return
def profile_changed(self, combobox):
position = combobox.get_active()
if position == -1:
return
profile = self.profile_store[position][0]
try:
username = self.profiles.get(profile, 'username')
except ConfigParser.NoOptionError:
username = ''
if username:
self.entry_login.set_text(username)
self.entry_password.grab_focus()
else:
self.entry_login.set_text('')
self.entry_login.grab_focus()
def run(self, dbname, parent):
def run(self, profile_name, parent):
if not profile_name:
selected_profile = CONFIG['login.profile']
if not selected_profile:
short_version = '.'.join(VERSION.split('.', 2)[:2])
selected_profile = 'demo%s.tryton.org' % short_version
else:
selected_profile = profile_name
for idx, row in enumerate(self.profile_store):
if row[0] == selected_profile:
self.combo_profile.set_active(idx)
break
self.dialog.show_all()
self.combo_label.hide()
self.combo_button.hide()
if not CONFIG['login.host']:
self.label_server.hide()
self.entry_server.hide()
self.button_server.hide()
host = CONFIG['login.server']
port = int(CONFIG['login.port'])
url = '%s:%d' % (host, port)
self.entry_server.set_text(url)
self.entry_login.set_text(CONFIG['login.login'])
# construct the list of available db and select the last one used
liststore = gtk.ListStore(str)
self.combo_database.set_model(liststore)
cell = gtk.CellRendererText()
self.combo_database.pack_start(cell, True)
self.combo_database.add_attribute(cell, 'text', 0)
res = self.refreshlist(None, self.combo_database, self.combo_label,
self.combo_button, host, port, self.button_connect)
self.button_server.connect_after('clicked', DBLogin.refreshlist_ask,
self.entry_server, self.combo_database, self.combo_label,
self.combo_button, self.button_connect, host, port, self.dialog)
if dbname:
i = liststore.get_iter_root()
while i:
if liststore.get_value(i, 0)==dbname:
self.combo_database.set_active_iter(i)
break
i = liststore.iter_next(i)
# Reshow dialog for gtk-quarks
self.dialog.reshow_with_initial_size()
res = self.dialog.run()
url_m = re.match('^([\w.:\-\d]+):(\d{1,5})$',
self.entry_server.get_text() or '')
if url_m:
CONFIG['login.server'] = url_m.group(1)
CONFIG['login.login'] = self.entry_login.get_text()
CONFIG['login.port'] = url_m.group(2)
CONFIG['login.db'] = self.combo_database.get_active_text()
result = (self.entry_login.get_text(),
self.entry_password.get_text(), url_m.group(1),
int(url_m.group(2)), self.combo_database.get_active_text())
else:
parent.present()
self.dialog.destroy()
raise Exception('QueryCanceled')
res, result = None, ('', '', '', '', '')
while not (res in (gtk.RESPONSE_CANCEL, gtk.RESPONSE_DELETE_EVENT)
or (res == gtk.RESPONSE_OK and all(result))):
res = self.dialog.run()
active_profile = self.combo_profile.get_active()
if active_profile != -1:
profile = self.profile_store[active_profile][0]
CONFIG['login.profile'] = profile
try:
result = (self.entry_login.get_text(),
self.entry_password.get_text(),
self.profiles.get(profile, 'host'),
int(self.profiles.get(profile, 'port')),
self.profiles.get(profile, 'database'))
except ConfigParser.NoOptionError, e:
pass
if res != gtk.RESPONSE_OK:
parent.present()
self.dialog.destroy()
+1 -10
View File
@@ -173,16 +173,7 @@ class DBRestore(object):
self.dialog.set_transient_for(parent)
self.dialog.show_all()
if not CONFIG['login.host']:
self.label_server_url.hide()
self.entry_server_url.hide()
self.button_server_change.hide()
self.label_server_password.hide()
self.entry_server_password.hide()
self.hseparator.hide()
url = '%s:%d' % (CONFIG['login.server'], int(CONFIG['login.port']))
self.entry_server_url.set_text(url)
self.entry_server_url.set_text('')
while True:
database = False
passwd = False
+6 -3
View File
@@ -49,9 +49,12 @@ def db_list(host, port):
_SEMAPHORE.release()
logging.getLogger('rpc.result').debug(repr(res))
return res
except Exception:
logging.getLogger('rpc.result').debug(repr(None))
return None
except Exception, exception:
if exception[0] == 'AccessDenied':
raise
else:
logging.getLogger('rpc.result').debug(repr(None))
return None
def db_exec(host, port, method, *args):
global _SOCK, SECURE