[MERGE] lxml+etree instead of deprecated XML libs which prevent install on Ubuntu...
[odoo/odoo.git] / bin / wizard / __init__.py
1 # -*- encoding: utf-8 -*-
2 ##############################################################################
3 #
4 #    OpenERP, Open Source Management Solution   
5 #    Copyright (C) 2004-2009 Tiny SPRL (<http://tiny.be>). All Rights Reserved
6 #    $Id$
7 #
8 #    This program is free software: you can redistribute it and/or modify
9 #    it under the terms of the GNU General Public License as published by
10 #    the Free Software Foundation, either version 3 of the License, or
11 #    (at your option) any later version.
12 #
13 #    This program is distributed in the hope that it will be useful,
14 #    but WITHOUT ANY WARRANTY; without even the implied warranty of
15 #    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 #    GNU General Public License for more details.
17 #
18 #    You should have received a copy of the GNU General Public License
19 #    along with this program.  If not, see <http://www.gnu.org/licenses/>.
20 #
21 ##############################################################################
22
23 import netsvc
24 from tools import copy
25 from tools.misc import UpdateableStr, UpdateableDict
26 from tools.translate import translate
27 from lxml import etree
28
29 import ir
30 import pooler
31
32 from osv.osv import except_osv
33 from osv.orm import except_orm
34 from netsvc import Logger, LOG_ERROR
35 import sys
36
37 class except_wizard(Exception):
38     def __init__(self, name, value):
39         self.name = name
40         self.value = value
41         self.args = (name, value)
42
43 class interface(netsvc.Service):
44     states = {}
45     
46     def __init__(self, name):
47         assert not netsvc.service_exist('wizard.'+name), 'The wizard "%s" already exists!'%name
48         super(interface, self).__init__('wizard.'+name)
49         self.exportMethod(self.execute)
50         self.wiz_name = name
51         
52     def translate_view(self, cr, node, state, lang):
53             if node.get('string'):
54                 trans = translate(cr, self.wiz_name+','+state, 'wizard_view', lang, node.get('string').encode('utf8'))
55                 if trans:
56                     node.set('string', trans)
57             for n in node.getchildren():
58                 self.translate_view(cr, n, state, lang)
59
60     def execute_cr(self, cr, uid, data, state='init', context=None):
61         if not context:
62             context={}
63         res = {}
64         try:
65             state_def = self.states[state]
66
67             result_def = state_def.get('result', {})
68             
69             actions_res = {}
70             # iterate through the list of actions defined for this state
71             for action in state_def.get('actions', []):
72                 # execute them
73                 action_res = action(self, cr, uid, data, context)
74                 assert isinstance(action_res, dict), 'The return value of wizard actions should be a dictionary'
75                 actions_res.update(action_res)
76                 
77             res = copy.copy(result_def)
78             res['datas'] = actions_res
79             
80             lang = context.get('lang', False)
81             if result_def['type'] == 'action':
82                 res['action'] = result_def['action'](self, cr, uid, data, context)
83             elif result_def['type'] == 'form':
84                 fields = copy.deepcopy(result_def['fields'])
85                 arch = copy.copy(result_def['arch'])
86                 button_list = copy.copy(result_def['state'])
87
88                 if isinstance(fields, UpdateableDict):
89                     fields = fields.dict
90                 if isinstance(arch, UpdateableStr):
91                     arch = arch.string
92
93                 # fetch user-set defaut values for the field... shouldn't we pass it the uid?
94                 defaults = ir.ir_get(cr, uid, 'default', False, [('wizard.'+self.wiz_name, False)])
95                 default_values = dict([(x[1], x[2]) for x in defaults])
96                 for val in fields.keys():
97                     if 'default' in fields[val]:
98                         # execute default method for this field
99                         if callable(fields[val]['default']):
100                             fields[val]['value'] = fields[val]['default'](uid, data, state)
101                         else:
102                             fields[val]['value'] = fields[val]['default']
103                         del fields[val]['default']
104                     else:
105                         # if user has set a default value for the field, use it
106                         if val in default_values:
107                             fields[val]['value'] = default_values[val]
108                     if 'selection' in fields[val]:
109                         if not isinstance(fields[val]['selection'], (tuple, list)):
110                             fields[val] = copy.copy(fields[val])
111                             fields[val]['selection'] = fields[val]['selection'](self, cr, uid, context)
112                         elif lang:
113                             res_name = "%s,%s,%s" % (self.wiz_name, state, val)
114                             trans = lambda x: translate(cr, res_name, 'selection', lang, x) or x
115                             for idx, (key, val2) in enumerate(fields[val]['selection']):
116                                 fields[val]['selection'][idx] = (key, trans(val2))
117
118                 if lang:
119                     # translate fields
120                     for field in fields:
121                         res_name = "%s,%s,%s" % (self.wiz_name, state, field)
122
123                         trans = translate(cr, res_name, 'wizard_field', lang)
124                         if trans:
125                             fields[field]['string'] = trans
126
127                         if 'help' in fields[field]:
128                             t = translate(cr, res_name, 'help', lang, fields[field]['help']) 
129                             if t:
130                                 fields[field]['help'] = t
131
132                     # translate arch
133                     if not isinstance(arch, UpdateableStr):
134                         doc = etree.XML(arch)
135                         self.translate_view(cr, doc, state, lang)
136                         arch = etree.tostring(doc)
137
138                     # translate buttons
139                     button_list = list(button_list)
140                     for i, aa  in enumerate(button_list):
141                         button_name = aa[0]
142                         trans = translate(cr, self.wiz_name+','+state+','+button_name, 'wizard_button', lang)
143                         if trans:
144                             aa = list(aa)
145                             aa[1] = trans
146                             button_list[i] = aa
147                     
148                 res['fields'] = fields
149                 res['arch'] = arch
150                 res['state'] = button_list
151
152         except Exception, e:
153             if isinstance(e, except_wizard) \
154                 or isinstance(e, except_osv) \
155                 or isinstance(e, except_orm):
156                 self.abortResponse(2, e.name, 'warning', e.value)
157             else:
158                 import traceback
159                 tb_s = reduce(lambda x, y: x+y, traceback.format_exception(
160                     sys.exc_type, sys.exc_value, sys.exc_traceback))
161                 logger = Logger()
162                 logger.notifyChannel("web-services", LOG_ERROR,
163                         'Exception in call: ' + tb_s)
164                 raise
165
166         if result_def['type'] == 'choice':
167             next_state = result_def['next_state'](self, cr, uid, data, context)
168             return self.execute_cr(cr, uid, data, next_state, context)
169         return res
170
171     def execute(self, db, uid, data, state='init', context=None):
172         if not context:
173             context={}
174         cr = pooler.get_db(db).cursor()
175         try:
176             try:
177                 res = self.execute_cr(cr, uid, data, state, context)
178                 cr.commit()
179             except Exception:
180                 cr.rollback()
181                 raise
182         finally:
183             cr.close()
184         return res
185
186 # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
187