diff --git a/share/tryton/tryton.glade b/share/tryton/tryton.glade index fdaf0be22f..04332ef184 100644 --- a/share/tryton/tryton.glade +++ b/share/tryton/tryton.glade @@ -509,568 +509,4 @@ Save as CSV - - Import from CSV - True - GTK_WIN_POS_CENTER_ON_PARENT - GDK_WINDOW_TYPE_HINT_DIALOG - - - True - 4 - - - True - 9 - - - True - - - True - 0 - GTK_SHADOW_NONE - - - True - 12 - - - True - True - GTK_POLICY_AUTOMATIC - GTK_POLICY_AUTOMATIC - - - True - - - - - - - - - - - - True - <b>All fields</b> - True - - - label_item - - - - - - - True - 5 - True - - - True - True - 0 - - - - True - 0 - 0 - - - True - 2 - - - True - tryton-list-add - - - False - False - - - - - True - _Add - True - - - False - False - 1 - - - - - - - - - False - False - - - - - True - True - 0 - - - - True - 0 - 0 - - - True - 2 - - - True - tryton-list-remove - - - False - False - - - - - True - _Remove - True - - - False - False - 1 - - - - - - - - - False - False - 1 - - - - - True - True - 0 - - - - True - 0 - 0 - - - True - 2 - - - True - tryton-clear - - - False - False - - - - - True - Clear - True - - - False - False - 1 - - - - - - - - - False - False - 2 - - - - - True - - - False - False - 3 - 3 - - - - - True - True - 0 - - - - True - 0 - 0 - - - True - 2 - - - True - tryton-find - - - False - False - - - - - True - Auto-Detect - True - - - False - False - 1 - - - - - - - - - False - False - 4 - - - - - False - 1 - - - - - True - 0 - GTK_SHADOW_NONE - - - True - 12 - - - True - True - GTK_POLICY_AUTOMATIC - - - True - - - - - - - - - - - - True - <b>Fields to import</b> - True - - - label_item - - - - - 2 - - - - - - - True - 0 - GTK_SHADOW_ETCHED_OUT - - - True - 7 - 7 - 7 - 7 - - - True - - - True - - - True - File to Import: - - - False - False - - - - - True - Open... - - - 1 - - - - - False - 4 - - - - - True - True - True - - - True - 8 - 2 - 4 - 8 - 9 - - - True - UTF-8 -Latin1 - - - - - - - 1 - 2 - 1 - 2 - GTK_FILL - GTK_FILL - - - - - True - True - 0 0 100 1 10 10 - 1 - - - 3 - 4 - 1 - 2 - GTK_FILL - - - - - - True - 1 - Lines to Skip: - - - 2 - 3 - 1 - 2 - GTK_FILL - - - - - - True - True - 1 - " - - - 3 - 4 - GTK_FILL - - - - - - True - 1 - Text Delimiter: - - - 2 - 3 - GTK_FILL - - - - - - True - True - 1 - 1 - , - - - 1 - 2 - GTK_FILL - - - - - - True - 1 - Encoding: - - - 1 - 2 - GTK_FILL - - - - - - True - 1 - Field Separater: - - - GTK_FILL - - - - - - - - True - CSV Parameters - - - label_item - - - - - False - 1 - - - - - - - - - False - 1 - - - - - 2 - - - - - True - GTK_BUTTONBOX_END - - - True - True - True - gtk-help - True - -11 - - - - - True - True - True - gtk-cancel - True - -6 - - - 1 - - - - - True - True - True - gtk-ok - True - -5 - - - 2 - - - - - False - GTK_PACK_END - - - - - diff --git a/tryton/gui/window/win_import.py b/tryton/gui/window/win_import.py index 5e582cc44f..a9eaf8e146 100644 --- a/tryton/gui/window/win_import.py +++ b/tryton/gui/window/win_import.py @@ -1,6 +1,5 @@ #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 gobject import gettext import tryton.common as common @@ -16,29 +15,182 @@ class WinImport(object): "Window import" def __init__(self, model, fields, preload=None, parent=None): - self.glade = glade.XML(GLADE, 'win_import', gettext.textdomain()) - self.glade.get_widget('import_csv_combo').set_active(0) - self.win = self.glade.get_widget('win_import') + self.dialog = gtk.Dialog( + title=_("Import from CSV"), parent=parent, + flags=gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT + | gtk.WIN_POS_CENTER_ON_PARENT) + dialog_vbox = gtk.VBox() + hbox_mapping = gtk.HBox(False, 0) + dialog_vbox.pack_start(hbox_mapping, True, True, 0) + + frame_fields = gtk.Frame(None) + frame_fields.set_shadow_type(gtk.SHADOW_NONE) + hbox_mapping.pack_start(frame_fields, True, True, 0) + alignment_fields = gtk.Alignment(0.5, 0.5, 1, 1) + alignment_fields.set_padding(0, 0, 12, 0) + frame_fields.add(alignment_fields) + scrolledwindow_fields = gtk.ScrolledWindow(None, None) + scrolledwindow_fields.set_policy(gtk.POLICY_AUTOMATIC, + gtk.POLICY_AUTOMATIC) + alignment_fields.add(scrolledwindow_fields) + viewport_fields = gtk.Viewport(None, None) + scrolledwindow_fields.add(viewport_fields) + label_all_fields = gtk.Label(_("All fields")) + label_all_fields.set_use_markup(True) + frame_fields.set_label_widget(label_all_fields) + vbox_buttons = gtk.VBox(True, 0) + vbox_buttons.set_border_width(5) + hbox_mapping.pack_start(vbox_buttons, False, True, 0) + + button_add = gtk.Button(_("_Add"), stock=None, use_underline=True) + button_add.set_alignment(0.0,0.0) + img_button = gtk.Image() + img_button.set_from_stock('tryton-list-add', gtk.ICON_SIZE_BUTTON) + button_add.set_image(img_button) + button_add.connect_after('clicked', self.sig_sel) + vbox_buttons.pack_start(button_add, False, False, 0) + + button_remove = gtk.Button(_("_Remove"), stock=None, + use_underline=True) + button_remove.set_alignment(0.0,0.0) + img_button = gtk.Image() + img_button.set_from_stock('tryton-list-remove', gtk.ICON_SIZE_BUTTON) + button_remove.set_image(img_button) + button_remove.connect_after('clicked', self.sig_unsel) + vbox_buttons.pack_start(button_remove, False, False, 0) + + button_remove_all = gtk.Button(_("Clear"), stock=None, + use_underline=True) + button_remove_all.set_alignment(0.0,0.0) + img_button = gtk.Image() + img_button.set_from_stock('tryton-clear', gtk.ICON_SIZE_BUTTON) + button_remove_all.set_image(img_button) + button_remove_all.connect_after('clicked', self.sig_unsel_all) + vbox_buttons.pack_start(button_remove_all, False, False, 0) + + hseparator_buttons = gtk.HSeparator() + vbox_buttons.pack_start(hseparator_buttons, False, False, 3) + + button_autodetect = gtk.Button(_("Auto-Detect"), stock=None, + use_underline=True) + button_autodetect.set_alignment(0.0,0.0) + img_button = gtk.Image() + img_button.set_from_stock('tryton-find', gtk.ICON_SIZE_BUTTON) + button_autodetect.set_image(img_button) + button_autodetect.connect_after('clicked', self.sig_autodetect) + vbox_buttons.pack_start(button_autodetect, False, False, 0) + + frame_import = gtk.Frame(None) + hbox_mapping.pack_start(frame_import, True, True, 0) + frame_import.set_shadow_type(gtk.SHADOW_NONE) + + alignment_import = gtk.Alignment(0.5, 0.5, 1, 1) + alignment_import.set_padding(0, 0, 12, 0) + frame_import.add(alignment_import) + scrolledwindow_import = gtk.ScrolledWindow(None, None) + scrolledwindow_import.set_policy(gtk.POLICY_AUTOMATIC, + gtk.POLICY_ALWAYS) + alignment_import.add(scrolledwindow_import) + viewport_import = gtk.Viewport(None, None) + scrolledwindow_import.add(viewport_import) + label_fields_import = gtk.Label(_("Fields to import")) + label_fields_import.set_use_markup(True) + frame_import.set_label_widget(label_fields_import) + + frame_csv_param = gtk.Frame(None) + frame_csv_param.set_shadow_type(gtk.SHADOW_ETCHED_OUT) + dialog_vbox.pack_start(frame_csv_param, False, True, 0) + alignment_csv_param = gtk.Alignment(0.5, 0.5, 1, 1) + alignment_csv_param.set_padding(7, 7, 7, 7) + frame_csv_param.add(alignment_csv_param) + + vbox_csv_param = gtk.VBox(False, 0) + alignment_csv_param.add(vbox_csv_param) + hbox_csv_import = gtk.HBox(False, 0) + vbox_csv_param.pack_start(hbox_csv_import, False, True, 4) + label_csv_import = gtk.Label(_("File to Import:")) + hbox_csv_import.pack_start(label_csv_import, False, False, 0) + self.import_csv_file = gtk.FileChooserButton(_("Open...")) + hbox_csv_import.pack_start(self.import_csv_file, True, True, 0) + + expander_csv_import = gtk.Expander(None) + expander_csv_import.set_expanded(True) + vbox_csv_param.pack_start(expander_csv_import, False, True, 0) + label_import_csv_param = gtk.Label(_("CSV Parameters")) + expander_csv_import.set_label_widget(label_import_csv_param) + table = gtk.Table(2, 4, False) + table.set_border_width(8) + table.set_row_spacings(9) + table.set_col_spacings(8) + expander_csv_import.add(table) + + label_import_csv_sep = gtk.Label(_("Field Separater:")) + label_import_csv_sep.set_alignment(1, 0.5) + table.attach(label_import_csv_sep, 0, 1, 0, 1) + self.import_csv_sep = gtk.Entry() + self.import_csv_sep.set_max_length(1) + self.import_csv_sep.set_text(",") + self.import_csv_sep.set_width_chars(1) + table.attach(self.import_csv_sep, 1, 2, 0, 1) + + label_import_csv_del = gtk.Label(_("Text Delimiter:")) + label_import_csv_del.set_alignment( 1, 0.5) + table.attach(label_import_csv_del, 2, 3, 0, 1) + self.import_csv_del = gtk.Entry() + self.import_csv_del.set_text( "\"") + self.import_csv_del.set_width_chars( 1) + table.attach(self.import_csv_del, 3, 4, 0, 1) + + label_import_csv_enc = gtk.Label(_("Encoding:")) + label_import_csv_enc.set_alignment( 1, 0.5) + table.attach(label_import_csv_enc, 0, 1, 1, 2) + self.import_csv_enc = gtk.combo_box_new_text() + self.import_csv_enc.append_text("UTF-8") + self.import_csv_enc.append_text("Latin1") + cboxent_import_csv_enc = gtk.Entry() + cboxent_import_csv_enc.unset_flags(gtk.CAN_FOCUS) + self.import_csv_enc.add(cboxent_import_csv_enc) + table.attach(self.import_csv_enc, 1, 2, 1, 2) + + label_import_csv_skip = gtk.Label(_("Lines to Skip:")) + label_import_csv_skip.set_alignment( 1, 0.5) + table.attach(label_import_csv_skip, 2, 3, 1, 2) + + self.import_csv_skip_adj = gtk.Adjustment(0, 0, 100, 1, 10, 0) + self.import_csv_skip = gtk.SpinButton(self.import_csv_skip_adj, 1, 0) + table.attach(self.import_csv_skip, 3, 4, 1, 2) + + button_cancel = gtk.Button("gtk-cancel", stock="gtk-cancel") + self.dialog.add_action_widget(button_cancel, gtk.RESPONSE_CANCEL) + button_cancel.set_flags(gtk.CAN_DEFAULT) + + button_ok = gtk.Button("gtk-ok", stock="gtk-ok") + self.dialog.add_action_widget(button_ok, gtk.RESPONSE_OK) + button_ok.set_flags(gtk.CAN_DEFAULT) + + self.dialog.vbox.pack_start(dialog_vbox) + self.model = model self.fields_data = {} - self.win.set_transient_for(parent) - self.win.set_icon(TRYTON_ICON) + self.dialog.set_transient_for(parent) + self.dialog.set_icon(TRYTON_ICON) self.parent = parent + self.dialog.show_all() + self.import_csv_file.set_current_folder(CONFIG['client.default_path']) - self.glade.get_widget('import_csv_file').set_current_folder( - CONFIG['client.default_path']) self.view1 = gtk.TreeView() self.view1.get_selection().set_mode(gtk.SELECTION_MULTIPLE) - self.glade.get_widget('import_vp_left').add(self.view1) + viewport_fields.add(self.view1) self.view2 = gtk.TreeView() self.view2.get_selection().set_mode(gtk.SELECTION_MULTIPLE) - self.glade.get_widget('import_vp_right').add(self.view2) + viewport_import.add(self.view2) self.view1.set_headers_visible(False) self.view2.set_headers_visible(False) cell = gtk.CellRendererText() - column = gtk.TreeViewColumn(_('Field name'), cell, text=0, background=2) + column = gtk.TreeViewColumn(_('Field name'), cell, text=0, + background=2) self.view1.append_column(column) cell = gtk.CellRendererText() @@ -55,23 +207,23 @@ class WinImport(object): self.fields = {} self.fields_invert = {} - def model_populate(fields, prefix_node='', prefix=None, prefix_value='', - level=2): + def model_populate(fields, prefix_node='', prefix=None, + prefix_value='', level=2): fields_order = fields.keys() fields_order.sort(lambda x, y: -cmp(fields[x].get('string', ''), - fields[y].get('string', ''))) + fields[y].get('string', ''))) for field in fields_order: if (fields[field]['type'] not in ('reference',)) \ and (not fields[field].get('readonly', False) \ or not dict(fields[field].get('states', {}).get( - 'draft', [('readonly', True)])).get('readonly', + 'draft', [('readonly', True)])).get('readonly', True)): self.fields_data[prefix_node+field] = fields[field] st_name = prefix_value+fields[field]['string'] or field node = self.model1.insert(prefix, 0, [st_name, - prefix_node+field, - (fields[field].get('required', False) and '#ddddff') \ - or 'white']) + prefix_node+field, + (fields[field].get('required', False) and \ + '#ddddff') or 'white']) self.fields[prefix_node+field] = st_name self.fields_invert[st_name] = prefix_node+field if fields[field]['type'] == 'one2many' and level > 0: @@ -80,7 +232,7 @@ class WinImport(object): 'execute', fields[field]['relation'], 'fields_get', False, rpc.CONTEXT) except Exception, exception: - common.process_exception(exception, self.win) + common.process_exception(exception, self.dialog) continue model_populate(fields2, prefix_node+field+'/', node, st_name+'/', level-1) @@ -91,26 +243,18 @@ class WinImport(object): self.view1.show_all() self.view2.show_all() - self.glade.signal_connect('on_but_unselect_all_clicked', - self.sig_unsel_all) - self.glade.signal_connect('on_but_select_all_clicked', self.sig_sel_all) - self.glade.signal_connect('on_but_select_clicked', self.sig_sel) - self.glade.signal_connect('on_but_unselect_clicked', self.sig_unsel) - self.glade.signal_connect('on_but_autodetect_clicked', - self.sig_autodetect) - def sig_autodetect(self, widget=None): - fname = self.glade.get_widget('import_csv_file').get_filename() + fname = self.import_csv_file.get_filename() if not fname: common.message('You must select an import file first !', self.parent) return True - csvsep = self.glade.get_widget('import_csv_sep').get_text() - csvdel = self.glade.get_widget('import_csv_del').get_text() - csvcode = self.glade.get_widget('import_csv_combo').get_active_text() \ + csvsep = self.import_csv_sep.get_text() + csvdel = self.import_csv_del.get_text() + csvcode = self.import_csv_enc.get_active_text() \ or 'UTF-8' - self.glade.get_widget('import_csv_skip').set_value(1) + self.import_csv_skip.set_value(1) try: data = csv.reader(file(fname), quotechar=csvdel, delimiter=csvsep) except: @@ -128,8 +272,8 @@ class WinImport(object): break except Exception, exception: common.warning(_('Error processing the file at field %s.\n' \ - 'Error message:\n%s') % (word, str(exception)), self.parent, - _('Error')) + 'Error message:\n%s') % (word, str(exception)), + self.parent, _('Error')) return True def sig_sel_all(self, widget=None): @@ -156,7 +300,7 @@ class WinImport(object): self.model2.clear() def run(self): - button = self.win.run() + button = self.dialog.run() if button == gtk.RESPONSE_OK: fields = [] fields2 = [] @@ -167,22 +311,20 @@ class WinImport(object): iter = self.model2.iter_next(iter) csv_data = { - 'fname': self.glade.get_widget('import_csv_file' - ).get_filename(), - 'sep': self.glade.get_widget('import_csv_sep').get_text(), - 'del': self.glade.get_widget('import_csv_del').get_text(), - 'skip': self.glade.get_widget('import_csv_skip').get_value(), - 'combo': self.glade.get_widget('import_csv_combo' - ).get_active_text() or 'UTF-8' + 'fname': self.import_csv_file.get_filename(), + 'sep': self.import_csv_sep.get_text(), + 'del': self.import_csv_del.get_text(), + 'skip': self.import_csv_skip.get_value(), + 'combo': self.import_csv_enc.get_active_text() or 'UTF-8' } self.parent.present() - self.win.destroy() + self.dialog.destroy() if csv_data['fname']: return self.import_csv(csv_data, fields, self.model) return False else: self.parent.present() - self.win.destroy() + self.dialog.destroy() return False def import_csv(self, csv_data, fields, model): @@ -203,19 +345,20 @@ class WinImport(object): res = rpc.execute('object', 'execute', model, 'import_data', fields, datas) except Exception, exception: - common.process_exception(exception, self.win) + common.process_exception(exception, self.dialog) return False if res[0] >= 0: if res[0] == 1: - common.message(_('%d record imported!') % (res[0],), self.parent) + common.message(_('%d record imported!') % (res[0],), + self.parent) else: - common.message(_('%d records imported!') % (res[0],), self.parent) + common.message(_('%d records imported!') % (res[0],), + self.parent) else: buf = '' for key, val in res[1].items(): buf += ('\t%s: %s\n' % (str(key), str(val))) common.error(_('Importation Error!'), self.parent, _('Error trying to import this record:\n' \ - '%s\nError Message:\n%s\n\n%s') % \ - (buf, res[2], res[3])) + '%s\nError Message:\n%s\n\n%s') % (buf, res[2], res[3])) return True