diff --git a/bin/addons/base/ir/ir_actions.py b/bin/addons/base/ir/ir_actions.py index 1fffd01c4bc..2e3d683c27a 100644 --- a/bin/addons/base/ir/ir_actions.py +++ b/bin/addons/base/ir/ir_actions.py @@ -231,7 +231,8 @@ class act_window_view(osv.osv): ('tree', 'Tree'), ('form', 'Form'), ('graph', 'Graph'), - ('calendar', 'Calendar')), string='Type of view', required=True), + ('calendar', 'Calendar'), + ('gantt', 'Gantt')), string='Type of view', required=True), 'act_window_id': fields.many2one('ir.actions.act_window', 'Action', ondelete='cascade'), 'multi': fields.boolean('On multiple doc.', help="If set to true, the action will not be displayed on the right toolbar of a form views."), @@ -251,7 +252,8 @@ class act_wizard(osv.osv): 'type': fields.char('Action type', size=32, required=True), 'wiz_name': fields.char('Wizard name', size=64, required=True), 'multi': fields.boolean('Action on multiple doc.', help="If set to true, the wizard will not be displayed on the right toolbar of a form views."), - 'groups_id': fields.many2many('res.groups', 'res_groups_wizard_rel', 'uid', 'gid', 'Groups') + 'groups_id': fields.many2many('res.groups', 'res_groups_wizard_rel', 'uid', 'gid', 'Groups'), + 'model': fields.char('Object', size=64), } _defaults = { 'type': lambda *a: 'ir.actions.wizard', @@ -708,3 +710,5 @@ class ir_actions_configuration_wizard(osv.osv_memory): return {'type':'ir.actions.act_window_close' } ir_actions_configuration_wizard() +# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: + diff --git a/bin/addons/base/ir/ir_model.py b/bin/addons/base/ir/ir_model.py index 0a9f71b3510..1fe8b61a1f1 100644 --- a/bin/addons/base/ir/ir_model.py +++ b/bin/addons/base/ir/ir_model.py @@ -31,7 +31,7 @@ from osv import fields,osv import ir, re import netsvc -from osv.orm import except_orm +from osv.orm import except_orm, browse_record import time import tools @@ -282,13 +282,19 @@ class ir_model_access(osv.osv): cr.execute("select 1 from res_groups_users_rel where uid=%i and gid=%i", (uid, group_id,)) return bool(cr.fetchone()) - def check(self, cr, uid, model_name, mode='read', raise_exception=True): + def check(self, cr, uid, model, mode='read', raise_exception=True): # Users root have all access (Todo: exclude xml-rpc requests) if uid==1: return True assert mode in ['read','write','create','unlink'], 'Invalid access mode' + if isinstance(model, browse_record): + assert model._table_name == 'ir.model', 'Invalid model object' + model_name = model.name + else: + model_name = model + # We check if a specific rule exists cr.execute('SELECT MAX(CASE WHEN perm_' + mode + ' THEN 1 ELSE 0 END) ' ' FROM ir_model_access a ' @@ -327,6 +333,7 @@ class ir_model_access(osv.osv): # Check rights on actions # def write(self, cr, uid, *args, **argv): + self.pool.get('ir.ui.menu').clear_cache() res = super(ir_model_access, self).write(cr, uid, *args, **argv) self.check() return res @@ -335,6 +342,7 @@ class ir_model_access(osv.osv): self.check() return res def unlink(self, cr, uid, *args, **argv): + self.pool.get('ir.ui.menu').clear_cache() res = super(ir_model_access, self).unlink(cr, uid, *args, **argv) self.check() return res diff --git a/bin/addons/base/ir/ir_ui_menu.py b/bin/addons/base/ir/ir_ui_menu.py index bc3693be85f..f787db2e5d2 100644 --- a/bin/addons/base/ir/ir_ui_menu.py +++ b/bin/addons/base/ir/ir_ui_menu.py @@ -58,33 +58,74 @@ class many2many_unique(fields.many2many): class ir_ui_menu(osv.osv): _name = 'ir.ui.menu' + + def __init__(self, *args, **kwargs): + self._cache = {} + return super(ir_ui_menu, self).__init__(*args, **kwargs) + + def clear_cache(self): + # radical but this doesn't frequently happen + self._cache = {} + def search(self, cr, uid, args, offset=0, limit=2000, order=None, context=None, count=False): if context is None: context = {} - ids = osv.orm.orm.search(self, cr, uid, args, offset, limit, order, - context=context) + ids = osv.orm.orm.search(self, cr, uid, args, offset, limit, order, context=context, count=(count and uid==1)) if uid==1: return ids - user_groups = set(self.pool.get('res.users').browse(cr, uid, uid)['groups_id'] or []) + + if not ids: + if count: + return 0 + return [] + + modelaccess = self.pool.get('ir.model.access') + user_groups = set(self.pool.get('res.users').read(cr, 1, uid)['groups_id']) result = [] for menu in self.browse(cr, uid, ids): - restrict_to_groups = menu.groups_id - if not restrict_to_groups: - if menu.action: - # if the menu itself has no restrictions, we get the groups of - # the action of the menu - try: - m, oid = menu.action.split(',', 1) - data = self.pool.get(m).browse(cr, uid, int(oid), context=context) - if data and 'groups_id' in data: - restrict_to_groups = data['groups_id'] - except: - pass - - if restrict_to_groups and not user_groups.intersection(restrict_to_groups): + # this key works because user access rights are all based on user's groups (cfr ir_model_access.check) + key = (cr.dbname, menu.id, tuple(user_groups)) + + if key in self._cache: + if self._cache[key]: + result.append(menu.id) continue + + self._cache[key] = False + if menu.groups_id: + restrict_to_groups = [g.id for g in menu.groups_id] + if not user_groups.intersection(restrict_to_groups): + continue + + if menu.action: # FIXME elif ? + # we check if the user has access to the action of the menu + m, oid = menu.action.split(',', 1) + data = self.pool.get(m).browse(cr, 1, int(oid)) + + if data: + model_field = { 'ir.actions.act_window': 'res_model', + 'ir.actions.report.custom': 'model', + 'ir.actions.report.xml': 'model', + 'ir.actions.wizard': 'model', + 'ir.actions.server': 'model_id', + } + + field = model_field.get(m) + if field and data[field]: + if not modelaccess.check(cr, uid, data[field], raise_exception=False): + continue + else: + # if there is no action, it's a 'folder' menu + if not menu.child_id: + # not displayed if there is no children + continue + + self._cache[key] = True result.append(menu.id) + + if count: + return len(result) return result def _get_full_name(self, cr, uid, ids, name, args, context): @@ -102,6 +143,14 @@ class ir_ui_menu(osv.osv): parent_path = '' return parent_path + menu.name + def write(self, *args, **kwargs): + self.clear_cache() + return super(ir_ui_menu, self).write(*args, **kwargs) + + def unlink(self, *args, **kwargs): + self.clear_cache() + return super(ir_ui_menu, self).unlink(*args, **kwargs) + def copy(self, cr, uid, id, default=None, context=None): ir_values_obj = self.pool.get('ir.values') res = super(ir_ui_menu, self).copy(cr, uid, id, context=context) diff --git a/bin/addons/base/ir/ir_ui_view.py b/bin/addons/base/ir/ir_ui_view.py index 276568c9e31..e3e7e639f02 100644 --- a/bin/addons/base/ir/ir_ui_view.py +++ b/bin/addons/base/ir/ir_ui_view.py @@ -66,7 +66,8 @@ class view(osv.osv): ('tree','Tree'), ('form','Form'), ('graph', 'Graph'), - ('calendar', 'Calendar')), 'View Type', required=True), + ('calendar', 'Calendar'), + ('gantt', 'Gantt')), 'View Type', required=True), 'arch': fields.text('View Architecture', required=True), 'inherit_id': fields.many2one('ir.ui.view', 'Inherited View', ondelete='cascade'), 'field_parent': fields.char('Childs Field',size=64), diff --git a/bin/addons/base/ir/wizard/wizard_menu.py b/bin/addons/base/ir/wizard/wizard_menu.py index 3724b1dd4e5..9030a6c7164 100644 --- a/bin/addons/base/ir/wizard/wizard_menu.py +++ b/bin/addons/base/ir/wizard/wizard_menu.py @@ -77,7 +77,12 @@ class wizard_model_menu_line(osv.osv_memory): _columns = { 'wizard_id': fields.many2one('wizard.ir.model.menu.create','Wizard'), 'sequence': fields.integer('Sequence'), - 'view_type': fields.selection([('tree','Tree'),('form','Form'),('graph','Graph'),('calendar','Calendar')],'View Type',required=True), + 'view_type': fields.selection([ + ('tree','Tree'), + ('form','Form'), + ('graph','Graph'), + ('calendar','Calendar'), + ('gantt','Gantt')],'View Type',required=True), 'view_id': fields.many2one('ir.ui.view', 'View'), } _defaults = { diff --git a/bin/addons/base/security/base_security.xml b/bin/addons/base/security/base_security.xml index c9d68d975b4..0dbbb974661 100644 --- a/bin/addons/base/security/base_security.xml +++ b/bin/addons/base/security/base_security.xml @@ -1,7 +1,6 @@ - - + + + + + + + + + + diff --git a/bin/addons/base/security/ir.model.access.csv b/bin/addons/base/security/ir.model.access.csv index 6ef1956c0f9..5636b89b92d 100644 --- a/bin/addons/base/security/ir.model.access.csv +++ b/bin/addons/base/security/ir.model.access.csv @@ -1,97 +1,109 @@ -id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink -access_ir_attachment_group_user,"ir_attachment group_system_user",model_ir_attachment,group_user,1,1,1,1 -access_ir_attachment_group_system,"ir_attachment group_system",model_ir_attachment,,1,0,0,0 -access_ir_cron_group_cron,"ir_cron group_cron",model_ir_cron,group_system,1,1,1,1 -access_ir_default_group_system,"ir_default group_system",model_ir_default,,1,1,1,1 -access_ir_exports_group_system,"ir_exports group_system",model_ir_exports,,1,1,1,1 -access_ir_exports_line_group_system,"ir_exports_line group_system",model_ir_exports_line,,1,1,1,1 -access_ir_model_group_system,"ir_model group_system",model_ir_model,,1,0,0,0 -access_ir_model_access_group_system,"ir_model_access group_system",model_ir_model_access,,1,0,0,0 -access_ir_model_grid_group_system,ir_model_access_grid_group_system,model_ir_model_grid,,1,0,0,0 -access_ir_model_config_group_system,"ir_model_config group_system",model_ir_model_config,,1,0,0,0 -access_ir_model_data_group_user,"ir_model_data group_user",model_ir_model_data,,1,0,0,0 -access_ir_model_fields_group_user,"ir_model_fields group_user",model_ir_model_fields,,1,0,0,0 -access_ir_module_category_group_user,"ir_module_category group_user",model_ir_module_category,group_system,1,0,0,0 -access_ir_module_module_group_user,"ir_module_module group_user",model_ir_module_module,group_system,1,1,1,1 -access_ir_module_module_dependency_group_system,"ir_module_module_dependency group_system",model_ir_module_module_dependency,group_system,1,1,1,1 -access_ir_module_repository_group_system,"ir_module_repository group_system",model_ir_module_repository,group_system,1,1,1,1 -access_ir_property_group_user,"ir_property group_user",model_ir_property,,1,0,0,0 -access_ir_report_custom_group_system,"ir_report_custom group_system",model_ir_report_custom,,1,0,0,0 -access_ir_report_custom_fields_group_system,"ir_report_custom_fields group_system",model_ir_report_custom_fields,,1,0,0,0 -access_ir_rule_group_user,"ir_rule group_user",model_ir_rule,,1,0,0,0 -access_ir_rule_group_group_user,"ir_rule_group group_user",model_ir_rule_group,,1,0,0,0 -access_ir_sequence_group_user,"ir_sequence group_user",model_ir_sequence,,1,1,1,1 -access_ir_sequence_type_group_user,"ir_sequence_type group_user",model_ir_sequence_type,,1,0,0,0 -access_ir_translation_group_system,"ir_translation group_system",model_ir_translation,,1,1,1,1 -access_ir_ui_menu_group_user,"ir_ui_menu group_user",model_ir_ui_menu,,1,0,0,0 -access_ir_ui_view_group_user,"ir_ui_view group_user",model_ir_ui_view,,1,0,0,0 -access_ir_ui_view_custom_group_user,ir_ui_view_custom_group_user,model_ir_ui_view_custom,,1,0,0,0 -access_ir_ui_view_sc_group_user,"ir_ui_view_sc group_user",model_ir_ui_view_sc,,1,1,1,1 -access_ir_values_group_erp_manager,"ir_values group_erp_manager",model_ir_values,,1,1,1,1 -access_wizard_ir_model_menu_create_group_system,"wizard_ir_model_menu_create group_system",model_wizard_ir_model_menu_create,group_system,1,1,1,1 -access_wizard_ir_model_menu_create_line_group_system,"wizard_ir_model_menu_create_line group_system",model_wizard_ir_model_menu_create_line,group_system,1,1,1,1 -access_wizard_module_lang_export_group_system,"wizard_module_lang_export group_system",model_wizard_module_lang_export,group_system,1,1,1,1 -access_res_company_group_erp_manager,"res_company group_erp_manager",model_res_company,group_erp_manager,1,1,1,1 -access_res_company_group_user,"res_company group_user",model_res_company,,1,0,0,0 -access_res_country_group_all,"res_country group_user_all",model_res_country,,1,0,0,0 -access_res_country_state_group_all,"res_country_state group_user_all",model_res_country_state,,1,0,0,0 -access_res_country_group_user,"res_country group_user",model_res_country,group_partner_manager,1,1,1,1 -access_res_country_state_group_user,"res_country_state group_user",model_res_country_state,group_partner_manager,1,1,1,1 -access_res_currency_group_all,"res_currency group_all",model_res_currency,,1,0,0,0 -access_res_currency_rate_group_all,"res_currency_rate group_all",model_res_currency_rate,,1,0,0,0 -access_res_currency_group_user,"res_currency group_user",model_res_currency,group_user,1,1,1,1 -access_res_currency_rate_group_user,"res_currency_rate group_user",model_res_currency_rate,group_user,1,1,1,1 -access_res_groups_group_erp_manager,"res_groups group_erp_manager",model_res_groups,group_erp_manager,1,1,1,1 -access_res_groups_group_user,"res_groups group_user",model_res_groups,,1,0,0,0 -access_res_lang_group_all,"res_lang group_all",model_res_lang,,1,0,0,0 -access_res_lang_group_user,"res_lang group_user",model_res_lang,group_system,1,1,1,1 -access_res_partner_group_partner_manager,"res_partner group_partner_manager",model_res_partner,group_partner_manager,1,1,1,1 -access_res_partner_group_user,"res_partner group_user",model_res_partner,,1,0,0,0 -access_res_partner_address_group_partner_manager,"res_partner_address group_partner_manager",model_res_partner_address,group_partner_manager,1,1,1,1 -access_res_partner_address_group_user,"res_partner_address group_user",model_res_partner_address,,1,0,0,0 -access_res_partner_bank_group_user,"res_partner_bank group_user",model_res_partner_bank,,1,0,0,0 -access_res_partner_bank_group_partner_manager,"res_partner_bank group_partner_manager",model_res_partner_bank,group_partner_manager,1,1,1,1 -access_res_partner_bank_type_group_partner_manager,"res_partner_bank_type group_partner_manager",model_res_partner_bank_type,group_partner_manager,1,1,1,1 -access_res_partner_bank_type_group_user,"res_partner_bank_type group_user",model_res_partner_bank_type,,1,0,0,0 -access_res_partner_bank_type_field_group_partner_manager,"res_partner_bank_type_field group_partner_manager",model_res_partner_bank_type_field,group_partner_manager,1,1,1,1 -access_res_partner_bank_type_field_group_user,"res_partner_bank_type_field group_user",model_res_partner_bank_type_field,,1,0,0,0 -access_res_partner_canal_group_user,"res_partner_canal group_user",model_res_partner_canal,,1,0,0,0 -access_res_partner_canal_group_partner_manager,"res_partner_canal group_partner_manager",model_res_partner_canal,group_partner_manager,1,1,1,1 -access_res_partner_category_group_user,"res_partner_category group_user",model_res_partner_category,group_partner_manager,1,1,1,0 -access_res_partner_category_group_partner_manager,"res_partner_category group_partner_manager",model_res_partner_category,,1,0,0,1 -access_res_partner_event_group_user,"res_partner_event group_user",model_res_partner_event,,1,1,1,1 -access_res_partner_event_type_group_partner_manager,"res_partner_event_type group_partner_manager",model_res_partner_event_type,group_partner_manager,1,1,1,1 -access_res_partner_event_type_group_user,"res_partner_event_type group_user",model_res_partner_event_type,,1,0,0,0 -access_res_partner_function_group_user,"res_partner_function group_user",model_res_partner_function,group_partner_manager,1,1,1,1 -access_res_partner_function_group_partner_manager,"res_partner_function group_partner_manager",model_res_partner_function,,1,0,0,0 -access_res_partner_som_group_user,"res_partner_som group_user",model_res_partner_som,group_partner_manager,1,1,1,1 -access_res_partner_som_group_partner_manager,"res_partner_som group_partner_manager",model_res_partner_som,,1,0,0,0 -access_res_partner_title_group_user,"res_partner_title group_user",model_res_partner_title,group_partner_manager,1,1,1,1 -access_res_partner_title_group_partner_manager,"res_partner_title group_partner_manager",model_res_partner_title,,1,0,0,0 -access_res_request_group_user,"res_request group_user",model_res_request,,1,1,1,1 -access_res_request_history_group_user,"res_request_history group_user",model_res_request_history,,1,1,1,1 -access_res_request_link_group_system,"res_request_link group_system",model_res_request_link,group_system,1,1,1,1 -access_res_request_link_group_user,"res_request_link group_user",model_res_request_link,,1,0,0,0 -access_res_users_group_user,"res_users group_user",model_res_users,,1,0,0,0 -access_res_users_group_erp_manager,"res_users group_erp_manager",model_res_users,group_erp_manager,1,1,1,1 -access_ir_actions_employee,ir_actions_employee,model_ir_actions_actions,group_user,1,0,0,0 -access_ir_actions_act_window_employee,ir_actions_act_window_employee,model_ir_actions_act_window,group_user,1,0,0,0 -access_ir_actions_act_window_close_group_system,ir_actions_act_window_close_system,model_ir_actions_act_window_close,group_system,1,0,0,0 -access_ir_actions_report_xml_group_system,ir_actions_report_xml_system,model_ir_actions_report_xml,group_system,1,0,0,0 -access_ir_actions_wizard_group_system,ir_actions_wizard,model_ir_actions_wizard,group_system,1,0,0,0 -access_workflow_group_system,workflow_group_system,model_workflow,group_system,1,0,0,0 -access_workflow_activity_group_system,workflow_activity_group_system,model_workflow_activity,group_system,1,0,0,0 -access_workflow_instance_group_system,workflow_instance_group_system,model_workflow_instance,group_system,1,0,0,0 -access_workflow_transition_group_system,workflow_transition_group_system,model_workflow_transition,group_system,1,0,0,0 -access_workflow_triggers_group_system,workflow_triggers_group_system,model_workflow_triggers,group_system,1,0,0,0 -access_workflow_workitem_group_system,workflow_workitem_group_system,model_workflow_workitem,group_system,1,0,0,0 -access_actions_report_custom_group_system,ir_actions_report_custom_group_system,model_ir_actions_report_custom,group_system,1,0,0,0 -access_ir_actions_act_window_view_group_employee,ir_actions_act_window_view_group_employee,model_ir_actions_act_window_view,group_user,1,0,0,0 -access_ir_actions_url_group_user,ir_actions_url_group_user,model_ir_actions_url,group_user,1,0,0,0 -access_ir_server_object_lines_group_user,ir_server_object_lines_group_user,model_ir_server_object_lines,group_user,1,0,0,0 -access_ir_actions_server_group_user,ir_actions_server_group_user,model_ir_actions_server,group_user,1,0,0,0 -access_module_update_translations_group_user,wizard_update_translations_group_user,model_wizard_module_update_translations,group_user,1,1,1,1 -access_res_bank_group_system,res_bank_group_system,model_res_bank,group_system,1,1,1,1 -access_res_payterm_group_system,res_payterm_group_system,model_res_payterm,group_system,1,1,1,1 -access_res_roles_group_erpmanager,res_roles_group_erp_manager,model_res_roles,group_erp_manager,1,1,1,1 -access_res_config_view_group_erpmanager,res_config_view_erp_manager,model_res_config_view,group_erp_manager,1,1,1,1 +"id","name","model_id:id","group_id:id","perm_read","perm_write","perm_create","perm_unlink" +"access_ir_attachment_group_user","ir_attachment group_system_user","model_ir_attachment","group_user",1,1,1,1 +"access_ir_attachment_group_system","ir_attachment group_system","model_ir_attachment",,1,0,0,0 +"access_ir_cron_group_cron","ir_cron group_cron","model_ir_cron","group_system",1,1,1,1 +"access_ir_default_group_system","ir_default group_system","model_ir_default",,1,1,1,1 +"access_ir_exports_group_system","ir_exports group_system","model_ir_exports",,1,1,1,1 +"access_ir_exports_line_group_system","ir_exports_line group_system","model_ir_exports_line",,1,1,1,1 +"access_ir_model_group_erp_manager","ir_model group_erp_manager","model_ir_model","group_erp_manager",1,1,1,1 +"access_ir_model_access_group_erp_manager","ir_model_access_group_erp_manager","model_ir_model_access","group_erp_manager",1,1,1,1 +"access_ir_model_grid_group_erp_manager","ir_model_access_grid_group_erp_manager","model_ir_model_grid","group_erp_manager",1,1,1,1 +"access_ir_model_config_group_erp_manager","ir_model_config group_erp_manager","model_ir_model_config","group_erp_manager",1,1,1,1 +"access_ir_model_data_group_erp_manager","ir_model_data group_erp_manager","model_ir_model_data","group_erp_manager",1,1,1,1 +"access_ir_model_fields_group_erp_manager","ir_model_fields group_erp_manager","model_ir_model_fields","group_erp_manager",1,1,1,1 +"access_ir_model_all","ir_model_all","model_ir_model",,1,0,0,0 +"access_ir_model_access_all","ir_model_access_all","model_ir_model_access",,1,0,0,0 +"access_ir_model_grid_all","ir_model_access_grid_all","model_ir_model_grid",,0,0,0,0 +"access_ir_model_config_all","ir_model_config_all","model_ir_model_config",,1,0,0,0 +"access_ir_model_data_all","ir_model_data all","model_ir_model_data",,1,0,0,0 +"access_ir_model_fields_all","ir_model_fields all","model_ir_model_fields",,1,0,0,0 +"access_ir_module_category_group_user","ir_module_category group_user","model_ir_module_category","group_system",1,0,0,0 +"access_ir_module_module_group_user","ir_module_module group_user","model_ir_module_module","group_system",1,1,1,1 +"access_ir_module_module_dependency_group_system","ir_module_module_dependency group_system","model_ir_module_module_dependency","group_system",1,1,1,1 +"access_ir_module_repository_group_system","ir_module_repository group_system","model_ir_module_repository","group_system",1,1,1,1 +"access_ir_property_group_user","ir_property group_user","model_ir_property",,1,0,0,0 +"access_ir_report_custom_group_system","ir_report_custom group_system","model_ir_report_custom",,1,0,0,0 +"access_ir_report_custom_fields_group_system","ir_report_custom_fields group_system","model_ir_report_custom_fields",,1,0,0,0 +"access_ir_rule_group_user","ir_rule group_user","model_ir_rule",,1,0,0,0 +"access_ir_rule_group_group_user","ir_rule_group group_user","model_ir_rule_group",,1,0,0,0 +"access_ir_rule_group_erp_manager","ir_rule group_erp_manager","model_ir_rule","group_erp_manager",1,1,1,1 +"access_ir_rule_group_group_erp_manager","ir_rule_group group_erp_manager","model_ir_rule_group","group_erp_manager",1,1,1,1 +"access_ir_sequence_group_user","ir_sequence group_user","model_ir_sequence",,1,1,1,1 +"access_ir_sequence_type_group_user","ir_sequence_type group_user","model_ir_sequence_type",,1,0,0,0 +"access_ir_translation_group_system","ir_translation group_system","model_ir_translation",,1,1,1,1 +"access_ir_ui_menu_group_user","ir_ui_menu group_user","model_ir_ui_menu",,1,0,0,0 +"access_ir_ui_view_group_user","ir_ui_view group_user","model_ir_ui_view",,1,0,0,0 +"access_ir_ui_view_custom_group_user","ir_ui_view_custom_group_user","model_ir_ui_view_custom",,1,0,0,0 +"access_ir_ui_view_sc_group_user","ir_ui_view_sc group_user","model_ir_ui_view_sc",,1,1,1,1 +"access_ir_values_group_erp_manager","ir_values group_erp_manager","model_ir_values",,1,1,1,1 +"access_wizard_ir_model_menu_create_group_system","wizard_ir_model_menu_create group_system","model_wizard_ir_model_menu_create","group_system",1,1,1,1 +"access_wizard_ir_model_menu_create_line_group_system","wizard_ir_model_menu_create_line group_system","model_wizard_ir_model_menu_create_line","group_system",1,1,1,1 +"access_wizard_module_lang_export_group_system","wizard_module_lang_export group_system","model_wizard_module_lang_export","group_system",1,1,1,1 +"access_res_company_group_erp_manager","res_company group_erp_manager","model_res_company","group_erp_manager",1,1,1,1 +"access_res_company_group_user","res_company group_user","model_res_company",,1,0,0,0 +"access_res_country_group_all","res_country group_user_all","model_res_country",,1,0,0,0 +"access_res_country_state_group_all","res_country_state group_user_all","model_res_country_state",,1,0,0,0 +"access_res_country_group_user","res_country group_user","model_res_country","group_partner_manager",1,1,1,1 +"access_res_country_state_group_user","res_country_state group_user","model_res_country_state","group_partner_manager",1,1,1,1 +"access_res_currency_group_all","res_currency group_all","model_res_currency",,1,0,0,0 +"access_res_currency_rate_group_all","res_currency_rate group_all","model_res_currency_rate",,1,0,0,0 +"access_res_currency_group_user","res_currency group_user","model_res_currency","group_user",1,1,1,1 +"access_res_currency_rate_group_user","res_currency_rate group_user","model_res_currency_rate","group_user",1,1,1,1 +"access_res_groups_group_erp_manager","res_groups group_erp_manager","model_res_groups","group_erp_manager",1,1,1,1 +"access_res_groups_group_user","res_groups group_user","model_res_groups",,1,0,0,0 +"access_res_lang_group_all","res_lang group_all","model_res_lang",,1,0,0,0 +"access_res_lang_group_user","res_lang group_user","model_res_lang","group_system",1,1,1,1 +"access_res_partner_group_partner_manager","res_partner group_partner_manager","model_res_partner","group_partner_manager",1,1,1,1 +"access_res_partner_group_user","res_partner group_user","model_res_partner",,1,0,0,0 +"access_res_partner_address_group_partner_manager","res_partner_address group_partner_manager","model_res_partner_address","group_partner_manager",1,1,1,1 +"access_res_partner_address_group_user","res_partner_address group_user","model_res_partner_address",,1,0,0,0 +"access_res_partner_bank_group_user","res_partner_bank group_user","model_res_partner_bank",,1,0,0,0 +"access_res_partner_bank_group_partner_manager","res_partner_bank group_partner_manager","model_res_partner_bank","group_partner_manager",1,1,1,1 +"access_res_partner_bank_type_group_partner_manager","res_partner_bank_type group_partner_manager","model_res_partner_bank_type","group_partner_manager",1,1,1,1 +"access_res_partner_bank_type_group_user","res_partner_bank_type group_user","model_res_partner_bank_type",,1,0,0,0 +"access_res_partner_bank_type_field_group_partner_manager","res_partner_bank_type_field group_partner_manager","model_res_partner_bank_type_field","group_partner_manager",1,1,1,1 +"access_res_partner_bank_type_field_group_user","res_partner_bank_type_field group_user","model_res_partner_bank_type_field",,1,0,0,0 +"access_res_partner_canal_group_user","res_partner_canal group_user","model_res_partner_canal",,1,0,0,0 +"access_res_partner_canal_group_partner_manager","res_partner_canal group_partner_manager","model_res_partner_canal","group_partner_manager",1,1,1,1 +"access_res_partner_category_group_user","res_partner_category group_user","model_res_partner_category","group_partner_manager",1,1,1,0 +"access_res_partner_category_group_partner_manager","res_partner_category group_partner_manager","model_res_partner_category",,1,0,0,1 +"access_res_partner_event_group_user","res_partner_event group_user","model_res_partner_event",,1,1,1,1 +"access_res_partner_event_type_group_partner_manager","res_partner_event_type group_partner_manager","model_res_partner_event_type","group_partner_manager",1,1,1,1 +"access_res_partner_event_type_group_user","res_partner_event_type group_user","model_res_partner_event_type",,1,0,0,0 +"access_res_partner_function_group_user","res_partner_function group_user","model_res_partner_function","group_partner_manager",1,1,1,1 +"access_res_partner_function_group_partner_manager","res_partner_function group_partner_manager","model_res_partner_function",,1,0,0,0 +"access_res_partner_som_group_user","res_partner_som group_user","model_res_partner_som","group_partner_manager",1,1,1,1 +"access_res_partner_som_group_partner_manager","res_partner_som group_partner_manager","model_res_partner_som",,1,0,0,0 +"access_res_partner_title_group_user","res_partner_title group_user","model_res_partner_title","group_partner_manager",1,1,1,1 +"access_res_partner_title_group_partner_manager","res_partner_title group_partner_manager","model_res_partner_title",,1,0,0,0 +"access_res_request_group_user","res_request group_user","model_res_request",,1,1,1,1 +"access_res_request_history_group_user","res_request_history group_user","model_res_request_history",,1,1,1,1 +"access_res_request_link_group_system","res_request_link group_system","model_res_request_link","group_system",1,1,1,1 +"access_res_request_link_group_user","res_request_link group_user","model_res_request_link",,1,0,0,0 +"access_res_users_group_user","res_users group_user","model_res_users",,1,0,0,0 +"access_res_users_group_erp_manager","res_users group_erp_manager","model_res_users","group_erp_manager",1,1,1,1 +"access_ir_actions_all","ir_actions_all","model_ir_actions_actions",,1,0,0,0 +"access_ir_actions_act_window_all","ir_actions_act_window_all","model_ir_actions_act_window",,1,0,0,0 +"access_ir_actions_act_window_close_group_all","ir_actions_act_window_close_all","model_ir_actions_act_window_close",,1,0,0,0 +"access_ir_actions_report_xml_all","ir_actions_report_xml","model_ir_actions_report_xml",,1,0,0,0 +"access_ir_actions_wizard_all","ir_actions_wizard","model_ir_actions_wizard",,1,0,0,0 +"access_ir_actions_todo_group_system","ir_actions_todo group system","model_ir_actions_todo","group_system",1,1,1,1 +"access_ir_actions_config_wiz_group_system","ir_actions_configuration_wizard group system","model_ir_actions_configuration_wizard","group_system",1,1,1,1 +"access_workflow_group_system","workflow_group_system","model_workflow","group_system",1,0,0,0 +"access_workflow_activity_group_system","workflow_activity_group_system","model_workflow_activity","group_system",1,0,0,0 +"access_workflow_instance_group_system","workflow_instance_group_system","model_workflow_instance","group_system",1,0,0,0 +"access_workflow_transition_group_system","workflow_transition_group_system","model_workflow_transition","group_system",1,0,0,0 +"access_workflow_triggers_group_system","workflow_triggers_group_system","model_workflow_triggers","group_system",1,0,0,0 +"access_workflow_workitem_group_system","workflow_workitem_group_system","model_workflow_workitem","group_system",1,0,0,0 +"access_actions_report_custom_group_system","ir_actions_report_custom_group_system","model_ir_actions_report_custom","group_system",1,0,0,0 +"access_ir_actions_act_window_view_group_employee","ir_actions_act_window_view_group_employee","model_ir_actions_act_window_view","group_system",1,0,0,0 +"access_ir_actions_url_group_user","ir_actions_url_group_user","model_ir_actions_url","group_system",1,0,0,0 +"access_ir_server_object_lines_group_user","ir_server_object_lines_group_user","model_ir_server_object_lines","group_system",1,0,0,0 +"access_ir_actions_server_group_user","ir_actions_server_group_user","model_ir_actions_server","group_system",1,0,0,0 +"access_module_update_translations_group_user","wizard_update_translations_group_user","model_wizard_module_update_translations","group_system",1,1,1,1 +"access_res_bank_group_system","res_bank_group_system","model_res_bank","group_system",1,1,1,1 +"access_res_payterm_group_system","res_payterm_group_system","model_res_payterm","group_system",1,1,1,1 +"access_res_roles_group_erpmanager","res_roles_group_erp_manager","model_res_roles","group_erp_manager",1,1,1,1 +"access_res_config_view_group_erpmanager","res_config_view_erp_manager","model_res_config_view","group_erp_manager",1,1,1,1 +"access_res_roles_all","res_roles_all","model_res_roles",,1,0,0,0 +"access_res_config_view_all","res_config_view_all","model_res_config_view",,1,0,0,0 diff --git a/bin/osv/expression.py b/bin/osv/expression.py index 1e21443d7ab..7397a82e88b 100644 --- a/bin/osv/expression.py +++ b/bin/osv/expression.py @@ -232,9 +232,9 @@ class expression(object): query = '(%s OR %s IS NULL)' % (query, left) else: params = [] - if right is False and operator == '=': + if (right == False or right is None) and operator == '=': query = '%s IS NULL' % left - elif right is False and operator in ['<>', '!=']: + elif (right == False or right is None) and operator in ['<>', '!=']: query = '%s IS NOT NULL' % left else: if left == 'id': diff --git a/bin/report/render/rml2pdf/utils.py b/bin/report/render/rml2pdf/utils.py index 35460a2faeb..a3c68d1eb64 100644 --- a/bin/report/render/rml2pdf/utils.py +++ b/bin/report/render/rml2pdf/utils.py @@ -57,7 +57,7 @@ def text_get(node): units = [ (re.compile('^(-?[0-9\.]+)\s*in$'), reportlab.lib.units.inch), - (re.compile('^(-?[0-9\.]+)\s*cm$'), reportlab.lib.units.cm), + (re.compile('^(-?[0-9\.]+)\s*cm$'), reportlab.lib.units.cm), (re.compile('^(-?[0-9\.]+)\s*mm$'), reportlab.lib.units.mm), (re.compile('^(-?[0-9\.]+)\s*$'), 1) ] @@ -93,7 +93,7 @@ def attr_get(node, attrs, dict={}): elif dict[key]=='int': res[key] = int(node.getAttribute(key)) elif dict[key]=='unit': - res[key] = unit_get(node.getAttribute(name)) + res[key] = unit_get(node.getAttribute(key)) return res # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: diff --git a/bin/tools/amount_to_text_en.py b/bin/tools/amount_to_text_en.py new file mode 100755 index 00000000000..61d6f5f8fcc --- /dev/null +++ b/bin/tools/amount_to_text_en.py @@ -0,0 +1,149 @@ +# -*- coding: iso8859-1 -*- +############################################################################## +# +# Copyright (c) 2004 TINY SPRL. (http://tiny.be) All Rights Reserved. +# Fabien Pinckaers +# +# WARNING: This program as such is intended to be used by professional +# programmers who take the whole responsability of assessing all potential +# consequences resulting from its eventual inadequacies and bugs +# End users who are looking for a ready-to-use solution with commercial +# garantees and support are strongly adviced to contract a Free Software +# Service Company +# +# This program is Free Software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +############################################################################## + +#------------------------------------------------------------- +#ENGLISH +#------------------------------------------------------------- + +ones = { + 0: '', 1:'One', 2:'Two', 3:'Three', 4:'Four', 5:'Five', 6:'Six', 7:'Seven', 8:'Eight', 9:'Nine', + 10:'Ten', 11:'Eleven', 12:'Twelve', 13:'Thirteen', 14:'Forteen', 15:'Fifteen', 16:'Sixteen', 17:"Seventeen",18:"Eighteen",19:"Nineteen", +} + +tens = { + 1: 'Ten', 2: 'Twenty ', 3:'Thirty', 4:'Forty', 5:'Fifty', 6: 'Sixty', 7 : 'Seventy', 8:'Eighty' ,9: 'Ninety'} + +hundred = { + 0:'',1: 'One Hundred', 2: 'Two Hundred', 3: 'Three Hundred', 4 :'Four Hundred', 5: 'Five Hundred', 6: 'Six Hundred', 7 :'Seven Hundred', 8:' Eight Hundred ', 9:'Nine Hundred ' +} + +thousands ={ + 0:'',1: 'One Thousand' +} + +lacs = { + 0:'',1: 'Lac' +} + +def _100_to_text(number): + if number in ones: + return ones[number] + else: + if number%10>0: + return tens[number / 10]+'-'+ones[number % 10] + else: + return tens[number / 10] + +def _1000_to_text(number): + d = _100_to_text(number % 100) + d2 = number/100 + if d2>0 and d: + return hundred[d2]+' '+d + elif d2>1 and not(d): + return hundred[d2]+'s' + else: + return hundred[d2] or d + +def _10000_to_text(number): + if number==0: + return 'zero' + part1 = _1000_to_text(number % 1000) + part2 = thousands.get(number / 1000, _1000_to_text(number / 1000)+' Thousands') + if part2 and part1: + part1 = ' '+part1 + return part2+part1 + +def _1000000_to_text(number): + if number==0: + return 'zero' + part1 = _10000_to_text(number % 100000) + part2 = lacs.get(number / 100000, _10000_to_text(number / 100000)+' Lacs') + if part2 and part1: + part1 = ' '+part1 + return part2+part1 + + +def amount_to_text(number, currency): + lacs_number = int(number) + units_name = currency + if lacs_number > 1: + units_name += 's' + + lacs = _1000000_to_text(lacs_number) + lacs = lacs_number and '%s %s' % (lacs, units_name) or '' + + units_number = int(number * 10000) % 10000 + units = _10000_to_text(units_number) + units = units_number and '%s %s' % (units, units_name) or '' + + cents_number = int(number * 100) % 100 + cents_name = (cents_number > 1) and 'cents' or 'cent' + cents = _100_to_text(cents_number) + cents = cents_number and '%s %s' % (cents, cents_name) or '' + return lacs + + +#------------------------------------------------------------- +# Generic functions +#------------------------------------------------------------- + +_translate_funcs = {'en' : amount_to_text} + +#TODO: we should use the country AND language (ex: septante VS soixante dix) +#TODO: we should use en by default, but the translation func is yet to be implemented +def amount_to_text(nbr, lang='en', currency='euro'): + """ + Converts an integer to its textual representation, using the language set in the context if any. + Example: + 1654: thousands six cent cinquante-quatre. + """ + if nbr > 10000000: +#TODO: use logger + print "WARNING: number too large '%d', can't translate it!" % (nbr,) + return str(nbr) + + if not _translate_funcs.has_key(lang): +#TODO: use logger + print "WARNING: no translation function found for lang: '%s'" % (lang,) +#TODO: (default should be en) same as above + lang = 'en' + return _translate_funcs[lang](nbr, currency) + +if __name__=='__main__': + from sys import argv + + lang = 'nl' + if len(argv) < 2: + for i in range(1,200): + print i, ">>", int_to_text(i, lang) + for i in range(200,999999,139): + print i, ">>", int_to_text(i, lang) + else: + print int_to_text(int(argv[1]), lang) + diff --git a/bin/tools/convert.py b/bin/tools/convert.py index 24a14c840b1..910c4089991 100644 --- a/bin/tools/convert.py +++ b/bin/tools/convert.py @@ -313,7 +313,7 @@ form: module.record_id""" % (xml_id,) xml_id = rec.getAttribute('id').encode('utf8') self._test_xml_id(xml_id) multi = rec.hasAttribute('multi') and eval(rec.getAttribute('multi')) - res = {'name': string, 'wiz_name': name, 'multi':multi} + res = {'name': string, 'wiz_name': name, 'multi': multi, 'model': model} if rec.hasAttribute('groups'): g_names = rec.getAttribute('groups').split(',') diff --git a/bin/tools/graph.py b/bin/tools/graph.py index 8508f10ce42..fd76cb54fab 100644 --- a/bin/tools/graph.py +++ b/bin/tools/graph.py @@ -56,7 +56,7 @@ class graph(object): """ self.edge_wt = {} for link in self.links: - self.edge_wt[link] = self.result[link[1]]['y'] - self.result[link[0]]['y'] + self.edge_wt[link] = self.result[link[1]]['x'] - self.result[link[0]]['x'] tot_node = self.partial_order.__len__() #do until all the nodes in the component are searched @@ -88,10 +88,10 @@ class graph(object): for node in self.result: if node in self.reachable_nodes: - self.result[node]['y'] += delta + self.result[node]['x'] += delta for edge in self.edge_wt: - self.edge_wt[edge] = self.result[edge[1]]['y'] - self.result[edge[0]]['y'] + self.edge_wt[edge] = self.result[edge[1]]['x'] - self.result[edge[0]]['x'] self.init_cutvalues() @@ -164,10 +164,10 @@ class graph(object): """ if node not in self.result: - self.result[node] = {'x': None, 'y':level, 'mark':0} + self.result[node] = {'y': None, 'x':level, 'mark':0} else: - if level > self.result[node]['y']: - self.result[node]['y'] = level + if level > self.result[node]['x']: + self.result[node]['x'] = level if self.result[node]['mark']==0: self.result[node]['mark'] = 1 @@ -272,7 +272,7 @@ class graph(object): def finalize_rank(self, node, level): - self.result[node]['y'] = level + self.result[node]['x'] = level for destination in self.optimal_edges.get(node, []): self.finalize_rank(destination, level+1) @@ -281,15 +281,11 @@ class graph(object): """The ranks are normalized by setting the least rank to zero. """ - least_rank=100 - - for node in self.result: - if least_rank>self.result[node]['y']: - least_rank = self.result[node]['y'] + least_rank = min(map(lambda x: x['x'], self.result.values())) if(least_rank!=0): for node in self.result: - self.result[node]['y']-=least_rank + self.result[node]['x']-=least_rank def make_chain(self): @@ -300,12 +296,12 @@ class graph(object): for edge in self.edge_wt: if self.edge_wt[edge]>1: self.transitions[edge[0]].remove(edge[1]) - start = self.result[edge[0]]['y'] - end = self.result[edge[1]]['y'] + start = self.result[edge[0]]['x'] + end = self.result[edge[1]]['x'] for rank in range(start+1, end): if not self.result.get((rank, 'temp'), False): - self.result[(rank, 'temp')] = {'x': None, 'y': rank, 'mark': 0} + self.result[(rank, 'temp')] = {'y': None, 'x': rank, 'mark': 0} for rank in range(start, end): if start==rank: @@ -319,12 +315,12 @@ class graph(object): def init_order(self, node, level): """Initialize orders the nodes in each rank with depth-first search """ - if not self.result[node]['x']: - self.result[node]['x'] = self.order[level] + if not self.result[node]['y']: + self.result[node]['y'] = self.order[level] self.order[level] = self.order[level]+1 for sec_end in self.transitions.get(node, []): - self.init_order(sec_end, self.result[sec_end]['y']) + self.init_order(sec_end, self.result[sec_end]['x']) def order_heuristic(self): @@ -349,10 +345,8 @@ class graph(object): self.levels[level] = new_list order = 0 for node in nodes: - self.result[node]['x'] = order - order +=1 - - + self.result[node]['y'] = order + order +=1 def median_value(self, node, adj_rank): @@ -390,7 +384,7 @@ class graph(object): if pre_level_nodes: for src in pre_level_nodes: if (self.transitions.get(src) and self.transitions[src].__contains__(node)): - adj_nodes.append(self.result[src]['x']) + adj_nodes.append(self.result[src]['y']) return adj_nodes @@ -399,7 +393,7 @@ class graph(object): levels = {} for r in self.partial_order: - l = self.result[r]['y'] + l = self.result[r]['x'] levels.setdefault(l,[]) levels[l].append(r) @@ -425,28 +419,28 @@ class graph(object): else: first_half = list[no/2+1:] if max_level==1:#for the case when horizontal graph is there - self.result[list[no/2]]['x'] = mid_pos + (self.result[list[no/2]]['y']%2 * 0.5) + self.result[list[no/2]]['y'] = mid_pos + (self.result[list[no/2]]['x']%2 * 0.5) else: - self.result[list[no/2]]['x'] = mid_pos + factor + self.result[list[no/2]]['y'] = mid_pos + factor last_half = list[:no/2] i=1 for node in first_half: - self.result[node]['x'] = mid_pos - (i + factor) + self.result[node]['y'] = mid_pos - (i + factor) i += 1 i=1 for node in last_half: - self.result[node]['x'] = mid_pos + (i + factor) + self.result[node]['y'] = mid_pos + (i + factor) i += 1 else: self.max_order += max_level+1 - mid_pos = self.result[self.start]['x'] + mid_pos = self.result[self.start]['y'] def tree_order(self, node, last=0): - mid_pos = self.result[node]['x'] + mid_pos = self.result[node]['y'] l = self.transitions.get(node, []) l.reverse() no = len(l) @@ -462,41 +456,41 @@ class graph(object): i=1 for child in first_half: - self.result[child]['x'] = mid_pos - (i - (factor * 0.5)) + self.result[child]['y'] = mid_pos - (i - (factor * 0.5)) i += 1 if self.transitions.get(child, False): if last: - self.result[child]['x'] = last + len(self.transitions[child])/2 + 1 + self.result[child]['y'] = last + len(self.transitions[child])/2 + 1 last = self.tree_order(child, last) if no%2: mid_node = l[no/2] - self.result[mid_node]['x'] = mid_pos + self.result[mid_node]['y'] = mid_pos if self.transitions.get((mid_node), False): if last: - self.result[mid_node]['x'] = last + len(self.transitions[mid_node])/2 + 1 + self.result[mid_node]['y'] = last + len(self.transitions[mid_node])/2 + 1 last = self.tree_order(mid_node) else: if last: - self.result[mid_node]['x'] = last + 1 - self.result[node]['x'] = self.result[mid_node]['x'] - mid_pos = self.result[node]['x'] + self.result[mid_node]['y'] = last + 1 + self.result[node]['y'] = self.result[mid_node]['y'] + mid_pos = self.result[node]['y'] i=1 last_child = None for child in last_half: - self.result[child]['x'] = mid_pos + (i - (factor * 0.5)) + self.result[child]['y'] = mid_pos + (i - (factor * 0.5)) last_child = child i += 1 if self.transitions.get(child, False): if last: - self.result[child]['x'] = last + len(self.transitions[child])/2 + 1 + self.result[child]['y'] = last + len(self.transitions[child])/2 + 1 last = self.tree_order(child, last) if last_child: - last = self.result[last_child]['x'] + last = self.result[last_child]['y'] return last @@ -504,27 +498,75 @@ class graph(object): def process_order(self): """Finds actual-order of the nodes with respect to maximum number of nodes in a rank in component """ - max_level = max(map(lambda x: len(x), self.levels.values())) - - if max_level%2: - self.result[self.start]['x'] = (max_level+1)/2 + self.max_order +1 - else: - self.result[self.start]['x'] = (max_level)/2 + self.max_order + 1 if self.Is_Cyclic: + max_level = max(map(lambda x: len(x), self.levels.values())) + + if max_level%2: + self.result[self.start]['y'] = (max_level+1)/2 + self.max_order + (self.max_order and 1) + else: + self.result[self.start]['y'] = (max_level)/2 + self.max_order + (self.max_order and 1) + self.graph_order() else: - self.result[self.start]['x'] = 0 + self.result[self.start]['y'] = 0 self.tree_order(self.start, 0) - min_order = math.fabs(min(map(lambda x: x['x'], self.result.values()))) - min_order += self.max_order + 1 + min_order = math.fabs(min(map(lambda x: x['y'], self.result.values()))) + + index = self.start_nodes.index(self.start) + same = False + + roots = [] + if index>0: + for start in self.start_nodes[:index]: + same = True + for edge in self.tree_list[start][1:]: + if self.tree_list[self.start].__contains__(edge): + continue + else: + same = False + break + if same: + roots.append(start) + + if roots: + min_order += self.max_order + else: + min_order += self.max_order + 1 for level in self.levels: for node in self.levels[level]: - self.result[node]['x'] += min_order - - self.max_order = max(map(lambda x: x['x'], self.result.values())) + self.result[node]['y'] += min_order + + if roots: + roots.append(self.start) + one_level_el = self.tree_list[self.start][0][1] + base = self.result[one_level_el]['y']# * 2 / (index + 2) + + + no = len(roots) + first_half = roots[:no/2] + + if no%2==0: + last_half = roots[no/2:] + else: + last_half = roots[no/2+1:] + + factor = -math.floor(no/2) + for start in first_half: + self.result[start]['y'] = base + factor + factor += 1 + + if no%2: + self.result[roots[no/2]]['y'] = base + factor + factor +=1 + + for start in last_half: + self.result[start]['y'] = base + factor + factor += 1 + + self.max_order = max(map(lambda x: x['y'], self.result.values())) def find_starts(self): """Finds other start nodes of the graph in the case when graph is disconneted @@ -579,8 +621,8 @@ class graph(object): self.links = [] self.Is_Cyclic = False - tree = self.make_acyclic(None, self.start, 0, []) - self.Is_Cyclic = self.rev_edges(tree) + self.tree_list[self.start] = self.make_acyclic(None, self.start, 0, []) + self.Is_Cyclic = self.rev_edges(self.tree_list[self.start]) self.process_ranking(self.start) self.init_rank() @@ -606,7 +648,7 @@ class graph(object): #normalization self.normalize() for edge in self.edge_wt: - self.edge_wt[edge] = self.result[edge[1]]['y'] - self.result[edge[0]]['y'] + self.edge_wt[edge] = self.result[edge[1]]['x'] - self.result[edge[0]]['x'] def order_in_rank(self): """Finds optimized order of the nodes within their ranks using median heuristic @@ -622,10 +664,10 @@ class graph(object): for i in range(max_rank+1): self.order[i] = 0 - self.init_order(self.start, self.result[self.start]['y']) + self.init_order(self.start, self.result[self.start]['x']) for level in self.levels: - self.levels[level].sort(lambda x, y: cmp(self.result[x]['x'], self.result[y]['x'])) + self.levels[level].sort(lambda x, y: cmp(self.result[x]['y'], self.result[y]['y'])) self.order_heuristic() self.process_order() @@ -639,6 +681,7 @@ class graph(object): self.start_nodes = starting_node or [] self.partial_order = {} self.links = [] + self.tree_list = {} if self.nodes: if self.start_nodes: @@ -673,7 +716,7 @@ class graph(object): for l in self.levels: result += 'PosY: ' + str(l) + '\n' for node in self.levels[l]: - result += '\tPosX: '+ str(self.result[node]['x']) + ' - Node:' + node + "\n" + result += '\tPosX: '+ str(self.result[node]['y']) + ' - Node:' + node + "\n" return result @@ -684,16 +727,16 @@ class graph(object): #for flat edges ie. source an destination nodes are on the same rank for src in self.transitions: for des in self.transitions[src]: - if (self.result[des]['y'] - self.result[src]['y'] == 0): - self.result[src]['y'] += 0.08 - self.result[des]['y'] -= 0.08 + if (self.result[des]['x'] - self.result[src]['x'] == 0): + self.result[src]['x'] += 0.08 + self.result[des]['x'] -= 0.08 factorX = maxx + nheight factorY = maxy + nwidth for node in self.result: - self.result[node]['x'] = (self.result[node]['x']) * factorX + margin - self.result[node]['y'] = (self.result[node]['y']) * factorY + margin + self.result[node]['y'] = (self.result[node]['y']) * factorX + margin + self.result[node]['x'] = (self.result[node]['x']) * factorY + margin def result_get(self): @@ -731,13 +774,13 @@ if __name__=='__main__': draw = ImageDraw.Draw(img) for name,node in g.result.items(): - draw.arc( (int(node['x']-radius), int(node['y']-radius),int(node['x']+radius), int(node['y']+radius) ), 0, 360, (128,128,128)) - draw.text( (int(node['x']), int(node['y'])), name, (128,128,128)) + draw.arc( (int(node['y']-radius), int(node['x']-radius),int(node['y']+radius), int(node['x']+radius) ), 0, 360, (128,128,128)) + draw.text( (int(node['y']), int(node['x'])), name, (128,128,128)) for nodefrom in g.transitions: for nodeto in g.transitions[nodefrom]: - draw.line( (int(g.result[nodefrom]['x']), int(g.result[nodefrom]['y']),int(g.result[nodeto]['x']),int(g.result[nodeto]['y'])),(128,128,128) ) + draw.line( (int(g.result[nodefrom]['y']), int(g.result[nodefrom]['x']),int(g.result[nodeto]['y']),int(g.result[nodeto]['x'])),(128,128,128) ) img.save("graph.png", "PNG") diff --git a/bin/tools/translate.py b/bin/tools/translate.py index a2e487fda79..538f1816ac2 100644 --- a/bin/tools/translate.py +++ b/bin/tools/translate.py @@ -39,6 +39,8 @@ import inspect import mx.DateTime as mxdt import tempfile import tarfile +import codecs + class UNIX_LINE_TERMINATOR(csv.excel): lineterminator = '\n' @@ -78,22 +80,31 @@ _ = GettextAlias() class TinyPoFile(object): def __init__(self, buffer): self.buffer = buffer - + def __iter__(self): self.buffer.seek(0) - self.lines = self.buffer.readlines() - self.lines.append('') # ensure that the file ends with at least an empty line + self.lines = self._get_lines() + self.first = True self.tnrs= [] return self - + + def _get_lines(self): + lines = self.buffer.readlines() + # remove the BOM (Byte Order Mark): + if len(lines): + lines[0] = unicode(lines[0], 'utf8').lstrip(unicode( codecs.BOM_UTF8, "utf8")) + + lines.append('') # ensure that the file ends with at least an empty line + return lines + def next(self): def unquote(str): return str[1:-1].replace("\\n", "\n") \ - .replace('\\"', '"') + .replace('\\"', '"') type = name = res_id = source = trad = None - + if self.tnrs: type, name, res_id, source, trad = self.tnrs.pop(0) else: @@ -104,7 +115,7 @@ class TinyPoFile(object): if 0 == len(self.lines): raise StopIteration() line = self.lines.pop(0).strip() - + while line.startswith('#'): if line.startswith('#:'): tmp_tnrs.append( line[2:].strip().split(':') ) @@ -112,18 +123,18 @@ class TinyPoFile(object): fuzzy = True line = self.lines.pop(0).strip() if not line.startswith('msgid'): - raise Exception("malformed file") + raise Exception("malformed file: bad line: %s" % line) source = unquote(line[6:]) line = self.lines.pop(0).strip() if not source and self.first: - # if the source is "" and it's the first msgid, it's the special - # msgstr with the informations about the traduction and the + # if the source is "" and it's the first msgid, it's the special + # msgstr with the informations about the traduction and the # traductor; we skip it self.tnrs = [] while line: line = self.lines.pop(0).strip() - return self.next() - + return self.next() + while not line.startswith('msgstr'): if not line: raise Exception('malformed file') @@ -135,7 +146,7 @@ class TinyPoFile(object): while line: trad += unquote(line) line = self.lines.pop(0).strip() - + if tmp_tnrs and not fuzzy: type, name, res_id = tmp_tnrs.pop(0) for t, n, r in tmp_tnrs: @@ -155,16 +166,16 @@ class TinyPoFile(object): "#\n" \ "msgid \"\"\n" \ "msgstr \"\"\n" \ - "\"Project-Id-Version: %(project)s %(version)s\"\n" \ - "\"Report-Msgid-Bugs-To: %(bugmail)s\"\n" \ - "\"POT-Creation-Date: %(now)s\"\n" \ - "\"PO-Revision-Date: %(now)s\"\n" \ - "\"Last-Translator: <>\"\n" \ - "\"Language-Team: \"\n" \ - "\"MIME-Version: 1.0\"\n" \ - "\"Content-Type: text/plain; charset=UTF-8\"\n" \ - "\"Content-Transfer-Encoding: \"\n" \ - "\"Plural-Forms: \"\n" \ + '''"Project-Id-Version: %(project)s %(version)s\\n"\n''' \ + '''"Report-Msgid-Bugs-To: %(bugmail)s\\n"\n''' \ + '''"POT-Creation-Date: %(now)s\\n"\n''' \ + '''"PO-Revision-Date: %(now)s\\n"\n''' \ + '''"Last-Translator: <>\\n"\n''' \ + '''"Language-Team: \\n"\n''' \ + '''"MIME-Version: 1.0\\n"\n''' \ + '''"Content-Type: text/plain; charset=UTF-8\\n"\n''' \ + '''"Content-Transfer-Encoding: \\n"\n''' \ + '''"Plural-Forms: \\n"\n''' \ "\n" % { 'project': release.description, @@ -182,11 +193,11 @@ class TinyPoFile(object): plurial = len(modules) > 1 and 's' or '' self.buffer.write("#. module%s: %s\n" % (plurial, ', '.join(modules))) - + if "code" in map(lambda e: e[0], tnrs): # only strings in python code are python formated self.buffer.write("#, python-format\n") - + for typy, name, res_id in tnrs: self.buffer.write("#: %s:%s:%s\n" % (typy, name, res_id)) @@ -234,7 +245,7 @@ def trans_export(lang, modules, buffer, format, dbname=None): for row in rows: module = row[0] rows_by_module.setdefault(module, []).append(row) - + tmpdir = tempfile.mkdtemp() for mod, modrows in rows_by_module.items(): tmpmoddir = join(tmpdir, mod, 'i18n') @@ -257,7 +268,7 @@ def trans_export(lang, modules, buffer, format, dbname=None): modules = set([t[0] for t in trans[1:]]) _process(format, modules, trans, buffer, lang, newlang) del trans - + def trans_parse_xsl(de): res = [] @@ -299,7 +310,7 @@ def trans_parse_view(de): def in_modules(object_name, modules): if 'all' in modules: return True - + module_dict = { 'ir': 'base', 'res': 'base', @@ -329,7 +340,7 @@ def trans_generate(lang, modules, dbname=None): if not 'all' in modules: query += ' WHERE module IN (%s)' % ','.join(['%s']*len(modules)) query += ' ORDER BY module, model, name' - + query_param = not 'all' in modules and modules or None cr.execute(query, query_param) @@ -452,10 +463,10 @@ def trans_generate(lang, modules, dbname=None): path = path[len(relative_addons_path)+1:] return path.split(os.path.sep)[0] return 'base' # files that are not in a module are considered as being in 'base' module - + modobj = pool.get('ir.module.module') installed_modids = modobj.search(cr, uid, [('state', '=', 'installed')]) - installed_modules = map(lambda m: m['name'], modobj.browse(cr, uid, installed_modids, ['name'])) + installed_modules = map(lambda m: m['name'], modobj.read(cr, uid, installed_modids, ['name'])) for root, dirs, files in tools.oswalksymlinks(tools.config['root_path']): for fname in fnmatch.filter(files, '*.py'): diff --git a/setup.py b/setup.py index c81a06e2f18..4c466bc4145 100755 --- a/setup.py +++ b/setup.py @@ -154,7 +154,10 @@ f.close() options = {"py2exe": { "compressed": 0, "optimize": 2, - "packages": ["decimal", "xml", "xml.dom", "xml.xpath", "encodings","mx.DateTime","wizard","pychart","PIL", "pyparsing", "pydot"], + "packages": ["lxml", "lxml.builder", "lxml._elementpath", "lxml.etree", + "lxml.objectify", "decimal", "xml", "xml.dom", "xml.xpath", + "encodings","mx.DateTime","wizard","pychart","PIL", "pyparsing", + "pydot"], "excludes" : ["Tkconstants","Tkinter","tcl"], }} diff --git a/win32/OpenERPServerService.py b/win32/OpenERPServerService.py index 85cd884a839..24df255f1d2 100644 --- a/win32/OpenERPServerService.py +++ b/win32/OpenERPServerService.py @@ -73,15 +73,13 @@ class OpenERPServerService(win32serviceutil.ServiceFramework): def StartTERP(self): - # The server finds now its configuration automatically on Windows - # We start the ERP Server as an independent process, but we keep its handle - # The server's binary must be one directory above the service's binary (when py2exe'd the python libraries shouldn' mix) - service_dir = os.path.dirname(sys.argv[0]) - server_dir = os.path.split(service_dir)[0] - server_path = os.path.join(server_dir, 'openerp-server.exe') - self.terpprocess = subprocess.Popen([server_path], \ - cwd=server_dir, - creationflags=win32process.CREATE_NO_WINDOW) + # The server finds now its configuration automatically on Windows + # We start the ERP Server as an independent process, but we keep its handle + # The server's binary must be one directory above the service's binary (when py2exe'd the python libraries shouldn' mix) + service_dir = os.path.dirname(sys.argv[0]) + server_dir = os.path.split(service_dir)[0] + server_path = os.path.join(server_dir, 'openerp-server.exe') + self.terpprocess = subprocess.Popen([server_path], cwd=server_dir, creationflags=win32process.CREATE_NO_WINDOW) def StartControl(self,ws): @@ -93,10 +91,10 @@ class OpenERPServerService(win32serviceutil.ServiceFramework): # Start OpenERP Server itself self.StartTERP() # start the loop waiting for the Service Manager's stop signal - thread.start_new_thread(self.StartControl, (self.hWaitStop,)) - # Log a info message that the server is running - servicemanager.LogInfoMsg("OpenERP Server up and running") - # verification if the server is really running, else quit with an error + thread.start_new_thread(self.StartControl, (self.hWaitStop,)) + # Log a info message that the server is running + servicemanager.LogInfoMsg("OpenERP Server up and running") + # verification if the server is really running, else quit with an error self.terpprocess.wait() if not self.stopping: sys.exit("OpenERP Server check: server not running, check the logfile for more info")