diff --git a/tryton/gui/window/form.py b/tryton/gui/window/form.py index 9283a547bf..2773913b84 100644 --- a/tryton/gui/window/form.py +++ b/tryton/gui/window/form.py @@ -12,7 +12,7 @@ from tryton.action import Action from tryton.config import CONFIG from tryton.gui.window.win_search import WinSearch from tryton.gui.window.preference import Preference -#import win_export +from tryton.gui.window.win_export import WinExport #import win_import _ = gettext.gettext @@ -202,9 +202,9 @@ class Form(object): fields = [] while(self.screen.view_to_load): self.screen.load_view_to_load() - win = win_export.win_export(self.model, self.screen.ids_get(), + win = WinExport(self.model, self.screen.ids_get(), self.screen.fields, fields, parent=self.window) - win.go() + win.run() def sig_new(self, widget=None, autosave=True): if autosave: diff --git a/tryton/gui/window/win_export.py b/tryton/gui/window/win_export.py new file mode 100644 index 0000000000..5952b46a0a --- /dev/null +++ b/tryton/gui/window/win_export.py @@ -0,0 +1,232 @@ +import gtk +from gtk import glade +import gobject +import gettext +import tryton.common as common +import tryton.rpc as rpc +import types +from tryton.config import GLADE, TRYTON_ICON +import csv + +_ = gettext.gettext + + + +class WinExport(object): + "Window export" + + def __init__(self, model, ids, fields, preload=None, parent=None): + if preload is None: + preload = [] + self.glade = glade.XML(GLADE, 'win_save_as', + gettext.textdomain()) + self.win = self.glade.get_widget('win_save_as') + self.ids = ids + self.model = model + self.fields_data = {} + + self.win.set_transient_for(parent) + self.win.set_icon(TRYTON_ICON) + self.parent = parent + + self.view1 = gtk.TreeView() + self.view1.get_selection().set_mode(gtk.SELECTION_MULTIPLE) + self.glade.get_widget('exp_vp1').add(self.view1) + self.view2 = gtk.TreeView() + self.view2.get_selection().set_mode(gtk.SELECTION_MULTIPLE) + self.glade.get_widget('exp_vp2').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) + self.view1.append_column(column) + + cell = gtk.CellRendererText() + column = gtk.TreeViewColumn('Field name', cell, text=0) + self.view2.append_column(column) + + self.model1 = gtk.TreeStore(gobject.TYPE_STRING, gobject.TYPE_STRING) + self.model2 = gtk.ListStore(gobject.TYPE_STRING, gobject.TYPE_STRING) + + for i in preload: + self.model2.set(self.model2.append(), 0, i[1], 1, i[0]) + + self.fields = {} + + 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', ''))) + for field in fields_order: + self.fields_data[prefix_node+field] = fields[field] + if prefix_node: + self.fields_data[prefix_node + field]['string'] = \ + '%s%s' % (prefix_value, + self.fields_data[prefix_node + \ + field]['string']) + st_name = fields[field]['string'] or field + node = self.model1.insert(prefix, 0, + [st_name, prefix_node+field]) + self.fields[prefix_node+field] = (st_name, + fields[field].get('relation', False)) + if fields[field].get('relation', False) and level>0: + fields2 = rpc.session.rpc_exec_auth('/object', 'execute', + fields[field]['relation'], 'fields_get', False, + rpc.session.context) + model_populate(fields2, prefix_node+field+'/', node, + st_name+'/', level-1) + model_populate(fields) + + self.view1.set_model(self.model1) + self.view2.set_model(self.model2) + self.view1.show_all() + self.view2.show_all() + + self.wid_action = self.glade.get_widget('win_saveas_combo') + self.wid_write_field_names = self.glade.get_widget('add_field_names_cb') + self.wid_action.set_active(1) + + 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_predefined_clicked', self.add_predef) + + # Creating the predefined export view + self.pref_export = gtk.TreeView() + self.pref_export.append_column(gtk.TreeViewColumn('Export name', + gtk.CellRendererText(), text=1)) + self.pref_export.append_column(gtk.TreeViewColumn('Exported fields', + gtk.CellRendererText(), text=2)) + self.glade.get_widget('predefined_exports').add(self.pref_export) + + self.pref_export.connect("row-activated", self.sel_predef) + + # Fill the predefined export tree view and show everything + self.fill_predefwin() + self.pref_export.show_all() + self.predef_model = gtk.ListStore(gobject.TYPE_PYOBJECT, + gobject.TYPE_STRING, gobject.TYPE_STRING) + + def sig_sel_all(self, widget=None): + self.model2.clear() + for field, relation in self.fields.keys(): + if not relation: + self.model2.set(self.model2.append(), 0, self.fields[field], + 1, field) + + def sig_sel(self, widget=None): + sel = self.view1.get_selection() + sel.selected_foreach(self._sig_sel_add) + + def _sig_sel_add(self, store, path, iter): + relation = self.fields[store.get_value(iter, 1)][1] + if relation: + return + num = self.model2.append() + self.model2.set(num, 0, store.get_value(iter, 0), 1, + store.get_value(iter, 1)) + + def sig_unsel(self, widget=None): + store, paths = self.view2.get_selection().get_selected_rows() + for i in paths: + store.remove(store.get_iter(i)) + + def sig_unsel_all(self, widget=None): + self.model2.clear() + + def fill_predefwin(self): + self.predef_model = gtk.ListStore(gobject.TYPE_PYOBJECT, + gobject.TYPE_STRING, gobject.TYPE_STRING) + ir_export = rpc.RPCProxy('ir.exports') + ir_export_line = rpc.RPCProxy('ir.exports.line') + export_ids = ir_export.search([('resource', '=', self.model)]) + for export in ir_export.read(export_ids): + fields = ir_export_line.read(export['export_fields']) + self.predef_model.append(([f['name'] for f in fields], + export['name'], + ', '.join([self.fields_data[f['name']]['string'] \ + for f in fields]))) + self.pref_export.set_model(self.predef_model) + + def add_predef(self, widget): + name = common.ask('What is the name of this export ?', self.parent) + if not name: + return + ir_export = rpc.RPCProxy('ir.exports') + iter = self.model2.get_iter_root() + fields = [] + while iter: + field_name = self.model2.get_value(iter, 1) + fields.append(field_name) + iter = self.model2.iter_next(iter) + ir_export.create({'name' : name, 'resource' : self.model, + 'export_fields' : [(0, 0, {'name' : f}) for f in fields]}) + self.predef_model.append((fields, name, + ','.join([self.fields_data[f]['string'] for f in fields]))) + + def sel_predef(self, widget, path, column): + self.model2.clear() + for field in self.predef_model[path[0]][0]: + self.model2.append((self.fields_data[field]['string'], field)) + + def run(self): + button = self.win.run() + if button == gtk.RESPONSE_OK: + fields = [] + fields2 = [] + iter = self.model2.get_iter_root() + while iter: + fields.append(self.model2.get_value(iter, 1)) + fields2.append(self.model2.get_value(iter, 0)) + iter = self.model2.iter_next(iter) + action = self.wid_action.get_active() + self.parent.present() + self.win.destroy() + result = WinExport.datas_read(self.ids, self.model, fields) + + if action == 0: + pass + else: + fname = common.file_selection(_('Save As...'), + parent=self.parent, action=gtk.FILE_CHOOSER_ACTION_SAVE) + if fname: + self.export_csv(fname, fields2, result, + self.wid_write_field_names.get_active()) + return True + else: + self.parent.present() + self.win.destroy() + return False + + def export_csv(self, fname, fields, result, write_title=False): + try: + file_p = file(fname, 'wb+') + writer = csv.writer(file_p) + if write_title: + writer.writerow(fields) + for data in result: + row = [] + for val in data: + if type(val) == types.StringType: + row.append(val.replace('\n',' ').replace('\t',' ')) + else: + row.append(val) + writer.writerow(row) + file_p.close() + common.message(str(len(result)) + _(' record(s) saved !'), + self.parent) + return True + except IOError, exception: + common.message(_("Operation failed !\nI/O error") + \ + "(%s)" % (exception[0],), self.parent) + return False + + @staticmethod + def datas_read(ids, model, fields): + datas = rpc.session.rpc_exec_auth('/object', 'execute', model, + 'export_data', ids, fields) + return datas