mirror of https://gitlab.com/datalifeit/tryton
666 lines
27 KiB
Python
666 lines
27 KiB
Python
# 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 configparser
|
|
import gtk
|
|
import gobject
|
|
import os
|
|
import gettext
|
|
import threading
|
|
import logging
|
|
|
|
from gi.repository import Gtk, Gdk
|
|
|
|
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.common.underline import set_underline
|
|
|
|
_ = gettext.gettext
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
class DBListEditor(object):
|
|
|
|
def __init__(self, parent, profile_store, profiles, callback):
|
|
self.profiles = profiles
|
|
self.current_database = None
|
|
self.old_profile, self.current_profile = None, None
|
|
self.db_cache = None
|
|
self.updating_db = False
|
|
|
|
# GTK Stuffs
|
|
self.parent = parent
|
|
self.dialog = gtk.Dialog(title=_('Profile Editor'), parent=parent,
|
|
flags=gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT)
|
|
self.ok_button = self.dialog.add_button(
|
|
set_underline(_("Close")), gtk.RESPONSE_CLOSE)
|
|
self.dialog.set_position(gtk.WIN_POS_CENTER_ON_PARENT)
|
|
self.dialog.set_icon(TRYTON_ICON)
|
|
|
|
tooltips = common.Tooltips()
|
|
|
|
hpaned = gtk.HPaned()
|
|
vbox_profiles = gtk.VBox(homogeneous=False, spacing=6)
|
|
self.cell = gtk.CellRendererText()
|
|
self.cell.set_property('editable', True)
|
|
self.cell.connect('editing-started', self.edit_started)
|
|
self.profile_tree = gtk.TreeView()
|
|
self.profile_tree.set_model(profile_store)
|
|
self.profile_tree.insert_column_with_attributes(-1, _('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()
|
|
self.add_button.set_image(common.IconFactory.get_image(
|
|
'tryton-add', gtk.ICON_SIZE_BUTTON))
|
|
tooltips.set_tip(self.add_button, _("Add new profile"))
|
|
self.add_button.connect('clicked', self.profile_create)
|
|
self.remove_button = gtk.Button()
|
|
self.remove_button.set_image(common.IconFactory.get_image(
|
|
'tryton-remove', gtk.ICON_SIZE_BUTTON))
|
|
tooltips.set_tip(self.remove_button, _("Remove selected profile"))
|
|
self.remove_button.get_style_context().add_class(
|
|
Gtk.STYLE_CLASS_DESTRUCTIVE_ACTION)
|
|
self.remove_button.connect('clicked', self.profile_delete)
|
|
bbox = Gtk.ButtonBox()
|
|
bbox.pack_start(self.remove_button)
|
|
bbox.pack_start(self.add_button)
|
|
vbox_profiles.pack_start(scroll, expand=True, fill=True)
|
|
vbox_profiles.pack_start(bbox, 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(set_underline(_('Host:')))
|
|
host.set_use_underline(True)
|
|
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)
|
|
host.set_mnemonic_widget(self.host_entry)
|
|
table.attach(host, 0, 1, 1, 2, yoptions=False, xoptions=gtk.FILL)
|
|
table.attach(self.host_entry, 1, 2, 1, 2, yoptions=False)
|
|
database = gtk.Label(set_underline(_('Database:')))
|
|
database.set_use_underline(True)
|
|
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_progressbar = gtk.ProgressBar()
|
|
self.database_progressbar.set_text(_('Fetching databases list'))
|
|
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_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, 2, 3, yoptions=False, xoptions=gtk.FILL)
|
|
table.attach(db_box, 1, 2, 2, 3, yoptions=False)
|
|
username = gtk.Label(set_underline(_('Username:')))
|
|
username.set_use_underline(True)
|
|
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')
|
|
username.set_mnemonic_widget(self.username_entry)
|
|
self.username_entry.set_activates_default(True)
|
|
table.attach(username, 0, 1, 3, 4, yoptions=False, xoptions=gtk.FILL)
|
|
table.attach(self.username_entry, 1, 2, 3, 4, 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_CLOSE)
|
|
|
|
self.dialog.connect('close', lambda *a: False)
|
|
self.dialog.connect('response', self.response)
|
|
self.callback = callback
|
|
|
|
def response(self, widget, response):
|
|
if self.callback:
|
|
self.callback(self.current_profile['name'])
|
|
self.parent.present()
|
|
self.dialog.destroy()
|
|
|
|
def run(self, profile_name):
|
|
self.clear_entries() # must be done before show_all for windows
|
|
self.dialog.show_all()
|
|
model = self.profile_tree.get_model()
|
|
if model:
|
|
for i, row in enumerate(model):
|
|
if row[0] == profile_name:
|
|
break
|
|
else:
|
|
i = 0
|
|
self.profile_tree.get_selection().select_path((i,))
|
|
self.profile_selected(self.profile_tree)
|
|
|
|
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', 'database', 'username'):
|
|
entry = getattr(self, '%s_entry' % entryname)
|
|
entry.handler_block_by_func(self.update_profiles)
|
|
entry.set_text('')
|
|
entry.handler_unblock_by_func(self.update_profiles)
|
|
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_progressbar.hide()
|
|
|
|
def profile_create(self, button):
|
|
self.clear_entries()
|
|
model = self.profile_tree.get_model()
|
|
model.append(['', False])
|
|
column = self.profile_tree.get_column(0)
|
|
self.profile_tree.set_cursor(len(model) - 1, column,
|
|
start_editing=True)
|
|
self.db_cache = None
|
|
|
|
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
|
|
fields = ('host', 'database', 'username')
|
|
for field in fields:
|
|
entry = getattr(self, '%s_entry' % field)
|
|
try:
|
|
entry_value = self.profiles.get(self.current_profile['name'],
|
|
field)
|
|
except configparser.NoOptionError:
|
|
entry_value = ''
|
|
entry.set_text(entry_value)
|
|
if field == 'database':
|
|
self.current_database = entry_value
|
|
|
|
self.display_dbwidget(None, None)
|
|
|
|
def edit_started(self, renderer, editable, path):
|
|
if isinstance(editable, gtk.Entry):
|
|
editable.connect('focus-out-event', self.edit_profilename,
|
|
renderer, path)
|
|
|
|
def edit_profilename(self, editable, event, renderer, path):
|
|
newtext = editable.get_text()
|
|
model = self.profile_tree.get_model()
|
|
try:
|
|
oldname = model[path][0]
|
|
except IndexError:
|
|
return
|
|
if oldname == newtext == '':
|
|
del model[path]
|
|
return
|
|
elif oldname == newtext or newtext == '':
|
|
return
|
|
elif newtext in self.profiles.sections():
|
|
if not oldname:
|
|
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', 'database'))
|
|
model[selection][1] = active
|
|
|
|
@classmethod
|
|
def test_server_version(cls, host, port):
|
|
'''
|
|
Tests if the server version is compatible with the client version
|
|
It returns None if no information on server version is available.
|
|
'''
|
|
version = rpc.server_version(host, port)
|
|
if not version:
|
|
return None
|
|
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 self.test_server_version(host, port) is False:
|
|
label = _('Incompatible version of the server')
|
|
elif dbs is None:
|
|
label = _('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)
|
|
self.database_entry.set_text(self.current_database
|
|
if self.current_database else '')
|
|
if dbs:
|
|
self.database_combo.show()
|
|
else:
|
|
self.database_entry.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:
|
|
return
|
|
port = common.get_port(netloc)
|
|
if (host, port, self.current_profile['name']) == self.db_cache:
|
|
return
|
|
if self.updating_db:
|
|
return
|
|
|
|
self.hide_database_info()
|
|
self.add_button.set_sensitive(False)
|
|
self.remove_button.set_sensitive(False)
|
|
self.ok_button.set_sensitive(False)
|
|
self.cell.set_property('editable', False)
|
|
self.host_entry.set_sensitive(False)
|
|
self.updating_db = True
|
|
self.refresh_databases(host, port)
|
|
|
|
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'])
|
|
|
|
def insert_text_port(self, entry, new_text, new_text_length, position):
|
|
value = entry.get_text()
|
|
position = entry.get_position()
|
|
new_value = value[:position] + new_text + value[position:]
|
|
try:
|
|
int(new_value)
|
|
except ValueError:
|
|
entry.stop_emission('insert-text')
|
|
|
|
|
|
class DBLogin(object):
|
|
def __init__(self):
|
|
# Fake windows to avoid warning about Dialog without transient
|
|
self._window = gtk.Window()
|
|
self.dialog = gtk.Dialog(title=_('Login'), flags=gtk.DIALOG_MODAL)
|
|
self.dialog.set_transient_for(self._window)
|
|
self.dialog.set_icon(TRYTON_ICON)
|
|
self.dialog.set_position(gtk.WIN_POS_CENTER_ALWAYS)
|
|
self.dialog.set_resizable(False)
|
|
|
|
tooltips = common.Tooltips()
|
|
button_cancel = gtk.Button(_('_Cancel'), use_underline=True)
|
|
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'), use_underline=True)
|
|
self.button_connect.get_style_context().add_class(
|
|
Gtk.STYLE_CLASS_SUGGESTED_ACTION)
|
|
self.button_connect.set_can_default(True)
|
|
tooltips.set_tip(self.button_connect, _('Connect the Tryton server'))
|
|
self.dialog.add_action_widget(self.button_connect, gtk.RESPONSE_OK)
|
|
self.dialog.set_default_response(gtk.RESPONSE_OK)
|
|
alignment = gtk.Alignment(yalign=0, yscale=0, xscale=1)
|
|
self.table_main = gtk.Table(3, 3, False)
|
|
self.table_main.set_border_width(0)
|
|
self.table_main.set_row_spacings(3)
|
|
self.table_main.set_col_spacings(3)
|
|
alignment.add(self.table_main)
|
|
self.dialog.vbox.pack_start(alignment, True, True, 0)
|
|
|
|
image = gtk.Image()
|
|
image.set_from_file(os.path.join(PIXMAPS_DIR, 'tryton.png'))
|
|
image.set_alignment(0.5, 1)
|
|
overlay = Gtk.Overlay()
|
|
overlay.add(image)
|
|
label = Gtk.Label(__version__)
|
|
label.props.halign = Gtk.Align.END
|
|
label.props.valign = Gtk.Align.START
|
|
label.props.margin_right = 10
|
|
label.props.margin_top = 5
|
|
label.override_color(
|
|
Gtk.StateFlags.NORMAL, Gdk.RGBA(1, 1, 1, 1))
|
|
overlay.add_overlay(label)
|
|
self.table_main.attach(overlay, 0, 3, 0, 1, ypadding=2)
|
|
|
|
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(set_underline(_('Profile:')))
|
|
self.profile_label.set_use_underline(True)
|
|
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_label.set_mnemonic_widget(self.combo_profile)
|
|
self.profile_button = gtk.Button(set_underline(_('Manage...')),
|
|
use_underline=True)
|
|
self.profile_button.connect('clicked', self.profile_manage)
|
|
self.table_main.attach(self.profile_label, 0, 1, 1, 2,
|
|
xoptions=gtk.FILL)
|
|
self.table_main.attach(self.combo_profile, 1, 2, 1, 2)
|
|
self.table_main.attach(self.profile_button, 2, 3, 1, 2,
|
|
xoptions=gtk.FILL)
|
|
self.expander = gtk.Expander()
|
|
self.expander.set_label(_('Host / Database information'))
|
|
self.expander.connect('notify::expanded', self.expand_hostspec)
|
|
self.table_main.attach(self.expander, 0, 3, 3, 4)
|
|
self.label_host = gtk.Label(set_underline(_('Host:')))
|
|
self.label_host.set_use_underline(True)
|
|
self.label_host.set_justify(gtk.JUSTIFY_RIGHT)
|
|
self.label_host.set_alignment(1, 0.5)
|
|
self.label_host.set_padding(3, 3)
|
|
self.entry_host = gtk.Entry()
|
|
self.entry_host.connect_after('focus-out-event',
|
|
self.clear_profile_combo)
|
|
self.entry_host.set_activates_default(True)
|
|
self.label_host.set_mnemonic_widget(self.entry_host)
|
|
self.table_main.attach(self.label_host, 0, 1, 4, 5, xoptions=gtk.FILL)
|
|
self.table_main.attach(self.entry_host, 1, 3, 4, 5)
|
|
self.label_database = gtk.Label(set_underline(_('Database:')))
|
|
self.label_database.set_use_underline(True)
|
|
self.label_database.set_justify(gtk.JUSTIFY_RIGHT)
|
|
self.label_database.set_alignment(1, 0.5)
|
|
self.label_database.set_padding(3, 3)
|
|
self.entry_database = gtk.Entry()
|
|
self.entry_database.connect_after('focus-out-event',
|
|
self.clear_profile_combo)
|
|
self.entry_database.set_activates_default(True)
|
|
self.label_database.set_mnemonic_widget(self.entry_database)
|
|
self.table_main.attach(self.label_database, 0, 1, 5, 6,
|
|
xoptions=gtk.FILL)
|
|
self.table_main.attach(self.entry_database, 1, 3, 5, 6)
|
|
self.entry_login = gtk.Entry()
|
|
self.entry_login.set_activates_default(True)
|
|
self.table_main.attach(self.entry_login, 1, 3, 6, 7)
|
|
label_username = gtk.Label(set_underline(_("User name:")))
|
|
label_username.set_use_underline(True)
|
|
label_username.set_alignment(1, 0.5)
|
|
label_username.set_padding(3, 3)
|
|
label_username.set_mnemonic_widget(self.entry_login)
|
|
self.table_main.attach(label_username, 0, 1, 6, 7, xoptions=gtk.FILL)
|
|
|
|
# Profile information
|
|
self.profile_cfg = os.path.join(get_config_dir(), 'profiles.cfg')
|
|
self.profiles = configparser.ConfigParser()
|
|
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, 'database', 'demo%s' % short_version)
|
|
self.profiles.set(name, 'username', 'demo')
|
|
else:
|
|
try:
|
|
self.profiles.read(self.profile_cfg)
|
|
except configparser.ParsingError:
|
|
logger.error("Fail to parse profiles.cfg", exc_info=True)
|
|
for section in self.profiles.sections():
|
|
active = all(self.profiles.has_option(section, option)
|
|
for option in ('host', 'database'))
|
|
self.profile_store.append([section, active])
|
|
|
|
def profile_manage(self, widget):
|
|
def callback(profile_name):
|
|
with open(self.profile_cfg, 'w') as configfile:
|
|
self.profiles.write(configfile)
|
|
|
|
for idx, row in enumerate(self.profile_store):
|
|
if row[0] == profile_name and row[1]:
|
|
self.combo_profile.set_active(idx)
|
|
self.profile_changed(self.combo_profile)
|
|
break
|
|
|
|
dia = DBListEditor(self.dialog, self.profile_store, self.profiles,
|
|
callback)
|
|
active_profile = self.combo_profile.get_active()
|
|
profile_name = None
|
|
if active_profile != -1:
|
|
profile_name = self.profile_store[active_profile][0]
|
|
dia.run(profile_name)
|
|
|
|
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 = ''
|
|
host = self.profiles.get(profile, 'host')
|
|
self.entry_host.set_text('%s' % host)
|
|
self.entry_database.set_text(self.profiles.get(profile, 'database'))
|
|
if username:
|
|
self.entry_login.set_text(username)
|
|
else:
|
|
self.entry_login.set_text('')
|
|
|
|
def clear_profile_combo(self, *args):
|
|
netloc = self.entry_host.get_text()
|
|
host = common.get_hostname(netloc)
|
|
port = common.get_port(netloc)
|
|
database = self.entry_database.get_text().strip()
|
|
login = self.entry_login.get_text()
|
|
for idx, profile_info in enumerate(self.profile_store):
|
|
if not profile_info[1]:
|
|
continue
|
|
profile = profile_info[0]
|
|
try:
|
|
profile_host = self.profiles.get(profile, 'host')
|
|
profile_db = self.profiles.get(profile, 'database')
|
|
profile_login = self.profiles.get(profile, 'username')
|
|
except configparser.NoOptionError:
|
|
continue
|
|
if (host == common.get_hostname(profile_host)
|
|
and port == common.get_port(profile_host)
|
|
and database == profile_db
|
|
and (not login or login == profile_login)):
|
|
break
|
|
else:
|
|
idx = -1
|
|
self.combo_profile.set_active(idx)
|
|
return False
|
|
|
|
def expand_hostspec(self, expander, *args):
|
|
visibility = expander.props.expanded
|
|
self.entry_host.props.visible = visibility
|
|
self.label_host.props.visible = visibility
|
|
self.entry_database.props.visible = visibility
|
|
self.label_database.props.visible = visibility
|
|
|
|
def run(self):
|
|
profile_name = CONFIG['login.profile']
|
|
can_use_profile = self.profiles.has_section(profile_name)
|
|
if can_use_profile:
|
|
for (configname, option) in [
|
|
('login.host', 'host'),
|
|
('login.db', 'database'),
|
|
]:
|
|
try:
|
|
value = self.profiles.get(profile_name, option)
|
|
except configparser.NoOptionError:
|
|
value = None
|
|
if value != CONFIG[configname]:
|
|
can_use_profile = False
|
|
break
|
|
|
|
if can_use_profile:
|
|
for idx, row in enumerate(self.profile_store):
|
|
if row[0] == profile_name:
|
|
self.combo_profile.set_active(idx)
|
|
break
|
|
else:
|
|
self.combo_profile.set_active(-1)
|
|
host = CONFIG['login.host'] if CONFIG['login.host'] else ''
|
|
self.entry_host.set_text(host)
|
|
db = CONFIG['login.db'] if CONFIG['login.db'] else ''
|
|
self.entry_database.set_text(db)
|
|
self.entry_login.set_text(CONFIG['login.login'])
|
|
self.clear_profile_combo()
|
|
self.dialog.show_all()
|
|
|
|
self.entry_login.grab_focus()
|
|
|
|
# Reshow dialog for gtk-quarks
|
|
self.dialog.reshow_with_initial_size()
|
|
self.expander.set_expanded(CONFIG['login.expanded'])
|
|
# The previous action did not called expand_hostspec
|
|
self.expand_hostspec(self.expander)
|
|
|
|
response, result = None, ('', '', '', '')
|
|
while not all(result):
|
|
response = self.dialog.run()
|
|
if response != gtk.RESPONSE_OK:
|
|
break
|
|
self.clear_profile_combo()
|
|
active_profile = self.combo_profile.get_active()
|
|
if active_profile != -1:
|
|
profile = self.profile_store[active_profile][0]
|
|
else:
|
|
profile = ''
|
|
host = self.entry_host.get_text()
|
|
hostname = common.get_hostname(host)
|
|
port = common.get_port(host)
|
|
test = DBListEditor.test_server_version(hostname, port)
|
|
if not test:
|
|
if test is False:
|
|
common.warning('',
|
|
_('Incompatible version of the server'),
|
|
parent=self.dialog)
|
|
else:
|
|
common.warning('',
|
|
_('Could not connect to the server'),
|
|
parent=self.dialog)
|
|
continue
|
|
database = self.entry_database.get_text()
|
|
login = self.entry_login.get_text()
|
|
CONFIG['login.profile'] = profile
|
|
CONFIG['login.host'] = host
|
|
CONFIG['login.db'] = database
|
|
CONFIG['login.expanded'] = self.expander.props.expanded
|
|
CONFIG['login.login'] = login
|
|
result = (
|
|
hostname, port, database, self.entry_login.get_text())
|
|
|
|
self.dialog.destroy()
|
|
self._window.destroy()
|
|
return response == gtk.RESPONSE_OK
|