diff --git a/tryton/common/common.py b/tryton/common/common.py index 76491ea9b7..a9bba0d58a 100644 --- a/tryton/common/common.py +++ b/tryton/common/common.py @@ -4,6 +4,7 @@ from gtk import glade import gobject import gettext import os +import re import logging from tryton.config import CONFIG from tryton.config import GLADE, TRYTON_ICON, PIXMAPS_DIR, DATA_DIR @@ -14,9 +15,113 @@ import md5 import webbrowser import traceback import tryton.rpc as rpc +import locale _ = gettext.gettext +def refresh_dblist(db_widget, host, port, dbtoload=None): + 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) + +def refresh_langlist(lang_widget, host, port): + liststore = lang_widget.get_model() + liststore.clear() + lang_list = rpc.db_exec(host, port, 'list_lang') + from tryton.gui.main import Main + Main.get_main().refresh_ssl() + 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, parent): + result = False + dialog = gtk.Dialog( + title = _('Server'), + parent = parent, + flags = gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT | + gtk.WIN_POS_CENTER_ON_PARENT | + gtk.gdk.WINDOW_TYPE_HINT_DIALOG,) + vbox = gtk.VBox() + label_connect = gtk.Label(_("Connect to a Tryton server")) + label_connect.set_use_markup(True) + label_connect.set_alignment(0, 0.5) + vbox.pack_start(label_connect, False, False, 0) + hseparator = gtk.HSeparator() + vbox.pack_start(hseparator, False, True, 0) + table = gtk.Table(2, 2, False) + table.set_border_width(12) + table.set_row_spacings(6) + vbox.pack_start(table, False, True, 0) + label_server = gtk.Label(_("Server:")) + label_server.set_alignment(1, 0) + label_server.set_padding(3, 0) + table.attach(label_server, 0, 1, 0, 1, yoptions=False, + xoptions=gtk.FILL) + entry_port = gtk.Entry() + entry_port.set_max_length(5) + entry_port.set_text("8069") + entry_port.set_activates_default(True) + entry_port.set_width_chars(16) + table.attach(entry_port, 1, 2, 1, 2, yoptions=False, + xoptions=gtk.FILL) + entry_server = gtk.Entry() + entry_server.set_text("localhost") + entry_server.set_activates_default(True) + entry_server.set_width_chars(16) + table.attach(entry_server, 1, 2, 0, 1,yoptions=False, + xoptions=gtk.FILL | gtk.EXPAND) + label_port = gtk.Label(_("Port:")) + label_port.set_alignment(1, 0.5) + label_port.set_padding(3, 3) + table.attach(label_port, 0, 1, 1, 2, yoptions=False, + xoptions=False) + dialog.add_button("gtk-cancel", gtk.RESPONSE_CANCEL | gtk.CAN_DEFAULT) + dialog.add_button("gtk-ok", gtk.RESPONSE_OK) + dialog.vbox.pack_start(vbox) + dialog.set_icon(TRYTON_ICON) + dialog.show_all() + dialog.set_default_response(gtk.RESPONSE_OK) + + url_m = re.match('^([\w.-]+):(\d{1,5})$', + server_widget.get_text()) + if url_m: + entry_server.set_text(url_m.group(1)) + entry_port.set_text(url_m.group(2)) + + res = dialog.run() + if res == gtk.RESPONSE_OK: + host = entry_server.get_text() + port = int(entry_port.get_text()) + url = '%s:%d' % (host, port) + server_widget.set_text(url) + result = (host, port) + parent.present() + dialog.destroy() + return result + def selection(title, values, parent, alwaysask=False): if not values or len(values)==0: diff --git a/tryton/gui/main.py b/tryton/gui/main.py index a8321d8e1d..32e3b95e7a 100644 --- a/tryton/gui/main.py +++ b/tryton/gui/main.py @@ -13,526 +13,17 @@ from tryton.action import Action from tryton.gui.window import Window 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.tips import Tips +from tryton.gui.window.credits import Credits import re import base64 import tryton.translate as translate import tryton.plugin -import locale _ = gettext.gettext -def _refresh_dblist(db_widget, host, port, dbtoload=None): - if not dbtoload: - dbtoload = CONFIG['login.db'] - index = 0 - liststore = db_widget.get_model() - liststore.clear() - result = rpc.db_list(host, port) - 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) - -def _refresh_langlist(lang_widget, host, port): - liststore = lang_widget.get_model() - liststore.clear() - lang_list = rpc.db_exec(host, port, 'list_lang') - Main.get_main().refresh_ssl() - 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, parent): - result = False - dialog = gtk.Dialog( - title = _('Server'), - parent = parent, - flags = gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT | - gtk.WIN_POS_CENTER_ON_PARENT | - gtk.gdk.WINDOW_TYPE_HINT_DIALOG,) - vbox = gtk.VBox() - label_connect = gtk.Label(_("Connect to a Tryton server")) - label_connect.set_use_markup(True) - label_connect.set_alignment(0, 0.5) - vbox.pack_start(label_connect, False, False, 0) - hseparator = gtk.HSeparator() - vbox.pack_start(hseparator, False, True, 0) - table = gtk.Table(2, 2, False) - table.set_border_width(12) - table.set_row_spacings(6) - vbox.pack_start(table, False, True, 0) - label_server = gtk.Label(_("Server:")) - label_server.set_alignment(1, 0) - label_server.set_padding(3, 0) - table.attach(label_server, 0, 1, 0, 1, yoptions=False, - xoptions=gtk.FILL) - entry_port = gtk.Entry() - entry_port.set_max_length(5) - entry_port.set_text("8069") - entry_port.set_activates_default(True) - entry_port.set_width_chars(16) - table.attach(entry_port, 1, 2, 1, 2, yoptions=False, - xoptions=gtk.FILL) - entry_server = gtk.Entry() - entry_server.set_text("localhost") - entry_server.set_activates_default(True) - entry_server.set_width_chars(16) - table.attach(entry_server, 1, 2, 0, 1,yoptions=False, - xoptions=gtk.FILL | gtk.EXPAND) - label_port = gtk.Label(_("Port:")) - label_port.set_alignment(1, 0.5) - label_port.set_padding(3, 3) - table.attach(label_port, 0, 1, 1, 2, yoptions=False, - xoptions=False) - dialog.add_button("gtk-cancel", gtk.RESPONSE_CANCEL | gtk.CAN_DEFAULT) - dialog.add_button("gtk-ok", gtk.RESPONSE_OK) - dialog.vbox.pack_start(vbox) - dialog.set_icon(TRYTON_ICON) - dialog.show_all() - dialog.set_default_response(gtk.RESPONSE_OK) - - url_m = re.match('^([\w.-]+):(\d{1,5})$', - server_widget.get_text()) - if url_m: - entry_server.set_text(url_m.group(1)) - entry_port.set_text(url_m.group(2)) - - res = dialog.run() - if res == gtk.RESPONSE_OK: - host = entry_server.get_text() - port = int(entry_port.get_text()) - url = '%s:%d' % (host, port) - server_widget.set_text(url) - result = (host, port) - parent.present() - dialog.destroy() - return result - - -class DBLogin(object): - def __init__(self, parent): - self.dialog = gtk.Dialog(title=_('Login'), parent=parent, - flags=gtk.DIALOG_MODAL|gtk.DIALOG_DESTROY_WITH_PARENT) - self.dialog.set_size_request(500, 301) - self.dialog.set_position(gtk.WIN_POS_CENTER_ON_PARENT) - self.dialog.set_has_separator(False) - self.dialog.set_icon(TRYTON_ICON) - self.dialog.add_button(gtk.STOCK_CLOSE, gtk.RESPONSE_CANCEL) - self.button_connect = gtk.Button(_('C_onnect')) - img_connect = gtk.Image() - img_connect.set_from_stock('tryton-connect', gtk.ICON_SIZE_BUTTON) - self.button_connect.set_image(img_connect) - self.button_connect.set_flags(gtk.CAN_DEFAULT) - self.dialog.add_action_widget(self.button_connect, gtk.RESPONSE_OK) - self.dialog.set_default_response(gtk.RESPONSE_OK) - dialog_vbox = gtk.VBox() - vbox_image = gtk.VBox() - image = gtk.Image() - image.set_from_file(os.path.join(PIXMAPS_DIR, 'tryton.png')) - image.set_size_request(500, 129) - vbox_image.pack_start(image) - dialog_vbox.pack_start(vbox_image) - 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) - vbox_image.pack_start(table_main, True, True, 0) - vbox_combo = gtk.VBox() - self.combo_database = gtk.ComboBox() - self.combo_label = gtk.Label() - self.combo_label.set_use_markup(True) - self.combo_label.set_alignment(0, 1) - vbox_combo.pack_start(self.combo_database, True, True, 0) - vbox_combo.pack_start(self.combo_label, False, False, 0) - table_main.attach(vbox_combo, 1, 3, 1, 2) - 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.entry_login = gtk.Entry() - self.entry_login.set_text("admin") - self.entry_login.set_activates_default(True) - table_main.attach(self.entry_login, 1, 3, 2, 3) - label_server = gtk.Label() - label_server.set_text(_("Server:")) - label_server.set_alignment(1, 0.5) - label_server.set_padding(3, 3) - table_main.attach(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) - table_main.attach(self.button_server, 2, 3, 0, 1, xoptions=gtk.FILL) - 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) - 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.entry_password.grab_focus() - self.dialog.vbox.pack_start(dialog_vbox) - - @staticmethod - def refreshlist(widget, db_widget, label, host, port, butconnect=None): - res = _refresh_dblist(db_widget, host, port) - if res is None: - label.set_label(''+_('Could not connect to server!')+'') - db_widget.hide() - label.show() - if butconnect: - butconnect.set_sensitive(False) - elif res==0: - label.set_label('' + \ - _('No database found, you must create one!') + '') - db_widget.hide() - label.show() - if butconnect: - butconnect.set_sensitive(False) - else: - label.hide() - db_widget.show() - if butconnect: - butconnect.set_sensitive(True) - return res - - @staticmethod - def refreshlist_ask(widget, server_widget, db_widget, label, - butconnect=False, host=False, port=0, parent=None): - host, port = _request_server(server_widget, parent) or (host, port) - return DBLogin.refreshlist(widget, db_widget, label, host, port, - butconnect) - - def run(self, dbname, parent): - self.dialog.show_all() - self.combo_label.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, - host, port, self.button_connect) - - self.button_server.connect_after('clicked', DBLogin.refreshlist_ask, - self.entry_server, self.combo_database, self.combo_label, - 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) - - 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') - if res != gtk.RESPONSE_OK: - parent.present() - self.dialog.destroy() - rpc.logout() - Main.get_main().refresh_ssl() - raise Exception('QueryCanceled') - parent.present() - self.dialog.destroy() - return result - -class DBCreate(object): - def set_sensitive(self, sensitive): - if sensitive: - label = self.dialog.get_widget('db_label_info') - label.set_text(_('Do not use special characters!')) - self.dialog.get_widget('button_db_ok').set_sensitive(True) - else: - label = self.dialog.get_widget('db_label_info') - label.set_markup('' + \ - _('Can not connect to server!') + '') - self.dialog.get_widget('button_db_ok').set_sensitive(False) - return sensitive - - def server_change(self, widget, parent): - host, port = _request_server(self.server_widget, parent) - try: - if self.lang_widget and host and port: - _refresh_langlist(self.lang_widget, host, port) - self.set_sensitive(True) - except: - self.set_sensitive(False) - return False - return url - - def __init__(self, sig_login): - self.dialog = glade.XML(GLADE, "win_createdb", gettext.textdomain()) - self.sig_login = sig_login - self.lang_widget = self.dialog.get_widget('db_create_combo') - self.db_widget = self.dialog.get_widget('ent_db') - self.server_widget = self.dialog.get_widget('ent_server_new') - - def run(self, parent): - win = self.dialog.get_widget('win_createdb') - win.set_default_response(gtk.RESPONSE_OK) - win.set_transient_for(parent) - win.show_all() - pass_widget = self.dialog.get_widget('ent_password_new') - change_button = self.dialog.get_widget('but_server_new') - - change_button.connect_after('clicked', self.server_change, win) - host = CONFIG['login.server'] - port = int(CONFIG['login.port']) - url = '%s:%d' % (host, port) - - self.server_widget.set_text(url) - liststore = gtk.ListStore(str, str) - self.lang_widget.set_model(liststore) - try: - _refresh_langlist(self.lang_widget, host, port) - except: - self.set_sensitive(False) - - while True: - res = win.run() - dbname = self.db_widget.get_text() - if (res==gtk.RESPONSE_OK) \ - and ((not dbname) \ - or (not re.match('^[a-zA-Z][a-zA-Z0-9_]+$', dbname))): - common.warning(_('The database name must contain ' \ - 'only normal characters or "_".\n' \ - 'You must avoid all accents, space ' \ - 'or special characters.'), parent, - _('Bad database name!')) - - else: - break - - langidx = self.lang_widget.get_active_iter() - langreal = langidx \ - and self.lang_widget.get_model().get_value(langidx, 1) - passwd = pass_widget.get_text() - url = self.server_widget.get_text() - url_m = re.match('^([\w.\-]+):(\d{1,5})$', - url or '') - if url_m: - CONFIG['login.server'] = host = url_m.group(1) - CONFIG['login.port'] = port = url_m.group(2) - parent.present() - win.destroy() - - if res == gtk.RESPONSE_OK: - try: - if rpc.db_exec(host, int(port), 'db_exist', dbname): - common.warning(_('Try with an other name.'), parent, - _('The Database already exists!')) - return False - users = rpc.db_exec(host, int(port), 'create', passwd, dbname, - langreal) - Main.get_main().refresh_ssl() - except Exception, exception: - common.warning(_('The server crashed during installation.\n' \ - 'We suggest you to drop this database.\n' \ - 'Error message:\n') + str(exception[0]), parent, - _("Error during database creation!")) - return False - dialog = glade.XML(GLADE, "dia_dbcreate_ok", gettext.textdomain()) - win = dialog.get_widget('dia_dbcreate_ok') - win.set_transient_for(parent) - win.show_all() - buf = dialog.get_widget('dia_tv').get_buffer() - - buf.delete(buf.get_start_iter(), buf.get_end_iter()) - iter_start = buf.get_start_iter() - - pwdlst = '\n'.join([' - %s: %s / %s' % \ - (x['name'], x['login'], x['password']) for x in users]) - - buf.insert(iter_start, _('The following users have been ' \ - 'installed on your database:') + '\n\n' + pwdlst + \ - '\n\n' + _('You can now connect to the database ' \ - 'as an administrator.')) - res = win.run() - parent.present() - win.destroy() - - if res == gtk.RESPONSE_OK: - url_m = re.match('^(http[s]?://|socket://)([\w.]+):(\d{1,5})$', - url) - res = ['admin', 'admin'] - if url_m: - res.append(url_m.group(2)) - res.append(url_m.group(3)) - res.append(url_m.group(1)) - res.append(dbname) - - self.sig_login(dbname=dbname) - return True - else: - rpc.logout() - Main.get_main().refresh_ssl() - - -class Tips(object): - - def __init__(self, parent): - self.win = gtk.Dialog(_('Tips'), parent, - gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT) - self.win.set_icon(TRYTON_ICON) - - self.win.add_button(gtk.STOCK_CLOSE, gtk.RESPONSE_CLOSE) - - vbox = gtk.VBox() - img = gtk.Image() - img.set_from_file(os.path.join(PIXMAPS_DIR, 'tryton.png')) - vbox.pack_start(img, False, False) - self.label = gtk.Label() - self.label.set_alignment(0, 0) - vbox.pack_start(self.label, True, True) - separator = gtk.HSeparator() - vbox.pack_start(separator, False, False) - - hbox = gtk.HBox() - self.check = gtk.CheckButton(_('_Display a new tip next time'), True) - self.check.set_active(True) - hbox.pack_start(self.check) - but_previous = gtk.Button() - hbox_previous = gtk.HBox() - img_previous = gtk.Image() - img_previous.set_from_stock('tryton-go-previous', gtk.ICON_SIZE_BUTTON) - hbox_previous.pack_start(img_previous) - label_previous = gtk.Label(_('Previous')) - hbox_previous.pack_start(label_previous) - but_previous.add(hbox_previous) - but_previous.set_relief(gtk.RELIEF_NONE) - but_previous.connect('clicked', self.tip_previous) - hbox.pack_start(but_previous) - hbox_next = gtk.HBox() - label_next = gtk.Label(_('Next')) - hbox_next.pack_start(label_next) - but_next = gtk.Button() - img_next = gtk.Image() - img_next.set_from_stock('tryton-go-next', gtk.ICON_SIZE_BUTTON) - hbox_next.pack_start(img_next) - but_next.add(hbox_next) - but_next.set_relief(gtk.RELIEF_NONE) - but_next.connect('clicked', self.tip_next) - hbox.pack_start(but_next) - vbox.pack_start(hbox, False, False) - self.win.vbox.pack_start(vbox) - self.win.show_all() - - try: - self.number = int(CONFIG['tip.position']) - except: - self.number = 0 - - self.tip_set() - - self.win.run() - CONFIG['tip.autostart'] = self.check.get_active() - CONFIG['tip.position'] = self.number + 1 - CONFIG.save() - parent.present() - self.win.destroy() - - def tip_set(self): - lang = CONFIG['client.lang'] - tip_file = False - if lang: - tip_file = os.path.join(DATA_DIR, 'tipoftheday.'+lang+'.txt') - if not os.path.isfile(tip_file): - tip_file = os.path.join(DATA_DIR, 'tipoftheday.txt') - if not os.path.isfile(tip_file): - return - tips = file(tip_file).read().split('---') - tip = tips[self.number % len(tips)].lstrip() - del tips - self.label.set_text(tip) - self.label.set_use_markup(True) - - def tip_next(self, widget): - self.number += 1 - self.tip_set() - - def tip_previous(self, widget): - self.number -= 1 - self.tip_set() - - -class Credits(object): - - def __init__(self, parent): - self.win = gtk.Dialog(_('Credits'), parent, - gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT) - self.win.set_icon(TRYTON_ICON) - - self.win.add_button(gtk.STOCK_CLOSE, gtk.RESPONSE_CLOSE) - - vbox = gtk.VBox() - img = gtk.Image() - img.set_from_file(os.path.join(PIXMAPS_DIR, 'tryton.png')) - vbox.pack_start(img, False, False) - self.label = gtk.Label() - self.label.set_alignment(0.5, 0) - contributors_file = os.path.join(DATA_DIR, 'contributors.txt') - contributors = '\n' + _('Contributors:') + '\n\n' - contributors += file(contributors_file).read() - self.label.set_text(contributors) - self.label.set_use_markup(True) - vbox.pack_start(self.label, True, True) - self.win.vbox.pack_start(vbox) - self.win.show_all() - - self.win.run() - parent.present() - self.win.destroy() _MAIN = [] @@ -1204,7 +695,7 @@ class Main(object): new_pass2_widget = dialog.get_widget('new_passwd2') change_button = dialog.get_widget('but_server_change') change_button.connect_after('clicked', \ - lambda a,b: _request_server(b, win), server_widget) + lambda a,b: common.request_server(b, win), server_widget) host = CONFIG['login.server'] port = int(CONFIG['login.port']) @@ -1272,7 +763,7 @@ class Main(object): def _choose_db_select(self, title=_("Backup a database")): def refreshlist(widget, db_widget, label, host, port): - res = _refresh_dblist(db_widget, host, port) + res = common.refresh_dblist(db_widget, host, port) if res == -1: label.set_label('' + \ _('Could not connect to server !') + '') @@ -1290,7 +781,7 @@ class Main(object): def refreshlist_ask(widget, server_widget, db_widget, label, parent=None): - host, port = _request_server(server_widget, parent) + host, port = common.request_server(server_widget, parent) if not url: return None refreshlist(widget, db_widget, label, host, port) @@ -1358,8 +849,8 @@ class Main(object): widget_url.set_text(url) change_button = dialog.get_widget('but_server_change') - change_button.connect_after('clicked', lambda a, b: _request_server(b, win), - widget_url) + change_button.connect_after('clicked', + lambda a, b: common.request_server(b, win), widget_url) res = win.run() diff --git a/tryton/gui/window/credits.py b/tryton/gui/window/credits.py new file mode 100644 index 0000000000..0f11470693 --- /dev/null +++ b/tryton/gui/window/credits.py @@ -0,0 +1,36 @@ +#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 os +from tryton.config import TRYTON_ICON, PIXMAPS_DIR, DATA_DIR + +_ = gettext.gettext + + +class Credits(object): + + def __init__(self, parent): + self.win = gtk.Dialog(_('Credits'), parent, + gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT) + self.win.set_icon(TRYTON_ICON) + + self.win.add_button(gtk.STOCK_CLOSE, gtk.RESPONSE_CLOSE) + + vbox = gtk.VBox() + img = gtk.Image() + img.set_from_file(os.path.join(PIXMAPS_DIR, 'tryton.png')) + vbox.pack_start(img, False, False) + self.label = gtk.Label() + self.label.set_alignment(0.5, 0) + contributors_file = os.path.join(DATA_DIR, 'contributors.txt') + contributors = '\n' + _('Contributors:') + '\n\n' + contributors += file(contributors_file).read() + self.label.set_text(contributors) + self.label.set_use_markup(True) + vbox.pack_start(self.label, True, True) + self.win.vbox.pack_start(vbox) + self.win.show_all() + + self.win.run() + parent.present() + self.win.destroy() diff --git a/tryton/gui/window/dbcreate.py b/tryton/gui/window/dbcreate.py new file mode 100644 index 0000000000..acf06ae5f2 --- /dev/null +++ b/tryton/gui/window/dbcreate.py @@ -0,0 +1,145 @@ +#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 +from gtk import glade +import gettext +import re +import tryton.common as common +from tryton.config import CONFIG, GLADE, TRYTON_ICON, PIXMAPS_DIR +import tryton.rpc as rpc + +_ = gettext.gettext + + +class DBCreate(object): + def set_sensitive(self, sensitive): + if sensitive: + label = self.dialog.get_widget('db_label_info') + label.set_text(_('Do not use special characters!')) + self.dialog.get_widget('button_db_ok').set_sensitive(True) + else: + label = self.dialog.get_widget('db_label_info') + label.set_markup('' + \ + _('Can not connect to server!') + '') + self.dialog.get_widget('button_db_ok').set_sensitive(False) + return sensitive + + def server_change(self, widget, parent): + host, port = common.request_server(self.server_widget, parent) + try: + if self.lang_widget and host and port: + common.refresh_langlist(self.lang_widget, host, port) + self.set_sensitive(True) + except: + self.set_sensitive(False) + return False + return url + + def __init__(self, sig_login): + self.dialog = glade.XML(GLADE, "win_createdb", gettext.textdomain()) + self.sig_login = sig_login + self.lang_widget = self.dialog.get_widget('db_create_combo') + self.db_widget = self.dialog.get_widget('ent_db') + self.server_widget = self.dialog.get_widget('ent_server_new') + + def run(self, parent): + win = self.dialog.get_widget('win_createdb') + win.set_default_response(gtk.RESPONSE_OK) + win.set_transient_for(parent) + win.show_all() + pass_widget = self.dialog.get_widget('ent_password_new') + change_button = self.dialog.get_widget('but_server_new') + + change_button.connect_after('clicked', self.server_change, win) + host = CONFIG['login.server'] + port = int(CONFIG['login.port']) + url = '%s:%d' % (host, port) + + self.server_widget.set_text(url) + liststore = gtk.ListStore(str, str) + self.lang_widget.set_model(liststore) + try: + common.refresh_langlist(self.lang_widget, host, port) + except: + self.set_sensitive(False) + + while True: + res = win.run() + dbname = self.db_widget.get_text() + if (res==gtk.RESPONSE_OK) \ + and ((not dbname) \ + or (not re.match('^[a-zA-Z][a-zA-Z0-9_]+$', dbname))): + common.warning(_('The database name must contain ' \ + 'only normal characters or "_".\n' \ + 'You must avoid all accents, space ' \ + 'or special characters.'), parent, + _('Bad database name!')) + + else: + break + + langidx = self.lang_widget.get_active_iter() + langreal = langidx \ + and self.lang_widget.get_model().get_value(langidx, 1) + passwd = pass_widget.get_text() + url = self.server_widget.get_text() + url_m = re.match('^([\w.\-]+):(\d{1,5})$', + url or '') + if url_m: + CONFIG['login.server'] = host = url_m.group(1) + CONFIG['login.port'] = port = url_m.group(2) + parent.present() + win.destroy() + + if res == gtk.RESPONSE_OK: + try: + if rpc.db_exec(host, int(port), 'db_exist', dbname): + common.warning(_('Try with an other name.'), parent, + _('The Database already exists!')) + return False + users = rpc.db_exec(host, int(port), 'create', passwd, dbname, + langreal) + from tryton.gui.main import Main + Main.get_main().refresh_ssl() + except Exception, exception: + common.warning(_('The server crashed during installation.\n' \ + 'We suggest you to drop this database.\n' \ + 'Error message:\n') + str(exception[0]), parent, + _("Error during database creation!")) + return False + dialog = glade.XML(GLADE, "dia_dbcreate_ok", gettext.textdomain()) + win = dialog.get_widget('dia_dbcreate_ok') + win.set_transient_for(parent) + win.show_all() + buf = dialog.get_widget('dia_tv').get_buffer() + + buf.delete(buf.get_start_iter(), buf.get_end_iter()) + iter_start = buf.get_start_iter() + + pwdlst = '\n'.join([' - %s: %s / %s' % \ + (x['name'], x['login'], x['password']) for x in users]) + + buf.insert(iter_start, _('The following users have been ' \ + 'installed on your database:') + '\n\n' + pwdlst + \ + '\n\n' + _('You can now connect to the database ' \ + 'as an administrator.')) + res = win.run() + parent.present() + win.destroy() + + if res == gtk.RESPONSE_OK: + url_m = re.match('^(http[s]?://|socket://)([\w.]+):(\d{1,5})$', + url) + res = ['admin', 'admin'] + if url_m: + res.append(url_m.group(2)) + res.append(url_m.group(3)) + res.append(url_m.group(1)) + res.append(dbname) + + self.sig_login(dbname=dbname) + return True + else: + rpc.logout() + from tryton.gui.main import Main + Main.get_main().refresh_ssl() + diff --git a/tryton/gui/window/dblogin.py b/tryton/gui/window/dblogin.py new file mode 100644 index 0000000000..e541fa9685 --- /dev/null +++ b/tryton/gui/window/dblogin.py @@ -0,0 +1,177 @@ +#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 os +import re +import gettext +import tryton.common as common +from tryton.config import CONFIG, TRYTON_ICON, PIXMAPS_DIR +import tryton.rpc as rpc + +_ = gettext.gettext + + +class DBLogin(object): + def __init__(self, parent): + self.dialog = gtk.Dialog(title=_('Login'), parent=parent, + flags=gtk.DIALOG_MODAL|gtk.DIALOG_DESTROY_WITH_PARENT) + self.dialog.set_size_request(500, 301) + self.dialog.set_position(gtk.WIN_POS_CENTER_ON_PARENT) + self.dialog.set_has_separator(False) + self.dialog.set_icon(TRYTON_ICON) + self.dialog.add_button(gtk.STOCK_CLOSE, gtk.RESPONSE_CANCEL) + self.button_connect = gtk.Button(_('C_onnect')) + img_connect = gtk.Image() + img_connect.set_from_stock('tryton-connect', gtk.ICON_SIZE_BUTTON) + self.button_connect.set_image(img_connect) + self.button_connect.set_flags(gtk.CAN_DEFAULT) + self.dialog.add_action_widget(self.button_connect, gtk.RESPONSE_OK) + self.dialog.set_default_response(gtk.RESPONSE_OK) + dialog_vbox = gtk.VBox() + vbox_image = gtk.VBox() + image = gtk.Image() + image.set_from_file(os.path.join(PIXMAPS_DIR, 'tryton.png')) + image.set_size_request(500, 129) + vbox_image.pack_start(image) + dialog_vbox.pack_start(vbox_image) + 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) + vbox_image.pack_start(table_main, True, True, 0) + vbox_combo = gtk.VBox() + self.combo_database = gtk.ComboBox() + self.combo_label = gtk.Label() + self.combo_label.set_use_markup(True) + self.combo_label.set_alignment(0, 1) + vbox_combo.pack_start(self.combo_database, True, True, 0) + vbox_combo.pack_start(self.combo_label, False, False, 0) + table_main.attach(vbox_combo, 1, 3, 1, 2) + 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.entry_login = gtk.Entry() + self.entry_login.set_text("admin") + self.entry_login.set_activates_default(True) + table_main.attach(self.entry_login, 1, 3, 2, 3) + label_server = gtk.Label() + label_server.set_text(_("Server:")) + label_server.set_alignment(1, 0.5) + label_server.set_padding(3, 3) + table_main.attach(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) + table_main.attach(self.button_server, 2, 3, 0, 1, xoptions=gtk.FILL) + 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) + 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.entry_password.grab_focus() + self.dialog.vbox.pack_start(dialog_vbox) + + @staticmethod + def refreshlist(widget, db_widget, label, host, port, butconnect=None): + res = common.refresh_dblist(db_widget, host, port) + if res is None: + label.set_label(''+_('Could not connect to server!')+'') + db_widget.hide() + label.show() + if butconnect: + butconnect.set_sensitive(False) + elif res==0: + label.set_label('' + \ + _('No database found, you must create one!') + '') + db_widget.hide() + label.show() + if butconnect: + butconnect.set_sensitive(False) + else: + label.hide() + db_widget.show() + if butconnect: + butconnect.set_sensitive(True) + return res + + @staticmethod + def refreshlist_ask(widget, server_widget, db_widget, label, + butconnect=False, host=False, port=0, parent=None): + host, port = common.request_server(server_widget, parent) or (host, port) + return DBLogin.refreshlist(widget, db_widget, label, host, port, + butconnect) + + def run(self, dbname, parent): + self.dialog.show_all() + self.combo_label.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, + host, port, self.button_connect) + + self.button_server.connect_after('clicked', DBLogin.refreshlist_ask, + self.entry_server, self.combo_database, self.combo_label, + 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) + + 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') + if res != gtk.RESPONSE_OK: + parent.present() + self.dialog.destroy() + rpc.logout() + from tryton.gui.main import Main + Main.get_main().refresh_ssl() + raise Exception('QueryCanceled') + parent.present() + self.dialog.destroy() + return result + diff --git a/tryton/gui/window/tips.py b/tryton/gui/window/tips.py new file mode 100644 index 0000000000..4a73601cf1 --- /dev/null +++ b/tryton/gui/window/tips.py @@ -0,0 +1,96 @@ +#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 os +from tryton.config import CONFIG, TRYTON_ICON, PIXMAPS_DIR, DATA_DIR + +_ = gettext.gettext + + +class Tips(object): + + def __init__(self, parent): + self.win = gtk.Dialog(_('Tips'), parent, + gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT) + self.win.set_icon(TRYTON_ICON) + + self.win.add_button(gtk.STOCK_CLOSE, gtk.RESPONSE_CLOSE) + + vbox = gtk.VBox() + img = gtk.Image() + img.set_from_file(os.path.join(PIXMAPS_DIR, 'tryton.png')) + vbox.pack_start(img, False, False) + self.label = gtk.Label() + self.label.set_alignment(0, 0) + vbox.pack_start(self.label, True, True) + separator = gtk.HSeparator() + vbox.pack_start(separator, False, False) + + hbox = gtk.HBox() + self.check = gtk.CheckButton(_('_Display a new tip next time'), True) + self.check.set_active(True) + hbox.pack_start(self.check) + but_previous = gtk.Button() + hbox_previous = gtk.HBox() + img_previous = gtk.Image() + img_previous.set_from_stock('tryton-go-previous', gtk.ICON_SIZE_BUTTON) + hbox_previous.pack_start(img_previous) + label_previous = gtk.Label(_('Previous')) + hbox_previous.pack_start(label_previous) + but_previous.add(hbox_previous) + but_previous.set_relief(gtk.RELIEF_NONE) + but_previous.connect('clicked', self.tip_previous) + hbox.pack_start(but_previous) + hbox_next = gtk.HBox() + label_next = gtk.Label(_('Next')) + hbox_next.pack_start(label_next) + but_next = gtk.Button() + img_next = gtk.Image() + img_next.set_from_stock('tryton-go-next', gtk.ICON_SIZE_BUTTON) + hbox_next.pack_start(img_next) + but_next.add(hbox_next) + but_next.set_relief(gtk.RELIEF_NONE) + but_next.connect('clicked', self.tip_next) + hbox.pack_start(but_next) + vbox.pack_start(hbox, False, False) + self.win.vbox.pack_start(vbox) + self.win.show_all() + + try: + self.number = int(CONFIG['tip.position']) + except: + self.number = 0 + + self.tip_set() + + self.win.run() + CONFIG['tip.autostart'] = self.check.get_active() + CONFIG['tip.position'] = self.number + 1 + CONFIG.save() + parent.present() + self.win.destroy() + + def tip_set(self): + lang = CONFIG['client.lang'] + tip_file = False + if lang: + tip_file = os.path.join(DATA_DIR, 'tipoftheday.'+lang+'.txt') + if not os.path.isfile(tip_file): + tip_file = os.path.join(DATA_DIR, 'tipoftheday.txt') + if not os.path.isfile(tip_file): + return + tips = file(tip_file).read().split('---') + tip = tips[self.number % len(tips)].lstrip() + del tips + self.label.set_text(tip) + self.label.set_use_markup(True) + + def tip_next(self, widget): + self.number += 1 + self.tip_set() + + def tip_previous(self, widget): + self.number -= 1 + self.tip_set() + +