From 2dd9723b8b3d38df8c8962300ab67afffa5cdaaa Mon Sep 17 00:00:00 2001 From: Christophe Simonis Date: Tue, 22 Jul 2008 16:24:36 +0200 Subject: [PATCH] convert tabs to 4 spaces bzr revid: christophe@tinyerp.com-20080722142436-143iu4ryy47w3av0 --- bin/addons/__init__.py | 506 +- bin/addons/base/__terp__.py | 80 +- bin/addons/base/ir/ir_actions.py | 520 +- bin/addons/base/ir/ir_attachment.py | 22 +- bin/addons/base/ir/ir_board.py | 16 +- bin/addons/base/ir/ir_cron.py | 158 +- bin/addons/base/ir/ir_default.py | 38 +- bin/addons/base/ir/ir_exports.py | 24 +- bin/addons/base/ir/ir_model.py | 712 +-- bin/addons/base/ir/ir_report_custom.py | 312 +- bin/addons/base/ir/ir_rule.py | 344 +- bin/addons/base/ir/ir_sequence.py | 78 +- bin/addons/base/ir/ir_translation.py | 228 +- bin/addons/base/ir/ir_ui_menu.py | 266 +- bin/addons/base/ir/ir_ui_view.py | 146 +- bin/addons/base/ir/ir_values.py | 406 +- bin/addons/base/ir/wizard/wizard_menu.py | 98 +- bin/addons/base/ir/workflow/print_instance.py | 268 +- bin/addons/base/ir/workflow/pydot/__init__.py | 0 .../base/ir/workflow/pydot/dot_parser.py | 544 +- bin/addons/base/ir/workflow/pydot/pydot.py | 1946 +++---- bin/addons/base/ir/workflow/pydot/setup.py | 36 +- bin/addons/base/ir/workflow/workflow.py | 260 +- bin/addons/base/module/module.py | 1094 ++-- .../report/ir_module_reference_print.py | 50 +- bin/addons/base/module/wizard/add_new.py | 84 +- .../base/module/wizard/wizard_export_lang.py | 182 +- .../base/module/wizard/wizard_import_lang.py | 78 +- .../module/wizard/wizard_module_import.py | 120 +- .../wizard/wizard_module_lang_install.py | 86 +- .../module/wizard/wizard_module_upgrade.py | 186 +- .../module/wizard/wizard_update_module.py | 118 +- bin/addons/base/res/bank.py | 44 +- bin/addons/base/res/country.py | 122 +- bin/addons/base/res/ir_property.py | 82 +- bin/addons/base/res/partner/crm.py | 102 +- bin/addons/base/res/partner/partner.py | 690 +-- .../res/partner/wizard/wizard_clear_ids.py | 22 +- .../res/partner/wizard/wizard_ean_check.py | 106 +- .../base/res/partner/wizard/wizard_sms.py | 62 +- .../base/res/partner/wizard/wizard_spam.py | 64 +- bin/addons/base/res/res_company.py | 256 +- bin/addons/base/res/res_currency.py | 160 +- bin/addons/base/res/res_lang.py | 26 +- bin/addons/base/res/res_request.py | 158 +- bin/addons/base/res/res_user.py | 402 +- bin/addons/module_graph.py | 18 +- bin/ir/ir.py | 14 +- bin/netsvc.py | 576 +- bin/osv/fields.py | 1020 ++-- bin/osv/orm.py | 4900 ++++++++--------- bin/osv/osv.py | 510 +- bin/pooler.py | 96 +- bin/report/common.py | 4 +- bin/report/custom.py | 1104 ++-- bin/report/int_to_text.py | 64 +- bin/report/interface.py | 314 +- bin/report/misc.py | 14 +- bin/report/print_fnc.py | 8 +- bin/report/print_xml.py | 570 +- bin/report/printscreen/ps_form.py | 202 +- bin/report/printscreen/ps_list.py | 270 +- bin/report/render/__init__.py | 4 +- bin/report/render/render.py | 60 +- bin/report/render/rml.py | 28 +- bin/report/render/rml2html/rml2html.py | 580 +- bin/report/render/rml2html/utils.py | 68 +- bin/report/render/rml2pdf/color.py | 20 +- bin/report/render/rml2pdf/trml2pdf.py | 1336 ++--- bin/report/render/rml2pdf/utils.py | 66 +- bin/report/render/simple.py | 90 +- bin/report/report_sxw.py | 1066 ++-- bin/service/security.py | 72 +- bin/service/web_services.py | 778 +-- bin/sql_db.py | 188 +- bin/tiny_socket.py | 112 +- bin/tinyerp-server.py | 190 +- bin/tools/amount_to_text.py | 250 +- bin/tools/config.py | 362 +- bin/tools/convert.py | 1308 ++--- bin/tools/graph.py | 556 +- bin/tools/import_email.py | 212 +- bin/tools/misc.py | 842 +-- bin/tools/translate.py | 836 +-- bin/tools/upgrade.py | 90 +- bin/wizard/__init__.py | 248 +- bin/workflow/common.py | 6 +- bin/workflow/instance.py | 84 +- bin/workflow/wkf_expr.py | 116 +- bin/workflow/wkf_logs.py | 4 +- bin/workflow/wkf_service.py | 134 +- bin/workflow/workitem.py | 272 +- doc/migrate/3.3.0-3.4.0/post.py | 46 +- doc/migrate/3.3.0-3.4.0/pre.py | 62 +- doc/migrate/3.4.0-4.0.0/post-tiny.py | 18 +- doc/migrate/3.4.0-4.0.0/post.py | 28 +- doc/migrate/3.4.0-4.0.0/pre-tiny.py | 56 +- doc/migrate/3.4.0-4.0.0/pre.py | 66 +- doc/migrate/4.0.0-4.2.0/pre.py | 128 +- doc/migrate/4.0.0-4.2.0/tiny/pre-tiny.py | 94 +- doc/migrate/4.2.0-4.4.0/pre.py | 36 +- doc/tests/check_profile_l10n_all.py | 114 +- setup.py | 0 win32/TinyERPServerService.py | 28 +- 104 files changed, 15820 insertions(+), 15820 deletions(-) mode change 100755 => 100644 bin/addons/base/ir/workflow/pydot/__init__.py mode change 100755 => 100644 bin/addons/base/ir/workflow/pydot/dot_parser.py mode change 100755 => 100644 bin/addons/base/ir/workflow/pydot/pydot.py mode change 100755 => 100644 bin/addons/base/ir/workflow/pydot/setup.py mode change 100755 => 100644 bin/report/render/rml2html/rml2html.py mode change 100755 => 100644 bin/report/render/rml2pdf/trml2pdf.py mode change 100755 => 100644 bin/tinyerp-server.py mode change 100755 => 100644 doc/tests/check_profile_l10n_all.py mode change 100755 => 100644 setup.py diff --git a/bin/addons/__init__.py b/bin/addons/__init__.py index cefd6859e6c..a28c87d1c34 100644 --- a/bin/addons/__init__.py +++ b/bin/addons/__init__.py @@ -45,310 +45,310 @@ logger = netsvc.Logger() opj = os.path.join -_ad = os.path.abspath(opj(tools.config['root_path'], 'addons')) # default addons path (base) -ad = os.path.abspath(tools.config['addons_path']) # alternate addons path +_ad = os.path.abspath(opj(tools.config['root_path'], 'addons')) # default addons path (base) +ad = os.path.abspath(tools.config['addons_path']) # alternate addons path sys.path.insert(1, _ad) if ad != _ad: - sys.path.insert(1, ad) + sys.path.insert(1, ad) class Graph(dict): - def addNode(self, name, deps): - max_depth, father = 0, None - for n in [Node(x, self) for x in deps]: - if n.depth >= max_depth: - father = n - max_depth = n.depth - if father: - father.addChild(name) - else: - Node(name, self) + def addNode(self, name, deps): + max_depth, father = 0, None + for n in [Node(x, self) for x in deps]: + if n.depth >= max_depth: + father = n + max_depth = n.depth + if father: + father.addChild(name) + else: + Node(name, self) - def __iter__(self): - level = 0 - done = Set(self.keys()) - while done: - level_modules = [(name, module) for name, module in self.items() if module.depth==level] - for name, module in level_modules: - done.remove(name) - yield module - level += 1 + def __iter__(self): + level = 0 + done = Set(self.keys()) + while done: + level_modules = [(name, module) for name, module in self.items() if module.depth==level] + for name, module in level_modules: + done.remove(name) + yield module + level += 1 class Singleton(object): - def __new__(cls, name, graph): - if name in graph: - inst = graph[name] - else: - inst = object.__new__(cls) - inst.name = name - graph[name] = inst - return inst + def __new__(cls, name, graph): + if name in graph: + inst = graph[name] + else: + inst = object.__new__(cls) + inst.name = name + graph[name] = inst + return inst class Node(Singleton): - def __init__(self, name, graph): - self.graph = graph - if not hasattr(self, 'childs'): - self.childs = [] - if not hasattr(self, 'depth'): - self.depth = 0 + def __init__(self, name, graph): + self.graph = graph + if not hasattr(self, 'childs'): + self.childs = [] + if not hasattr(self, 'depth'): + self.depth = 0 - def addChild(self, name): - node = Node(name, self.graph) - node.depth = self.depth + 1 - if node not in self.childs: - self.childs.append(node) - for attr in ('init', 'update', 'demo'): - if hasattr(self, attr): - setattr(node, attr, True) - self.childs.sort(lambda x,y: cmp(x.name, y.name)) + def addChild(self, name): + node = Node(name, self.graph) + node.depth = self.depth + 1 + if node not in self.childs: + self.childs.append(node) + for attr in ('init', 'update', 'demo'): + if hasattr(self, attr): + setattr(node, attr, True) + self.childs.sort(lambda x,y: cmp(x.name, y.name)) - def hasChild(self, name): - return Node(name, self.graph) in self.childs or \ - bool([c for c in self.childs if c.hasChild(name)]) + def hasChild(self, name): + return Node(name, self.graph) in self.childs or \ + bool([c for c in self.childs if c.hasChild(name)]) - def __setattr__(self, name, value): - super(Singleton, self).__setattr__(name, value) - if name in ('init', 'update', 'demo'): - tools.config[name][self.name] = 1 - for child in self.childs: - setattr(child, name, value) - if name == 'depth': - for child in self.childs: - setattr(child, name, value + 1) + def __setattr__(self, name, value): + super(Singleton, self).__setattr__(name, value) + if name in ('init', 'update', 'demo'): + tools.config[name][self.name] = 1 + for child in self.childs: + setattr(child, name, value) + if name == 'depth': + for child in self.childs: + setattr(child, name, value + 1) - def __iter__(self): - return itertools.chain(iter(self.childs), *map(iter, self.childs)) + def __iter__(self): + return itertools.chain(iter(self.childs), *map(iter, self.childs)) - def __str__(self): - return self._pprint() + def __str__(self): + return self._pprint() - def _pprint(self, depth=0): - s = '%s\n' % self.name - for c in self.childs: - s += '%s`-> %s' % (' ' * depth, c._pprint(depth+1)) - return s + def _pprint(self, depth=0): + s = '%s\n' % self.name + for c in self.childs: + s += '%s`-> %s' % (' ' * depth, c._pprint(depth+1)) + return s def get_module_path(module): - """Return the path of the given module. - """ + """Return the path of the given module. + """ - if os.path.exists(opj(ad, module)) or os.path.exists(opj(ad, '%s.zip' % module)): - return opj(ad, module) + if os.path.exists(opj(ad, module)) or os.path.exists(opj(ad, '%s.zip' % module)): + return opj(ad, module) - if os.path.exists(opj(_ad, module)) or os.path.exists(opj(_ad, '%s.zip' % module)): - return opj(_ad, module) + if os.path.exists(opj(_ad, module)) or os.path.exists(opj(_ad, '%s.zip' % module)): + return opj(_ad, module) - raise IOError, 'Module not found : %s' % module + raise IOError, 'Module not found : %s' % module def get_module_resource(module, *args): - """Return the full path of a resource of the given module. + """Return the full path of a resource of the given module. - @param module: the module - @param args: the resource path components + @param module: the module + @param args: the resource path components - @return: absolute path to the resource - """ - return opj(get_module_path(module), *args) + @return: absolute path to the resource + """ + return opj(get_module_path(module), *args) def get_modules(): - """Returns the list of module names - """ + """Returns the list of module names + """ - module_list = os.listdir(ad) - module_names = [os.path.basename(m) for m in module_list] - module_list += [m for m in os.listdir(_ad) if m not in module_names] + module_list = os.listdir(ad) + module_names = [os.path.basename(m) for m in module_list] + module_list += [m for m in os.listdir(_ad) if m not in module_names] - return module_list + return module_list def create_graph(module_list, force=None): - if not force: - force=[] - graph = Graph() - packages = [] + if not force: + force=[] + graph = Graph() + packages = [] - for module in module_list: - if module[-4:]=='.zip': - module = module[:-4] - mod_path = get_module_path(module) - terp_file = get_module_resource(module, '__terp__.py') - if os.path.isfile(terp_file) or zipfile.is_zipfile(mod_path): - try: - info = eval(tools.file_open(terp_file).read()) - except: - logger.notifyChannel('init', netsvc.LOG_ERROR, 'addon:%s:eval file %s' % (module, terp_file)) - raise - if info.get('installable', True): - packages.append((module, info.get('depends', []), info)) + for module in module_list: + if module[-4:]=='.zip': + module = module[:-4] + mod_path = get_module_path(module) + terp_file = get_module_resource(module, '__terp__.py') + if os.path.isfile(terp_file) or zipfile.is_zipfile(mod_path): + try: + info = eval(tools.file_open(terp_file).read()) + except: + logger.notifyChannel('init', netsvc.LOG_ERROR, 'addon:%s:eval file %s' % (module, terp_file)) + raise + if info.get('installable', True): + packages.append((module, info.get('depends', []), info)) - current,later = Set([p for p, dep, data in packages]), Set() - while packages and current > later: - package, deps, datas = packages[0] + current,later = Set([p for p, dep, data in packages]), Set() + while packages and current > later: + package, deps, datas = packages[0] - # if all dependencies of 'package' are already in the graph, add 'package' in the graph - if reduce(lambda x,y: x and y in graph, deps, True): - if not package in current: - packages.pop(0) - continue - later.clear() - current.remove(package) - graph.addNode(package, deps) - node = Node(package, graph) - node.datas = datas - for kind in ('init', 'demo', 'update'): - if package in tools.config[kind] or 'all' in tools.config[kind] or kind in force: - setattr(node, kind, True) - else: - later.add(package) - packages.append((package, deps, datas)) - packages.pop(0) - - for package in later: - logger.notifyChannel('init', netsvc.LOG_ERROR, 'addon:%s:Unmet dependency' % package) + # if all dependencies of 'package' are already in the graph, add 'package' in the graph + if reduce(lambda x,y: x and y in graph, deps, True): + if not package in current: + packages.pop(0) + continue + later.clear() + current.remove(package) + graph.addNode(package, deps) + node = Node(package, graph) + node.datas = datas + for kind in ('init', 'demo', 'update'): + if package in tools.config[kind] or 'all' in tools.config[kind] or kind in force: + setattr(node, kind, True) + else: + later.add(package) + packages.append((package, deps, datas)) + packages.pop(0) + + for package in later: + logger.notifyChannel('init', netsvc.LOG_ERROR, 'addon:%s:Unmet dependency' % package) - return graph + return graph def init_module_objects(cr, module_name, obj_list): - pool = pooler.get_pool(cr.dbname) - logger.notifyChannel('init', netsvc.LOG_INFO, 'addon:%s:creating or updating database tables' % module_name) - for obj in obj_list: - if hasattr(obj, 'init'): - obj.init(cr) - obj._auto_init(cr, {'module': module_name}) - cr.commit() + pool = pooler.get_pool(cr.dbname) + logger.notifyChannel('init', netsvc.LOG_INFO, 'addon:%s:creating or updating database tables' % module_name) + for obj in obj_list: + if hasattr(obj, 'init'): + obj.init(cr) + obj._auto_init(cr, {'module': module_name}) + cr.commit() def load_module_graph(cr, graph, status=None, **kwargs): - # **kwargs is passed directly to convert_xml_import - if not status: - status={} + # **kwargs is passed directly to convert_xml_import + if not status: + status={} - status = status.copy() - package_todo = [] - statusi = 0 - for package in graph: - status['progress'] = (float(statusi)+0.1)/len(graph) - m = package.name - logger.notifyChannel('init', netsvc.LOG_INFO, 'addon:%s' % m) - sys.stdout.flush() - pool = pooler.get_pool(cr.dbname) - modules = pool.instanciate(m, cr) - cr.execute('select state, demo from ir_module_module where name=%s', (m,)) - (package_state, package_demo) = (cr.rowcount and cr.fetchone()) or ('uninstalled', False) - idref = {} - status['progress'] = (float(statusi)+0.4)/len(graph) - if hasattr(package, 'init') or hasattr(package, 'update') or package_state in ('to install', 'to upgrade'): - init_module_objects(cr, m, modules) - for kind in ('init', 'update'): - for filename in package.datas.get('%s_xml' % kind, []): - mode = 'update' - if hasattr(package, 'init') or package_state=='to install': - mode = 'init' - logger.notifyChannel('init', netsvc.LOG_INFO, 'addon:%s:loading %s' % (m, filename)) - name, ext = os.path.splitext(filename) - if ext == '.csv': - tools.convert_csv_import(cr, m, os.path.basename(filename), tools.file_open(opj(m, filename)).read(), idref, mode=mode) - elif ext == '.sql': - queries = tools.file_open(opj(m, filename)).read().split(';') - for query in queries: - new_query = ' '.join(query.split()) - if new_query: - cr.execute(new_query) - else: - tools.convert_xml_import(cr, m, tools.file_open(opj(m, filename)), idref, mode=mode, **kwargs) - if hasattr(package, 'demo') or (package_demo and package_state != 'installed'): - status['progress'] = (float(statusi)+0.75)/len(graph) - for xml in package.datas.get('demo_xml', []): - name, ext = os.path.splitext(xml) - logger.notifyChannel('init', netsvc.LOG_INFO, 'addon:%s:loading %s' % (m, xml)) - if ext == '.csv': - tools.convert_csv_import(cr, m, os.path.basename(xml), tools.file_open(opj(m, xml)).read(), idref, noupdate=True) - else: - tools.convert_xml_import(cr, m, tools.file_open(opj(m, xml)), idref, noupdate=True, **kwargs) - cr.execute('update ir_module_module set demo=%s where name=%s', (True, package.name)) - package_todo.append(package.name) - cr.execute("update ir_module_module set state='installed' where state in ('to upgrade', 'to install') and name=%s", (package.name,)) - cr.commit() - statusi+=1 + status = status.copy() + package_todo = [] + statusi = 0 + for package in graph: + status['progress'] = (float(statusi)+0.1)/len(graph) + m = package.name + logger.notifyChannel('init', netsvc.LOG_INFO, 'addon:%s' % m) + sys.stdout.flush() + pool = pooler.get_pool(cr.dbname) + modules = pool.instanciate(m, cr) + cr.execute('select state, demo from ir_module_module where name=%s', (m,)) + (package_state, package_demo) = (cr.rowcount and cr.fetchone()) or ('uninstalled', False) + idref = {} + status['progress'] = (float(statusi)+0.4)/len(graph) + if hasattr(package, 'init') or hasattr(package, 'update') or package_state in ('to install', 'to upgrade'): + init_module_objects(cr, m, modules) + for kind in ('init', 'update'): + for filename in package.datas.get('%s_xml' % kind, []): + mode = 'update' + if hasattr(package, 'init') or package_state=='to install': + mode = 'init' + logger.notifyChannel('init', netsvc.LOG_INFO, 'addon:%s:loading %s' % (m, filename)) + name, ext = os.path.splitext(filename) + if ext == '.csv': + tools.convert_csv_import(cr, m, os.path.basename(filename), tools.file_open(opj(m, filename)).read(), idref, mode=mode) + elif ext == '.sql': + queries = tools.file_open(opj(m, filename)).read().split(';') + for query in queries: + new_query = ' '.join(query.split()) + if new_query: + cr.execute(new_query) + else: + tools.convert_xml_import(cr, m, tools.file_open(opj(m, filename)), idref, mode=mode, **kwargs) + if hasattr(package, 'demo') or (package_demo and package_state != 'installed'): + status['progress'] = (float(statusi)+0.75)/len(graph) + for xml in package.datas.get('demo_xml', []): + name, ext = os.path.splitext(xml) + logger.notifyChannel('init', netsvc.LOG_INFO, 'addon:%s:loading %s' % (m, xml)) + if ext == '.csv': + tools.convert_csv_import(cr, m, os.path.basename(xml), tools.file_open(opj(m, xml)).read(), idref, noupdate=True) + else: + tools.convert_xml_import(cr, m, tools.file_open(opj(m, xml)), idref, noupdate=True, **kwargs) + cr.execute('update ir_module_module set demo=%s where name=%s', (True, package.name)) + package_todo.append(package.name) + cr.execute("update ir_module_module set state='installed' where state in ('to upgrade', 'to install') and name=%s", (package.name,)) + cr.commit() + statusi+=1 - pool = pooler.get_pool(cr.dbname) - cr.execute('select * from ir_model where state=%s', ('manual',)) - for model in cr.dictfetchall(): - pool.get('ir.model').instanciate(cr, 1, model['model'], {}) + pool = pooler.get_pool(cr.dbname) + cr.execute('select * from ir_model where state=%s', ('manual',)) + for model in cr.dictfetchall(): + pool.get('ir.model').instanciate(cr, 1, model['model'], {}) - pool.get('ir.model.data')._process_end(cr, 1, package_todo) - cr.commit() + pool.get('ir.model.data')._process_end(cr, 1, package_todo) + cr.commit() def register_classes(): - module_list = get_modules() - for package in create_graph(module_list): - m = package.name - logger.notifyChannel('init', netsvc.LOG_INFO, 'addon:%s:registering classes' % m) - sys.stdout.flush() + module_list = get_modules() + for package in create_graph(module_list): + m = package.name + logger.notifyChannel('init', netsvc.LOG_INFO, 'addon:%s:registering classes' % m) + sys.stdout.flush() - mod_path = get_module_path(m) - if not os.path.isfile(mod_path+'.zip'): - # XXX must restrict to only addons paths - imp.load_module(m, *imp.find_module(m)) - else: - import zipimport - try: - zimp = zipimport.zipimporter(mod_path+'.zip') - zimp.load_module(m) - except zipimport.ZipImportError: - logger.notifyChannel('init', netsvc.LOG_ERROR, 'Couldn\'t find module %s' % m) + mod_path = get_module_path(m) + if not os.path.isfile(mod_path+'.zip'): + # XXX must restrict to only addons paths + imp.load_module(m, *imp.find_module(m)) + else: + import zipimport + try: + zimp = zipimport.zipimporter(mod_path+'.zip') + zimp.load_module(m) + except zipimport.ZipImportError: + logger.notifyChannel('init', netsvc.LOG_ERROR, 'Couldn\'t find module %s' % m) def load_modules(db, force_demo=False, status=None, update_module=False): - if not status: - status={} - cr = db.cursor() - force = [] - if force_demo: - force.append('demo') - if update_module: - cr.execute("select name from ir_module_module where state in ('installed', 'to install', 'to upgrade','to remove')") - else: - cr.execute("select name from ir_module_module where state in ('installed', 'to upgrade', 'to remove')") - module_list = [name for (name,) in cr.fetchall()] - graph = create_graph(module_list, force) - report = tools.assertion_report() - load_module_graph(cr, graph, status, report=report) - if report.get_report(): - logger.notifyChannel('init', netsvc.LOG_INFO, 'assert:%s' % report) + if not status: + status={} + cr = db.cursor() + force = [] + if force_demo: + force.append('demo') + if update_module: + cr.execute("select name from ir_module_module where state in ('installed', 'to install', 'to upgrade','to remove')") + else: + cr.execute("select name from ir_module_module where state in ('installed', 'to upgrade', 'to remove')") + module_list = [name for (name,) in cr.fetchall()] + graph = create_graph(module_list, force) + report = tools.assertion_report() + load_module_graph(cr, graph, status, report=report) + if report.get_report(): + logger.notifyChannel('init', netsvc.LOG_INFO, 'assert:%s' % report) - for kind in ('init', 'demo', 'update'): - tools.config[kind]={} + for kind in ('init', 'demo', 'update'): + tools.config[kind]={} - cr.commit() - if update_module: - cr.execute("select id,name from ir_module_module where state in ('to remove')") - for mod_id, mod_name in cr.fetchall(): - pool = pooler.get_pool(cr.dbname) - cr.execute('select model,res_id from ir_model_data where not noupdate and module=%s order by id desc', (mod_name,)) - for rmod,rid in cr.fetchall(): - # - # TO BE Improved: - # I can not use the class_pool has _table could be defined in __init__ - # and I can not use the pool has the module could not be loaded in the pool - # - uid = 1 - pool.get(rmod).unlink(cr, uid, [rid]) - cr.commit() - # - # TODO: remove menu without actions of childs - # - cr.execute('''delete from - ir_ui_menu - where - (id not in (select parent_id from ir_ui_menu where parent_id is not null)) - and - (id not in (select res_id from ir_values where model='ir.ui.menu')) - and - (id not in (select res_id from ir_model_data where model='ir.ui.menu'))''') + cr.commit() + if update_module: + cr.execute("select id,name from ir_module_module where state in ('to remove')") + for mod_id, mod_name in cr.fetchall(): + pool = pooler.get_pool(cr.dbname) + cr.execute('select model,res_id from ir_model_data where not noupdate and module=%s order by id desc', (mod_name,)) + for rmod,rid in cr.fetchall(): + # + # TO BE Improved: + # I can not use the class_pool has _table could be defined in __init__ + # and I can not use the pool has the module could not be loaded in the pool + # + uid = 1 + pool.get(rmod).unlink(cr, uid, [rid]) + cr.commit() + # + # TODO: remove menu without actions of childs + # + cr.execute('''delete from + ir_ui_menu + where + (id not in (select parent_id from ir_ui_menu where parent_id is not null)) + and + (id not in (select res_id from ir_values where model='ir.ui.menu')) + and + (id not in (select res_id from ir_model_data where model='ir.ui.menu'))''') - cr.execute("update ir_module_module set state=%s where state in ('to remove')", ('uninstalled', )) - cr.commit() - pooler.restart_pool(cr.dbname) - cr.close() + cr.execute("update ir_module_module set state=%s where state in ('to remove')", ('uninstalled', )) + cr.commit() + pooler.restart_pool(cr.dbname) + cr.close() diff --git a/bin/addons/base/__terp__.py b/bin/addons/base/__terp__.py index 0de434c7e31..8903596f5db 100644 --- a/bin/addons/base/__terp__.py +++ b/bin/addons/base/__terp__.py @@ -26,44 +26,44 @@ # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ############################################################################### { - "name" : "Base", - "version" : "1.0", - "author" : "Tiny", - "website" : "http://tinyerp.com", - "category" : "Generic Modules/Base", - "description": "The kernel of Tiny ERP, needed for all installation.", - "depends" : [], - "init_xml" : [ - "base_data.xml", - "base_menu.xml", - ], - "demo_xml" : [ - "base_demo.xml", - "res/partner/partner_demo.xml", - "res/partner/crm_demo.xml", - ], - "update_xml" : [ - "base_update.xml", - "ir/wizard/wizard_menu_view.xml", - "ir/ir.xml", - "ir/workflow/workflow_view.xml", - "module/module_data.xml", - "module/module_wizard.xml", - "module/module_view.xml", - "module/module_report.xml", - "res/res_request_view.xml", - "res/res_lang_view.xml", - "res/partner/partner_report.xml", - "res/partner/partner_view.xml", - "res/partner/partner_wizard.xml", - "res/bank_view.xml", - "res/country_view.xml", - "res/res_currency_view.xml", - "res/partner/crm_view.xml", - "res/partner/partner_data.xml", - "res/ir_property_view.xml", - "base_security.xml", - ], - "active": True, - "installable": True, + "name" : "Base", + "version" : "1.0", + "author" : "Tiny", + "website" : "http://tinyerp.com", + "category" : "Generic Modules/Base", + "description": "The kernel of Tiny ERP, needed for all installation.", + "depends" : [], + "init_xml" : [ + "base_data.xml", + "base_menu.xml", + ], + "demo_xml" : [ + "base_demo.xml", + "res/partner/partner_demo.xml", + "res/partner/crm_demo.xml", + ], + "update_xml" : [ + "base_update.xml", + "ir/wizard/wizard_menu_view.xml", + "ir/ir.xml", + "ir/workflow/workflow_view.xml", + "module/module_data.xml", + "module/module_wizard.xml", + "module/module_view.xml", + "module/module_report.xml", + "res/res_request_view.xml", + "res/res_lang_view.xml", + "res/partner/partner_report.xml", + "res/partner/partner_view.xml", + "res/partner/partner_wizard.xml", + "res/bank_view.xml", + "res/country_view.xml", + "res/res_currency_view.xml", + "res/partner/crm_view.xml", + "res/partner/partner_data.xml", + "res/ir_property_view.xml", + "base_security.xml", + ], + "active": True, + "installable": True, } diff --git a/bin/addons/base/ir/ir_actions.py b/bin/addons/base/ir/ir_actions.py index a4a7ae71d1c..9e5f6435408 100644 --- a/bin/addons/base/ir/ir_actions.py +++ b/bin/addons/base/ir/ir_actions.py @@ -32,263 +32,263 @@ import tools import time class actions(osv.osv): - _name = 'ir.actions.actions' - _table = 'ir_actions' - _columns = { - 'name': fields.char('Action Name', required=True, size=64), - 'type': fields.char('Action Type', required=True, size=32), - 'usage': fields.char('Action Usage', size=32), - 'parent_id': fields.many2one('ir.actions.server', 'Parent Action'), - } - _defaults = { - 'usage': lambda *a: False, - } + _name = 'ir.actions.actions' + _table = 'ir_actions' + _columns = { + 'name': fields.char('Action Name', required=True, size=64), + 'type': fields.char('Action Type', required=True, size=32), + 'usage': fields.char('Action Usage', size=32), + 'parent_id': fields.many2one('ir.actions.server', 'Parent Action'), + } + _defaults = { + 'usage': lambda *a: False, + } actions() class report_custom(osv.osv): - _name = 'ir.actions.report.custom' - _table = 'ir_act_report_custom' - _sequence = 'ir_actions_id_seq' - _columns = { - 'name': fields.char('Report Name', size=64, required=True, translate=True), - 'type': fields.char('Report Type', size=32, required=True), - 'model':fields.char('Model', size=64, required=True), - 'report_id': fields.integer('Report Ref.', required=True), - 'usage': fields.char('Action Usage', size=32), - '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.") - } - _defaults = { - 'multi': lambda *a: False, - 'type': lambda *a: 'ir.actions.report.custom', - } + _name = 'ir.actions.report.custom' + _table = 'ir_act_report_custom' + _sequence = 'ir_actions_id_seq' + _columns = { + 'name': fields.char('Report Name', size=64, required=True, translate=True), + 'type': fields.char('Report Type', size=32, required=True), + 'model':fields.char('Model', size=64, required=True), + 'report_id': fields.integer('Report Ref.', required=True), + 'usage': fields.char('Action Usage', size=32), + '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.") + } + _defaults = { + 'multi': lambda *a: False, + 'type': lambda *a: 'ir.actions.report.custom', + } report_custom() class report_xml(osv.osv): - def _report_content(self, cursor, user, ids, name, arg, context=None): - res = {} - for report in self.browse(cursor, user, ids, context=context): - data = report[name + '_data'] - if not data and report[name[:-8]]: - try: - fp = tools.file_open(report[name[:-8]], mode='rb') - data = fp.read() - except: - data = False - res[report.id] = data - return res + def _report_content(self, cursor, user, ids, name, arg, context=None): + res = {} + for report in self.browse(cursor, user, ids, context=context): + data = report[name + '_data'] + if not data and report[name[:-8]]: + try: + fp = tools.file_open(report[name[:-8]], mode='rb') + data = fp.read() + except: + data = False + res[report.id] = data + return res - def _report_content_inv(self, cursor, user, id, name, value, arg, context=None): - self.write(cursor, user, id, {name+'_data': value}, context=context) + def _report_content_inv(self, cursor, user, id, name, value, arg, context=None): + self.write(cursor, user, id, {name+'_data': value}, context=context) - def _report_sxw(self, cursor, user, ids, name, arg, context=None): - res = {} - for report in self.browse(cursor, user, ids, context=context): - if report.report_rml: - res[report.id] = report.report_rml.replace('.rml', '.sxw') - else: - res[report.id] = False - return res + def _report_sxw(self, cursor, user, ids, name, arg, context=None): + res = {} + for report in self.browse(cursor, user, ids, context=context): + if report.report_rml: + res[report.id] = report.report_rml.replace('.rml', '.sxw') + else: + res[report.id] = False + return res - _name = 'ir.actions.report.xml' - _table = 'ir_act_report_xml' - _sequence = 'ir_actions_id_seq' - _columns = { - 'name': fields.char('Name', size=64, required=True, translate=True), - 'type': fields.char('Report Type', size=32, required=True), - 'model': fields.char('Model', size=64, required=True), - 'report_name': fields.char('Internal Name', size=64, required=True), - 'report_xsl': fields.char('XSL path', size=256), - 'report_xml': fields.char('XML path', size=256), - 'report_rml': fields.char('RML path', size=256, - help="The .rml path of the file or NULL if the content is in report_rml_content"), - 'report_sxw': fields.function(_report_sxw, method=True, type='char', - string='SXW path'), - 'report_sxw_content_data': fields.binary('SXW content'), - 'report_rml_content_data': fields.binary('RML content'), - 'report_sxw_content': fields.function(_report_content, - fnct_inv=_report_content_inv, method=True, - type='binary', string='SXW content',), - 'report_rml_content': fields.function(_report_content, - fnct_inv=_report_content_inv, method=True, - type='binary', string='RML content'), - 'auto': fields.boolean('Automatic XSL:RML', required=True), - 'usage': fields.char('Action Usage', size=32), - 'header': fields.boolean('Add RML header', - help="Add or not the coporate RML header"), - '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."), - 'report_type': fields.selection([ - ('pdf', 'pdf'), - ('html', 'html'), - ('raw', 'raw'), - ('sxw', 'sxw'), - ], string='Type', required=True), - 'groups_id': fields.many2many('res.groups', 'res_groups_report_rel', 'uid', 'gid', 'Groups') - - } - _defaults = { - 'type': lambda *a: 'ir.actions.report.xml', - 'multi': lambda *a: False, - 'auto': lambda *a: True, - 'header': lambda *a: True, - 'report_sxw_content': lambda *a: False, - 'report_type': lambda *a: 'pdf', - } + _name = 'ir.actions.report.xml' + _table = 'ir_act_report_xml' + _sequence = 'ir_actions_id_seq' + _columns = { + 'name': fields.char('Name', size=64, required=True, translate=True), + 'type': fields.char('Report Type', size=32, required=True), + 'model': fields.char('Model', size=64, required=True), + 'report_name': fields.char('Internal Name', size=64, required=True), + 'report_xsl': fields.char('XSL path', size=256), + 'report_xml': fields.char('XML path', size=256), + 'report_rml': fields.char('RML path', size=256, + help="The .rml path of the file or NULL if the content is in report_rml_content"), + 'report_sxw': fields.function(_report_sxw, method=True, type='char', + string='SXW path'), + 'report_sxw_content_data': fields.binary('SXW content'), + 'report_rml_content_data': fields.binary('RML content'), + 'report_sxw_content': fields.function(_report_content, + fnct_inv=_report_content_inv, method=True, + type='binary', string='SXW content',), + 'report_rml_content': fields.function(_report_content, + fnct_inv=_report_content_inv, method=True, + type='binary', string='RML content'), + 'auto': fields.boolean('Automatic XSL:RML', required=True), + 'usage': fields.char('Action Usage', size=32), + 'header': fields.boolean('Add RML header', + help="Add or not the coporate RML header"), + '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."), + 'report_type': fields.selection([ + ('pdf', 'pdf'), + ('html', 'html'), + ('raw', 'raw'), + ('sxw', 'sxw'), + ], string='Type', required=True), + 'groups_id': fields.many2many('res.groups', 'res_groups_report_rel', 'uid', 'gid', 'Groups') + + } + _defaults = { + 'type': lambda *a: 'ir.actions.report.xml', + 'multi': lambda *a: False, + 'auto': lambda *a: True, + 'header': lambda *a: True, + 'report_sxw_content': lambda *a: False, + 'report_type': lambda *a: 'pdf', + } report_xml() class act_window(osv.osv): - _name = 'ir.actions.act_window' - _table = 'ir_act_window' - _sequence = 'ir_actions_id_seq' + _name = 'ir.actions.act_window' + _table = 'ir_act_window' + _sequence = 'ir_actions_id_seq' - def _views_get_fnc(self, cr, uid, ids, name, arg, context={}): - res={} - for act in self.browse(cr, uid, ids): - res[act.id]=[(view.view_id.id, view.view_mode) for view in act.view_ids] - if (not act.view_ids): - modes = act.view_mode.split(',') - find = False - if act.view_id.id: - res[act.id].append((act.view_id.id, act.view_id.type)) - for t in modes: - if act.view_id and (t == act.view_id.type) and not find: - find = True - continue - res[act.id].append((False, t)) + def _views_get_fnc(self, cr, uid, ids, name, arg, context={}): + res={} + for act in self.browse(cr, uid, ids): + res[act.id]=[(view.view_id.id, view.view_mode) for view in act.view_ids] + if (not act.view_ids): + modes = act.view_mode.split(',') + find = False + if act.view_id.id: + res[act.id].append((act.view_id.id, act.view_id.type)) + for t in modes: + if act.view_id and (t == act.view_id.type) and not find: + find = True + continue + res[act.id].append((False, t)) - if 'calendar' not in modes: - mobj = self.pool.get(act.res_model) - if mobj._date_name in mobj._columns: - res[act.id].append((False, 'calendar')) - return res + if 'calendar' not in modes: + mobj = self.pool.get(act.res_model) + if mobj._date_name in mobj._columns: + res[act.id].append((False, 'calendar')) + return res - _columns = { - 'name': fields.char('Action Name', size=64, translate=True), - 'type': fields.char('Action Type', size=32, required=True), - 'view_id': fields.many2one('ir.ui.view', 'View Ref.', ondelete='cascade'), - 'domain': fields.char('Domain Value', size=250), - 'context': fields.char('Context Value', size=250), - 'res_model': fields.char('Model', size=64), - 'src_model': fields.char('Source model', size=64), - 'target': fields.selection([('current','Current Window'),('new','New Window')], 'Target Window'), - 'view_type': fields.selection((('tree','Tree'),('form','Form')),string='Type of view'), - 'view_mode': fields.char('Mode of view', size=250), - 'usage': fields.char('Action Usage', size=32), - 'view_ids': fields.one2many('ir.actions.act_window.view', 'act_window_id', 'Views'), - 'views': fields.function(_views_get_fnc, method=True, type='binary', string='Views'), - 'limit': fields.integer('Limit', help='Default limit for the list view'), - 'auto_refresh': fields.integer('Auto-Refresh', - help='Add an auto-refresh on the view'), - } - _defaults = { - 'type': lambda *a: 'ir.actions.act_window', - 'view_type': lambda *a: 'form', - 'view_mode': lambda *a: 'tree,form', - 'context': lambda *a: '{}', - 'limit': lambda *a: 80, - 'target': lambda *a: 'current', - 'auto_refresh': lambda *a: 0, - } + _columns = { + 'name': fields.char('Action Name', size=64, translate=True), + 'type': fields.char('Action Type', size=32, required=True), + 'view_id': fields.many2one('ir.ui.view', 'View Ref.', ondelete='cascade'), + 'domain': fields.char('Domain Value', size=250), + 'context': fields.char('Context Value', size=250), + 'res_model': fields.char('Model', size=64), + 'src_model': fields.char('Source model', size=64), + 'target': fields.selection([('current','Current Window'),('new','New Window')], 'Target Window'), + 'view_type': fields.selection((('tree','Tree'),('form','Form')),string='Type of view'), + 'view_mode': fields.char('Mode of view', size=250), + 'usage': fields.char('Action Usage', size=32), + 'view_ids': fields.one2many('ir.actions.act_window.view', 'act_window_id', 'Views'), + 'views': fields.function(_views_get_fnc, method=True, type='binary', string='Views'), + 'limit': fields.integer('Limit', help='Default limit for the list view'), + 'auto_refresh': fields.integer('Auto-Refresh', + help='Add an auto-refresh on the view'), + } + _defaults = { + 'type': lambda *a: 'ir.actions.act_window', + 'view_type': lambda *a: 'form', + 'view_mode': lambda *a: 'tree,form', + 'context': lambda *a: '{}', + 'limit': lambda *a: 80, + 'target': lambda *a: 'current', + 'auto_refresh': lambda *a: 0, + } act_window() class act_window_view(osv.osv): - _name = 'ir.actions.act_window.view' - _table = 'ir_act_window_view' - _rec_name = 'view_id' - _columns = { - 'sequence': fields.integer('Sequence'), - 'view_id': fields.many2one('ir.ui.view', 'View'), - 'view_mode': fields.selection(( - ('tree', 'Tree'), - ('form', 'Form'), - ('graph', 'Graph'), - ('calendar', 'Calendar')), 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."), - } - _defaults = { - 'multi': lambda *a: False, - } - _order = 'sequence' + _name = 'ir.actions.act_window.view' + _table = 'ir_act_window_view' + _rec_name = 'view_id' + _columns = { + 'sequence': fields.integer('Sequence'), + 'view_id': fields.many2one('ir.ui.view', 'View'), + 'view_mode': fields.selection(( + ('tree', 'Tree'), + ('form', 'Form'), + ('graph', 'Graph'), + ('calendar', 'Calendar')), 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."), + } + _defaults = { + 'multi': lambda *a: False, + } + _order = 'sequence' act_window_view() class act_wizard(osv.osv): - _name = 'ir.actions.wizard' - _table = 'ir_act_wizard' - _sequence = 'ir_actions_id_seq' - _columns = { - 'name': fields.char('Wizard info', size=64, required=True, translate=True), - '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') - } - _defaults = { - 'type': lambda *a: 'ir.actions.wizard', - 'multi': lambda *a: False, - } + _name = 'ir.actions.wizard' + _table = 'ir_act_wizard' + _sequence = 'ir_actions_id_seq' + _columns = { + 'name': fields.char('Wizard info', size=64, required=True, translate=True), + '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') + } + _defaults = { + 'type': lambda *a: 'ir.actions.wizard', + 'multi': lambda *a: False, + } act_wizard() class act_url(osv.osv): - _name = 'ir.actions.url' - _table = 'ir_act_url' - _sequence = 'ir_actions_id_seq' - _columns = { - 'name': fields.char('Action Name', size=64, translate=True), - 'type': fields.char('Action Type', size=32, required=True), - 'url': fields.text('Action Url',required=True), - 'target': fields.selection(( - ('new', 'New Window'), - ('self', 'This Window')), - 'Action Target', required=True - ) - } - _defaults = { - 'type': lambda *a: 'ir.actions.act_url', - 'target': lambda *a: 'new' - } + _name = 'ir.actions.url' + _table = 'ir_act_url' + _sequence = 'ir_actions_id_seq' + _columns = { + 'name': fields.char('Action Name', size=64, translate=True), + 'type': fields.char('Action Type', size=32, required=True), + 'url': fields.text('Action Url',required=True), + 'target': fields.selection(( + ('new', 'New Window'), + ('self', 'This Window')), + 'Action Target', required=True + ) + } + _defaults = { + 'type': lambda *a: 'ir.actions.act_url', + 'target': lambda *a: 'new' + } act_url() # # Actions that are run on the server side # class actions_server(osv.osv): - _name = 'ir.actions.server' - _table = 'ir_act_server' - _sequence = 'ir_actions_id_seq' - _columns = { - 'name': fields.char('Action Name', required=True, size=64), - 'state': fields.selection([ - ('python','Python Code'), - ('dummy','Dummy'), - ('trigger','Trigger'), - ('email','Email'), - ('sms','SMS'), - ('object_create','Create Object'), - ('object_write','Write Object'), - ('client_action','Client Action'), - ('other','Others Actions'), - ], 'Action State', required=True, size=32), - 'code': fields.text('Python Code'), - 'sequence': fields.integer('Sequence'), - 'model_id': fields.many2one('ir.model', 'Model', required=True), - 'trigger_name': fields.char('Trigger Name', size=128), - 'trigger_object': fields.char('Trigger Object', size=128), - 'trigger_object_id': fields.char('Trigger Object ID', size=128), - 'message': fields.text('Message', translate=True), - 'address': fields.char('Email Address', size=128), - 'child_ids': fields.one2many('ir.actions.actions', 'parent_id', 'Others Actions'), - 'usage': fields.char('Action Usage', size=32), - 'type': fields.char('Report Type', size=32, required=True), - } - _defaults = { - 'state': lambda *a: 'dummy', - 'type': lambda *a: 'ir.actions.server', - 'sequence': lambda *a: 0, - 'code': lambda *a: """# You can use the following variables + _name = 'ir.actions.server' + _table = 'ir_act_server' + _sequence = 'ir_actions_id_seq' + _columns = { + 'name': fields.char('Action Name', required=True, size=64), + 'state': fields.selection([ + ('python','Python Code'), + ('dummy','Dummy'), + ('trigger','Trigger'), + ('email','Email'), + ('sms','SMS'), + ('object_create','Create Object'), + ('object_write','Write Object'), + ('client_action','Client Action'), + ('other','Others Actions'), + ], 'Action State', required=True, size=32), + 'code': fields.text('Python Code'), + 'sequence': fields.integer('Sequence'), + 'model_id': fields.many2one('ir.model', 'Model', required=True), + 'trigger_name': fields.char('Trigger Name', size=128), + 'trigger_object': fields.char('Trigger Object', size=128), + 'trigger_object_id': fields.char('Trigger Object ID', size=128), + 'message': fields.text('Message', translate=True), + 'address': fields.char('Email Address', size=128), + 'child_ids': fields.one2many('ir.actions.actions', 'parent_id', 'Others Actions'), + 'usage': fields.char('Action Usage', size=32), + 'type': fields.char('Report Type', size=32, required=True), + } + _defaults = { + 'state': lambda *a: 'dummy', + 'type': lambda *a: 'ir.actions.server', + 'sequence': lambda *a: 0, + 'code': lambda *a: """# You can use the following variables # - object # - object2 # - time @@ -297,43 +297,43 @@ class actions_server(osv.osv): # - ids # If you plan to return an action, assign: action = {...} """ - } - # - # Context should contains: - # ids : original ids - # id : current id of the object - # OUT: - # False : Finnished correctly - # ACTION_ID : Action to launch - def run(self, cr, uid, ids, context={}): - for action in self.browse(cr, uid, ids, context): - if action.state=='python': - localdict = { - 'self': self.pool.get(action.model_id.model), - 'context': context, - 'time': time, - 'ids': ids, - 'cr': cr, - 'uid': uid - } - print action.code - exec action.code in localdict - print localdict.keys() - if 'action' in localdict: - return localdict['action'] - return False + } + # + # Context should contains: + # ids : original ids + # id : current id of the object + # OUT: + # False : Finnished correctly + # ACTION_ID : Action to launch + def run(self, cr, uid, ids, context={}): + for action in self.browse(cr, uid, ids, context): + if action.state=='python': + localdict = { + 'self': self.pool.get(action.model_id.model), + 'context': context, + 'time': time, + 'ids': ids, + 'cr': cr, + 'uid': uid + } + print action.code + exec action.code in localdict + print localdict.keys() + if 'action' in localdict: + return localdict['action'] + return False actions_server() class act_window_close(osv.osv): - _name = 'ir.actions.act_window_close' - _table = 'ir_actions' - _sequence = 'ir_actions_id_seq' - _columns = { - 'name': fields.char('Action Name', size=64, translate=True), - 'type': fields.char('Action Type', size=32, required=True), - } - _defaults = { - 'type': lambda *a: 'ir.actions.act_window_close', - } + _name = 'ir.actions.act_window_close' + _table = 'ir_actions' + _sequence = 'ir_actions_id_seq' + _columns = { + 'name': fields.char('Action Name', size=64, translate=True), + 'type': fields.char('Action Type', size=32, required=True), + } + _defaults = { + 'type': lambda *a: 'ir.actions.act_window_close', + } act_window_close() diff --git a/bin/addons/base/ir/ir_attachment.py b/bin/addons/base/ir/ir_attachment.py index 4c505462473..f4e931826b1 100644 --- a/bin/addons/base/ir/ir_attachment.py +++ b/bin/addons/base/ir/ir_attachment.py @@ -30,16 +30,16 @@ from osv import fields,osv class ir_attachment(osv.osv): - _name = 'ir.attachment' - _columns = { - 'name': fields.char('Attachment Name',size=64, required=True), - 'datas': fields.binary('Data'), - 'datas_fname': fields.char('Data Filename',size=64), - 'description': fields.text('Description'), - # Not required due to the document module ! - 'res_model': fields.char('Resource Model',size=64, readonly=True), - 'res_id': fields.integer('Resource ID', readonly=True), - 'link': fields.char('Link', size=256) - } + _name = 'ir.attachment' + _columns = { + 'name': fields.char('Attachment Name',size=64, required=True), + 'datas': fields.binary('Data'), + 'datas_fname': fields.char('Data Filename',size=64), + 'description': fields.text('Description'), + # Not required due to the document module ! + 'res_model': fields.char('Resource Model',size=64, readonly=True), + 'res_id': fields.integer('Resource ID', readonly=True), + 'link': fields.char('Link', size=256) + } ir_attachment() diff --git a/bin/addons/base/ir/ir_board.py b/bin/addons/base/ir/ir_board.py index 380e7c183a6..f8bf28a4fe1 100644 --- a/bin/addons/base/ir/ir_board.py +++ b/bin/addons/base/ir/ir_board.py @@ -30,12 +30,12 @@ from osv import fields,osv class board(osv.osv): - _name = 'ir.board' - def create(self, cr, user, vals, context={}): - return False - def copy(self, cr, uid, id, default=None, context={}): - return False - _columns = { - 'name': fields.char('Board', size=64), - } + _name = 'ir.board' + def create(self, cr, user, vals, context={}): + return False + def copy(self, cr, uid, id, default=None, context={}): + return False + _columns = { + 'name': fields.char('Board', size=64), + } board() diff --git a/bin/addons/base/ir/ir_cron.py b/bin/addons/base/ir/ir_cron.py index 1f7376b8b28..d04251ae4d3 100644 --- a/bin/addons/base/ir/ir_cron.py +++ b/bin/addons/base/ir/ir_cron.py @@ -28,13 +28,13 @@ ############################################################################## # # SPEC: Execute "model.function(*eval(args))" periodically -# date : date to execute the job or NULL if directly -# delete_after: delete the ir.cron entry after execution -# interval_* : period -# max_repeat : number of execution or NULL if endlessly +# date : date to execute the job or NULL if directly +# delete_after: delete the ir.cron entry after execution +# interval_* : period +# max_repeat : number of execution or NULL if endlessly # # TODO: -# Error treatment: exception, request, ... -> send request to uid +# Error treatment: exception, request, ... -> send request to uid # from mx import DateTime @@ -47,85 +47,85 @@ from osv import fields,osv next_wait = 60 _intervalTypes = { - 'work_days': lambda interval: DateTime.RelativeDateTime(days=interval), - 'days': lambda interval: DateTime.RelativeDateTime(days=interval), - 'hours': lambda interval: DateTime.RelativeDateTime(hours=interval), - 'weeks': lambda interval: DateTime.RelativeDateTime(days=7*interval), - 'months': lambda interval: DateTime.RelativeDateTime(months=interval), - 'minutes': lambda interval: DateTime.RelativeDateTime(minutes=interval), + 'work_days': lambda interval: DateTime.RelativeDateTime(days=interval), + 'days': lambda interval: DateTime.RelativeDateTime(days=interval), + 'hours': lambda interval: DateTime.RelativeDateTime(hours=interval), + 'weeks': lambda interval: DateTime.RelativeDateTime(days=7*interval), + 'months': lambda interval: DateTime.RelativeDateTime(months=interval), + 'minutes': lambda interval: DateTime.RelativeDateTime(minutes=interval), } class ir_cron(osv.osv, netsvc.Agent): - _name = "ir.cron" - _columns = { - 'name': fields.char('Name', size=60, required=True), - 'user_id': fields.many2one('res.users', 'User', required=True), - 'active': fields.boolean('Active'), - 'interval_number': fields.integer('Interval Number'), - 'interval_type': fields.selection( [('minutes', 'Minutes'), - ('hours', 'Hours'), ('work_days','Work Days'), ('days', 'Days'),('weeks', 'Weeks'), ('months', 'Months')], 'Interval Unit'), - 'numbercall': fields.integer('Number of calls', help='Number of time the function is called,\na negative number indicates that the function will always be called'), - 'doall' : fields.boolean('Repeat missed'), - 'nextcall' : fields.datetime('Next call date', required=True), - 'model': fields.char('Model', size=64), - 'function': fields.char('Function', size=64), - 'args': fields.text('Arguments'), - 'priority': fields.integer('Priority', help='0=Very Urgent\n10=Not urgent') - } + _name = "ir.cron" + _columns = { + 'name': fields.char('Name', size=60, required=True), + 'user_id': fields.many2one('res.users', 'User', required=True), + 'active': fields.boolean('Active'), + 'interval_number': fields.integer('Interval Number'), + 'interval_type': fields.selection( [('minutes', 'Minutes'), + ('hours', 'Hours'), ('work_days','Work Days'), ('days', 'Days'),('weeks', 'Weeks'), ('months', 'Months')], 'Interval Unit'), + 'numbercall': fields.integer('Number of calls', help='Number of time the function is called,\na negative number indicates that the function will always be called'), + 'doall' : fields.boolean('Repeat missed'), + 'nextcall' : fields.datetime('Next call date', required=True), + 'model': fields.char('Model', size=64), + 'function': fields.char('Function', size=64), + 'args': fields.text('Arguments'), + 'priority': fields.integer('Priority', help='0=Very Urgent\n10=Not urgent') + } - _defaults = { - 'nextcall' : lambda *a: time.strftime('%Y-%m-%d %H:%M:%S'), - 'priority' : lambda *a: 5, - 'user_id' : lambda obj,cr,uid,context: uid, - 'interval_number' : lambda *a: 1, - 'interval_type' : lambda *a: 'months', - 'numbercall' : lambda *a: 1, - 'active' : lambda *a: 1, - 'doall' : lambda *a: 1 - } + _defaults = { + 'nextcall' : lambda *a: time.strftime('%Y-%m-%d %H:%M:%S'), + 'priority' : lambda *a: 5, + 'user_id' : lambda obj,cr,uid,context: uid, + 'interval_number' : lambda *a: 1, + 'interval_type' : lambda *a: 'months', + 'numbercall' : lambda *a: 1, + 'active' : lambda *a: 1, + 'doall' : lambda *a: 1 + } - def _callback(self, cr, uid, model, func, args): - args = (args or []) and eval(args) - m=self.pool.get(model) - if m and hasattr(m, func): - f = getattr(m, func) - f(cr, uid, *args) + def _callback(self, cr, uid, model, func, args): + args = (args or []) and eval(args) + m=self.pool.get(model) + if m and hasattr(m, func): + f = getattr(m, func) + f(cr, uid, *args) - def _poolJobs(self, db_name, check=False): - now = DateTime.now() - #FIXME: multidb. Solution: a l'instanciation d'une nouvelle connection bd (ds pooler) fo que j'instancie - # un nouveau pooljob avec comme parametre la bd - try: - cr = pooler.get_db(db_name).cursor() - except: - return False + def _poolJobs(self, db_name, check=False): + now = DateTime.now() + #FIXME: multidb. Solution: a l'instanciation d'une nouvelle connection bd (ds pooler) fo que j'instancie + # un nouveau pooljob avec comme parametre la bd + try: + cr = pooler.get_db(db_name).cursor() + except: + return False - try: - cr.execute('select * from ir_cron where numbercall<>0 and active and nextcall<=now() order by priority') - for job in cr.dictfetchall(): - nextcall = DateTime.strptime(job['nextcall'], '%Y-%m-%d %H:%M:%S') - numbercall = job['numbercall'] - - ok = False - while nextcall 0: - numbercall -= 1 - if not ok or job['doall']: - self._callback(cr, job['user_id'], job['model'], job['function'], job['args']) - if numbercall: - nextcall += _intervalTypes[job['interval_type']](job['interval_number']) - ok = True - addsql='' - if not numbercall: - addsql = ', active=False' - cr.execute("update ir_cron set nextcall=%s, numbercall=%d"+addsql+" where id=%d", (nextcall.strftime('%Y-%m-%d %H:%M:%S'), numbercall, job['id'])) - cr.commit() - finally: - cr.close() - # - # Can be improved to do at the min(min(nextcalls), time()+next_wait) - # But is this an improvement ? - # - if not check: - self.setAlarm(self._poolJobs, int(time.time())+next_wait, [db_name]) + try: + cr.execute('select * from ir_cron where numbercall<>0 and active and nextcall<=now() order by priority') + for job in cr.dictfetchall(): + nextcall = DateTime.strptime(job['nextcall'], '%Y-%m-%d %H:%M:%S') + numbercall = job['numbercall'] + + ok = False + while nextcall 0: + numbercall -= 1 + if not ok or job['doall']: + self._callback(cr, job['user_id'], job['model'], job['function'], job['args']) + if numbercall: + nextcall += _intervalTypes[job['interval_type']](job['interval_number']) + ok = True + addsql='' + if not numbercall: + addsql = ', active=False' + cr.execute("update ir_cron set nextcall=%s, numbercall=%d"+addsql+" where id=%d", (nextcall.strftime('%Y-%m-%d %H:%M:%S'), numbercall, job['id'])) + cr.commit() + finally: + cr.close() + # + # Can be improved to do at the min(min(nextcalls), time()+next_wait) + # But is this an improvement ? + # + if not check: + self.setAlarm(self._poolJobs, int(time.time())+next_wait, [db_name]) ir_cron() diff --git a/bin/addons/base/ir/ir_default.py b/bin/addons/base/ir/ir_default.py index bec15da4573..dccb410f7ce 100644 --- a/bin/addons/base/ir/ir_default.py +++ b/bin/addons/base/ir/ir_default.py @@ -30,26 +30,26 @@ from osv import fields,osv class ir_default(osv.osv): - _name = 'ir.default' - _columns = { - 'field_tbl': fields.char('Model',size=64), - 'field_name': fields.char('Model field',size=64), - 'value': fields.char('Default Value',size=64), - 'uid': fields.many2one('res.users', 'Users'), - 'page': fields.char('View',size=64), - 'ref_table': fields.char('Table Ref.',size=64), - 'ref_id': fields.integer('ID Ref.',size=64), - 'company_id': fields.many2one('res.company','Company') - } + _name = 'ir.default' + _columns = { + 'field_tbl': fields.char('Model',size=64), + 'field_name': fields.char('Model field',size=64), + 'value': fields.char('Default Value',size=64), + 'uid': fields.many2one('res.users', 'Users'), + 'page': fields.char('View',size=64), + 'ref_table': fields.char('Table Ref.',size=64), + 'ref_id': fields.integer('ID Ref.',size=64), + 'company_id': fields.many2one('res.company','Company') + } - def _get_company_id(self, cr, uid, context={}): - res = self.pool.get('res.users').read(cr, uid, [uid], ['company_id'], context=context) - if res and res[0]['company_id']: - return res[0]['company_id'][0] - return False + def _get_company_id(self, cr, uid, context={}): + res = self.pool.get('res.users').read(cr, uid, [uid], ['company_id'], context=context) + if res and res[0]['company_id']: + return res[0]['company_id'][0] + return False - _defaults = { - 'company_id': _get_company_id, - } + _defaults = { + 'company_id': _get_company_id, + } ir_default() diff --git a/bin/addons/base/ir/ir_exports.py b/bin/addons/base/ir/ir_exports.py index c5329ab5191..5b2cb625d3d 100644 --- a/bin/addons/base/ir/ir_exports.py +++ b/bin/addons/base/ir/ir_exports.py @@ -31,20 +31,20 @@ from osv import fields,osv class ir_exports(osv.osv): - _name = "ir.exports" - _columns = { - 'name': fields.char('Export name', size=128), - 'resource': fields.char('Resource', size=128), - 'export_fields': fields.one2many('ir.exports.line', 'export_id', - 'Export Id'), - } + _name = "ir.exports" + _columns = { + 'name': fields.char('Export name', size=128), + 'resource': fields.char('Resource', size=128), + 'export_fields': fields.one2many('ir.exports.line', 'export_id', + 'Export Id'), + } ir_exports() class ir_exports_line(osv.osv): - _name = 'ir.exports.line' - _columns = { - 'name': fields.char('Field name', size=64), - 'export_id': fields.many2one('ir.exports', 'Exportation', select=True, ondelete='cascade'), - } + _name = 'ir.exports.line' + _columns = { + 'name': fields.char('Field name', size=64), + 'export_id': fields.many2one('ir.exports', 'Exportation', select=True, ondelete='cascade'), + } ir_exports_line() diff --git a/bin/addons/base/ir/ir_model.py b/bin/addons/base/ir/ir_model.py index 0c6bfc7edb1..5d971e079e7 100644 --- a/bin/addons/base/ir/ir_model.py +++ b/bin/addons/base/ir/ir_model.py @@ -37,395 +37,395 @@ import tools import pooler def _get_fields_type(self, cr, uid, context=None): - cr.execute('select distinct ttype,ttype from ir_model_fields') - return cr.fetchall() + cr.execute('select distinct ttype,ttype from ir_model_fields') + return cr.fetchall() class ir_model(osv.osv): - _name = 'ir.model' - _description = "Objects" - _rec_name = 'name' - _columns = { - 'name': fields.char('Model Name', size=64, translate=True, required=True), - 'model': fields.char('Object Name', size=64, required=True, search=1), - 'info': fields.text('Information'), - 'field_id': fields.one2many('ir.model.fields', 'model_id', 'Fields', required=True), - 'state': fields.selection([('manual','Custom Object'),('base','Base Field')],'Manualy Created',readonly=1), - } - _defaults = { - 'model': lambda *a: 'x_', - 'state': lambda self,cr,uid,ctx={}: (ctx and ctx.get('manual',False)) and 'manual' or 'base', - } - - def _check_model_name(self, cr, uid, ids): - for model in self.browse(cr, uid, ids): - if model.state=='manual': - if not model.model.startswith('x_'): - return False - if not re.match('^[a-z_A-Z0-9]+$',model.model): - return False - return True + _name = 'ir.model' + _description = "Objects" + _rec_name = 'name' + _columns = { + 'name': fields.char('Model Name', size=64, translate=True, required=True), + 'model': fields.char('Object Name', size=64, required=True, search=1), + 'info': fields.text('Information'), + 'field_id': fields.one2many('ir.model.fields', 'model_id', 'Fields', required=True), + 'state': fields.selection([('manual','Custom Object'),('base','Base Field')],'Manualy Created',readonly=1), + } + _defaults = { + 'model': lambda *a: 'x_', + 'state': lambda self,cr,uid,ctx={}: (ctx and ctx.get('manual',False)) and 'manual' or 'base', + } + + def _check_model_name(self, cr, uid, ids): + for model in self.browse(cr, uid, ids): + if model.state=='manual': + if not model.model.startswith('x_'): + return False + if not re.match('^[a-z_A-Z0-9]+$',model.model): + return False + return True - _constraints = [ - (_check_model_name, 'The model name must start with x_ and not contain any special character !', ['model']), - ] - def unlink(self, cr, user, ids, context=None): - for model in self.browse(cr, user, ids, context): - if model.state <> 'manual': - raise except_orm(_('Error'), _("You can not remove the model '%s' !") %(field.name,)) - res = super(ir_model, self).unlink(cr, user, ids, context) - pooler.restart_pool(cr.dbname) - return res + _constraints = [ + (_check_model_name, 'The model name must start with x_ and not contain any special character !', ['model']), + ] + def unlink(self, cr, user, ids, context=None): + for model in self.browse(cr, user, ids, context): + if model.state <> 'manual': + raise except_orm(_('Error'), _("You can not remove the model '%s' !") %(field.name,)) + res = super(ir_model, self).unlink(cr, user, ids, context) + pooler.restart_pool(cr.dbname) + return res - def create(self, cr, user, vals, context=None): - if context and context.get('manual',False): - vals['state']='manual' - res = super(ir_model,self).create(cr, user, vals, context) - if vals.get('state','base')=='manual': - pooler.restart_pool(cr.dbname) - return res + def create(self, cr, user, vals, context=None): + if context and context.get('manual',False): + vals['state']='manual' + res = super(ir_model,self).create(cr, user, vals, context) + if vals.get('state','base')=='manual': + pooler.restart_pool(cr.dbname) + return res - def instanciate(self, cr, user, model, context={}): - class x_custom_model(osv.osv): - pass - x_custom_model._name = model - x_custom_model._module = False - x_custom_model.createInstance(self.pool, '', cr) - if 'x_name' in x_custom_model._columns: - x_custom_model._rec_name = 'x_name' - else: - x_custom_model._rec_name = x_custom_model._columns.keys()[0] + def instanciate(self, cr, user, model, context={}): + class x_custom_model(osv.osv): + pass + x_custom_model._name = model + x_custom_model._module = False + x_custom_model.createInstance(self.pool, '', cr) + if 'x_name' in x_custom_model._columns: + x_custom_model._rec_name = 'x_name' + else: + x_custom_model._rec_name = x_custom_model._columns.keys()[0] ir_model() class ir_model_fields(osv.osv): - _name = 'ir.model.fields' - _description = "Fields" - _columns = { - 'name': fields.char('Name', required=True, size=64, select=1), - 'model': fields.char('Object Name', size=64, required=True), - 'relation': fields.char('Model Relation', size=64), - 'model_id': fields.many2one('ir.model', 'Model id', required=True, select=True, ondelete='cascade'), - 'field_description': fields.char('Field Label', required=True, size=256), - 'relate': fields.boolean('Click and Relate'), + _name = 'ir.model.fields' + _description = "Fields" + _columns = { + 'name': fields.char('Name', required=True, size=64, select=1), + 'model': fields.char('Object Name', size=64, required=True), + 'relation': fields.char('Model Relation', size=64), + 'model_id': fields.many2one('ir.model', 'Model id', required=True, select=True, ondelete='cascade'), + 'field_description': fields.char('Field Label', required=True, size=256), + 'relate': fields.boolean('Click and Relate'), - 'ttype': fields.selection(_get_fields_type, 'Field Type',size=64, required=True), - 'selection': fields.char('Field Selection',size=128), - 'required': fields.boolean('Required'), - 'readonly': fields.boolean('Readonly'), - 'select_level': fields.selection([('0','Not Searchable'),('1','Always Searchable'),('2','Advanced Search')],'Searchable', required=True), - 'translate': fields.boolean('Translate'), - 'size': fields.integer('Size'), - 'state': fields.selection([('manual','Custom Field'),('base','Base Field')],'Manualy Created'), - 'on_delete': fields.selection([('cascade','Cascade'),('set null','Set NULL')], 'On delete', help='On delete property for many2one fields'), - 'domain': fields.char('Domain', size=256), + 'ttype': fields.selection(_get_fields_type, 'Field Type',size=64, required=True), + 'selection': fields.char('Field Selection',size=128), + 'required': fields.boolean('Required'), + 'readonly': fields.boolean('Readonly'), + 'select_level': fields.selection([('0','Not Searchable'),('1','Always Searchable'),('2','Advanced Search')],'Searchable', required=True), + 'translate': fields.boolean('Translate'), + 'size': fields.integer('Size'), + 'state': fields.selection([('manual','Custom Field'),('base','Base Field')],'Manualy Created'), + 'on_delete': fields.selection([('cascade','Cascade'),('set null','Set NULL')], 'On delete', help='On delete property for many2one fields'), + 'domain': fields.char('Domain', size=256), - 'groups': fields.many2many('res.groups', 'ir_model_fields_group_rel', 'field_id', 'group_id', 'Groups'), - 'group_name': fields.char('Group Name', size=128), - 'view_load': fields.boolean('View Auto-Load'), - } - _defaults = { - 'relate': lambda *a: 0, - 'view_load': lambda *a: 0, - 'selection': lambda *a: "[]", - 'domain': lambda *a: "[]", - 'name': lambda *a: 'x_', - 'state': lambda self,cr,uid,ctx={}: (ctx and ctx.get('manual',False)) and 'manual' or 'base', - 'on_delete': lambda *a: 'set null', - 'select_level': lambda *a: '0', - 'size': lambda *a: 64, - 'field_description': lambda *a: '', - } - _order = "id" - def unlink(self, cr, user, ids, context=None): - for field in self.browse(cr, user, ids, context): - if field.state <> 'manual': - raise except_orm(_('Error'), _("You can not remove the field '%s' !") %(field.name,)) - # - # MAY BE ADD A ALTER TABLE DROP ? - # - return super(ir_model_fields, self).unlink(cr, user, ids, context) + 'groups': fields.many2many('res.groups', 'ir_model_fields_group_rel', 'field_id', 'group_id', 'Groups'), + 'group_name': fields.char('Group Name', size=128), + 'view_load': fields.boolean('View Auto-Load'), + } + _defaults = { + 'relate': lambda *a: 0, + 'view_load': lambda *a: 0, + 'selection': lambda *a: "[]", + 'domain': lambda *a: "[]", + 'name': lambda *a: 'x_', + 'state': lambda self,cr,uid,ctx={}: (ctx and ctx.get('manual',False)) and 'manual' or 'base', + 'on_delete': lambda *a: 'set null', + 'select_level': lambda *a: '0', + 'size': lambda *a: 64, + 'field_description': lambda *a: '', + } + _order = "id" + def unlink(self, cr, user, ids, context=None): + for field in self.browse(cr, user, ids, context): + if field.state <> 'manual': + raise except_orm(_('Error'), _("You can not remove the field '%s' !") %(field.name,)) + # + # MAY BE ADD A ALTER TABLE DROP ? + # + return super(ir_model_fields, self).unlink(cr, user, ids, context) - def create(self, cr, user, vals, context=None): - if 'model_id' in vals: - model_data=self.pool.get('ir.model').read(cr,user,vals['model_id']) - vals['model']=model_data['model'] - if context and context.get('manual',False): - vals['state']='manual' - res = super(ir_model_fields,self).create(cr, user, vals, context) - if vals.get('state','base')=='manual': - if not vals['name'].startswith('x_'): - raise except_orm(_('Error'), _("Custom fields must have a name that starts with 'x_' !")) - if self.pool.get(vals['model']): - self.pool.get(vals['model']).__init__(self.pool, cr) - self.pool.get(vals['model'])._auto_init(cr,{}) - return res + def create(self, cr, user, vals, context=None): + if 'model_id' in vals: + model_data=self.pool.get('ir.model').read(cr,user,vals['model_id']) + vals['model']=model_data['model'] + if context and context.get('manual',False): + vals['state']='manual' + res = super(ir_model_fields,self).create(cr, user, vals, context) + if vals.get('state','base')=='manual': + if not vals['name'].startswith('x_'): + raise except_orm(_('Error'), _("Custom fields must have a name that starts with 'x_' !")) + if self.pool.get(vals['model']): + self.pool.get(vals['model']).__init__(self.pool, cr) + self.pool.get(vals['model'])._auto_init(cr,{}) + return res ir_model_fields() class ir_model_access(osv.osv): - _name = 'ir.model.access' - _columns = { - 'name': fields.char('Name', size=64, required=True), - 'model_id': fields.many2one('ir.model', 'Model', required=True), - 'group_id': fields.many2one('res.groups', 'Group'), - 'perm_read': fields.boolean('Read Access'), - 'perm_write': fields.boolean('Write Access'), - 'perm_create': fields.boolean('Create Access'), - 'perm_unlink': fields.boolean('Delete Permission'), - } - - def check_groups(self, cr, uid, group): - res = False - grouparr = group.split('.') - if grouparr: - cr.execute("select * from res_groups_users_rel where uid=" + str(uid) + " and gid in(select res_id from ir_model_data where module='%s' and name='%s')" % (grouparr[0], grouparr[1])) - r = cr.fetchall() - if not r: - res = False - else: - res = True - else: - res = False - return res - - def check(self, cr, uid, model_name, mode='read',raise_exception=True): - assert mode in ['read','write','create','unlink'], 'Invalid access mode for security' - if uid == 1: - return True # TODO: check security: don't allow xml-rpc request with uid == 1 + _name = 'ir.model.access' + _columns = { + 'name': fields.char('Name', size=64, required=True), + 'model_id': fields.many2one('ir.model', 'Model', required=True), + 'group_id': fields.many2one('res.groups', 'Group'), + 'perm_read': fields.boolean('Read Access'), + 'perm_write': fields.boolean('Write Access'), + 'perm_create': fields.boolean('Create Access'), + 'perm_unlink': fields.boolean('Delete Permission'), + } + + def check_groups(self, cr, uid, group): + res = False + grouparr = group.split('.') + if grouparr: + cr.execute("select * from res_groups_users_rel where uid=" + str(uid) + " and gid in(select res_id from ir_model_data where module='%s' and name='%s')" % (grouparr[0], grouparr[1])) + r = cr.fetchall() + if not r: + res = False + else: + res = True + else: + res = False + return res + + def check(self, cr, uid, model_name, mode='read',raise_exception=True): + assert mode in ['read','write','create','unlink'], 'Invalid access mode for security' + if uid == 1: + return True # TODO: check security: don't allow xml-rpc request with uid == 1 - cr.execute('SELECT MAX(CASE WHEN perm_'+mode+' THEN 1 else 0 END) ' - 'FROM ir_model_access a ' - 'JOIN ir_model m ' - 'ON (a.model_id=m.id) ' - 'JOIN res_groups_users_rel gu ' - 'ON (gu.gid = a.group_id) ' - 'WHERE m.model = %s AND gu.uid = %s', (model_name, uid,)) - r = cr.fetchall() - if r[0][0] == None: - cr.execute('SELECT MAX(CASE WHEN perm_'+mode+' THEN 1 else 0 END) ' - 'FROM ir_model_access a ' - 'JOIN ir_model m ' - 'ON (a.model_id = m.id) ' - 'WHERE a.group_id IS NULL AND m.model = %s', (model_name,)) - r= cr.fetchall() - if r[0][0] == None: - return False # by default, the user had no access + cr.execute('SELECT MAX(CASE WHEN perm_'+mode+' THEN 1 else 0 END) ' + 'FROM ir_model_access a ' + 'JOIN ir_model m ' + 'ON (a.model_id=m.id) ' + 'JOIN res_groups_users_rel gu ' + 'ON (gu.gid = a.group_id) ' + 'WHERE m.model = %s AND gu.uid = %s', (model_name, uid,)) + r = cr.fetchall() + if r[0][0] == None: + cr.execute('SELECT MAX(CASE WHEN perm_'+mode+' THEN 1 else 0 END) ' + 'FROM ir_model_access a ' + 'JOIN ir_model m ' + 'ON (a.model_id = m.id) ' + 'WHERE a.group_id IS NULL AND m.model = %s', (model_name,)) + r= cr.fetchall() + if r[0][0] == None: + return False # by default, the user had no access - if not r[0][0]: - if raise_exception: - msgs = { - 'read': _('You can not read this document! (%s)'), - 'write': _('You can not write in this document! (%s)'), - 'create': _('You can not create this kind of document! (%s)'), - 'unlink': _('You can not delete this document! (%s)'), - } - # due to the assert at the begin of the function, we will never have a KeyError - raise except_orm(_('AccessError'), msgs[mode] % model_name ) - return r[0][0] + if not r[0][0]: + if raise_exception: + msgs = { + 'read': _('You can not read this document! (%s)'), + 'write': _('You can not write in this document! (%s)'), + 'create': _('You can not create this kind of document! (%s)'), + 'unlink': _('You can not delete this document! (%s)'), + } + # due to the assert at the begin of the function, we will never have a KeyError + raise except_orm(_('AccessError'), msgs[mode] % model_name ) + return r[0][0] - check = tools.cache()(check) + check = tools.cache()(check) - # - # Methods to clean the cache on the Check Method. - # - def write(self, cr, uid, *args, **argv): - res = super(ir_model_access, self).write(cr, uid, *args, **argv) - self.check() - return res - def create(self, cr, uid, *args, **argv): - res = super(ir_model_access, self).create(cr, uid, *args, **argv) - self.check() - return res - def unlink(self, cr, uid, *args, **argv): - res = super(ir_model_access, self).unlink(cr, uid, *args, **argv) - self.check() - return res + # + # Methods to clean the cache on the Check Method. + # + def write(self, cr, uid, *args, **argv): + res = super(ir_model_access, self).write(cr, uid, *args, **argv) + self.check() + return res + def create(self, cr, uid, *args, **argv): + res = super(ir_model_access, self).create(cr, uid, *args, **argv) + self.check() + return res + def unlink(self, cr, uid, *args, **argv): + res = super(ir_model_access, self).unlink(cr, uid, *args, **argv) + self.check() + return res ir_model_access() class ir_model_data(osv.osv): - _name = 'ir.model.data' - _columns = { - 'name': fields.char('XML Identifier', required=True, size=64), - 'model': fields.char('Model', required=True, size=64), - 'module': fields.char('Module', required=True, size=64), - 'res_id': fields.integer('Resource ID'), - 'noupdate': fields.boolean('Non Updatable'), - 'date_update': fields.datetime('Update Date'), - 'date_init': fields.datetime('Init Date') - } - _defaults = { - 'date_init': lambda *a: time.strftime('%Y-%m-%d %H:%M:%S'), - 'date_update': lambda *a: time.strftime('%Y-%m-%d %H:%M:%S'), - 'noupdate': lambda *a: False - } + _name = 'ir.model.data' + _columns = { + 'name': fields.char('XML Identifier', required=True, size=64), + 'model': fields.char('Model', required=True, size=64), + 'module': fields.char('Module', required=True, size=64), + 'res_id': fields.integer('Resource ID'), + 'noupdate': fields.boolean('Non Updatable'), + 'date_update': fields.datetime('Update Date'), + 'date_init': fields.datetime('Init Date') + } + _defaults = { + 'date_init': lambda *a: time.strftime('%Y-%m-%d %H:%M:%S'), + 'date_update': lambda *a: time.strftime('%Y-%m-%d %H:%M:%S'), + 'noupdate': lambda *a: False + } - def __init__(self, pool, cr): - osv.osv.__init__(self, pool, cr) - self.loads = {} - self.doinit = True - self.unlink_mark = {} + def __init__(self, pool, cr): + osv.osv.__init__(self, pool, cr) + self.loads = {} + self.doinit = True + self.unlink_mark = {} - def _get_id(self,cr, uid, module, xml_id): - ids = self.search(cr, uid, [('module','=',module),('name','=', xml_id)]) - assert len(ids)==1, '%d reference(s) to %s. You should have only one !' % (len(ids),xml_id) - return ids[0] - _get_id = tools.cache()(_get_id) + def _get_id(self,cr, uid, module, xml_id): + ids = self.search(cr, uid, [('module','=',module),('name','=', xml_id)]) + assert len(ids)==1, '%d reference(s) to %s. You should have only one !' % (len(ids),xml_id) + return ids[0] + _get_id = tools.cache()(_get_id) - def _update_dummy(self,cr, uid, model, module, xml_id=False, store=True): - if not xml_id: - return False - try: - id = self.read(cr, uid, [self._get_id(cr, uid, module, xml_id)], ['res_id'])[0]['res_id'] - self.loads[(module,xml_id)] = (model,id) - except: - id = False - return id + def _update_dummy(self,cr, uid, model, module, xml_id=False, store=True): + if not xml_id: + return False + try: + id = self.read(cr, uid, [self._get_id(cr, uid, module, xml_id)], ['res_id'])[0]['res_id'] + self.loads[(module,xml_id)] = (model,id) + except: + id = False + return id - def _update(self,cr, uid, model, module, values, xml_id=False, store=True, noupdate=False, mode='init', res_id=False): - warning = True - model_obj = self.pool.get(model) - context = {} - if xml_id and ('.' in xml_id): - assert len(xml_id.split('.'))==2, _('"%s" contains too many dots. XML ids should not contain dots ! These are used to refer to other modules data, as in module.reference_id') % (xml_id) - warning = False - module, xml_id = xml_id.split('.') - if (not xml_id) and (not self.doinit): - return False - action_id = False - if xml_id: - cr.execute('select id,res_id from ir_model_data where module=%s and name=%s', (module,xml_id)) - results = cr.fetchall() - for action_id2,res_id2 in results: - cr.execute('select id from '+self.pool.get(model)._table+' where id=%d', (res_id2,)) - result3 = cr.fetchone() - if not result3: - cr.execute('delete from ir_model_data where id=%d', (action_id2,)) - else: - res_id,action_id = res_id2,action_id2 + def _update(self,cr, uid, model, module, values, xml_id=False, store=True, noupdate=False, mode='init', res_id=False): + warning = True + model_obj = self.pool.get(model) + context = {} + if xml_id and ('.' in xml_id): + assert len(xml_id.split('.'))==2, _('"%s" contains too many dots. XML ids should not contain dots ! These are used to refer to other modules data, as in module.reference_id') % (xml_id) + warning = False + module, xml_id = xml_id.split('.') + if (not xml_id) and (not self.doinit): + return False + action_id = False + if xml_id: + cr.execute('select id,res_id from ir_model_data where module=%s and name=%s', (module,xml_id)) + results = cr.fetchall() + for action_id2,res_id2 in results: + cr.execute('select id from '+self.pool.get(model)._table+' where id=%d', (res_id2,)) + result3 = cr.fetchone() + if not result3: + cr.execute('delete from ir_model_data where id=%d', (action_id2,)) + else: + res_id,action_id = res_id2,action_id2 - if action_id and res_id: - model_obj.write(cr, uid, [res_id], values) - self.write(cr, uid, [action_id], { - 'date_update': time.strftime('%Y-%m-%d %H:%M:%S'), - }) - elif res_id: - model_obj.write(cr, uid, [res_id], values) - if xml_id: - self.create(cr, uid, { - 'name': xml_id, - 'model': model, - 'module':module, - 'res_id':res_id, - 'noupdate': noupdate, - }) - if model_obj._inherits: - for table in model_obj._inherits: - inherit_id = model_obj.browse(cr, uid, - res_id)[model_obj._inherits[table]] - self.create(cr, uid, { - 'name': xml_id + '_' + table.replace('.', '_'), - 'model': table, - 'module': module, - 'res_id': inherit_id, - 'noupdate': noupdate, - }) - else: - if mode=='init' or (mode=='update' and xml_id): - res_id = model_obj.create(cr, uid, values) - if xml_id: - self.create(cr, uid, { - 'name': xml_id, - 'model': model, - 'module': module, - 'res_id': res_id, - 'noupdate': noupdate - }) - if model_obj._inherits: - for table in model_obj._inherits: - inherit_id = model_obj.browse(cr, uid, - res_id)[model_obj._inherits[table]] - self.create(cr, uid, { - 'name': xml_id + '_' + table.replace('.', '_'), - 'model': table, - 'module': module, - 'res_id': inherit_id, - 'noupdate': noupdate, - }) - if xml_id: - if res_id: - self.loads[(module, xml_id)] = (model, res_id) - if model_obj._inherits: - for table in model_obj._inherits: - inherit_field = model_obj._inherits[table] - inherit_id = model_obj.read(cr, uid, res_id, - [inherit_field])[inherit_field] - self.loads[(module, xml_id + '_' + \ - table.replace('.', '_'))] = (table, inherit_id) - return res_id + if action_id and res_id: + model_obj.write(cr, uid, [res_id], values) + self.write(cr, uid, [action_id], { + 'date_update': time.strftime('%Y-%m-%d %H:%M:%S'), + }) + elif res_id: + model_obj.write(cr, uid, [res_id], values) + if xml_id: + self.create(cr, uid, { + 'name': xml_id, + 'model': model, + 'module':module, + 'res_id':res_id, + 'noupdate': noupdate, + }) + if model_obj._inherits: + for table in model_obj._inherits: + inherit_id = model_obj.browse(cr, uid, + res_id)[model_obj._inherits[table]] + self.create(cr, uid, { + 'name': xml_id + '_' + table.replace('.', '_'), + 'model': table, + 'module': module, + 'res_id': inherit_id, + 'noupdate': noupdate, + }) + else: + if mode=='init' or (mode=='update' and xml_id): + res_id = model_obj.create(cr, uid, values) + if xml_id: + self.create(cr, uid, { + 'name': xml_id, + 'model': model, + 'module': module, + 'res_id': res_id, + 'noupdate': noupdate + }) + if model_obj._inherits: + for table in model_obj._inherits: + inherit_id = model_obj.browse(cr, uid, + res_id)[model_obj._inherits[table]] + self.create(cr, uid, { + 'name': xml_id + '_' + table.replace('.', '_'), + 'model': table, + 'module': module, + 'res_id': inherit_id, + 'noupdate': noupdate, + }) + if xml_id: + if res_id: + self.loads[(module, xml_id)] = (model, res_id) + if model_obj._inherits: + for table in model_obj._inherits: + inherit_field = model_obj._inherits[table] + inherit_id = model_obj.read(cr, uid, res_id, + [inherit_field])[inherit_field] + self.loads[(module, xml_id + '_' + \ + table.replace('.', '_'))] = (table, inherit_id) + return res_id - def _unlink(self, cr, uid, model, ids, direct=False): - #self.pool.get(model).unlink(cr, uid, ids) - for id in ids: - self.unlink_mark[(model, id)]=False - cr.execute('delete from ir_model_data where res_id=%d and model=\'%s\'', (id,model)) - return True + def _unlink(self, cr, uid, model, ids, direct=False): + #self.pool.get(model).unlink(cr, uid, ids) + for id in ids: + self.unlink_mark[(model, id)]=False + cr.execute('delete from ir_model_data where res_id=%d and model=\'%s\'', (id,model)) + return True - def ir_set(self, cr, uid, key, key2, name, models, value, replace=True, isobject=False, meta=None, xml_id=False): - obj = self.pool.get('ir.values') - if type(models[0])==type([]) or type(models[0])==type(()): - model,res_id = models[0] - else: - res_id=None - model = models[0] + def ir_set(self, cr, uid, key, key2, name, models, value, replace=True, isobject=False, meta=None, xml_id=False): + obj = self.pool.get('ir.values') + if type(models[0])==type([]) or type(models[0])==type(()): + model,res_id = models[0] + else: + res_id=None + model = models[0] - if res_id: - where = ' and res_id=%d' % (res_id,) - else: - where = ' and (res_id is null)' + if res_id: + where = ' and res_id=%d' % (res_id,) + else: + where = ' and (res_id is null)' - if key2: - where += ' and key2=\'%s\'' % (key2,) - else: - where += ' and (key2 is null)' + if key2: + where += ' and key2=\'%s\'' % (key2,) + else: + where += ' and (key2 is null)' - cr.execute('select * from ir_values where model=%s and key=%s and name=%s'+where,(model, key, name)) - res = cr.fetchone() - if not res: - res = ir.ir_set(cr, uid, key, key2, name, models, value, replace, isobject, meta) - elif xml_id: - cr.execute('UPDATE ir_values set value=%s WHERE model=%s and key=%s and name=%s'+where,(value, model, key, name)) - return True + cr.execute('select * from ir_values where model=%s and key=%s and name=%s'+where,(model, key, name)) + res = cr.fetchone() + if not res: + res = ir.ir_set(cr, uid, key, key2, name, models, value, replace, isobject, meta) + elif xml_id: + cr.execute('UPDATE ir_values set value=%s WHERE model=%s and key=%s and name=%s'+where,(value, model, key, name)) + return True - def _process_end(self, cr, uid, modules): - if not modules: - return True - module_str = ["'%s'" % m for m in modules] - cr.execute('select id,name,model,res_id,module from ir_model_data where module in ('+','.join(module_str)+') and not noupdate') - wkf_todo = [] - for (id, name, model, res_id,module) in cr.fetchall(): - if (module,name) not in self.loads: - self.unlink_mark[(model,res_id)] = id - if model=='workflow.activity': - cr.execute('select res_type,res_id from wkf_instance where id in (select inst_id from wkf_workitem where act_id=%d)', (res_id,)) - wkf_todo.extend(cr.fetchall()) - cr.execute("update wkf_transition set condition='True', role_id=NULL, signal=NULL,act_to=act_from,act_from=%d where act_to=%d", (res_id,res_id)) - cr.execute("delete from wkf_transition where act_to=%d", (res_id,)) + def _process_end(self, cr, uid, modules): + if not modules: + return True + module_str = ["'%s'" % m for m in modules] + cr.execute('select id,name,model,res_id,module from ir_model_data where module in ('+','.join(module_str)+') and not noupdate') + wkf_todo = [] + for (id, name, model, res_id,module) in cr.fetchall(): + if (module,name) not in self.loads: + self.unlink_mark[(model,res_id)] = id + if model=='workflow.activity': + cr.execute('select res_type,res_id from wkf_instance where id in (select inst_id from wkf_workitem where act_id=%d)', (res_id,)) + wkf_todo.extend(cr.fetchall()) + cr.execute("update wkf_transition set condition='True', role_id=NULL, signal=NULL,act_to=act_from,act_from=%d where act_to=%d", (res_id,res_id)) + cr.execute("delete from wkf_transition where act_to=%d", (res_id,)) - for model,id in wkf_todo: - wf_service = netsvc.LocalService("workflow") - wf_service.trg_write(uid, model, id, cr) + for model,id in wkf_todo: + wf_service = netsvc.LocalService("workflow") + wf_service.trg_write(uid, model, id, cr) - cr.commit() - for (model,id) in self.unlink_mark.keys(): - if self.pool.get(model): - logger = netsvc.Logger() - logger.notifyChannel('init', netsvc.LOG_INFO, 'Deleting %s@%s' % (id, model)) - try: - self.pool.get(model).unlink(cr, uid, [id]) - if self.unlink_mark[(model,id)]: - self.unlink(cr, uid, [self.unlink_mark[(model,id)]]) - cr.execute('DELETE FROM ir_values WHERE value=%s', (model+','+str(id),)) - cr.commit() - except: - logger.notifyChannel('init', netsvc.LOG_ERROR, 'Could not delete id: %d of model %s\tThere should be some relation that points to this resource\tYou should manually fix this and restart --update=module' % (id, model)) - return True + cr.commit() + for (model,id) in self.unlink_mark.keys(): + if self.pool.get(model): + logger = netsvc.Logger() + logger.notifyChannel('init', netsvc.LOG_INFO, 'Deleting %s@%s' % (id, model)) + try: + self.pool.get(model).unlink(cr, uid, [id]) + if self.unlink_mark[(model,id)]: + self.unlink(cr, uid, [self.unlink_mark[(model,id)]]) + cr.execute('DELETE FROM ir_values WHERE value=%s', (model+','+str(id),)) + cr.commit() + except: + logger.notifyChannel('init', netsvc.LOG_ERROR, 'Could not delete id: %d of model %s\tThere should be some relation that points to this resource\tYou should manually fix this and restart --update=module' % (id, model)) + return True ir_model_data() diff --git a/bin/addons/base/ir/ir_report_custom.py b/bin/addons/base/ir/ir_report_custom.py index af413f54e41..cc8b3acc7e5 100644 --- a/bin/addons/base/ir/ir_report_custom.py +++ b/bin/addons/base/ir/ir_report_custom.py @@ -34,176 +34,176 @@ import report.custom from tools.translate import _ class report_custom(osv.osv): - _name = 'ir.report.custom' - _columns = { - 'name': fields.char('Report Name', size=64, required=True, translate=True), - 'model_id': fields.many2one('ir.model','Model', required=True, change_default=True), - 'type': fields.selection([('table','Tabular'),('pie','Pie Chart'),('bar','Bar Chart'),('line','Line Plot')], "Report Type", size=64, required='True'), - 'title': fields.char("Report title", size=64, required='True', translate=True), - 'print_format': fields.selection((('A4','a4'),('A5','a5')), 'Print format', required=True), - 'print_orientation': fields.selection((('landscape','Landscape'),('portrait','Portrait')), 'Print orientation', required=True, size=16), - 'repeat_header': fields.boolean('Repeat Header'), - 'footer': fields.char('Report Footer', size=64, required=True), - 'sortby': fields.char('Sorted By', size=64), - 'fields_child0': fields.one2many('ir.report.custom.fields', 'report_id','Fields', required=True), - 'field_parent': fields.many2one('ir.model.fields','Child Field'), - 'state': fields.selection([('unsubscribed','Unsubscribed'),('subscribed','Subscribed')], 'State', size=64), - 'frequency': fields.selection([('Y','Yearly'),('M','Monthly'),('D','Daily')], 'Frequency', size=64), - 'limitt': fields.char('Limit', size=9), - 'menu_id': fields.many2one('ir.ui.menu', 'Menu') - } - _defaults = { - 'print_format': lambda *a: 'A4', - 'print_orientation': lambda *a: 'portrait', - 'state': lambda *a: 'unsubscribed', - 'type': lambda *a: 'table', - 'footer': lambda *a: 'Generated by Tiny ERP' - } - - def onchange_model_id(self, cr, uid, ids, model_id): - if not(model_id): - return {} - return {'domain': {'field_parent': [('model_id','=',model_id)]}} + _name = 'ir.report.custom' + _columns = { + 'name': fields.char('Report Name', size=64, required=True, translate=True), + 'model_id': fields.many2one('ir.model','Model', required=True, change_default=True), + 'type': fields.selection([('table','Tabular'),('pie','Pie Chart'),('bar','Bar Chart'),('line','Line Plot')], "Report Type", size=64, required='True'), + 'title': fields.char("Report title", size=64, required='True', translate=True), + 'print_format': fields.selection((('A4','a4'),('A5','a5')), 'Print format', required=True), + 'print_orientation': fields.selection((('landscape','Landscape'),('portrait','Portrait')), 'Print orientation', required=True, size=16), + 'repeat_header': fields.boolean('Repeat Header'), + 'footer': fields.char('Report Footer', size=64, required=True), + 'sortby': fields.char('Sorted By', size=64), + 'fields_child0': fields.one2many('ir.report.custom.fields', 'report_id','Fields', required=True), + 'field_parent': fields.many2one('ir.model.fields','Child Field'), + 'state': fields.selection([('unsubscribed','Unsubscribed'),('subscribed','Subscribed')], 'State', size=64), + 'frequency': fields.selection([('Y','Yearly'),('M','Monthly'),('D','Daily')], 'Frequency', size=64), + 'limitt': fields.char('Limit', size=9), + 'menu_id': fields.many2one('ir.ui.menu', 'Menu') + } + _defaults = { + 'print_format': lambda *a: 'A4', + 'print_orientation': lambda *a: 'portrait', + 'state': lambda *a: 'unsubscribed', + 'type': lambda *a: 'table', + 'footer': lambda *a: 'Generated by Tiny ERP' + } + + def onchange_model_id(self, cr, uid, ids, model_id): + if not(model_id): + return {} + return {'domain': {'field_parent': [('model_id','=',model_id)]}} - def unsubscribe(self, cr, uid, ids, context={}): + def unsubscribe(self, cr, uid, ids, context={}): #TODO: should delete the ir.actions.report.custom for these reports and do an ir_del - self.write(cr, uid, ids, {'state':'unsubscribed'}) - return True + self.write(cr, uid, ids, {'state':'unsubscribed'}) + return True - def subscribe(self, cr, uid, ids, context={}): - for report in self.browse(cr, uid, ids): - report.fields_child0.sort(lambda x,y : x.sequence - y.sequence) - - # required on field0 does not seem to work( cause we use o2m_l ?) - if not report.fields_child0: - raise osv.except_osv(_('Invalid operation'), _('Enter at least one field !')) - - if report.type in ['pie', 'bar', 'line'] and report.field_parent: - raise osv.except_osv(_('Invalid operation'), _('Tree can only be used in tabular reports')) - - # Otherwise it won't build a good tree. See level.pop in custom.py. - if report.type == 'table' and report.field_parent and report.fields_child0 and not report.fields_child0[0].groupby: - raise osv.except_osv('Invalid operation :', 'When creating tree (field child) report, data must be group by the first field') + def subscribe(self, cr, uid, ids, context={}): + for report in self.browse(cr, uid, ids): + report.fields_child0.sort(lambda x,y : x.sequence - y.sequence) + + # required on field0 does not seem to work( cause we use o2m_l ?) + if not report.fields_child0: + raise osv.except_osv(_('Invalid operation'), _('Enter at least one field !')) + + if report.type in ['pie', 'bar', 'line'] and report.field_parent: + raise osv.except_osv(_('Invalid operation'), _('Tree can only be used in tabular reports')) + + # Otherwise it won't build a good tree. See level.pop in custom.py. + if report.type == 'table' and report.field_parent and report.fields_child0 and not report.fields_child0[0].groupby: + raise osv.except_osv('Invalid operation :', 'When creating tree (field child) report, data must be group by the first field') - if report.type == 'pie': - if len(report.fields_child0) != 2: - raise osv.except_osv(_('Invalid operation'), _('Pie charts need exactly two fields')) - else: - c_f = {} - for i in range(2): - c_f[i] = [] - tmp = report.fields_child0[i] - for j in range(3): - c_f[i].append((not isinstance(eval('tmp.field_child'+str(j)), browse_null) and eval('tmp.field_child'+str(j)+'.ttype')) or None) - if not reduce(lambda x,y : x or y, map(lambda x: x in ['integer', 'float'], c_f[1])): - raise osv.except_osv(_('Invalid operation'), _('Second field should be figures')) - - if report.type == 'bar': - if len(report.fields_child0) < 2: - raise osv.except_osv(_('Invalid operation'), _('Bar charts need at least two fields')) - else: - c_f = {} - for i in range(len(report.fields_child0)): - c_f[i] = [] - tmp = report.fields_child0[i] - for j in range(3): - c_f[i].append((not isinstance(eval('tmp.field_child'+str(j)), browse_null) and eval('tmp.field_child'+str(j)+'.ttype')) or None) + if report.type == 'pie': + if len(report.fields_child0) != 2: + raise osv.except_osv(_('Invalid operation'), _('Pie charts need exactly two fields')) + else: + c_f = {} + for i in range(2): + c_f[i] = [] + tmp = report.fields_child0[i] + for j in range(3): + c_f[i].append((not isinstance(eval('tmp.field_child'+str(j)), browse_null) and eval('tmp.field_child'+str(j)+'.ttype')) or None) + if not reduce(lambda x,y : x or y, map(lambda x: x in ['integer', 'float'], c_f[1])): + raise osv.except_osv(_('Invalid operation'), _('Second field should be figures')) + + if report.type == 'bar': + if len(report.fields_child0) < 2: + raise osv.except_osv(_('Invalid operation'), _('Bar charts need at least two fields')) + else: + c_f = {} + for i in range(len(report.fields_child0)): + c_f[i] = [] + tmp = report.fields_child0[i] + for j in range(3): + c_f[i].append((not isinstance(eval('tmp.field_child'+str(j)), browse_null) and eval('tmp.field_child'+str(j)+'.ttype')) or None) - if i == 0: - pass - else: - if not reduce(lambda x,y : x or y, map(lambda x: x in ['integer', 'float'], c_f[i])): - raise osv.except_osv(_('Invalid operation'), _('Field %d should be a figure') %(i,)) + if i == 0: + pass + else: + if not reduce(lambda x,y : x or y, map(lambda x: x in ['integer', 'float'], c_f[i])): + raise osv.except_osv(_('Invalid operation'), _('Field %d should be a figure') %(i,)) - if report.state=='subscribed': - continue + if report.state=='subscribed': + continue - name = report.name - model = report.model_id.model + name = report.name + model = report.model_id.model - action_def = {'report_id':report.id, 'type':'ir.actions.report.custom', 'model':model, 'name':name} - id = self.pool.get('ir.actions.report.custom').create(cr, uid, action_def) - m_id = report.menu_id.id - action = "ir.actions.report.custom,%d" % (id,) - if not report.menu_id: - ir.ir_set(cr, uid, 'action', 'client_print_multi', name, [(model, False)], action, False, True) - else: - ir.ir_set(cr, uid, 'action', 'tree_but_open', 'Menuitem', [('ir.ui.menu', int(m_id))], action, False, True) + action_def = {'report_id':report.id, 'type':'ir.actions.report.custom', 'model':model, 'name':name} + id = self.pool.get('ir.actions.report.custom').create(cr, uid, action_def) + m_id = report.menu_id.id + action = "ir.actions.report.custom,%d" % (id,) + if not report.menu_id: + ir.ir_set(cr, uid, 'action', 'client_print_multi', name, [(model, False)], action, False, True) + else: + ir.ir_set(cr, uid, 'action', 'tree_but_open', 'Menuitem', [('ir.ui.menu', int(m_id))], action, False, True) - self.write(cr, uid, [report.id], {'state':'subscribed'}, context) - return True + self.write(cr, uid, [report.id], {'state':'subscribed'}, context) + return True report_custom() class report_custom_fields(osv.osv): - _name = 'ir.report.custom.fields' - _columns = { - 'name': fields.char('Name', size=64, required=True), - 'report_id': fields.many2one('ir.report.custom', 'Report Ref', select=True), - 'field_child0': fields.many2one('ir.model.fields', 'field child0', required=True), - 'fc0_operande': fields.many2one('ir.model.fields', 'Constraint'), - 'fc0_condition': fields.char('Condition', size=64), - 'fc0_op': fields.selection((('>','>'),('<','<'),('==','='),('in','in'),('gety,==','(year)=')), 'Relation'), - 'field_child1': fields.many2one('ir.model.fields', 'field child1'), - 'fc1_operande': fields.many2one('ir.model.fields', 'Constraint'), - 'fc1_condition': fields.char('condition', size=64), - 'fc1_op': fields.selection((('>','>'),('<','<'),('==','='),('in','in'),('gety,==','(year)=')), 'Relation'), - 'field_child2': fields.many2one('ir.model.fields', 'field child2'), - 'fc2_operande': fields.many2one('ir.model.fields', 'Constraint'), - 'fc2_condition': fields.char('condition', size=64), - 'fc2_op': fields.selection((('>','>'),('<','<'),('==','='),('in','in'),('gety,==','(year)=')), 'Relation'), - 'field_child3': fields.many2one('ir.model.fields', 'field child3'), - 'fc3_operande': fields.many2one('ir.model.fields', 'Constraint'), - 'fc3_condition': fields.char('condition', size=64), - 'fc3_op': fields.selection((('>','>'),('<','<'),('==','='),('in','in'),('gety,==','(year)=')), 'Relation'), - 'alignment': fields.selection((('left','left'),('right','right'),('center','center')), 'Alignment', required=True), - 'sequence': fields.integer('Sequence', required=True), - 'width': fields.integer('Fixed Width'), - 'operation': fields.selection((('none', 'None'),('calc_sum','Calculate Sum'),('calc_avg','Calculate Average'),('calc_count','Calculate Count'),('calc_max', 'Get Max'))), - 'groupby' : fields.boolean('Group by'), - 'bgcolor': fields.char('Background Color', size=64), - 'fontcolor': fields.char('Font color', size=64), - 'cumulate': fields.boolean('Cumulate') - } - _defaults = { - 'alignment': lambda *a: 'left', - 'bgcolor': lambda *a: 'white', - 'fontcolor': lambda *a: 'black', - 'operation': lambda *a: 'none', - } - _order = "sequence" + _name = 'ir.report.custom.fields' + _columns = { + 'name': fields.char('Name', size=64, required=True), + 'report_id': fields.many2one('ir.report.custom', 'Report Ref', select=True), + 'field_child0': fields.many2one('ir.model.fields', 'field child0', required=True), + 'fc0_operande': fields.many2one('ir.model.fields', 'Constraint'), + 'fc0_condition': fields.char('Condition', size=64), + 'fc0_op': fields.selection((('>','>'),('<','<'),('==','='),('in','in'),('gety,==','(year)=')), 'Relation'), + 'field_child1': fields.many2one('ir.model.fields', 'field child1'), + 'fc1_operande': fields.many2one('ir.model.fields', 'Constraint'), + 'fc1_condition': fields.char('condition', size=64), + 'fc1_op': fields.selection((('>','>'),('<','<'),('==','='),('in','in'),('gety,==','(year)=')), 'Relation'), + 'field_child2': fields.many2one('ir.model.fields', 'field child2'), + 'fc2_operande': fields.many2one('ir.model.fields', 'Constraint'), + 'fc2_condition': fields.char('condition', size=64), + 'fc2_op': fields.selection((('>','>'),('<','<'),('==','='),('in','in'),('gety,==','(year)=')), 'Relation'), + 'field_child3': fields.many2one('ir.model.fields', 'field child3'), + 'fc3_operande': fields.many2one('ir.model.fields', 'Constraint'), + 'fc3_condition': fields.char('condition', size=64), + 'fc3_op': fields.selection((('>','>'),('<','<'),('==','='),('in','in'),('gety,==','(year)=')), 'Relation'), + 'alignment': fields.selection((('left','left'),('right','right'),('center','center')), 'Alignment', required=True), + 'sequence': fields.integer('Sequence', required=True), + 'width': fields.integer('Fixed Width'), + 'operation': fields.selection((('none', 'None'),('calc_sum','Calculate Sum'),('calc_avg','Calculate Average'),('calc_count','Calculate Count'),('calc_max', 'Get Max'))), + 'groupby' : fields.boolean('Group by'), + 'bgcolor': fields.char('Background Color', size=64), + 'fontcolor': fields.char('Font color', size=64), + 'cumulate': fields.boolean('Cumulate') + } + _defaults = { + 'alignment': lambda *a: 'left', + 'bgcolor': lambda *a: 'white', + 'fontcolor': lambda *a: 'black', + 'operation': lambda *a: 'none', + } + _order = "sequence" - def onchange_any_field_child(self, cr, uid, ids, field_id, level): - if not(field_id): - return {} - next_level_field_name = 'field_child%d' % (level+1) - next_level_operande = 'fc%d_operande' % (level+1) - field = self.pool.get('ir.model.fields').browse(cr, uid, [field_id])[0] - res = self.pool.get(field.model).fields_get(cr, uid, field.name) - if res[field.name].has_key('relation'): - cr.execute('select id from ir_model where model=%s', (res[field.name]['relation'],)) - (id,) = cr.fetchone() or (False,) - if id: - return { - 'domain': { - next_level_field_name: [('model_id', '=', id)], - next_level_operande: [('model_id', '=', id)] - }, - 'required': { - next_level_field_name: True - } - } - else: - print _("Warning: using a relation field which uses an unknown object") #TODO use the logger - return {'required': {next_level_field_name: True}} - else: - return {'domain': {next_level_field_name: []}} - - def get_field_child_onchange_method(level): - return lambda self, cr, uid, ids, field_id: self.onchange_any_field_child(cr, uid, ids, field_id, level) + def onchange_any_field_child(self, cr, uid, ids, field_id, level): + if not(field_id): + return {} + next_level_field_name = 'field_child%d' % (level+1) + next_level_operande = 'fc%d_operande' % (level+1) + field = self.pool.get('ir.model.fields').browse(cr, uid, [field_id])[0] + res = self.pool.get(field.model).fields_get(cr, uid, field.name) + if res[field.name].has_key('relation'): + cr.execute('select id from ir_model where model=%s', (res[field.name]['relation'],)) + (id,) = cr.fetchone() or (False,) + if id: + return { + 'domain': { + next_level_field_name: [('model_id', '=', id)], + next_level_operande: [('model_id', '=', id)] + }, + 'required': { + next_level_field_name: True + } + } + else: + print _("Warning: using a relation field which uses an unknown object") #TODO use the logger + return {'required': {next_level_field_name: True}} + else: + return {'domain': {next_level_field_name: []}} + + def get_field_child_onchange_method(level): + return lambda self, cr, uid, ids, field_id: self.onchange_any_field_child(cr, uid, ids, field_id, level) - onchange_field_child0 = get_field_child_onchange_method(0) - onchange_field_child1 = get_field_child_onchange_method(1) - onchange_field_child2 = get_field_child_onchange_method(2) + onchange_field_child0 = get_field_child_onchange_method(0) + onchange_field_child1 = get_field_child_onchange_method(1) + onchange_field_child2 = get_field_child_onchange_method(2) report_custom_fields() diff --git a/bin/addons/base/ir/ir_rule.py b/bin/addons/base/ir/ir_rule.py index 6f76133341d..bdd5312f291 100644 --- a/bin/addons/base/ir/ir_rule.py +++ b/bin/addons/base/ir/ir_rule.py @@ -33,208 +33,208 @@ import tools class ir_rule_group(osv.osv): - _name = 'ir.rule.group' + _name = 'ir.rule.group' - _columns = { - 'name': fields.char('Name', size=128, select=1), - 'model_id': fields.many2one('ir.model', 'Model',select=1, required=True), - 'global': fields.boolean('Global', select=1, help="Make the rule global or it needs to be put on a group or user"), - 'rules': fields.one2many('ir.rule', 'rule_group', 'Tests', help="The rule is satisfied if at least one test is True"), - 'groups': fields.many2many('res.groups', 'group_rule_group_rel', 'rule_group_id', 'group_id', 'Groups'), - 'users': fields.many2many('res.users', 'user_rule_group_rel', 'rule_group_id', 'user_id', 'Users'), - } + _columns = { + 'name': fields.char('Name', size=128, select=1), + 'model_id': fields.many2one('ir.model', 'Model',select=1, required=True), + 'global': fields.boolean('Global', select=1, help="Make the rule global or it needs to be put on a group or user"), + 'rules': fields.one2many('ir.rule', 'rule_group', 'Tests', help="The rule is satisfied if at least one test is True"), + 'groups': fields.many2many('res.groups', 'group_rule_group_rel', 'rule_group_id', 'group_id', 'Groups'), + 'users': fields.many2many('res.users', 'user_rule_group_rel', 'rule_group_id', 'user_id', 'Users'), + } - _order = 'model_id, global DESC' + _order = 'model_id, global DESC' - _defaults={ - 'global': lambda *a: True, - } + _defaults={ + 'global': lambda *a: True, + } - def unlink(self, cr, uid, ids, context=None): - res = super(ir_rule_group, self).unlink(cr, uid, ids, context=context) - # Restart the cache on the domain_get method of ir.rule - self.pool.get('ir.rule').domain_get() - return res + def unlink(self, cr, uid, ids, context=None): + res = super(ir_rule_group, self).unlink(cr, uid, ids, context=context) + # Restart the cache on the domain_get method of ir.rule + self.pool.get('ir.rule').domain_get() + return res - def create(self, cr, user, vals, context=None): - res = super(ir_rule_group, self).create(cr, user, vals, context=context) - # Restart the cache on the domain_get method of ir.rule - self.pool.get('ir.rule').domain_get() - return res + def create(self, cr, user, vals, context=None): + res = super(ir_rule_group, self).create(cr, user, vals, context=context) + # Restart the cache on the domain_get method of ir.rule + self.pool.get('ir.rule').domain_get() + return res - def write(self, cr, uid, ids, vals, context=None): - if not context: - context={} - res = super(ir_rule_group, self).write(cr, uid, ids, vals, context=context) - # Restart the cache on the domain_get method of ir.rule - self.pool.get('ir.rule').domain_get() - return res + def write(self, cr, uid, ids, vals, context=None): + if not context: + context={} + res = super(ir_rule_group, self).write(cr, uid, ids, vals, context=context) + # Restart the cache on the domain_get method of ir.rule + self.pool.get('ir.rule').domain_get() + return res ir_rule_group() class ir_rule(osv.osv): - _name = 'ir.rule' - _rec_name = 'field_id' + _name = 'ir.rule' + _rec_name = 'field_id' - def _operand(self,cr,uid,context): + def _operand(self,cr,uid,context): - def get(object, level=3, recur=None, root_tech='', root=''): - res = [] - if not recur: - recur = [] - fields = self.pool.get(object).fields_get(cr,uid) - key = fields.keys() - key.sort() - for k in key: + def get(object, level=3, recur=None, root_tech='', root=''): + res = [] + if not recur: + recur = [] + fields = self.pool.get(object).fields_get(cr,uid) + key = fields.keys() + key.sort() + for k in key: - if fields[k]['type'] in ('many2one'): - res.append((root_tech+'.'+k+'.id', - root+'/'+fields[k]['string'])) + if fields[k]['type'] in ('many2one'): + res.append((root_tech+'.'+k+'.id', + root+'/'+fields[k]['string'])) - elif fields[k]['type'] in ('many2many', 'one2many'): - res.append(('\',\'.join(map(lambda x: str(x.id), '+root_tech+'.'+k+'))', - root+'/'+fields[k]['string'])) + elif fields[k]['type'] in ('many2many', 'one2many'): + res.append(('\',\'.join(map(lambda x: str(x.id), '+root_tech+'.'+k+'))', + root+'/'+fields[k]['string'])) - else: - res.append((root_tech+'.'+k, - root+'/'+fields[k]['string'])) + else: + res.append((root_tech+'.'+k, + root+'/'+fields[k]['string'])) - if (fields[k]['type'] in recur) and (level>0): - res.extend(get(fields[k]['relation'], level-1, - recur, root_tech+'.'+k, root+'/'+fields[k]['string'])) + if (fields[k]['type'] in recur) and (level>0): + res.extend(get(fields[k]['relation'], level-1, + recur, root_tech+'.'+k, root+'/'+fields[k]['string'])) - return res + return res - res = [("False", "False"), ("True", "True"), ("user.id", "User")] - res += get('res.users', level=1, - recur=['many2one'], root_tech='user', root='User') - return res + res = [("False", "False"), ("True", "True"), ("user.id", "User")] + res += get('res.users', level=1, + recur=['many2one'], root_tech='user', root='User') + return res - def _domain_force_get(self, cr, uid, ids, field_name, arg, context={}): - res = {} - for rule in self.browse(cr, uid, ids, context): - if rule.domain_force: - res[rule.id] = eval(rule.domain_force, {'user': self.pool.get('res.users').browse(cr, 1, uid), - 'time':time}) - else: - if rule.operator in ('in', 'child_of'): - dom = eval("[('%s', '%s', [%s])]" % (rule.field_id.name, rule.operator, - rule.operand), {'user': self.pool.get('res.users').browse(cr, 1, uid), - 'time':time}) - else: - dom = eval("[('%s', '%s', %s)]" % (rule.field_id.name, rule.operator, - rule.operand), {'user': self.pool.get('res.users').browse(cr, 1, uid), - 'time':time}) - res[rule.id] = dom - return res + def _domain_force_get(self, cr, uid, ids, field_name, arg, context={}): + res = {} + for rule in self.browse(cr, uid, ids, context): + if rule.domain_force: + res[rule.id] = eval(rule.domain_force, {'user': self.pool.get('res.users').browse(cr, 1, uid), + 'time':time}) + else: + if rule.operator in ('in', 'child_of'): + dom = eval("[('%s', '%s', [%s])]" % (rule.field_id.name, rule.operator, + rule.operand), {'user': self.pool.get('res.users').browse(cr, 1, uid), + 'time':time}) + else: + dom = eval("[('%s', '%s', %s)]" % (rule.field_id.name, rule.operator, + rule.operand), {'user': self.pool.get('res.users').browse(cr, 1, uid), + 'time':time}) + res[rule.id] = dom + return res - _columns = { - 'field_id': fields.many2one('ir.model.fields', 'Field',domain= "[('model_id','=', parent.model_id)]", select=1, required=True), - 'operator':fields.selection((('=', '='), ('<>', '<>'), ('<=', '<='), ('>=', '>='), ('in', 'in'), ('child_of', 'child_of')), 'Operator', required=True), - 'operand':fields.selection(_operand,'Operand', size=64, required=True), - 'rule_group': fields.many2one('ir.rule.group', 'Group', select=2, required=True, ondelete="cascade"), - 'domain_force': fields.char('Force Domain', size=250), - 'domain': fields.function(_domain_force_get, method=True, string='Domain', type='char', size=250) - } + _columns = { + 'field_id': fields.many2one('ir.model.fields', 'Field',domain= "[('model_id','=', parent.model_id)]", select=1, required=True), + 'operator':fields.selection((('=', '='), ('<>', '<>'), ('<=', '<='), ('>=', '>='), ('in', 'in'), ('child_of', 'child_of')), 'Operator', required=True), + 'operand':fields.selection(_operand,'Operand', size=64, required=True), + 'rule_group': fields.many2one('ir.rule.group', 'Group', select=2, required=True, ondelete="cascade"), + 'domain_force': fields.char('Force Domain', size=250), + 'domain': fields.function(_domain_force_get, method=True, string='Domain', type='char', size=250) + } - def onchange_all(self, cr, uid, ids, field_id, operator, operand): - if not (field_id or operator or operand): - return {} + def onchange_all(self, cr, uid, ids, field_id, operator, operand): + if not (field_id or operator or operand): + return {} - def domain_get(self, cr, uid, model_name): - # root user above constraint - if uid == 1: - return '', [] + def domain_get(self, cr, uid, model_name): + # root user above constraint + if uid == 1: + return '', [] - cr.execute("""SELECT r.id FROM - ir_rule r - JOIN (ir_rule_group g - JOIN ir_model m ON (g.model_id = m.id)) - ON (g.id = r.rule_group) - WHERE m.model = %s - AND (g.id IN (SELECT rule_group_id FROM group_rule_group_rel g_rel - JOIN res_groups_users_rel u_rel ON (g_rel.group_id = u_rel.gid) - WHERE u_rel.uid = %d) OR g.global)""", (model_name, uid)) - ids = map(lambda x:x[0], cr.fetchall()) - if not ids: - return '', [] - obj = self.pool.get(model_name) - add = [] - add_str = [] - sub = [] - sub_str = [] - clause={} - clause_global={} - for rule in self.browse(cr, uid, ids): - dom = rule.domain - if rule.rule_group['global']: - clause_global.setdefault(rule.rule_group.id, []) - clause_global[rule.rule_group.id].append(obj._where_calc(cr, uid, dom, active_test=False)) - else: - clause.setdefault(rule.rule_group.id, []) - clause[rule.rule_group.id].append(obj._where_calc(cr, uid, dom, active_test=False)) + cr.execute("""SELECT r.id FROM + ir_rule r + JOIN (ir_rule_group g + JOIN ir_model m ON (g.model_id = m.id)) + ON (g.id = r.rule_group) + WHERE m.model = %s + AND (g.id IN (SELECT rule_group_id FROM group_rule_group_rel g_rel + JOIN res_groups_users_rel u_rel ON (g_rel.group_id = u_rel.gid) + WHERE u_rel.uid = %d) OR g.global)""", (model_name, uid)) + ids = map(lambda x:x[0], cr.fetchall()) + if not ids: + return '', [] + obj = self.pool.get(model_name) + add = [] + add_str = [] + sub = [] + sub_str = [] + clause={} + clause_global={} + for rule in self.browse(cr, uid, ids): + dom = rule.domain + if rule.rule_group['global']: + clause_global.setdefault(rule.rule_group.id, []) + clause_global[rule.rule_group.id].append(obj._where_calc(cr, uid, dom, active_test=False)) + else: + clause.setdefault(rule.rule_group.id, []) + clause[rule.rule_group.id].append(obj._where_calc(cr, uid, dom, active_test=False)) - def _query(clause, test): - query = '' - val = [] - for g in clause.values(): - if not g: - continue - if len(query): - query += ' '+test+' ' - query += '(' - first = True - for c in g: - if not first: - query += ' AND ' - first = False - query += '(' - first2 = True - for clause in c[0]: - if not first2: - query += ' AND ' - first2 = False - query += clause - query += ')' - val += c[1] - query += ')' - return query, val + def _query(clause, test): + query = '' + val = [] + for g in clause.values(): + if not g: + continue + if len(query): + query += ' '+test+' ' + query += '(' + first = True + for c in g: + if not first: + query += ' AND ' + first = False + query += '(' + first2 = True + for clause in c[0]: + if not first2: + query += ' AND ' + first2 = False + query += clause + query += ')' + val += c[1] + query += ')' + return query, val - query, val = _query(clause, 'OR') - query_global, val_global = _query(clause_global, 'OR') - if query_global: - if query: - query = '('+query+') OR '+query_global - val.extend(val_global) - else: - query = query_global - val = val_global + query, val = _query(clause, 'OR') + query_global, val_global = _query(clause_global, 'OR') + if query_global: + if query: + query = '('+query+') OR '+query_global + val.extend(val_global) + else: + query = query_global + val = val_global - if query: - query = '('+query+')' - return query, val - domain_get = tools.cache()(domain_get) + if query: + query = '('+query+')' + return query, val + domain_get = tools.cache()(domain_get) - def unlink(self, cr, uid, ids, context=None): - res = super(ir_rule, self).unlink(cr, uid, ids, context=context) - # Restart the cache on the domain_get method of ir.rule - self.domain_get() - return res + def unlink(self, cr, uid, ids, context=None): + res = super(ir_rule, self).unlink(cr, uid, ids, context=context) + # Restart the cache on the domain_get method of ir.rule + self.domain_get() + return res - def create(self, cr, user, vals, context=None): - res = super(ir_rule, self).create(cr, user, vals, context=context) - # Restart the cache on the domain_get method of ir.rule - self.domain_get() - return res + def create(self, cr, user, vals, context=None): + res = super(ir_rule, self).create(cr, user, vals, context=context) + # Restart the cache on the domain_get method of ir.rule + self.domain_get() + return res - def write(self, cr, uid, ids, vals, context=None): - if not context: - context={} - res = super(ir_rule, self).write(cr, uid, ids, vals, context=context) - # Restart the cache on the domain_get method - self.domain_get() - return res + def write(self, cr, uid, ids, vals, context=None): + if not context: + context={} + res = super(ir_rule, self).write(cr, uid, ids, vals, context=context) + # Restart the cache on the domain_get method + self.domain_get() + return res ir_rule() diff --git a/bin/addons/base/ir/ir_sequence.py b/bin/addons/base/ir/ir_sequence.py index c8941f5c324..7eff555ab10 100644 --- a/bin/addons/base/ir/ir_sequence.py +++ b/bin/addons/base/ir/ir_sequence.py @@ -31,52 +31,52 @@ import time from osv import fields,osv class ir_sequence_type(osv.osv): - _name = 'ir.sequence.type' - _columns = { - 'name': fields.char('Sequence Name',size=64, required=True), - 'code': fields.char('Sequence Code',size=32, required=True), - } + _name = 'ir.sequence.type' + _columns = { + 'name': fields.char('Sequence Name',size=64, required=True), + 'code': fields.char('Sequence Code',size=32, required=True), + } ir_sequence_type() def _code_get(self, cr, uid, context={}): - cr.execute('select code, name from ir_sequence_type') - return cr.fetchall() + cr.execute('select code, name from ir_sequence_type') + return cr.fetchall() class ir_sequence(osv.osv): - _name = 'ir.sequence' - _columns = { - 'name': fields.char('Sequence Name',size=64, required=True), - 'code': fields.selection(_code_get, 'Sequence Code',size=64, required=True), - 'active': fields.boolean('Active'), - 'prefix': fields.char('Prefix',size=64), - 'suffix': fields.char('Suffix',size=64), - 'number_next': fields.integer('Next Number', required=True), - 'number_increment': fields.integer('Increment Number', required=True), - 'padding' : fields.integer('Number padding', required=True), - } - _defaults = { - 'active': lambda *a: True, - 'number_increment': lambda *a: 1, - 'number_next': lambda *a: 1, - 'padding' : lambda *a : 0, - } + _name = 'ir.sequence' + _columns = { + 'name': fields.char('Sequence Name',size=64, required=True), + 'code': fields.selection(_code_get, 'Sequence Code',size=64, required=True), + 'active': fields.boolean('Active'), + 'prefix': fields.char('Prefix',size=64), + 'suffix': fields.char('Suffix',size=64), + 'number_next': fields.integer('Next Number', required=True), + 'number_increment': fields.integer('Increment Number', required=True), + 'padding' : fields.integer('Number padding', required=True), + } + _defaults = { + 'active': lambda *a: True, + 'number_increment': lambda *a: 1, + 'number_next': lambda *a: 1, + 'padding' : lambda *a : 0, + } - def _process(self, s): - return (s or '') % {'year':time.strftime('%Y'), 'month': time.strftime('%m'), 'day':time.strftime('%d')} + def _process(self, s): + return (s or '') % {'year':time.strftime('%Y'), 'month': time.strftime('%m'), 'day':time.strftime('%d')} - def get_id(self, cr, uid, sequence_id, test='id=%d'): - cr.execute('lock table ir_sequence') - cr.execute('select id,number_next,number_increment,prefix,suffix,padding from ir_sequence where '+test+' and active=True', (sequence_id,)) - res = cr.dictfetchone() - if res: - cr.execute('update ir_sequence set number_next=number_next+number_increment where id=%d and active=True', (res['id'],)) - if res['number_next']: - return self._process(res['prefix']) + '%%0%sd' % res['padding'] % res['number_next'] + self._process(res['suffix']) - else: - return self._process(res['prefix']) + self._process(res['suffix']) - return False + def get_id(self, cr, uid, sequence_id, test='id=%d'): + cr.execute('lock table ir_sequence') + cr.execute('select id,number_next,number_increment,prefix,suffix,padding from ir_sequence where '+test+' and active=True', (sequence_id,)) + res = cr.dictfetchone() + if res: + cr.execute('update ir_sequence set number_next=number_next+number_increment where id=%d and active=True', (res['id'],)) + if res['number_next']: + return self._process(res['prefix']) + '%%0%sd' % res['padding'] % res['number_next'] + self._process(res['suffix']) + else: + return self._process(res['prefix']) + self._process(res['suffix']) + return False - def get(self, cr, uid, code): - return self.get_id(cr, uid, code, test='code=%s') + def get(self, cr, uid, code): + return self.get_id(cr, uid, code, test='code=%s') ir_sequence() diff --git a/bin/addons/base/ir/ir_translation.py b/bin/addons/base/ir/ir_translation.py index ac87f08d76a..bda2654b033 100644 --- a/bin/addons/base/ir/ir_translation.py +++ b/bin/addons/base/ir/ir_translation.py @@ -32,131 +32,131 @@ from osv.osv import Cacheable import tools TRANSLATION_TYPE = [ - ('field', 'Field'), - ('model', 'Model'), - ('rml', 'RML'), - ('selection', 'Selection'), - ('view', 'View'), - ('wizard_button', 'Wizard Button'), - ('wizard_field', 'Wizard Field'), - ('wizard_view', 'Wizard View'), - ('xsl', 'XSL'), - ('help', 'Help'), - ('code', 'Code'), - ('constraint', 'Constraint'), + ('field', 'Field'), + ('model', 'Model'), + ('rml', 'RML'), + ('selection', 'Selection'), + ('view', 'View'), + ('wizard_button', 'Wizard Button'), + ('wizard_field', 'Wizard Field'), + ('wizard_view', 'Wizard View'), + ('xsl', 'XSL'), + ('help', 'Help'), + ('code', 'Code'), + ('constraint', 'Constraint'), ] class ir_translation(osv.osv, Cacheable): - _name = "ir.translation" - _log_access = False + _name = "ir.translation" + _log_access = False - def _get_language(self, cr, uid, context): - lang_obj = self.pool.get('res.lang') - lang_ids = lang_obj.search(cr, uid, [('translatable', '=', True)], - context=context) - langs = lang_obj.browse(cr, uid, lang_ids, context=context) - res = [(lang.code, lang.name) for lang in langs] - for lang_dict in tools.scan_languages(): - if lang_dict not in res: - res.append(lang_dict) - return res + def _get_language(self, cr, uid, context): + lang_obj = self.pool.get('res.lang') + lang_ids = lang_obj.search(cr, uid, [('translatable', '=', True)], + context=context) + langs = lang_obj.browse(cr, uid, lang_ids, context=context) + res = [(lang.code, lang.name) for lang in langs] + for lang_dict in tools.scan_languages(): + if lang_dict not in res: + res.append(lang_dict) + return res - _columns = { - 'name': fields.char('Field Name', size=128, required=True), - 'res_id': fields.integer('Resource ID'), - 'lang': fields.selection(_get_language, string='Language', size=5), - 'type': fields.selection(TRANSLATION_TYPE, string='Type', size=16), - 'src': fields.text('Source'), - 'value': fields.text('Translation Value'), - } - _sql = """ - create index ir_translation_ltn on ir_translation (lang,type,name); - create index ir_translation_res_id on ir_translation (res_id); - """ + _columns = { + 'name': fields.char('Field Name', size=128, required=True), + 'res_id': fields.integer('Resource ID'), + 'lang': fields.selection(_get_language, string='Language', size=5), + 'type': fields.selection(TRANSLATION_TYPE, string='Type', size=16), + 'src': fields.text('Source'), + 'value': fields.text('Translation Value'), + } + _sql = """ + create index ir_translation_ltn on ir_translation (lang,type,name); + create index ir_translation_res_id on ir_translation (res_id); + """ - def _get_ids(self, cr, uid, name, tt, lang, ids): - translations, to_fetch = {}, [] - for id in ids: - trans = self.get((lang, name, id)) - if trans is not None: - translations[id] = trans - else: - to_fetch.append(id) - if to_fetch: - cr.execute('select res_id,value ' \ - 'from ir_translation ' \ - 'where lang=%s ' \ - 'and type=%s ' \ - 'and name=%s ' \ - 'and res_id in ('+','.join(map(str, to_fetch))+')', - (lang,tt,name)) - for res_id, value in cr.fetchall(): - self.add((lang, tt, name, res_id), value) - translations[res_id] = value - for res_id in ids: - if res_id not in translations: - self.add((lang, tt, name, res_id), False) - translations[res_id] = False - return translations + def _get_ids(self, cr, uid, name, tt, lang, ids): + translations, to_fetch = {}, [] + for id in ids: + trans = self.get((lang, name, id)) + if trans is not None: + translations[id] = trans + else: + to_fetch.append(id) + if to_fetch: + cr.execute('select res_id,value ' \ + 'from ir_translation ' \ + 'where lang=%s ' \ + 'and type=%s ' \ + 'and name=%s ' \ + 'and res_id in ('+','.join(map(str, to_fetch))+')', + (lang,tt,name)) + for res_id, value in cr.fetchall(): + self.add((lang, tt, name, res_id), value) + translations[res_id] = value + for res_id in ids: + if res_id not in translations: + self.add((lang, tt, name, res_id), False) + translations[res_id] = False + return translations - def _set_ids(self, cr, uid, name, tt, lang, ids, value): - cr.execute('delete from ir_translation ' \ - 'where lang=%s ' \ - 'and type=%s ' \ - 'and name=%s ' \ - 'and res_id in ('+','.join(map(str,ids))+')', - (lang,tt,name)) - for id in ids: - self.create(cr, uid, { - 'lang':lang, - 'type':tt, - 'name':name, - 'res_id':id, - 'value':value, - }) - return len(ids) + def _set_ids(self, cr, uid, name, tt, lang, ids, value): + cr.execute('delete from ir_translation ' \ + 'where lang=%s ' \ + 'and type=%s ' \ + 'and name=%s ' \ + 'and res_id in ('+','.join(map(str,ids))+')', + (lang,tt,name)) + for id in ids: + self.create(cr, uid, { + 'lang':lang, + 'type':tt, + 'name':name, + 'res_id':id, + 'value':value, + }) + return len(ids) - def _get_source(self, cr, uid, name, tt, lang, source=None): - trans = self.get((lang, tt, name, source)) - if trans is not None: - return trans + def _get_source(self, cr, uid, name, tt, lang, source=None): + trans = self.get((lang, tt, name, source)) + if trans is not None: + return trans - if source: - #if isinstance(source, unicode): - # source = source.encode('utf8') - cr.execute('select value ' \ - 'from ir_translation ' \ - 'where lang=%s ' \ - 'and type=%s ' \ - 'and name=%s ' \ - 'and src=%s', - (lang, tt, str(name), source)) - else: - cr.execute('select value ' \ - 'from ir_translation ' \ - 'where lang=%s ' \ - 'and type=%s ' \ - 'and name=%s', - (lang, tt, str(name))) - res = cr.fetchone() - - trad = res and res[0] or '' - self.add((lang, tt, name, source), trad) - return trad + if source: + #if isinstance(source, unicode): + # source = source.encode('utf8') + cr.execute('select value ' \ + 'from ir_translation ' \ + 'where lang=%s ' \ + 'and type=%s ' \ + 'and name=%s ' \ + 'and src=%s', + (lang, tt, str(name), source)) + else: + cr.execute('select value ' \ + 'from ir_translation ' \ + 'where lang=%s ' \ + 'and type=%s ' \ + 'and name=%s', + (lang, tt, str(name))) + res = cr.fetchone() + + trad = res and res[0] or '' + self.add((lang, tt, name, source), trad) + return trad - def unlink(self, cursor, user, ids, context=None): - self.clear() - return super(ir_translation, self).unlink(cusor, user, ids, - context=context) + def unlink(self, cursor, user, ids, context=None): + self.clear() + return super(ir_translation, self).unlink(cusor, user, ids, + context=context) - def create(self, cursor, user, vals, context=None): - self.clear() - return super(ir_translation, self).create(cursor, user, vals, - context=context) + def create(self, cursor, user, vals, context=None): + self.clear() + return super(ir_translation, self).create(cursor, user, vals, + context=context) - def write(self, cursor, user, ids, vals, context=None): - self.clear() - return super(ir_translation, self).write(cursor, user, ids, vals, - context=context) + def write(self, cursor, user, ids, vals, context=None): + self.clear() + return super(ir_translation, self).write(cursor, user, ids, vals, + context=context) ir_translation() diff --git a/bin/addons/base/ir/ir_ui_menu.py b/bin/addons/base/ir/ir_ui_menu.py index 13445bb8df9..2fa9268776c 100644 --- a/bin/addons/base/ir/ir_ui_menu.py +++ b/bin/addons/base/ir/ir_ui_menu.py @@ -32,12 +32,12 @@ from osv.orm import browse_null, browse_record import re def one_in(setA, setB): - """Check the presence of an element of setA in setB - """ - for x in setA: - if x in setB: - return True - return False + """Check the presence of an element of setA in setB + """ + for x in setA: + if x in setB: + return True + return False icons = map(lambda x: (x,x), ['STOCK_ABOUT', 'STOCK_ADD', 'STOCK_APPLY', 'STOCK_BOLD', 'STOCK_CANCEL', 'STOCK_CDROM', 'STOCK_CLEAR', 'STOCK_CLOSE', 'STOCK_COLOR_PICKER', @@ -68,143 +68,143 @@ icons = map(lambda x: (x,x), ['STOCK_ABOUT', 'STOCK_ADD', 'STOCK_APPLY', 'STOCK_ ]) class many2many_unique(fields.many2many): - def set(self, cr, obj, id, name, values, user=None, context=None): - if not values: - return - val = values[:] - for act in values: - if act[0]==4: - cr.execute('SELECT * FROM '+self._rel+' \ - WHERE '+self._id1+'=%d AND '+self._id2+'=%d', (id, act[1])) - if cr.fetchall(): - val.remove(act) - return super(many2many_unique, self).set(cr, obj, id, name, val, user=user, - context=context) + def set(self, cr, obj, id, name, values, user=None, context=None): + if not values: + return + val = values[:] + for act in values: + if act[0]==4: + cr.execute('SELECT * FROM '+self._rel+' \ + WHERE '+self._id1+'=%d AND '+self._id2+'=%d', (id, act[1])) + if cr.fetchall(): + val.remove(act) + return super(many2many_unique, self).set(cr, obj, id, name, val, user=user, + context=context) class ir_ui_menu(osv.osv): - _name = 'ir.ui.menu' - 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) - if uid==1: - return ids - user_groups = self.pool.get('res.users').read(cr, uid, [uid])[0]['groups_id'] - result = [] - for menu in self.browse(cr, uid, ids): - if not len(menu.groups_id): - result.append(menu.id) - continue - for g in menu.groups_id: - if g.id in user_groups: - result.append(menu.id) - break - return result + _name = 'ir.ui.menu' + 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) + if uid==1: + return ids + user_groups = self.pool.get('res.users').read(cr, uid, [uid])[0]['groups_id'] + result = [] + for menu in self.browse(cr, uid, ids): + if not len(menu.groups_id): + result.append(menu.id) + continue + for g in menu.groups_id: + if g.id in user_groups: + result.append(menu.id) + break + return result - def _get_full_name(self, cr, uid, ids, name, args, context): - res = {} - for m in self.browse(cr, uid, ids, context=context): - res[m.id] = self._get_one_full_name(m) - return res + def _get_full_name(self, cr, uid, ids, name, args, context): + res = {} + for m in self.browse(cr, uid, ids, context=context): + res[m.id] = self._get_one_full_name(m) + return res - def _get_one_full_name(self, menu, level=6): - if level<=0: - return '...' - if menu.parent_id: - parent_path = self._get_one_full_name(menu.parent_id, level-1) + "/" - else: - parent_path = '' - return parent_path + menu.name + def _get_one_full_name(self, menu, level=6): + if level<=0: + return '...' + if menu.parent_id: + parent_path = self._get_one_full_name(menu.parent_id, level-1) + "/" + else: + parent_path = '' + return parent_path + menu.name - 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) - datas=self.read(cr,uid,[res],['name'])[0] - rex=re.compile('\([0-9]+\)') - concat=rex.findall(datas['name']) - if concat: - next_num=eval(concat[0])+1 - datas['name']=rex.sub(('(%d)'%next_num),datas['name']) - else: - datas['name']=datas['name']+'(1)' - self.write(cr,uid,[res],{'name':datas['name']}) - ids = ir_values_obj.search(cr, uid, [ - ('model', '=', 'ir.ui.menu'), - ('res_id', '=', id), - ]) - for iv in ir_values_obj.browse(cr, uid, ids): - new_id = ir_values_obj.copy(cr, uid, iv.id, - default={'res_id': res}, context=context) - return res + 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) + datas=self.read(cr,uid,[res],['name'])[0] + rex=re.compile('\([0-9]+\)') + concat=rex.findall(datas['name']) + if concat: + next_num=eval(concat[0])+1 + datas['name']=rex.sub(('(%d)'%next_num),datas['name']) + else: + datas['name']=datas['name']+'(1)' + self.write(cr,uid,[res],{'name':datas['name']}) + ids = ir_values_obj.search(cr, uid, [ + ('model', '=', 'ir.ui.menu'), + ('res_id', '=', id), + ]) + for iv in ir_values_obj.browse(cr, uid, ids): + new_id = ir_values_obj.copy(cr, uid, iv.id, + default={'res_id': res}, context=context) + return res - def _action(self, cursor, user, ids, name, arg, context=None): - res = {} - values_obj = self.pool.get('ir.values') - value_ids = values_obj.search(cursor, user, [ - ('model', '=', self._name), ('key', '=', 'action'), - ('key2', '=', 'tree_but_open'), ('res_id', 'in', ids)], - context=context) - values_action = {} - for value in values_obj.browse(cursor, user, value_ids, - context=context): - values_action[value.res_id] = value.value - for menu_id in ids: - res[menu_id] = values_action.get(menu_id, False) - return res + def _action(self, cursor, user, ids, name, arg, context=None): + res = {} + values_obj = self.pool.get('ir.values') + value_ids = values_obj.search(cursor, user, [ + ('model', '=', self._name), ('key', '=', 'action'), + ('key2', '=', 'tree_but_open'), ('res_id', 'in', ids)], + context=context) + values_action = {} + for value in values_obj.browse(cursor, user, value_ids, + context=context): + values_action[value.res_id] = value.value + for menu_id in ids: + res[menu_id] = values_action.get(menu_id, False) + return res - def _action_inv(self, cursor, user, menu_id, name, value, arg, context=None): - if context is None: - context = {} - ctx = context.copy() - if 'read_delta' in ctx: - del ctx['read_delta'] - values_obj = self.pool.get('ir.values') - values_ids = values_obj.search(cursor, user, [ - ('model', '=', self._name), ('key', '=', 'action'), - ('key2', '=', 'tree_but_open'), ('res_id', '=', menu_id)], - context=context) - if values_ids: - values_obj.write(cursor, user, values_ids[0], {'value': value}, - context=ctx) - else: - values_obj.create(cursor, user, { - 'name': 'Menuitem', - 'model': self._name, - 'value': value, - 'object': True, - 'key': 'action', - 'key2': 'tree_but_open', - 'res_id': menu_id, - }, context=ctx) + def _action_inv(self, cursor, user, menu_id, name, value, arg, context=None): + if context is None: + context = {} + ctx = context.copy() + if 'read_delta' in ctx: + del ctx['read_delta'] + values_obj = self.pool.get('ir.values') + values_ids = values_obj.search(cursor, user, [ + ('model', '=', self._name), ('key', '=', 'action'), + ('key2', '=', 'tree_but_open'), ('res_id', '=', menu_id)], + context=context) + if values_ids: + values_obj.write(cursor, user, values_ids[0], {'value': value}, + context=ctx) + else: + values_obj.create(cursor, user, { + 'name': 'Menuitem', + 'model': self._name, + 'value': value, + 'object': True, + 'key': 'action', + 'key2': 'tree_but_open', + 'res_id': menu_id, + }, context=ctx) - _columns = { - 'name': fields.char('Menu', size=64, required=True, translate=True), - 'sequence': fields.integer('Sequence'), - 'child_id' : fields.one2many('ir.ui.menu', 'parent_id','Child ids'), - 'parent_id': fields.many2one('ir.ui.menu', 'Parent Menu', select=True), - 'groups_id': many2many_unique('res.groups', 'ir_ui_menu_group_rel', - 'menu_id', 'gid', 'Groups'), - 'complete_name': fields.function(_get_full_name, method=True, - string='Complete Name', type='char', size=128), - 'icon': fields.selection(icons, 'Icon', size=64), - 'action': fields.function(_action, fnct_inv=_action_inv, - method=True, type='reference', string='Action', - selection=[ - ('ir.actions.report.custom', 'ir.actions.report.custom'), - ('ir.actions.report.xml', 'ir.actions.report.xml'), - ('ir.actions.act_window', 'ir.actions.act_window'), - ('ir.actions.wizard', 'ir.actions.wizard'), + _columns = { + 'name': fields.char('Menu', size=64, required=True, translate=True), + 'sequence': fields.integer('Sequence'), + 'child_id' : fields.one2many('ir.ui.menu', 'parent_id','Child ids'), + 'parent_id': fields.many2one('ir.ui.menu', 'Parent Menu', select=True), + 'groups_id': many2many_unique('res.groups', 'ir_ui_menu_group_rel', + 'menu_id', 'gid', 'Groups'), + 'complete_name': fields.function(_get_full_name, method=True, + string='Complete Name', type='char', size=128), + 'icon': fields.selection(icons, 'Icon', size=64), + 'action': fields.function(_action, fnct_inv=_action_inv, + method=True, type='reference', string='Action', + selection=[ + ('ir.actions.report.custom', 'ir.actions.report.custom'), + ('ir.actions.report.xml', 'ir.actions.report.xml'), + ('ir.actions.act_window', 'ir.actions.act_window'), + ('ir.actions.wizard', 'ir.actions.wizard'), ('ir.actions.url', 'ir.actions.act_url'), - ]), - } - _defaults = { - 'icon' : lambda *a: 'STOCK_OPEN', - 'sequence' : lambda *a: 10 - } - _order = "sequence,id" + ]), + } + _defaults = { + 'icon' : lambda *a: 'STOCK_OPEN', + 'sequence' : lambda *a: 10 + } + _order = "sequence,id" ir_ui_menu() diff --git a/bin/addons/base/ir/ir_ui_view.py b/bin/addons/base/ir/ir_ui_view.py index 2ab5fa16895..75d93f04d3a 100644 --- a/bin/addons/base/ir/ir_ui_view.py +++ b/bin/addons/base/ir/ir_ui_view.py @@ -34,89 +34,89 @@ import netsvc import os def _check_xml(self, cr, uid, ids, context={}): - for view in self.browse(cr, uid, ids, context): - eview = etree.fromstring(view.arch) - frng = tools.file_open(os.path.join('base','rng',view.type+'.rng')) - relaxng = etree.RelaxNG(file=frng) - if not relaxng.validate(eview): - logger = netsvc.Logger() - logger.notifyChannel('init', netsvc.LOG_ERROR, 'The view do not fit the required schema !') - logger.notifyChannel('init', netsvc.LOG_ERROR, relaxng.error_log.last_error) - print view.arch - return False - return True + for view in self.browse(cr, uid, ids, context): + eview = etree.fromstring(view.arch) + frng = tools.file_open(os.path.join('base','rng',view.type+'.rng')) + relaxng = etree.RelaxNG(file=frng) + if not relaxng.validate(eview): + logger = netsvc.Logger() + logger.notifyChannel('init', netsvc.LOG_ERROR, 'The view do not fit the required schema !') + logger.notifyChannel('init', netsvc.LOG_ERROR, relaxng.error_log.last_error) + print view.arch + return False + return True class view(osv.osv): - _name = 'ir.ui.view' - _columns = { - 'name': fields.char('View Name',size=64, required=True), - 'model': fields.char('Model', size=64, required=True), - 'priority': fields.integer('Priority', required=True), - 'type': fields.selection(( - ('tree','Tree'), - ('form','Form'), - ('graph', 'Graph'), - ('calendar', 'Calendar')), 'View Type', required=True), - 'arch': fields.text('View Architecture', required=True), - 'inherit_id': fields.many2one('ir.ui.view', 'Inherited View'), - 'field_parent': fields.char('Childs Field',size=64), - } - _defaults = { - 'arch': lambda *a: '\n\n\t\n', - 'priority': lambda *a: 16 - } - _order = "priority" - _constraints = [ - (_check_xml, 'Invalid XML for View Architecture!', ['arch']) - ] + _name = 'ir.ui.view' + _columns = { + 'name': fields.char('View Name',size=64, required=True), + 'model': fields.char('Model', size=64, required=True), + 'priority': fields.integer('Priority', required=True), + 'type': fields.selection(( + ('tree','Tree'), + ('form','Form'), + ('graph', 'Graph'), + ('calendar', 'Calendar')), 'View Type', required=True), + 'arch': fields.text('View Architecture', required=True), + 'inherit_id': fields.many2one('ir.ui.view', 'Inherited View'), + 'field_parent': fields.char('Childs Field',size=64), + } + _defaults = { + 'arch': lambda *a: '\n\n\t\n', + 'priority': lambda *a: 16 + } + _order = "priority" + _constraints = [ + (_check_xml, 'Invalid XML for View Architecture!', ['arch']) + ] view() #class UserView(osv.osv): -# _name = 'ir.ui.view.user' -# _columns = { -# 'name': fields.char('View Name',size=64, required=True), -# 'model': fields.char('Model', size=64, required=True), -# 'priority': fields.integer('Priority', required=True), -# 'type': fields.selection(( -# ('tree','Tree'), -# ('form','Form'), -# ('graph', 'Graph'), -# ('calendar', 'Calendar')), 'View Type', required=True), -# 'arch': fields.text('View Architecture', required=True), -# 'inherit_id': fields.many2one('ir.ui.view', 'Inherited View'), -# 'field_parent': fields.char('Childs Field',size=64), -# 'user_id': fields.many2one('res.users', 'User'), -# 'ref_id': fields.many2one('ir.ui.view', 'Inherited View'), -# } -# _defaults = { -# 'arch': lambda *a: '\n\n\t\n', -# 'priority': lambda *a: 16 -# } -# _order = "priority" -# _constraints = [ -# (_check_xml, 'Invalid XML for View Architecture!', ['arch']) -# ] +# _name = 'ir.ui.view.user' +# _columns = { +# 'name': fields.char('View Name',size=64, required=True), +# 'model': fields.char('Model', size=64, required=True), +# 'priority': fields.integer('Priority', required=True), +# 'type': fields.selection(( +# ('tree','Tree'), +# ('form','Form'), +# ('graph', 'Graph'), +# ('calendar', 'Calendar')), 'View Type', required=True), +# 'arch': fields.text('View Architecture', required=True), +# 'inherit_id': fields.many2one('ir.ui.view', 'Inherited View'), +# 'field_parent': fields.char('Childs Field',size=64), +# 'user_id': fields.many2one('res.users', 'User'), +# 'ref_id': fields.many2one('ir.ui.view', 'Inherited View'), +# } +# _defaults = { +# 'arch': lambda *a: '\n\n\t\n', +# 'priority': lambda *a: 16 +# } +# _order = "priority" +# _constraints = [ +# (_check_xml, 'Invalid XML for View Architecture!', ['arch']) +# ] # #UserView() class view_sc(osv.osv): - _name = 'ir.ui.view_sc' - _columns = { - 'name': fields.char('Shortcut Name', size=64, required=True), - 'res_id': fields.many2one('ir.values','Resource Ref.', ondelete='cascade'), - 'sequence': fields.integer('Sequence'), - 'user_id': fields.many2one('res.users', 'User Ref.', required=True, ondelete='cascade'), - 'resource': fields.char('Resource Name', size=64, required=True) - } + _name = 'ir.ui.view_sc' + _columns = { + 'name': fields.char('Shortcut Name', size=64, required=True), + 'res_id': fields.many2one('ir.values','Resource Ref.', ondelete='cascade'), + 'sequence': fields.integer('Sequence'), + 'user_id': fields.many2one('res.users', 'User Ref.', required=True, ondelete='cascade'), + 'resource': fields.char('Resource Name', size=64, required=True) + } - def get_sc(self, cr, uid, user_id, model='ir.ui.menu', context={}): - ids = self.search(cr, uid, [('user_id','=',user_id),('resource','=',model)], context=context) - return self.read(cr, uid, ids, ['res_id','name'], context=context) + def get_sc(self, cr, uid, user_id, model='ir.ui.menu', context={}): + ids = self.search(cr, uid, [('user_id','=',user_id),('resource','=',model)], context=context) + return self.read(cr, uid, ids, ['res_id','name'], context=context) - _order = 'sequence' - _defaults = { - 'resource': lambda *a: 'ir.ui.menu', - 'user_id': lambda obj, cr, uid, context: uid, - } + _order = 'sequence' + _defaults = { + 'resource': lambda *a: 'ir.ui.menu', + 'user_id': lambda obj, cr, uid, context: uid, + } view_sc() diff --git a/bin/addons/base/ir/ir_values.py b/bin/addons/base/ir/ir_values.py index 84fafefa3f4..2681e562ec7 100644 --- a/bin/addons/base/ir/ir_values.py +++ b/bin/addons/base/ir/ir_values.py @@ -32,221 +32,221 @@ import pickle from tools.translate import _ class ir_values(osv.osv): - _name = 'ir.values' + _name = 'ir.values' - def _value_unpickle(self, cursor, user, ids, name, arg, context=None): - res = {} - for report in self.browse(cursor, user, ids, context=context): - value = report[name[:-9]] - if not report.object and value: - try: - value = str(pickle.loads(value)) - except: - pass - res[report.id] = value - return res + def _value_unpickle(self, cursor, user, ids, name, arg, context=None): + res = {} + for report in self.browse(cursor, user, ids, context=context): + value = report[name[:-9]] + if not report.object and value: + try: + value = str(pickle.loads(value)) + except: + pass + res[report.id] = value + return res - def _value_pickle(self, cursor, user, id, name, value, arg, context=None): - if context is None: - context = {} - ctx = context.copy() - if 'read_delta' in ctx: - del ctx['read_delta'] - if not self.browse(cursor, user, id, context=context).object: - value = pickle.dumps(eval(value)) - self.write(cursor, user, id, {name[:-9]: value}, context=ctx) + def _value_pickle(self, cursor, user, id, name, value, arg, context=None): + if context is None: + context = {} + ctx = context.copy() + if 'read_delta' in ctx: + del ctx['read_delta'] + if not self.browse(cursor, user, id, context=context).object: + value = pickle.dumps(eval(value)) + self.write(cursor, user, id, {name[:-9]: value}, context=ctx) - _columns = { - 'name': fields.char('Name', size=128), - 'model': fields.char('Model', size=128), - 'value': fields.text('Value'), - 'value_unpickle': fields.function(_value_unpickle, fnct_inv=_value_pickle, - method=True, type='text', string='Value'), - 'object': fields.boolean('Is Object'), - 'key': fields.char('Type', size=128), - 'key2': fields.char('Value', size=256), - 'meta': fields.text('Meta Datas'), - 'meta_unpickle': fields.function(_value_unpickle, fnct_inv=_value_pickle, - method=True, type='text', string='Meta Datas'), - 'res_id': fields.integer('Resource ID'), - 'user_id': fields.many2one('res.users', 'User', ondelete='cascade'), - 'company_id': fields.many2one('res.company', 'Company') - } - _defaults = { - 'key': lambda *a: 'action', - 'key2': lambda *a: 'tree_but_open', - 'company_id': lambda *a: False - } + _columns = { + 'name': fields.char('Name', size=128), + 'model': fields.char('Model', size=128), + 'value': fields.text('Value'), + 'value_unpickle': fields.function(_value_unpickle, fnct_inv=_value_pickle, + method=True, type='text', string='Value'), + 'object': fields.boolean('Is Object'), + 'key': fields.char('Type', size=128), + 'key2': fields.char('Value', size=256), + 'meta': fields.text('Meta Datas'), + 'meta_unpickle': fields.function(_value_unpickle, fnct_inv=_value_pickle, + method=True, type='text', string='Meta Datas'), + 'res_id': fields.integer('Resource ID'), + 'user_id': fields.many2one('res.users', 'User', ondelete='cascade'), + 'company_id': fields.many2one('res.company', 'Company') + } + _defaults = { + 'key': lambda *a: 'action', + 'key2': lambda *a: 'tree_but_open', + 'company_id': lambda *a: False + } - def _auto_init(self, cr, context={}): - super(ir_values, self)._auto_init(cr, context) - cr.execute('SELECT indexname FROM pg_indexes WHERE indexname = \'ir_values_key_model_key2_index\'') - if not cr.fetchone(): - cr.execute('CREATE INDEX ir_values_key_model_key2_index ON ir_values (key, model, key2)') - cr.commit() + def _auto_init(self, cr, context={}): + super(ir_values, self)._auto_init(cr, context) + cr.execute('SELECT indexname FROM pg_indexes WHERE indexname = \'ir_values_key_model_key2_index\'') + if not cr.fetchone(): + cr.execute('CREATE INDEX ir_values_key_model_key2_index ON ir_values (key, model, key2)') + cr.commit() - def set(self, cr, uid, key, key2, name, models, value, replace=True, isobject=False, meta=False, preserve_user=False, company=False): - if type(value)==type(u''): - value = value.encode('utf8') - if not isobject: - value = pickle.dumps(value) - if meta: - meta = pickle.dumps(meta) - ids_res = [] - for model in models: - if type(model)==type([]) or type(model)==type(()): - model,res_id = model - else: - res_id=False - if replace: - if key in ('meta', 'default'): - ids = self.search(cr, uid, [ - ('key', '=', key), - ('key2', '=', key2), - ('name', '=', name), - ('model', '=', model), - ('res_id', '=', res_id), - ('user_id', '=', preserve_user and uid) - ]) - else: - ids = self.search(cr, uid, [ - ('key', '=', key), - ('key2', '=', key2), - ('value', '=', value), - ('model', '=', model), - ('res_id', '=', res_id), - ('user_id', '=', preserve_user and uid) - ]) - self.unlink(cr, uid, ids) - vals = { - 'name': name, - 'value': value, - 'model': model, - 'object': isobject, - 'key': key, - 'key2': key2 and key2[:200], - 'meta': meta, - 'user_id': preserve_user and uid, - } - if company: - cid = self.pool.get('res.users').browse(cr, uid, uid, context={}).company_id.id - vals['company_id']=cid - if res_id: - vals['res_id']= res_id - ids_res.append(self.create(cr, uid, vals)) - return ids_res + def set(self, cr, uid, key, key2, name, models, value, replace=True, isobject=False, meta=False, preserve_user=False, company=False): + if type(value)==type(u''): + value = value.encode('utf8') + if not isobject: + value = pickle.dumps(value) + if meta: + meta = pickle.dumps(meta) + ids_res = [] + for model in models: + if type(model)==type([]) or type(model)==type(()): + model,res_id = model + else: + res_id=False + if replace: + if key in ('meta', 'default'): + ids = self.search(cr, uid, [ + ('key', '=', key), + ('key2', '=', key2), + ('name', '=', name), + ('model', '=', model), + ('res_id', '=', res_id), + ('user_id', '=', preserve_user and uid) + ]) + else: + ids = self.search(cr, uid, [ + ('key', '=', key), + ('key2', '=', key2), + ('value', '=', value), + ('model', '=', model), + ('res_id', '=', res_id), + ('user_id', '=', preserve_user and uid) + ]) + self.unlink(cr, uid, ids) + vals = { + 'name': name, + 'value': value, + 'model': model, + 'object': isobject, + 'key': key, + 'key2': key2 and key2[:200], + 'meta': meta, + 'user_id': preserve_user and uid, + } + if company: + cid = self.pool.get('res.users').browse(cr, uid, uid, context={}).company_id.id + vals['company_id']=cid + if res_id: + vals['res_id']= res_id + ids_res.append(self.create(cr, uid, vals)) + return ids_res - def get(self, cr, uid, key, key2, models, meta=False, context={}, res_id_req=False, without_user=True, key2_req=True): - result = [] - for m in models: - if type(m)==type([]) or type(m)==type(()): - m,res_id = m - else: - res_id=False - - where1 = ['key=%s','model=%s'] - where2 = [key,str(m)] - where_opt = [] - if key2: - where1.append('key2=%s') - where2.append(key2[:200]) - else: - dest = where1 - if not key2_req or meta: - dest=where_opt - dest.append('key2 is null') + def get(self, cr, uid, key, key2, models, meta=False, context={}, res_id_req=False, without_user=True, key2_req=True): + result = [] + for m in models: + if type(m)==type([]) or type(m)==type(()): + m,res_id = m + else: + res_id=False + + where1 = ['key=%s','model=%s'] + where2 = [key,str(m)] + where_opt = [] + if key2: + where1.append('key2=%s') + where2.append(key2[:200]) + else: + dest = where1 + if not key2_req or meta: + dest=where_opt + dest.append('key2 is null') - if res_id_req and (models[-1][0]==m): - if res_id: - where1.append('res_id=%d' % (res_id,)) - else: - where1.append('(res_id is NULL)') - elif res_id: - if (models[-1][0]==m): - where1.append('(res_id=%d or (res_id is null))' % (res_id,)) - where_opt.append('res_id=%d' % (res_id,)) - else: - where1.append('res_id=%d' % (res_id,)) + if res_id_req and (models[-1][0]==m): + if res_id: + where1.append('res_id=%d' % (res_id,)) + else: + where1.append('(res_id is NULL)') + elif res_id: + if (models[-1][0]==m): + where1.append('(res_id=%d or (res_id is null))' % (res_id,)) + where_opt.append('res_id=%d' % (res_id,)) + else: + where1.append('res_id=%d' % (res_id,)) -# if not without_user: - where_opt.append('user_id=%d' % (uid,)) +# if not without_user: + where_opt.append('user_id=%d' % (uid,)) - result = [] - ok = True - while ok: - if not where_opt: - cr.execute('select id from ir_values where ' +\ - ' and '.join(where1)+' and user_id is null', where2) - else: - cr.execute('select id from ir_values where ' +\ - ' and '.join(where1+where_opt), where2) - result.extend([x[0] for x in cr.fetchall()]) - if len(where_opt): - where_opt.pop() - else: - ok = False + result = [] + ok = True + while ok: + if not where_opt: + cr.execute('select id from ir_values where ' +\ + ' and '.join(where1)+' and user_id is null', where2) + else: + cr.execute('select id from ir_values where ' +\ + ' and '.join(where1+where_opt), where2) + result.extend([x[0] for x in cr.fetchall()]) + if len(where_opt): + where_opt.pop() + else: + ok = False - if result: - break + if result: + break - if not result: - return [] - cid = self.pool.get('res.users').browse(cr, uid, uid, context={}).company_id.id - cr.execute('select id,name,value,object,meta, key ' \ - 'from ir_values ' \ - 'where id in ('+','.join(map(str,result))+') ' \ - 'and (company_id is null or company_id = %d) '\ - 'ORDER BY user_id', (cid,)) - result = cr.fetchall() - - def _result_get(x, keys): - if x[1] in keys: - return False - keys.append(x[1]) - if x[3]: - model,id = x[2].split(',') - try: - id = int(id) - datas = self.pool.get(model).read(cr, uid, [id], False, context) - except: - return False - if not len(datas): - #ir_del(cr, uid, x[0]) - return False - def clean(x): - for key in ('report_sxw_content', 'report_rml_content', - 'report_sxw', 'report_rml', 'report_sxw_content_data', - 'report_rml_content_data'): - if key in x: - del x[key] - return x - datas = clean(datas[0]) - else: - datas = pickle.loads(x[2]) - if meta: - meta2 = pickle.loads(x[4]) - return (x[0],x[1],datas,meta2) - return (x[0],x[1],datas) - keys = [] - res = filter(bool, map(lambda x: _result_get(x, keys), list(result))) - res2 = res[:] - for r in res: - if type(r) == type([]): - if r[2]['type'] == 'ir.actions.report.xml' or r[2]['type'] == 'ir.actions.report.xml': - print - if r[2].has_key('groups_id'): - groups = r[2]['groups_id'] - if len(groups) > 0: - group_ids = ','.join([ str(x) for x in r[2]['groups_id']]) - cr.execute("select count(*) from res_groups_users_rel where gid in (%s) and uid='%s'" % (group_ids, uid)) - gr_ids = cr.fetchall() - if not gr_ids[0][0] > 0: - res2.remove(r) - else: - #raise osv.except_osv('Error !','You have not permission to perform operation !!!') - res2.remove(r) - return res2 + if not result: + return [] + cid = self.pool.get('res.users').browse(cr, uid, uid, context={}).company_id.id + cr.execute('select id,name,value,object,meta, key ' \ + 'from ir_values ' \ + 'where id in ('+','.join(map(str,result))+') ' \ + 'and (company_id is null or company_id = %d) '\ + 'ORDER BY user_id', (cid,)) + result = cr.fetchall() + + def _result_get(x, keys): + if x[1] in keys: + return False + keys.append(x[1]) + if x[3]: + model,id = x[2].split(',') + try: + id = int(id) + datas = self.pool.get(model).read(cr, uid, [id], False, context) + except: + return False + if not len(datas): + #ir_del(cr, uid, x[0]) + return False + def clean(x): + for key in ('report_sxw_content', 'report_rml_content', + 'report_sxw', 'report_rml', 'report_sxw_content_data', + 'report_rml_content_data'): + if key in x: + del x[key] + return x + datas = clean(datas[0]) + else: + datas = pickle.loads(x[2]) + if meta: + meta2 = pickle.loads(x[4]) + return (x[0],x[1],datas,meta2) + return (x[0],x[1],datas) + keys = [] + res = filter(bool, map(lambda x: _result_get(x, keys), list(result))) + res2 = res[:] + for r in res: + if type(r) == type([]): + if r[2]['type'] == 'ir.actions.report.xml' or r[2]['type'] == 'ir.actions.report.xml': + print + if r[2].has_key('groups_id'): + groups = r[2]['groups_id'] + if len(groups) > 0: + group_ids = ','.join([ str(x) for x in r[2]['groups_id']]) + cr.execute("select count(*) from res_groups_users_rel where gid in (%s) and uid='%s'" % (group_ids, uid)) + gr_ids = cr.fetchall() + if not gr_ids[0][0] > 0: + res2.remove(r) + else: + #raise osv.except_osv('Error !','You have not permission to perform operation !!!') + res2.remove(r) + return res2 ir_values() diff --git a/bin/addons/base/ir/wizard/wizard_menu.py b/bin/addons/base/ir/wizard/wizard_menu.py index 966bb84430b..32d25e3c849 100644 --- a/bin/addons/base/ir/wizard/wizard_menu.py +++ b/bin/addons/base/ir/wizard/wizard_menu.py @@ -30,57 +30,57 @@ from osv import fields,osv class wizard_model_menu(osv.osv_memory): - _name = 'wizard.ir.model.menu.create' - _columns = { - 'model_id': fields.many2one('ir.model','Model', required=True), - 'menu_id': fields.many2one('ir.ui.menu', 'Parent Menu', required=True), - 'name': fields.char('Menu Name', size=64, required=True), - 'view_ids': fields.one2many('wizard.ir.model.menu.create.line', 'wizard_id', 'Views'), - } - _defaults = { - 'model_id': lambda self,cr,uid,ctx: ctx.get('model_id', False) - } - def menu_create(self, cr, uid, ids, context={}): - for menu in self.browse(cr, uid, ids, context): - view_mode = [] - views = [] - for view in menu.view_ids: - view_mode.append(view.view_type) - views.append( (0,0,{ - 'view_id': view.view_id and view.view_id.id or False, - 'view_mode': view.view_type, - 'sequence': view.sequence - })) - val = { - 'name': menu.name, - 'res_model': menu.model_id.model, - 'view_type': 'form', - 'view_mode': ','.join(view_mode) - } - if views: - val['view_ids'] = views - else: - val['view_mode'] = 'tree,form' - action_id = self.pool.get('ir.actions.act_window').create(cr, uid, val) - self.pool.get('ir.ui.menu').create(cr, uid, { - 'name': menu.name, - 'parent_id': menu.menu_id.id, - 'action': 'ir.actions.act_window,%d' % (action_id,), - 'icon': 'STOCK_INDENT' - }, context) - return {'type':'ir.actions.act_window_close'} + _name = 'wizard.ir.model.menu.create' + _columns = { + 'model_id': fields.many2one('ir.model','Model', required=True), + 'menu_id': fields.many2one('ir.ui.menu', 'Parent Menu', required=True), + 'name': fields.char('Menu Name', size=64, required=True), + 'view_ids': fields.one2many('wizard.ir.model.menu.create.line', 'wizard_id', 'Views'), + } + _defaults = { + 'model_id': lambda self,cr,uid,ctx: ctx.get('model_id', False) + } + def menu_create(self, cr, uid, ids, context={}): + for menu in self.browse(cr, uid, ids, context): + view_mode = [] + views = [] + for view in menu.view_ids: + view_mode.append(view.view_type) + views.append( (0,0,{ + 'view_id': view.view_id and view.view_id.id or False, + 'view_mode': view.view_type, + 'sequence': view.sequence + })) + val = { + 'name': menu.name, + 'res_model': menu.model_id.model, + 'view_type': 'form', + 'view_mode': ','.join(view_mode) + } + if views: + val['view_ids'] = views + else: + val['view_mode'] = 'tree,form' + action_id = self.pool.get('ir.actions.act_window').create(cr, uid, val) + self.pool.get('ir.ui.menu').create(cr, uid, { + 'name': menu.name, + 'parent_id': menu.menu_id.id, + 'action': 'ir.actions.act_window,%d' % (action_id,), + 'icon': 'STOCK_INDENT' + }, context) + return {'type':'ir.actions.act_window_close'} wizard_model_menu() class wizard_model_menu_line(osv.osv_memory): - _name = 'wizard.ir.model.menu.create.line' - _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_id': fields.many2one('ir.ui.view', 'View'), - } - _defaults = { - 'view_type': lambda self,cr,uid,ctx: 'tree' - } + _name = 'wizard.ir.model.menu.create.line' + _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_id': fields.many2one('ir.ui.view', 'View'), + } + _defaults = { + 'view_type': lambda self,cr,uid,ctx: 'tree' + } wizard_model_menu_line() diff --git a/bin/addons/base/ir/workflow/print_instance.py b/bin/addons/base/ir/workflow/print_instance.py index 74f2bd31733..428df57ac0e 100644 --- a/bin/addons/base/ir/workflow/print_instance.py +++ b/bin/addons/base/ir/workflow/print_instance.py @@ -34,175 +34,175 @@ import report,pooler,tools def graph_get(cr, graph, wkf_id, nested=False, workitem={}): - import pydot - cr.execute('select * from wkf_activity where wkf_id=%d', (wkf_id,)) - nodes = cr.dictfetchall() - activities = {} - actfrom = {} - actto = {} - for n in nodes: - activities[n['id']] = n - if n['subflow_id'] and nested: - cr.execute('select * from wkf where id=%d', (n['subflow_id'],)) - wkfinfo = cr.dictfetchone() - graph2 = pydot.Cluster('subflow'+str(n['subflow_id']), fontsize=12, label = "Subflow: "+n['name']+'\\nOSV: '+wkfinfo['osv']) - (s1,s2) = graph_get(cr, graph2, n['subflow_id'], nested,workitem) - graph.add_subgraph(graph2) - actfrom[n['id']] = s2 - actto[n['id']] = s1 - else: - args = {} - if n['flow_start'] or n['flow_stop']: - args['style']='filled' - args['color']='lightgrey' - args['label']=n['name'] - if n['subflow_id']: - args['shape'] = 'box' - if n['id'] in workitem: - args['label']+='\\nx '+str(workitem[n['id']]) - args['color'] = "red" - graph.add_node(pydot.Node(n['id'], **args)) - actfrom[n['id']] = (n['id'],{}) - actto[n['id']] = (n['id'],{}) - cr.execute('select * from wkf_transition where act_from in ('+','.join(map(lambda x: str(x['id']),nodes))+')') - transitions = cr.dictfetchall() - for t in transitions: - args = {} - args['label'] = str(t['condition']).replace(' or ', '\\nor ').replace(' and ', '\\nand ') - if t['signal']: - args['label'] += '\\n'+str(t['signal']) - args['style'] = 'bold' + import pydot + cr.execute('select * from wkf_activity where wkf_id=%d', (wkf_id,)) + nodes = cr.dictfetchall() + activities = {} + actfrom = {} + actto = {} + for n in nodes: + activities[n['id']] = n + if n['subflow_id'] and nested: + cr.execute('select * from wkf where id=%d', (n['subflow_id'],)) + wkfinfo = cr.dictfetchone() + graph2 = pydot.Cluster('subflow'+str(n['subflow_id']), fontsize=12, label = "Subflow: "+n['name']+'\\nOSV: '+wkfinfo['osv']) + (s1,s2) = graph_get(cr, graph2, n['subflow_id'], nested,workitem) + graph.add_subgraph(graph2) + actfrom[n['id']] = s2 + actto[n['id']] = s1 + else: + args = {} + if n['flow_start'] or n['flow_stop']: + args['style']='filled' + args['color']='lightgrey' + args['label']=n['name'] + if n['subflow_id']: + args['shape'] = 'box' + if n['id'] in workitem: + args['label']+='\\nx '+str(workitem[n['id']]) + args['color'] = "red" + graph.add_node(pydot.Node(n['id'], **args)) + actfrom[n['id']] = (n['id'],{}) + actto[n['id']] = (n['id'],{}) + cr.execute('select * from wkf_transition where act_from in ('+','.join(map(lambda x: str(x['id']),nodes))+')') + transitions = cr.dictfetchall() + for t in transitions: + args = {} + args['label'] = str(t['condition']).replace(' or ', '\\nor ').replace(' and ', '\\nand ') + if t['signal']: + args['label'] += '\\n'+str(t['signal']) + args['style'] = 'bold' - if activities[t['act_from']]['split_mode']=='AND': - args['arrowtail']='box' - elif str(activities[t['act_from']]['split_mode'])=='OR ': - args['arrowtail']='inv' + if activities[t['act_from']]['split_mode']=='AND': + args['arrowtail']='box' + elif str(activities[t['act_from']]['split_mode'])=='OR ': + args['arrowtail']='inv' - if activities[t['act_to']]['join_mode']=='AND': - args['arrowhead']='crow' + if activities[t['act_to']]['join_mode']=='AND': + args['arrowhead']='crow' - activity_from = actfrom[t['act_from']][1].get(t['signal'], actfrom[t['act_from']][0]) - activity_to = actto[t['act_to']][1].get(t['signal'], actto[t['act_to']][0]) - graph.add_edge(pydot.Edge( activity_from ,activity_to, fontsize=10, **args)) - nodes = cr.dictfetchall() - cr.execute('select id from wkf_activity where flow_start=True and wkf_id=%d limit 1', (wkf_id,)) - start = cr.fetchone()[0] - cr.execute("select 'subflow.'||name,id from wkf_activity where flow_stop=True and wkf_id=%d", (wkf_id,)) - stop = cr.fetchall() - stop = (stop[0][1], dict(stop)) - return ((start,{}),stop) + activity_from = actfrom[t['act_from']][1].get(t['signal'], actfrom[t['act_from']][0]) + activity_to = actto[t['act_to']][1].get(t['signal'], actto[t['act_to']][0]) + graph.add_edge(pydot.Edge( activity_from ,activity_to, fontsize=10, **args)) + nodes = cr.dictfetchall() + cr.execute('select id from wkf_activity where flow_start=True and wkf_id=%d limit 1', (wkf_id,)) + start = cr.fetchone()[0] + cr.execute("select 'subflow.'||name,id from wkf_activity where flow_stop=True and wkf_id=%d", (wkf_id,)) + stop = cr.fetchall() + stop = (stop[0][1], dict(stop)) + return ((start,{}),stop) def graph_instance_get(cr, graph, inst_id, nested=False): - workitems = {} - cr.execute('select * from wkf_instance where id=%d', (inst_id,)) - inst = cr.dictfetchone() + workitems = {} + cr.execute('select * from wkf_instance where id=%d', (inst_id,)) + inst = cr.dictfetchone() - def workitem_get(instance): - cr.execute('select act_id,count(*) from wkf_workitem where inst_id=%d group by act_id', (instance,)) - workitems = dict(cr.fetchall()) + def workitem_get(instance): + cr.execute('select act_id,count(*) from wkf_workitem where inst_id=%d group by act_id', (instance,)) + workitems = dict(cr.fetchall()) - cr.execute('select subflow_id from wkf_workitem where inst_id=%d', (instance,)) - for (subflow_id,) in cr.fetchall(): - workitems.update(workitem_get(subflow_id)) - return workitems - graph_get(cr, graph, inst['wkf_id'], nested, workitem_get(inst_id)) + cr.execute('select subflow_id from wkf_workitem where inst_id=%d', (instance,)) + for (subflow_id,) in cr.fetchall(): + workitems.update(workitem_get(subflow_id)) + return workitems + graph_get(cr, graph, inst['wkf_id'], nested, workitem_get(inst_id)) # # TODO: pas clean: concurrent !!! # class report_graph_instance(object): - def __init__(self, cr, uid, ids, data): - logger = netsvc.Logger() - try: - import pydot - except Exception,e: - logger.notifyChannel('workflow', netsvc.LOG_WARNING, - 'Import Error for pydot, you will not be able to render workflows\n' - 'Consider Installing PyDot or dependencies: http://dkbza.org/pydot.html') - raise e - self.done = False + def __init__(self, cr, uid, ids, data): + logger = netsvc.Logger() + try: + import pydot + except Exception,e: + logger.notifyChannel('workflow', netsvc.LOG_WARNING, + 'Import Error for pydot, you will not be able to render workflows\n' + 'Consider Installing PyDot or dependencies: http://dkbza.org/pydot.html') + raise e + self.done = False - try: - cr.execute('select * from wkf where osv=%s limit 1', - (data['model'],)) - wkfinfo = cr.dictfetchone() - if not wkfinfo: - ps_string = '''%PS-Adobe-3.0 + try: + cr.execute('select * from wkf where osv=%s limit 1', + (data['model'],)) + wkfinfo = cr.dictfetchone() + if not wkfinfo: + ps_string = '''%PS-Adobe-3.0 /inch {72 mul} def /Times-Roman findfont 50 scalefont setfont 1.5 inch 15 inch moveto (No workflow defined) show showpage''' - else: - cr.execute('SELECT id FROM wkf_instance \ - WHERE res_id=%d AND wkf_id=%d \ - ORDER BY state LIMIT 1', - (data['id'], wkfinfo['id'])) - inst_id = cr.fetchone() - if not inst_id: - ps_string = '''%PS-Adobe-3.0 + else: + cr.execute('SELECT id FROM wkf_instance \ + WHERE res_id=%d AND wkf_id=%d \ + ORDER BY state LIMIT 1', + (data['id'], wkfinfo['id'])) + inst_id = cr.fetchone() + if not inst_id: + ps_string = '''%PS-Adobe-3.0 /inch {72 mul} def /Times-Roman findfont 50 scalefont setfont 1.5 inch 15 inch moveto (No workflow instance defined) show showpage''' - else: - inst_id = inst_id[0] - graph = pydot.Dot(fontsize=16, label="\\n\\nWorkflow: %s\\n OSV: %s" % (wkfinfo['name'],wkfinfo['osv'])) - graph.set('size', '10.7,7.3') - graph.set('center', '1') - graph.set('ratio', 'auto') - graph.set('rotate', '90') - graph.set('rankdir', 'LR') - graph_instance_get(cr, graph, inst_id, data.get('nested', False)) - ps_string = graph.create_ps(prog='dot') - except Exception, e: - import traceback, sys - tb_s = reduce(lambda x, y: x+y, traceback.format_exception(sys.exc_type, sys.exc_value, sys.exc_traceback)) - logger.notifyChannel('workflow', netsvc.LOG_ERROR, 'Exception in call: ' + tb_s) - # string is in PS, like the success message would have been - ps_string = '''%PS-Adobe-3.0 + else: + inst_id = inst_id[0] + graph = pydot.Dot(fontsize=16, label="\\n\\nWorkflow: %s\\n OSV: %s" % (wkfinfo['name'],wkfinfo['osv'])) + graph.set('size', '10.7,7.3') + graph.set('center', '1') + graph.set('ratio', 'auto') + graph.set('rotate', '90') + graph.set('rankdir', 'LR') + graph_instance_get(cr, graph, inst_id, data.get('nested', False)) + ps_string = graph.create_ps(prog='dot') + except Exception, e: + import traceback, sys + tb_s = reduce(lambda x, y: x+y, traceback.format_exception(sys.exc_type, sys.exc_value, sys.exc_traceback)) + logger.notifyChannel('workflow', netsvc.LOG_ERROR, 'Exception in call: ' + tb_s) + # string is in PS, like the success message would have been + ps_string = '''%PS-Adobe-3.0 /inch {72 mul} def /Times-Roman findfont 50 scalefont setfont 1.5 inch 15 inch moveto (No workflow available) show showpage''' - if os.name == "nt": - prog = 'ps2pdf.bat' - else: - prog = 'ps2pdf' - args = (prog, '-', '-') - input, output = tools.exec_command_pipe(*args) - input.write(ps_string) - input.close() - self.result = output.read() - output.close() - self.done = True + if os.name == "nt": + prog = 'ps2pdf.bat' + else: + prog = 'ps2pdf' + args = (prog, '-', '-') + input, output = tools.exec_command_pipe(*args) + input.write(ps_string) + input.close() + self.result = output.read() + output.close() + self.done = True - def is_done(self): - return self.done + def is_done(self): + return self.done - def get(self): - if self.done: - return self.result - else: - return None + def get(self): + if self.done: + return self.result + else: + return None class report_graph(report.interface.report_int): - def __init__(self, name, table): - report.interface.report_int.__init__(self, name) - self.table = table + def __init__(self, name, table): + report.interface.report_int.__init__(self, name) + self.table = table - def result(self): - if self.obj.is_done(): - return (True, self.obj.get(), 'pdf') - else: - return (False, False, False) + def result(self): + if self.obj.is_done(): + return (True, self.obj.get(), 'pdf') + else: + return (False, False, False) - def create(self, cr, uid, ids, data, context={}): - self.obj = report_graph_instance(cr, uid, ids, data) - return (self.obj.get(), 'pdf') + def create(self, cr, uid, ids, data, context={}): + self.obj = report_graph_instance(cr, uid, ids, data) + return (self.obj.get(), 'pdf') report_graph('report.workflow.instance.graph', 'ir.workflow') diff --git a/bin/addons/base/ir/workflow/pydot/__init__.py b/bin/addons/base/ir/workflow/pydot/__init__.py old mode 100755 new mode 100644 diff --git a/bin/addons/base/ir/workflow/pydot/dot_parser.py b/bin/addons/base/ir/workflow/pydot/dot_parser.py old mode 100755 new mode 100644 index 30007ed47de..67a763144c7 --- a/bin/addons/base/ir/workflow/pydot/dot_parser.py +++ b/bin/addons/base/ir/workflow/pydot/dot_parser.py @@ -14,339 +14,339 @@ import glob import pydot from pyparsing import __version__ as pyparsing_version -from pyparsing import Literal, CaselessLiteral, Word, \ - Upcase, OneOrMore, ZeroOrMore, Forward, NotAny, \ - delimitedList, oneOf, Group, Optional, Combine, \ - alphas, nums, restOfLine, cStyleComment, nums, \ - alphanums, printables, empty, quotedString, \ - ParseException, ParseResults, CharsNotIn, _noncomma +from pyparsing import Literal, CaselessLiteral, Word, \ + Upcase, OneOrMore, ZeroOrMore, Forward, NotAny, \ + delimitedList, oneOf, Group, Optional, Combine, \ + alphas, nums, restOfLine, cStyleComment, nums, \ + alphanums, printables, empty, quotedString, \ + ParseException, ParseResults, CharsNotIn, _noncomma class P_AttrList: - def __init__(self, toks): - self.attrs = {} - i = 0 - while i < len(toks): - attrname = toks[i] - attrvalue = toks[i+1] - self.attrs[attrname] = attrvalue - i += 2 + def __init__(self, toks): + self.attrs = {} + i = 0 + while i < len(toks): + attrname = toks[i] + attrvalue = toks[i+1] + self.attrs[attrname] = attrvalue + i += 2 - def __repr__(self): - return "%s(%r)" % (self.__class__.__name__, self.attrs) + def __repr__(self): + return "%s(%r)" % (self.__class__.__name__, self.attrs) class DefaultStatement(P_AttrList): - def __init__(self, default_type, attrs): - self.default_type = default_type - self.attrs = attrs + def __init__(self, default_type, attrs): + self.default_type = default_type + self.attrs = attrs - def __repr__(self): - return "%s(%s, %r)" % \ - (self.__class__.__name__, self.default_type, self.attrs) + def __repr__(self): + return "%s(%s, %r)" % \ + (self.__class__.__name__, self.default_type, self.attrs) def push_top_graph_stmt(str, loc, toks): - attrs = {} - g = None - - for element in toks: - if isinstance(element, ParseResults) or \ - isinstance(element, tuple) or \ - isinstance(element, list): - - element = element[0] + attrs = {} + g = None + + for element in toks: + if isinstance(element, ParseResults) or \ + isinstance(element, tuple) or \ + isinstance(element, list): + + element = element[0] - if element == 'strict': - attrs['strict'] = True - elif element in ['graph', 'digraph']: - attrs['graph_type'] = element - elif type(element) == type(''): - attrs['graph_name'] = element - elif isinstance(element, pydot.Graph): - g = pydot.Graph(**attrs) - g.__dict__.update(element.__dict__) - for e in g.get_edge_list(): - e.parent_graph = g - for e in g.get_node_list(): - e.parent_graph = g - for e in g.get_subgraph_list(): - e.set_graph_parent(g) + if element == 'strict': + attrs['strict'] = True + elif element in ['graph', 'digraph']: + attrs['graph_type'] = element + elif type(element) == type(''): + attrs['graph_name'] = element + elif isinstance(element, pydot.Graph): + g = pydot.Graph(**attrs) + g.__dict__.update(element.__dict__) + for e in g.get_edge_list(): + e.parent_graph = g + for e in g.get_node_list(): + e.parent_graph = g + for e in g.get_subgraph_list(): + e.set_graph_parent(g) - elif isinstance(element, P_AttrList): - attrs.update(element.attrs) - else: - raise ValueError, "Unknown element statement: %r " % element - - if g is not None: - g.__dict__.update(attrs) - return g + elif isinstance(element, P_AttrList): + attrs.update(element.attrs) + else: + raise ValueError, "Unknown element statement: %r " % element + + if g is not None: + g.__dict__.update(attrs) + return g def add_defaults(element, defaults): - d = element.__dict__ - for key, value in defaults.items(): - if not d.get(key): - d[key] = value + d = element.__dict__ + for key, value in defaults.items(): + if not d.get(key): + d[key] = value def add_elements(g, toks, defaults_graph=None, defaults_node=None, defaults_edge=None): - - if defaults_graph is None: - defaults_graph = {} - if defaults_node is None: - defaults_node = {} - if defaults_edge is None: - defaults_edge = {} - - for element in toks: - if isinstance(element, pydot.Graph): - add_defaults(element, defaults_graph) - g.add_subgraph(element) - elif isinstance(element, pydot.Node): - add_defaults(element, defaults_node) - g.add_node(element) - elif isinstance(element, pydot.Edge): - add_defaults(element, defaults_edge) - g.add_edge(element) - elif isinstance(element, ParseResults): - for e in element: - add_elements(g, [e], defaults_graph, defaults_node, defaults_edge) - elif isinstance(element, DefaultStatement): - if element.default_type == 'graph': - default_graph_attrs = pydot.Node('graph') - default_graph_attrs.__dict__.update(element.attrs) - g.add_node(default_graph_attrs) -# defaults_graph.update(element.attrs) -# g.__dict__.update(element.attrs) - elif element.default_type == 'node': - default_node_attrs = pydot.Node('node') - default_node_attrs.__dict__.update(element.attrs) - g.add_node(default_node_attrs) - #defaults_node.update(element.attrs) - elif element.default_type == 'edge': - default_edge_attrs = pydot.Node('edge') - default_edge_attrs.__dict__.update(element.attrs) - g.add_node(default_edge_attrs) - #defaults_edge.update(element.attrs) - else: - raise ValueError, "Unknown DefaultStatement: %s " % element.default_type - elif isinstance(element, P_AttrList): - g.__dict__.update(element.attrs) - else: - raise ValueError, "Unknown element statement: %r " % element + + if defaults_graph is None: + defaults_graph = {} + if defaults_node is None: + defaults_node = {} + if defaults_edge is None: + defaults_edge = {} + + for element in toks: + if isinstance(element, pydot.Graph): + add_defaults(element, defaults_graph) + g.add_subgraph(element) + elif isinstance(element, pydot.Node): + add_defaults(element, defaults_node) + g.add_node(element) + elif isinstance(element, pydot.Edge): + add_defaults(element, defaults_edge) + g.add_edge(element) + elif isinstance(element, ParseResults): + for e in element: + add_elements(g, [e], defaults_graph, defaults_node, defaults_edge) + elif isinstance(element, DefaultStatement): + if element.default_type == 'graph': + default_graph_attrs = pydot.Node('graph') + default_graph_attrs.__dict__.update(element.attrs) + g.add_node(default_graph_attrs) +# defaults_graph.update(element.attrs) +# g.__dict__.update(element.attrs) + elif element.default_type == 'node': + default_node_attrs = pydot.Node('node') + default_node_attrs.__dict__.update(element.attrs) + g.add_node(default_node_attrs) + #defaults_node.update(element.attrs) + elif element.default_type == 'edge': + default_edge_attrs = pydot.Node('edge') + default_edge_attrs.__dict__.update(element.attrs) + g.add_node(default_edge_attrs) + #defaults_edge.update(element.attrs) + else: + raise ValueError, "Unknown DefaultStatement: %s " % element.default_type + elif isinstance(element, P_AttrList): + g.__dict__.update(element.attrs) + else: + raise ValueError, "Unknown element statement: %r " % element def push_graph_stmt(str, loc, toks): - g = pydot.Subgraph() - add_elements(g, toks) - return g + g = pydot.Subgraph() + add_elements(g, toks) + return g -def push_subgraph_stmt(str, loc, toks): - for e in toks: - if len(e)==3: - g = e[2] - g.set_name(e[1]) +def push_subgraph_stmt(str, loc, toks): + for e in toks: + if len(e)==3: + g = e[2] + g.set_name(e[1]) - return g + return g def push_default_stmt(str, loc, toks): - # The pydot class instances should be marked as - # default statements to be inherited by actual - # graphs, nodes and edges. - # print "push_default_stmt", toks - default_type = toks[0][0] - if len(toks) > 1: - attrs = toks[1].attrs - else: - attrs = {} + # The pydot class instances should be marked as + # default statements to be inherited by actual + # graphs, nodes and edges. + # print "push_default_stmt", toks + default_type = toks[0][0] + if len(toks) > 1: + attrs = toks[1].attrs + else: + attrs = {} - if default_type in ['graph', 'node', 'edge']: - return DefaultStatement(default_type, attrs) - else: - raise ValueError, "Unknown default statement: %r " % toks + if default_type in ['graph', 'node', 'edge']: + return DefaultStatement(default_type, attrs) + else: + raise ValueError, "Unknown default statement: %r " % toks def push_attr_list(str, loc, toks): - p = P_AttrList(toks) - return p + p = P_AttrList(toks) + return p def get_port(node): - if len(node)>1: - if isinstance(node[1], ParseResults): - if len(node[1][0])==2: - if node[1][0][0]==':': - return node[1][0][1] - - return None + if len(node)>1: + if isinstance(node[1], ParseResults): + if len(node[1][0])==2: + if node[1][0][0]==':': + return node[1][0][1] + + return None def push_edge_stmt(str, loc, toks): - - tok_attrs = [a for a in toks if isinstance(a, P_AttrList)] - attrs = {} - for a in tok_attrs: - attrs.update(a.attrs) - - n_prev = toks[0] - e = [] - for n_next in tuple(toks)[2::2]: - port = get_port(n_prev) - if port is not None: - n_prev_port = ':'+port - else: - n_prev_port = '' - - port = get_port(n_next) - if port is not None: - n_next_port = ':'+port - else: - n_next_port = '' - - e.append(pydot.Edge(n_prev[0]+n_prev_port, n_next[0]+n_next_port, **attrs)) - n_prev = n_next - return e + + tok_attrs = [a for a in toks if isinstance(a, P_AttrList)] + attrs = {} + for a in tok_attrs: + attrs.update(a.attrs) + + n_prev = toks[0] + e = [] + for n_next in tuple(toks)[2::2]: + port = get_port(n_prev) + if port is not None: + n_prev_port = ':'+port + else: + n_prev_port = '' + + port = get_port(n_next) + if port is not None: + n_next_port = ':'+port + else: + n_next_port = '' + + e.append(pydot.Edge(n_prev[0]+n_prev_port, n_next[0]+n_next_port, **attrs)) + n_prev = n_next + return e def push_node_stmt(str, loc, toks): - if len(toks) == 2: - attrs = toks[1].attrs - else: - attrs = {} - - node_name = toks[0] - if isinstance(node_name, list) or isinstance(node_name, tuple): - if len(node_name)>0: - node_name = node_name[0] - - n = pydot.Node(node_name, **attrs) - return n + if len(toks) == 2: + attrs = toks[1].attrs + else: + attrs = {} + + node_name = toks[0] + if isinstance(node_name, list) or isinstance(node_name, tuple): + if len(node_name)>0: + node_name = node_name[0] + + n = pydot.Node(node_name, **attrs) + return n def strip_quotes( s, l, t ): - return [ t[0].strip('"') ] + return [ t[0].strip('"') ] graphparser = None def GRAPH_DEF(): - global graphparser - - if not graphparser: - # punctuation - colon = Literal(":") - lbrace = Literal("{") - rbrace = Literal("}") - lbrack = Literal("[") - rbrack = Literal("]") - lparen = Literal("(") - rparen = Literal(")") - equals = Literal("=") - comma = Literal(",") - dot = Literal(".") - slash = Literal("/") - bslash = Literal("\\") - star = Literal("*") - semi = Literal(";") - at = Literal("@") - minus = Literal("-") - - # keywords - strict_ = Literal("strict") - graph_ = Literal("graph") - digraph_ = Literal("digraph") - subgraph_ = Literal("subgraph") - node_ = Literal("node") - edge_ = Literal("edge") - - identifier = Word(alphanums + "_" ).setName("identifier") - - double_quote = Literal('"') - double_quoted_string = \ - Combine( double_quote + ZeroOrMore(CharsNotIn('"')) + double_quote ) + global graphparser + + if not graphparser: + # punctuation + colon = Literal(":") + lbrace = Literal("{") + rbrace = Literal("}") + lbrack = Literal("[") + rbrack = Literal("]") + lparen = Literal("(") + rparen = Literal(")") + equals = Literal("=") + comma = Literal(",") + dot = Literal(".") + slash = Literal("/") + bslash = Literal("\\") + star = Literal("*") + semi = Literal(";") + at = Literal("@") + minus = Literal("-") + + # keywords + strict_ = Literal("strict") + graph_ = Literal("graph") + digraph_ = Literal("digraph") + subgraph_ = Literal("subgraph") + node_ = Literal("node") + edge_ = Literal("edge") + + identifier = Word(alphanums + "_" ).setName("identifier") + + double_quote = Literal('"') + double_quoted_string = \ + Combine( double_quote + ZeroOrMore(CharsNotIn('"')) + double_quote ) - alphastring_ = OneOrMore(CharsNotIn(_noncomma)) + alphastring_ = OneOrMore(CharsNotIn(_noncomma)) - ID = (identifier | double_quoted_string.setParseAction(strip_quotes) |\ - alphastring_).setName("ID") - - html_text = Combine(Literal("<<") + OneOrMore(CharsNotIn(",]"))) - - float_number = Combine(Optional(minus) + \ - OneOrMore(Word(nums + "."))).setName("float_number") - - righthand_id = (float_number | ID | html_text).setName("righthand_id") + ID = (identifier | double_quoted_string.setParseAction(strip_quotes) |\ + alphastring_).setName("ID") + + html_text = Combine(Literal("<<") + OneOrMore(CharsNotIn(",]"))) + + float_number = Combine(Optional(minus) + \ + OneOrMore(Word(nums + "."))).setName("float_number") + + righthand_id = (float_number | ID | html_text).setName("righthand_id") - port_angle = (at + ID).setName("port_angle") - - port_location = (Group(colon + ID) | \ - Group(colon + lparen + ID + comma + ID + rparen)).setName("port_location") - - port = (Group(port_location + Optional(port_angle)) | \ - Group(port_angle + Optional(port_location))).setName("port") - - node_id = (ID + Optional(port)) - a_list = OneOrMore(ID + Optional(equals.suppress() + righthand_id) + \ - Optional(comma.suppress())).setName("a_list") - - attr_list = OneOrMore(lbrack.suppress() + Optional(a_list) + \ - rbrack.suppress()).setName("attr_list") - - attr_stmt = (Group(graph_ | node_ | edge_) + attr_list).setName("attr_stmt") + port_angle = (at + ID).setName("port_angle") + + port_location = (Group(colon + ID) | \ + Group(colon + lparen + ID + comma + ID + rparen)).setName("port_location") + + port = (Group(port_location + Optional(port_angle)) | \ + Group(port_angle + Optional(port_location))).setName("port") + + node_id = (ID + Optional(port)) + a_list = OneOrMore(ID + Optional(equals.suppress() + righthand_id) + \ + Optional(comma.suppress())).setName("a_list") + + attr_list = OneOrMore(lbrack.suppress() + Optional(a_list) + \ + rbrack.suppress()).setName("attr_list") + + attr_stmt = (Group(graph_ | node_ | edge_) + attr_list).setName("attr_stmt") - edgeop = (Literal("--") | Literal("->")).setName("edgeop") + edgeop = (Literal("--") | Literal("->")).setName("edgeop") - stmt_list = Forward() - graph_stmt = Group(lbrace.suppress() + Optional(stmt_list) + \ - rbrace.suppress()).setName("graph_stmt") - - subgraph = (Group(Optional(subgraph_ + Optional(ID)) + graph_stmt) | \ - Group(subgraph_ + ID)).setName("subgraph") - - edgeRHS = OneOrMore(edgeop + Group(node_id | subgraph)) - - edge_stmt = Group(node_id | subgraph) + edgeRHS + Optional(attr_list) + stmt_list = Forward() + graph_stmt = Group(lbrace.suppress() + Optional(stmt_list) + \ + rbrace.suppress()).setName("graph_stmt") + + subgraph = (Group(Optional(subgraph_ + Optional(ID)) + graph_stmt) | \ + Group(subgraph_ + ID)).setName("subgraph") + + edgeRHS = OneOrMore(edgeop + Group(node_id | subgraph)) + + edge_stmt = Group(node_id | subgraph) + edgeRHS + Optional(attr_list) - node_stmt = (node_id + Optional(attr_list) + semi.suppress()).setName("node_stmt") - - assignment = (ID + equals.suppress() + righthand_id).setName("assignment") - stmt = (assignment | edge_stmt | attr_stmt | node_stmt | subgraph).setName("stmt") - stmt_list << OneOrMore(stmt + Optional(semi.suppress())) + node_stmt = (node_id + Optional(attr_list) + semi.suppress()).setName("node_stmt") + + assignment = (ID + equals.suppress() + righthand_id).setName("assignment") + stmt = (assignment | edge_stmt | attr_stmt | node_stmt | subgraph).setName("stmt") + stmt_list << OneOrMore(stmt + Optional(semi.suppress())) - graphparser = (Optional(strict_) + Group((graph_ | digraph_)) + \ - Optional(ID) + graph_stmt).setResultsName("graph") + graphparser = (Optional(strict_) + Group((graph_ | digraph_)) + \ + Optional(ID) + graph_stmt).setResultsName("graph") - singleLineComment = "//" + restOfLine - graphparser.ignore(singleLineComment) - graphparser.ignore(cStyleComment) + singleLineComment = "//" + restOfLine + graphparser.ignore(singleLineComment) + graphparser.ignore(cStyleComment) - assignment.setParseAction(push_attr_list) - a_list.setParseAction(push_attr_list) - edge_stmt.setParseAction(push_edge_stmt) - node_stmt.setParseAction(push_node_stmt) - attr_stmt.setParseAction(push_default_stmt) + assignment.setParseAction(push_attr_list) + a_list.setParseAction(push_attr_list) + edge_stmt.setParseAction(push_edge_stmt) + node_stmt.setParseAction(push_node_stmt) + attr_stmt.setParseAction(push_default_stmt) - subgraph.setParseAction(push_subgraph_stmt) - graph_stmt.setParseAction(push_graph_stmt) - graphparser.setParseAction(push_top_graph_stmt) + subgraph.setParseAction(push_subgraph_stmt) + graph_stmt.setParseAction(push_graph_stmt) + graphparser.setParseAction(push_top_graph_stmt) - return graphparser + return graphparser def parse_dot_data(data): - try: - graphparser = GRAPH_DEF() - if pyparsing_version >= '1.2': - graphparser.parseWithTabs() - tokens = graphparser.parseString(data) - graph = tokens.graph - return graph - except ParseException, err: - print err.line - print " "*(err.column-1) + "^" - print err - return None + try: + graphparser = GRAPH_DEF() + if pyparsing_version >= '1.2': + graphparser.parseWithTabs() + tokens = graphparser.parseString(data) + graph = tokens.graph + return graph + except ParseException, err: + print err.line + print " "*(err.column-1) + "^" + print err + return None diff --git a/bin/addons/base/ir/workflow/pydot/pydot.py b/bin/addons/base/ir/workflow/pydot/pydot.py old mode 100755 new mode 100644 index 947099f3ca0..e793a0a593b --- a/bin/addons/base/ir/workflow/pydot/pydot.py +++ b/bin/addons/base/ir/workflow/pydot/pydot.py @@ -6,12 +6,12 @@ and process graphs in Graphviz's dot language. References: -pydot Homepage: http://www.dkbza.org/pydot.html -Graphviz: http://www.research.att.com/sw/tools/graphviz/ -DOT Language: http://www.research.att.com/~erg/graphviz/info/lang.html +pydot Homepage: http://www.dkbza.org/pydot.html +Graphviz: http://www.research.att.com/sw/tools/graphviz/ +DOT Language: http://www.research.att.com/~erg/graphviz/info/lang.html Programmed and tested with Graphviz 1.12 and Python 2.3.3 on GNU/Linux -by Ero Carrera (c) 2004 [ero@dkbza.org] +by Ero Carrera (c) 2004 [ero@dkbza.org] Distributed under MIT license [http://opensource.org/licenses/mit-license.html]. """ @@ -27,1049 +27,1049 @@ import dot_parser def graph_from_dot_data(data): - """Load graph as defined by data in DOT format. - - The data is assumed to be in DOT format. It will - be parsed and a Dot class will be returned, - representing the graph. - """ - - graph = dot_parser.parse_dot_data(data) - if graph is not None: - dot = Dot() - dot.__dict__.update(graph.__dict__) - return dot - - return None + """Load graph as defined by data in DOT format. + + The data is assumed to be in DOT format. It will + be parsed and a Dot class will be returned, + representing the graph. + """ + + graph = dot_parser.parse_dot_data(data) + if graph is not None: + dot = Dot() + dot.__dict__.update(graph.__dict__) + return dot + + return None def graph_from_dot_file(path): - """Load graph as defined by a DOT file. - - The file is assumed to be in DOT format. It will - be loaded, parsed and a Dot class will be returned, - representing the graph. - """ - - fd = file(path, 'rb') - data = fd.read() - fd.close() - - return graph_from_dot_data(data) + """Load graph as defined by a DOT file. + + The file is assumed to be in DOT format. It will + be loaded, parsed and a Dot class will be returned, + representing the graph. + """ + + fd = file(path, 'rb') + data = fd.read() + fd.close() + + return graph_from_dot_data(data) def graph_from_edges(edge_list, node_prefix='', directed=False): - """Creates a basic graph out of an edge list. - - The edge list has to be a list of tuples representing - the nodes connected by the edge. - The values can be anything: bool, int, float, str. - - If the graph is undirected by default, it is only - calculated from one of the symmetric halves of the matrix. - """ - if directed: - graph = Dot(graph_type='digraph') - else: - graph = Dot(graph_type='graph') - for edge in edge_list: - e = Edge(node_prefix+str(edge[0]), node_prefix+str(edge[1])) - graph.add_edge(e) - return graph + """Creates a basic graph out of an edge list. + + The edge list has to be a list of tuples representing + the nodes connected by the edge. + The values can be anything: bool, int, float, str. + + If the graph is undirected by default, it is only + calculated from one of the symmetric halves of the matrix. + """ + if directed: + graph = Dot(graph_type='digraph') + else: + graph = Dot(graph_type='graph') + for edge in edge_list: + e = Edge(node_prefix+str(edge[0]), node_prefix+str(edge[1])) + graph.add_edge(e) + return graph def graph_from_adjacency_matrix(matrix, node_prefix='', directed=False): - """Creates a basic graph out of an adjacency matrix. - - The matrix has to be a list of rows of values - representing an adjacency matrix. - The values can be anything: bool, int, float, as long - as they can evaluate to True or False. - """ - node_orig = 1 - if directed: - graph = Dot(graph_type='digraph') - else: - graph = Dot(graph_type='graph') - for row in matrix: - if not directed: - skip = matrix.index(row) - r = row[skip:] - else: - skip = 0 - r = row - node_dest = skip+1 - for e in r: - if e: - graph.add_edge( \ - Edge( node_prefix+str(node_orig), \ - node_prefix+str(node_dest))) - node_dest += 1 - node_orig += 1 - return graph + """Creates a basic graph out of an adjacency matrix. + + The matrix has to be a list of rows of values + representing an adjacency matrix. + The values can be anything: bool, int, float, as long + as they can evaluate to True or False. + """ + node_orig = 1 + if directed: + graph = Dot(graph_type='digraph') + else: + graph = Dot(graph_type='graph') + for row in matrix: + if not directed: + skip = matrix.index(row) + r = row[skip:] + else: + skip = 0 + r = row + node_dest = skip+1 + for e in r: + if e: + graph.add_edge( \ + Edge( node_prefix+str(node_orig), \ + node_prefix+str(node_dest))) + node_dest += 1 + node_orig += 1 + return graph def graph_from_incidence_matrix(matrix, node_prefix='', directed=False): - """Creates a basic graph out of an incidence matrix. - - The matrix has to be a list of rows of values - representing an incidence matrix. - The values can be anything: bool, int, float, as long - as they can evaluate to True or False. - """ - node_orig = 1 - if directed: - graph = Dot(graph_type='digraph') - else: - graph = Dot(graph_type='graph') - for row in matrix: - nodes = [] - c = 1 - for node in row: - if node: - nodes.append(c*node) - c += 1 - nodes.sort() - if len(nodes) == 2: - graph.add_edge( \ - Edge(node_prefix+str(abs(nodes[0])), \ - node_prefix+str(nodes[1]) )) - if not directed: - graph.set_simplify(True) - return graph + """Creates a basic graph out of an incidence matrix. + + The matrix has to be a list of rows of values + representing an incidence matrix. + The values can be anything: bool, int, float, as long + as they can evaluate to True or False. + """ + node_orig = 1 + if directed: + graph = Dot(graph_type='digraph') + else: + graph = Dot(graph_type='graph') + for row in matrix: + nodes = [] + c = 1 + for node in row: + if node: + nodes.append(c*node) + c += 1 + nodes.sort() + if len(nodes) == 2: + graph.add_edge( \ + Edge(node_prefix+str(abs(nodes[0])), \ + node_prefix+str(nodes[1]) )) + if not directed: + graph.set_simplify(True) + return graph - + def find_graphviz(): - """Locate Graphviz's executables in the system. + """Locate Graphviz's executables in the system. - Attempts to locate graphviz's executables in a Unix system. - It will look for 'dot', 'twopi' and 'neato' in all the directories - specified in the PATH environment variable. - It will return a dictionary containing the program names as keys - and their paths as values. - """ - progs = {'dot': '', 'twopi': '', 'neato': '', 'circo': '', 'fdp': ''} - if not os.environ.has_key('PATH'): - return None - for path in os.environ['PATH'].split(os.pathsep): - for prg in progs.keys(): - if os.path.exists(path+os.path.sep+prg): - progs[prg] = path+os.path.sep+prg - elif os.path.exists(path+os.path.sep+prg + '.exe'): - progs[prg] = path+os.path.sep+prg + '.exe' - return progs + Attempts to locate graphviz's executables in a Unix system. + It will look for 'dot', 'twopi' and 'neato' in all the directories + specified in the PATH environment variable. + It will return a dictionary containing the program names as keys + and their paths as values. + """ + progs = {'dot': '', 'twopi': '', 'neato': '', 'circo': '', 'fdp': ''} + if not os.environ.has_key('PATH'): + return None + for path in os.environ['PATH'].split(os.pathsep): + for prg in progs.keys(): + if os.path.exists(path+os.path.sep+prg): + progs[prg] = path+os.path.sep+prg + elif os.path.exists(path+os.path.sep+prg + '.exe'): + progs[prg] = path+os.path.sep+prg + '.exe' + return progs class Common: - """Common information to several classes. - - Should not be directly used, several classes are derived from - this one. - """ - chars_ID = None - parent_graph = None - - def char_range(self, a,b): - """Generate a list containing a range of characters. - - Returns a list of characters starting from 'a' up to 'b' - both inclusive. - """ - return map(chr, range(ord(a), ord(b)+1)) - - def is_ID(self, s): - """Checks whether a string is an dot language ID. - - It will check whether the string is solely composed - by the characters allowed in an ID or not. - """ - if not self.chars_ID: - self.chars_ID = self.char_range('a','z')+self.char_range('A','Z')+ \ - self.char_range('0','9')+['_'] - for c in s: - if c not in self.chars_ID: - return False - return True + """Common information to several classes. + + Should not be directly used, several classes are derived from + this one. + """ + chars_ID = None + parent_graph = None + + def char_range(self, a,b): + """Generate a list containing a range of characters. + + Returns a list of characters starting from 'a' up to 'b' + both inclusive. + """ + return map(chr, range(ord(a), ord(b)+1)) + + def is_ID(self, s): + """Checks whether a string is an dot language ID. + + It will check whether the string is solely composed + by the characters allowed in an ID or not. + """ + if not self.chars_ID: + self.chars_ID = self.char_range('a','z')+self.char_range('A','Z')+ \ + self.char_range('0','9')+['_'] + for c in s: + if c not in self.chars_ID: + return False + return True class Error(Exception): - """General error handling class. - """ - def __init__(self, value): - self.value = value - def __str__(self): - return self.value + """General error handling class. + """ + def __init__(self, value): + self.value = value + def __str__(self): + return self.value class Node(object, Common): - """A graph node. - - This class represents a graph's node with all its attributes. - - node(name, attribute=value, ...) - - name: node's name - - All the attributes defined in the Graphviz dot language should - be supported. - """ - attributes = ['showboxes', 'URL', 'fontcolor', 'fontsize', 'label', 'fontname', \ - 'comment', 'root', 'toplabel', 'vertices', 'width', 'z', 'bottomlabel', \ - 'distortion', 'fixedsize', 'group', 'height', 'orientation', 'pin', \ - 'rects', 'regular', 'shape', 'shapefile', 'sides', 'skew', 'pos', \ - 'layer', 'tooltip', 'style', 'target', 'color', 'peripheries', - 'fillcolor'] + """A graph node. + + This class represents a graph's node with all its attributes. + + node(name, attribute=value, ...) + + name: node's name + + All the attributes defined in the Graphviz dot language should + be supported. + """ + attributes = ['showboxes', 'URL', 'fontcolor', 'fontsize', 'label', 'fontname', \ + 'comment', 'root', 'toplabel', 'vertices', 'width', 'z', 'bottomlabel', \ + 'distortion', 'fixedsize', 'group', 'height', 'orientation', 'pin', \ + 'rects', 'regular', 'shape', 'shapefile', 'sides', 'skew', 'pos', \ + 'layer', 'tooltip', 'style', 'target', 'color', 'peripheries', + 'fillcolor'] - def __init__(self, name, **attrs): - - if isinstance(name, str) and not name.startswith('"'): - idx = name.find(':') - if idx>0: - name = name[:idx] - - self.name = str(name) - for attr in self.attributes: - # Set all the attributes to None. - self.__setattr__(attr, None) - # Generate all the Setter methods. - self.__setattr__('set_'+attr, lambda x, a=attr : self.__setattr__(a, x)) - # Generate all the Getter methods. - self.__setattr__('get_'+attr, lambda a=attr : self.__getattribute__(a)) - for attr, val in attrs.items(): - self.__setattr__(attr, val) + def __init__(self, name, **attrs): + + if isinstance(name, str) and not name.startswith('"'): + idx = name.find(':') + if idx>0: + name = name[:idx] + + self.name = str(name) + for attr in self.attributes: + # Set all the attributes to None. + self.__setattr__(attr, None) + # Generate all the Setter methods. + self.__setattr__('set_'+attr, lambda x, a=attr : self.__setattr__(a, x)) + # Generate all the Getter methods. + self.__setattr__('get_'+attr, lambda a=attr : self.__getattribute__(a)) + for attr, val in attrs.items(): + self.__setattr__(attr, val) - def set_name(self, node_name): - """Set the node's name.""" - - self.name = str(node_name) - - def get_name(self): - """Get the node's name.""" - - return self.name + def set_name(self, node_name): + """Set the node's name.""" + + self.name = str(node_name) + + def get_name(self): + """Get the node's name.""" + + return self.name - def set(self, name, value): - """Set an attribute value by name. - - Given an attribute 'name' it will set its value to 'value'. - There's always the possibility of using the methods: - set_'name'(value) - which are defined for all the existing attributes. - """ - if name in self.attributes: - self.__dict__[name] = value - return True - # Attribute is not known - return False + def set(self, name, value): + """Set an attribute value by name. + + Given an attribute 'name' it will set its value to 'value'. + There's always the possibility of using the methods: + set_'name'(value) + which are defined for all the existing attributes. + """ + if name in self.attributes: + self.__dict__[name] = value + return True + # Attribute is not known + return False - def to_string(self): - """Returns a string representation of the node in dot language. - """ - - if not isinstance(self.name, str): - self.name = str(self.name) - - # RMF: special case defaults for node, edge and graph properties. - if self.name in ['node', 'edge', 'graph']: - node = self.name - else: - node = '"'+self.name+'"' + def to_string(self): + """Returns a string representation of the node in dot language. + """ + + if not isinstance(self.name, str): + self.name = str(self.name) + + # RMF: special case defaults for node, edge and graph properties. + if self.name in ['node', 'edge', 'graph']: + node = self.name + else: + node = '"'+self.name+'"' - node_attr = None - all_attrs = [a for a in self.attributes] - all_attrs += [a for a in Graph.attributes if a not in all_attrs] - all_attrs += [a for a in Edge.attributes if a not in all_attrs] - for attr in all_attrs: - if self.__dict__.has_key(attr) \ - and self.__getattribute__(attr) is not None: - if not node_attr: - node_attr = '' - else: - node_attr += ', ' - node_attr += attr+'=' - val = self.__dict__[attr] - - if val.startswith('<') and val.endswith('>'): - node_attr += val - elif (isinstance(val, str) or isinstance(val, unicode)) and not self.is_ID(val): - node_attr += '"'+val+'"' - else: - node_attr += str(val) + node_attr = None + all_attrs = [a for a in self.attributes] + all_attrs += [a for a in Graph.attributes if a not in all_attrs] + all_attrs += [a for a in Edge.attributes if a not in all_attrs] + for attr in all_attrs: + if self.__dict__.has_key(attr) \ + and self.__getattribute__(attr) is not None: + if not node_attr: + node_attr = '' + else: + node_attr += ', ' + node_attr += attr+'=' + val = self.__dict__[attr] + + if val.startswith('<') and val.endswith('>'): + node_attr += val + elif (isinstance(val, str) or isinstance(val, unicode)) and not self.is_ID(val): + node_attr += '"'+val+'"' + else: + node_attr += str(val) - if node_attr: - node += ' ['+node_attr+']' - node += ';' + if node_attr: + node += ' ['+node_attr+']' + node += ';' - return node + return node class Edge(object, Common): - """A graph edge. - - This class represents a graph's edge with all its attributes. - - edge(src, dst, attribute=value, ...) - - src: source node's name - dst: destination node's name - - All the attributes defined in the Graphviz dot language should - be supported. - - Attributes can be set through the dynamically generated methods: - - set_[attribute name], i.e. set_label, set_fontname - - or using the instance's attributes: - - Edge.[attribute name], i.e. edge_instance.label, edge_instance.fontname - """ - attributes = ['style', 'target', 'pos', 'layer', 'tooltip', 'color', 'showboxes',\ - 'URL', 'fontcolor', 'fontsize', 'label', 'fontname', 'comment', 'lp', \ - 'arrowhead', 'arrowsize', 'arrowtail', 'constraint', 'decorate', 'dir', \ - 'headURL', 'headclip', 'headhref', 'headlabel', 'headport', \ - 'headtarget', 'headtooltip', 'href', 'labelangle', 'labeldistance', \ - 'labelfloat', 'labelfontcolor', 'labelfontname', 'labelfontsize', 'len',\ - 'lhead', 'ltail', 'minlen', 'samehead', 'sametail', 'weight', 'tailURL',\ - 'tailclip', 'tailhref', 'taillabel', 'tailport', 'tailtarget', \ - 'tailtooltip'] + """A graph edge. + + This class represents a graph's edge with all its attributes. + + edge(src, dst, attribute=value, ...) + + src: source node's name + dst: destination node's name + + All the attributes defined in the Graphviz dot language should + be supported. + + Attributes can be set through the dynamically generated methods: + + set_[attribute name], i.e. set_label, set_fontname + + or using the instance's attributes: + + Edge.[attribute name], i.e. edge_instance.label, edge_instance.fontname + """ + attributes = ['style', 'target', 'pos', 'layer', 'tooltip', 'color', 'showboxes',\ + 'URL', 'fontcolor', 'fontsize', 'label', 'fontname', 'comment', 'lp', \ + 'arrowhead', 'arrowsize', 'arrowtail', 'constraint', 'decorate', 'dir', \ + 'headURL', 'headclip', 'headhref', 'headlabel', 'headport', \ + 'headtarget', 'headtooltip', 'href', 'labelangle', 'labeldistance', \ + 'labelfloat', 'labelfontcolor', 'labelfontname', 'labelfontsize', 'len',\ + 'lhead', 'ltail', 'minlen', 'samehead', 'sametail', 'weight', 'tailURL',\ + 'tailclip', 'tailhref', 'taillabel', 'tailport', 'tailtarget', \ + 'tailtooltip'] - def __init__(self, src, dst, **attrs): - self.src = src - self.dst = dst - for attr in self.attributes: - # Set all the attributes to None. - self.__setattr__(attr, None) - # Generate all the Setter methods. - self.__setattr__('set_'+attr, lambda x, a=attr : self.__setattr__(a, x)) - # Generate all the Getter methods. - self.__setattr__('get_'+attr, lambda a=attr : self.__getattribute__(a)) - for attr, val in attrs.items(): - self.__setattr__(attr, val) + def __init__(self, src, dst, **attrs): + self.src = src + self.dst = dst + for attr in self.attributes: + # Set all the attributes to None. + self.__setattr__(attr, None) + # Generate all the Setter methods. + self.__setattr__('set_'+attr, lambda x, a=attr : self.__setattr__(a, x)) + # Generate all the Getter methods. + self.__setattr__('get_'+attr, lambda a=attr : self.__getattribute__(a)) + for attr, val in attrs.items(): + self.__setattr__(attr, val) - def get_source(self): - """Get the edges source node name.""" - - return self.src - - def get_destination(self): - """Get the edge's destination node name.""" - - return self.dst - - def __eq__(self, edge): - """Compare two edges. - - If the parent graph is directed, arcs linking - node A to B are considered equal and A->B != B->A - - If the parent graph is undirected, any edge - connecting two nodes is equal to any other - edge connecting the same nodes, A->B == B->A - """ - - if not isinstance(edge, Edge): - raise Error, 'Can\'t compare and edge to a non-edge object.' - if self.parent_graph.graph_type=='graph': - # If the graph is undirected, the edge has neither - # source nor destination. - if (self.src==edge.src and self.dst==edge.dst) or \ - (self.src==edge.dst and self.dst==edge.src): - return True - else: - if self.src==edge.src and self.dst==edge.dst: - return True - return False + def get_source(self): + """Get the edges source node name.""" + + return self.src + + def get_destination(self): + """Get the edge's destination node name.""" + + return self.dst + + def __eq__(self, edge): + """Compare two edges. + + If the parent graph is directed, arcs linking + node A to B are considered equal and A->B != B->A + + If the parent graph is undirected, any edge + connecting two nodes is equal to any other + edge connecting the same nodes, A->B == B->A + """ + + if not isinstance(edge, Edge): + raise Error, 'Can\'t compare and edge to a non-edge object.' + if self.parent_graph.graph_type=='graph': + # If the graph is undirected, the edge has neither + # source nor destination. + if (self.src==edge.src and self.dst==edge.dst) or \ + (self.src==edge.dst and self.dst==edge.src): + return True + else: + if self.src==edge.src and self.dst==edge.dst: + return True + return False - - def set(self, name, value): - """Set an attribute value by name. - - Given an attribute 'name' it will set its value to 'value'. - There's always the possibility of using the methods: - set_'name'(value) - which are defined for all the existing attributes. - """ - if name in self.attributes: - self.__dict__[name] = value - return True - # Attribute is not known - return False + + def set(self, name, value): + """Set an attribute value by name. + + Given an attribute 'name' it will set its value to 'value'. + There's always the possibility of using the methods: + set_'name'(value) + which are defined for all the existing attributes. + """ + if name in self.attributes: + self.__dict__[name] = value + return True + # Attribute is not known + return False - - def parse_node_ref(self, node_str): - - if not isinstance(node_str, str): - node_str = str(node_str) - - if node_str[0]=='"' and node_str[-1]=='"' and node_str[0].count('"')%2!=0: - return node_str - - node_port_idx = node_str.rfind(':') - - if node_port_idx>0 and node_str[0]=='"' and node_str[node_port_idx-1]=='"': - return node_str - - node_str = node_str.replace('"', '') - - if node_port_idx>0: - a = node_str[:node_port_idx] - b = node_str[node_port_idx+1:] - if self.is_ID(a): - node = a - else: - node = '"'+a+'"' - if self.is_ID(b): - node += ':'+b - else: - node+=':"'+b+'"' - return node - - return '"'+node_str+'"' - - - def to_string(self): - """Returns a string representation of the edge in dot language. - """ + + def parse_node_ref(self, node_str): + + if not isinstance(node_str, str): + node_str = str(node_str) + + if node_str[0]=='"' and node_str[-1]=='"' and node_str[0].count('"')%2!=0: + return node_str + + node_port_idx = node_str.rfind(':') + + if node_port_idx>0 and node_str[0]=='"' and node_str[node_port_idx-1]=='"': + return node_str + + node_str = node_str.replace('"', '') + + if node_port_idx>0: + a = node_str[:node_port_idx] + b = node_str[node_port_idx+1:] + if self.is_ID(a): + node = a + else: + node = '"'+a+'"' + if self.is_ID(b): + node += ':'+b + else: + node+=':"'+b+'"' + return node + + return '"'+node_str+'"' + + + def to_string(self): + """Returns a string representation of the edge in dot language. + """ - src = self.parse_node_ref(self.src) - dst = self.parse_node_ref(self.dst) - - edge = src - if self.parent_graph and \ - self.parent_graph.graph_type and \ - self.parent_graph.graph_type=='digraph': - edge+=' -> ' - else: - edge+=' -- ' - edge+=dst + src = self.parse_node_ref(self.src) + dst = self.parse_node_ref(self.dst) + + edge = src + if self.parent_graph and \ + self.parent_graph.graph_type and \ + self.parent_graph.graph_type=='digraph': + edge+=' -> ' + else: + edge+=' -- ' + edge+=dst - edge_attr = None - for attr in self.attributes: - if self.__dict__.has_key(attr) \ - and self.__getattribute__(attr) is not None: - if not edge_attr: - edge_attr = '' - else: - edge_attr+=', ' - edge_attr+=attr+'=' - val = self.__dict__[attr] - if (isinstance(val, str) or isinstance(val, unicode)) and not self.is_ID(val): - edge_attr+='"'+val+'"' - else: - edge_attr+=str(val) + edge_attr = None + for attr in self.attributes: + if self.__dict__.has_key(attr) \ + and self.__getattribute__(attr) is not None: + if not edge_attr: + edge_attr = '' + else: + edge_attr+=', ' + edge_attr+=attr+'=' + val = self.__dict__[attr] + if (isinstance(val, str) or isinstance(val, unicode)) and not self.is_ID(val): + edge_attr+='"'+val+'"' + else: + edge_attr+=str(val) - if edge_attr: - edge+=' ['+edge_attr+']' - edge+=';' + if edge_attr: + edge+=' ['+edge_attr+']' + edge+=';' - return edge - + return edge + class Graph(object, Common): - """Class representing a graph in Graphviz's dot language. + """Class representing a graph in Graphviz's dot language. - This class implements the methods to work on a representation - of a graph in Graphviz's dot language. - - graph(graph_name='G', type='digraph', strict=False, suppress_disconnected=False, attribute=value, ...) - - graph_name: - the graph's name - type: - can be 'graph' or 'digraph' - suppress_disconnected: - defaults to False, which will remove from the - graph any disconnected nodes. - simplify: - if True it will avoid displaying equal edges, i.e. - only one edge between two nodes. removing the - duplicated ones. - - All the attributes defined in the Graphviz dot language should - be supported. - - Attributes can be set through the dynamically generated methods: - - set_[attribute name], i.e. set_size, set_fontname - - or using the instance's attributes: - - Graph.[attribute name], i.e. graph_instance.label, graph_instance.fontname - """ - - attributes = ['Damping', 'bb', 'center', 'clusterrank', 'compound', 'concentrate',\ - 'defaultdist', 'dim', 'fontpath', 'epsilon', 'layers', 'layersep', \ - 'margin', 'maxiter', 'mclimit', 'mindist', 'pack', 'packmode', 'model', \ - 'page', 'pagedir', 'nodesep', 'normalize', 'nslimit1', 'ordering', \ - 'orientation', 'outputorder', 'overlap', 'remincross', 'resolution', \ - 'rankdir', 'ranksep', 'ratio', 'rotate', 'samplepoints', 'searchsize', \ - 'sep', 'size', 'splines', 'start', 'stylesheet', 'truecolor', \ - 'viewport', 'voro_margin', 'quantum', 'bgcolor', 'labeljust', \ - 'labelloc', 'root', 'showboxes', 'URL', 'fontcolor', 'fontsize', \ - 'label' ,'fontname', 'comment', 'lp', 'target', 'color', 'style', \ - 'concentrators'] + This class implements the methods to work on a representation + of a graph in Graphviz's dot language. + + graph(graph_name='G', type='digraph', strict=False, suppress_disconnected=False, attribute=value, ...) + + graph_name: + the graph's name + type: + can be 'graph' or 'digraph' + suppress_disconnected: + defaults to False, which will remove from the + graph any disconnected nodes. + simplify: + if True it will avoid displaying equal edges, i.e. + only one edge between two nodes. removing the + duplicated ones. + + All the attributes defined in the Graphviz dot language should + be supported. + + Attributes can be set through the dynamically generated methods: + + set_[attribute name], i.e. set_size, set_fontname + + or using the instance's attributes: + + Graph.[attribute name], i.e. graph_instance.label, graph_instance.fontname + """ + + attributes = ['Damping', 'bb', 'center', 'clusterrank', 'compound', 'concentrate',\ + 'defaultdist', 'dim', 'fontpath', 'epsilon', 'layers', 'layersep', \ + 'margin', 'maxiter', 'mclimit', 'mindist', 'pack', 'packmode', 'model', \ + 'page', 'pagedir', 'nodesep', 'normalize', 'nslimit1', 'ordering', \ + 'orientation', 'outputorder', 'overlap', 'remincross', 'resolution', \ + 'rankdir', 'ranksep', 'ratio', 'rotate', 'samplepoints', 'searchsize', \ + 'sep', 'size', 'splines', 'start', 'stylesheet', 'truecolor', \ + 'viewport', 'voro_margin', 'quantum', 'bgcolor', 'labeljust', \ + 'labelloc', 'root', 'showboxes', 'URL', 'fontcolor', 'fontsize', \ + 'label' ,'fontname', 'comment', 'lp', 'target', 'color', 'style', \ + 'concentrators'] - def __init__(self, graph_name='G', graph_type='digraph', strict=False, \ - suppress_disconnected=False, simplify=False, **attrs): - - if graph_type not in ['graph', 'digraph']: - raise Error, 'Invalid type. Accepted graph types are: graph, digraph, subgraph' - self.graph_type = graph_type - self.graph_name = graph_name - self.strict = strict - self.suppress_disconnected = suppress_disconnected - self.simplify = simplify - self.node_list = [] - self.edge_list = [] - self.edge_src_list = [] - self.edge_dst_list = [] - self.subgraph_list = [] - self.parent_graph = self - for attr in self.attributes: - # Set all the attributes to None. - self.__setattr__(attr, None) - # Generate all the Setter methods. - self.__setattr__('set_'+attr, lambda x, a=attr : self.__setattr__(a, x)) - # Generate all the Getter methods. - self.__setattr__('get_'+attr, lambda a=attr : self.__getattribute__(a)) - for attr, val in attrs.items(): - self.__setattr__(attr, val) - - def set_simplify(self, simplify): - """Set whether to simplify or not. - - If True it will avoid displaying equal edges, i.e. - only one edge between two nodes. removing the - duplicated ones. - """ - - self.simplify = simplify + def __init__(self, graph_name='G', graph_type='digraph', strict=False, \ + suppress_disconnected=False, simplify=False, **attrs): + + if graph_type not in ['graph', 'digraph']: + raise Error, 'Invalid type. Accepted graph types are: graph, digraph, subgraph' + self.graph_type = graph_type + self.graph_name = graph_name + self.strict = strict + self.suppress_disconnected = suppress_disconnected + self.simplify = simplify + self.node_list = [] + self.edge_list = [] + self.edge_src_list = [] + self.edge_dst_list = [] + self.subgraph_list = [] + self.parent_graph = self + for attr in self.attributes: + # Set all the attributes to None. + self.__setattr__(attr, None) + # Generate all the Setter methods. + self.__setattr__('set_'+attr, lambda x, a=attr : self.__setattr__(a, x)) + # Generate all the Getter methods. + self.__setattr__('get_'+attr, lambda a=attr : self.__getattribute__(a)) + for attr, val in attrs.items(): + self.__setattr__(attr, val) + + def set_simplify(self, simplify): + """Set whether to simplify or not. + + If True it will avoid displaying equal edges, i.e. + only one edge between two nodes. removing the + duplicated ones. + """ + + self.simplify = simplify - def get_simplify(self): - """Get whether to simplify or not. - - Refer to set_simplify for more information. - """ - - return self.simplify + def get_simplify(self): + """Get whether to simplify or not. + + Refer to set_simplify for more information. + """ + + return self.simplify - - def set_type(self, graph_type): - """Set the graph's type, 'graph' or 'digraph'.""" - self.graph_type = graph_type - - def get_type(self): - """Get the graph's type, 'graph' or 'digraph'.""" - return self.graph_type + + def set_type(self, graph_type): + """Set the graph's type, 'graph' or 'digraph'.""" + self.graph_type = graph_type + + def get_type(self): + """Get the graph's type, 'graph' or 'digraph'.""" + return self.graph_type - def set_name(self, graph_name): - """Set the graph's name.""" - - self.graph_name = graph_name + def set_name(self, graph_name): + """Set the graph's name.""" + + self.graph_name = graph_name - def get_name(self): - """Get the graph's name.""" - - return self.graph_name - - def set_strict(self, val): - """Set graph to 'strict' mode. - - This option is only valid for top level graphs. - """ - - self.strict = val + def get_name(self): + """Get the graph's name.""" + + return self.graph_name + + def set_strict(self, val): + """Set graph to 'strict' mode. + + This option is only valid for top level graphs. + """ + + self.strict = val - def get_strict(self, val): - """Get graph's 'strict' mode (True, False). - - This option is only valid for top level graphs. - """ - - return self.strict - - def set_suppress_disconnected(self, val): - """Suppress disconnected nodes in the output graph. - - This option will skip nodes in the graph with no incoming or outgoing - edges. This option works also for subgraphs and has effect only in the - current graph/subgraph. - """ - - self.suppress_disconnected = val - - def get_suppress_disconnected(self, val): - """Get if suppress disconnected is set. - - Refer to set_suppress_disconnected for more information. - """ - - self.suppress_disconnected = val - - def set(self, name, value): - """Set an attribute value by name. - - Given an attribute 'name' it will set its value to 'value'. - There's always the possibility of using the methods: - - set_'name'(value) - - which are defined for all the existing attributes. - """ - if name in self.attributes: - self.__dict__[name] = value - return True - # Attribute is not known - return False + def get_strict(self, val): + """Get graph's 'strict' mode (True, False). + + This option is only valid for top level graphs. + """ + + return self.strict + + def set_suppress_disconnected(self, val): + """Suppress disconnected nodes in the output graph. + + This option will skip nodes in the graph with no incoming or outgoing + edges. This option works also for subgraphs and has effect only in the + current graph/subgraph. + """ + + self.suppress_disconnected = val + + def get_suppress_disconnected(self, val): + """Get if suppress disconnected is set. + + Refer to set_suppress_disconnected for more information. + """ + + self.suppress_disconnected = val + + def set(self, name, value): + """Set an attribute value by name. + + Given an attribute 'name' it will set its value to 'value'. + There's always the possibility of using the methods: + + set_'name'(value) + + which are defined for all the existing attributes. + """ + if name in self.attributes: + self.__dict__[name] = value + return True + # Attribute is not known + return False - def get(self, name): - """Get an attribute value by name. - - Given an attribute 'name' it will get its value. - There's always the possibility of using the methods: - - get_'name'() - - which are defined for all the existing attributes. - """ - return self.__dict__[name] - - def add_node(self, graph_node): - """Adds a node object to the graph. + def get(self, name): + """Get an attribute value by name. + + Given an attribute 'name' it will get its value. + There's always the possibility of using the methods: + + get_'name'() + + which are defined for all the existing attributes. + """ + return self.__dict__[name] + + def add_node(self, graph_node): + """Adds a node object to the graph. - It takes a node object as its only argument and returns - None. - """ - - if not isinstance(graph_node, Node): - raise Error, 'add_node received a non node class object' - - if self.get_node(graph_node.get_name()) is None: - self.node_list.append(graph_node) - graph_node.parent_graph = self.parent_graph + It takes a node object as its only argument and returns + None. + """ + + if not isinstance(graph_node, Node): + raise Error, 'add_node received a non node class object' + + if self.get_node(graph_node.get_name()) is None: + self.node_list.append(graph_node) + graph_node.parent_graph = self.parent_graph - def get_node(self, name): - """Retrieved a node from the graph. - - Given a node's name the corresponding Node - instance will be returned. - - If multiple nodes exist with that name, a list of - Node instances is returned. - If only one node exists, the instance is returned. - None is returned otherwise. - """ - - match = [node for node in self.node_list if node.get_name() == str(name)] - - l = len(match) - if l==1: - return match[0] - elif l>1: - return match - else: - return None - - def get_node_list(self): - """Get the list of Node instances. - - This method returns the list of Node instances - composing the graph. - """ - - return self.node_list - - def add_edge(self, graph_edge): - """Adds an edge object to the graph. - - It takes a edge object as its only argument and returns - None. - """ - - if not isinstance(graph_edge, Edge): - raise Error, 'add_edge received a non edge class object' - - self.edge_list.append(graph_edge) - - src = self.get_node(graph_edge.get_source()) - if src is None: - self.add_node(Node(graph_edge.get_source())) - - dst = self.get_node(graph_edge.get_destination()) - if dst is None: - self.add_node(Node(graph_edge.get_destination())) - - graph_edge.parent_graph = self.parent_graph - - if graph_edge.src not in self.edge_src_list: - self.edge_src_list.append(graph_edge.src) - - if graph_edge.dst not in self.edge_dst_list: - self.edge_dst_list.append(graph_edge.dst) + def get_node(self, name): + """Retrieved a node from the graph. + + Given a node's name the corresponding Node + instance will be returned. + + If multiple nodes exist with that name, a list of + Node instances is returned. + If only one node exists, the instance is returned. + None is returned otherwise. + """ + + match = [node for node in self.node_list if node.get_name() == str(name)] + + l = len(match) + if l==1: + return match[0] + elif l>1: + return match + else: + return None + + def get_node_list(self): + """Get the list of Node instances. + + This method returns the list of Node instances + composing the graph. + """ + + return self.node_list + + def add_edge(self, graph_edge): + """Adds an edge object to the graph. + + It takes a edge object as its only argument and returns + None. + """ + + if not isinstance(graph_edge, Edge): + raise Error, 'add_edge received a non edge class object' + + self.edge_list.append(graph_edge) + + src = self.get_node(graph_edge.get_source()) + if src is None: + self.add_node(Node(graph_edge.get_source())) + + dst = self.get_node(graph_edge.get_destination()) + if dst is None: + self.add_node(Node(graph_edge.get_destination())) + + graph_edge.parent_graph = self.parent_graph + + if graph_edge.src not in self.edge_src_list: + self.edge_src_list.append(graph_edge.src) + + if graph_edge.dst not in self.edge_dst_list: + self.edge_dst_list.append(graph_edge.dst) - def get_edge(self, src, dst): - """Retrieved an edge from the graph. - - Given an edge's source and destination the corresponding - Edge instance will be returned. - - If multiple edges exist with that source and destination, - a list of Edge instances is returned. - If only one edge exists, the instance is returned. - None is returned otherwise. - """ - - match = [edge for edge in self.edge_list if edge.src == src and edge.dst == dst] - - l = len(match) - if l==1: - return match[0] - elif l>1: - return match - else: - return None - - def get_edge_list(self): - """Get the list of Edge instances. - - This method returns the list of Edge instances - composing the graph. - """ - - return self.edge_list - - def add_subgraph(self, sgraph): - """Adds an edge object to the graph. - - It takes a subgraph object as its only argument and returns - None. - """ - if not isinstance(sgraph, Subgraph) and not isinstance(sgraph, Cluster): - raise Error, 'add_subgraph received a non subgraph class object' - - self.subgraph_list.append(sgraph) - - sgraph.set_graph_parent(self.parent_graph) - return None - - def get_subgraph(self, name): - """Retrieved a subgraph from the graph. - - Given a subgraph's name the corresponding - Subgraph instance will be returned. - - If multiple subgraphs exist with the same name, a list of - Subgraph instances is returned. - If only one Subgraph exists, the instance is returned. - None is returned otherwise. - """ - - match = [sgraph for sgraph in self.subgraph_list if sgraph.graph_name == name] - - l = len(match) - if l==1: - return match[0] - elif l>1: - return match - else: - return None - - def get_subgraph_list(self): - """Get the list of Subgraph instances. - - This method returns the list of Subgraph instances - in the graph. - """ - - return self.subgraph_list - - def set_graph_parent(self, parent): - """Sets a graph and its elements to point the the parent. - - Any subgraph added to a parent graph receives a reference - to the parent to access some common data. - """ - self.parent_graph = parent - - for elm in self.edge_list: - elm.parent_graph = parent - - for elm in self.node_list: - elm.parent_graph = parent - - for elm in self.subgraph_list: - elm.parent_graph = parent - elm.set_graph_parent(parent) - - def to_string(self, indent=''): - """Returns a string representation of the graph in dot language. - - It will return the graph and all its subelements in string from. - """ - graph = indent+'' - if self.__dict__.has_key('strict'): - if self==self.parent_graph and self.strict: - graph+='strict ' - - graph+=self.graph_type+' '+self.graph_name+' {\n' + def get_edge(self, src, dst): + """Retrieved an edge from the graph. + + Given an edge's source and destination the corresponding + Edge instance will be returned. + + If multiple edges exist with that source and destination, + a list of Edge instances is returned. + If only one edge exists, the instance is returned. + None is returned otherwise. + """ + + match = [edge for edge in self.edge_list if edge.src == src and edge.dst == dst] + + l = len(match) + if l==1: + return match[0] + elif l>1: + return match + else: + return None + + def get_edge_list(self): + """Get the list of Edge instances. + + This method returns the list of Edge instances + composing the graph. + """ + + return self.edge_list + + def add_subgraph(self, sgraph): + """Adds an edge object to the graph. + + It takes a subgraph object as its only argument and returns + None. + """ + if not isinstance(sgraph, Subgraph) and not isinstance(sgraph, Cluster): + raise Error, 'add_subgraph received a non subgraph class object' + + self.subgraph_list.append(sgraph) + + sgraph.set_graph_parent(self.parent_graph) + return None + + def get_subgraph(self, name): + """Retrieved a subgraph from the graph. + + Given a subgraph's name the corresponding + Subgraph instance will be returned. + + If multiple subgraphs exist with the same name, a list of + Subgraph instances is returned. + If only one Subgraph exists, the instance is returned. + None is returned otherwise. + """ + + match = [sgraph for sgraph in self.subgraph_list if sgraph.graph_name == name] + + l = len(match) + if l==1: + return match[0] + elif l>1: + return match + else: + return None + + def get_subgraph_list(self): + """Get the list of Subgraph instances. + + This method returns the list of Subgraph instances + in the graph. + """ + + return self.subgraph_list + + def set_graph_parent(self, parent): + """Sets a graph and its elements to point the the parent. + + Any subgraph added to a parent graph receives a reference + to the parent to access some common data. + """ + self.parent_graph = parent + + for elm in self.edge_list: + elm.parent_graph = parent + + for elm in self.node_list: + elm.parent_graph = parent + + for elm in self.subgraph_list: + elm.parent_graph = parent + elm.set_graph_parent(parent) + + def to_string(self, indent=''): + """Returns a string representation of the graph in dot language. + + It will return the graph and all its subelements in string from. + """ + graph = indent+'' + if self.__dict__.has_key('strict'): + if self==self.parent_graph and self.strict: + graph+='strict ' + + graph+=self.graph_type+' '+self.graph_name+' {\n' - for attr in self.attributes: - if self.__dict__.has_key(attr) \ - and self.__getattribute__(attr) is not None: - graph += indent+'\t'+attr+'=' - val = self.__dict__[attr] - if isinstance(val, str) and not self.is_ID(val): - graph += '"'+val+'"' - else: - graph += str(val) - graph+=';\n' + for attr in self.attributes: + if self.__dict__.has_key(attr) \ + and self.__getattribute__(attr) is not None: + graph += indent+'\t'+attr+'=' + val = self.__dict__[attr] + if isinstance(val, str) and not self.is_ID(val): + graph += '"'+val+'"' + else: + graph += str(val) + graph+=';\n' - # RMF: for graphviz to handle edge/node defaults correctly, - # it seems they must appear before the rest of the nodes/edges - # so if they exist, dump them out first. - for elm in self.node_list: - if elm.name in ['node', 'edge', 'graph']: - graph += indent+'\t'+elm.to_string()+'\n' - - for elm in self.subgraph_list: - graph += elm.to_string(indent+'\t')+'\n' - - for elm in self.node_list: - # RMF: don't repeat the node/edge defaults - if elm.name in ['node', 'edge', 'graph']: - continue - if self.suppress_disconnected: - if elm.name not in self.edge_src_list+self.edge_dst_list: - continue - graph+=indent+'\t'+elm.to_string()+'\n' + # RMF: for graphviz to handle edge/node defaults correctly, + # it seems they must appear before the rest of the nodes/edges + # so if they exist, dump them out first. + for elm in self.node_list: + if elm.name in ['node', 'edge', 'graph']: + graph += indent+'\t'+elm.to_string()+'\n' + + for elm in self.subgraph_list: + graph += elm.to_string(indent+'\t')+'\n' + + for elm in self.node_list: + # RMF: don't repeat the node/edge defaults + if elm.name in ['node', 'edge', 'graph']: + continue + if self.suppress_disconnected: + if elm.name not in self.edge_src_list+self.edge_dst_list: + continue + graph+=indent+'\t'+elm.to_string()+'\n' - edges_done = [] - for elm in self.edge_list: - if self.simplify and elm in edges_done: - continue - graph+=indent+'\t'+elm.to_string()+'\n' - edges_done.append(elm) + edges_done = [] + for elm in self.edge_list: + if self.simplify and elm in edges_done: + continue + graph+=indent+'\t'+elm.to_string()+'\n' + edges_done.append(elm) - graph+=indent+'}\n' - - return graph + graph+=indent+'}\n' + + return graph class Subgraph(Graph): - """Class representing a subgraph in Graphviz's dot language. + """Class representing a subgraph in Graphviz's dot language. - This class implements the methods to work on a representation - of a subgraph in Graphviz's dot language. - - subgraph(graph_name='subG', suppress_disconnected=False, attribute=value, ...) - - graph_name: - the subgraph's name - suppress_disconnected: - defaults to false, which will remove from the - subgraph any disconnected nodes. - All the attributes defined in the Graphviz dot language should - be supported. - - Attributes can be set through the dynamically generated methods: - - set_[attribute name], i.e. set_size, set_fontname - - or using the instance's attributes: - - Subgraph.[attribute name], i.e. - subgraph_instance.label, subgraph_instance.fontname - """ - - attributes = Graph.attributes+['rank'] - - # RMF: subgraph should have all the attributes of graph so it can be passed - # as a graph to all methods - def __init__(self, graph_name='subG', suppress_disconnected=False, \ - simplify=False, **attrs): - - self.graph_type = 'subgraph' - self.graph_name = graph_name - self.suppress_disconnected = suppress_disconnected - self.simplify = simplify - self.node_list = [] - self.edge_list = [] - self.edge_src_list = [] - self.edge_dst_list = [] - self.subgraph_list = [] - for attr in self.attributes: - # Set all the attributes to None. - self.__setattr__(attr, None) - # Generate all the Setter methods. - self.__setattr__('set_'+attr, lambda x, a=attr : self.__setattr__(a, x)) - # Generate all the Getter methods. - self.__setattr__('get_'+attr, lambda a=attr : self.__getattribute__(a)) - for attr, val in attrs.items(): - self.__setattr__(attr, val) - + This class implements the methods to work on a representation + of a subgraph in Graphviz's dot language. + + subgraph(graph_name='subG', suppress_disconnected=False, attribute=value, ...) + + graph_name: + the subgraph's name + suppress_disconnected: + defaults to false, which will remove from the + subgraph any disconnected nodes. + All the attributes defined in the Graphviz dot language should + be supported. + + Attributes can be set through the dynamically generated methods: + + set_[attribute name], i.e. set_size, set_fontname + + or using the instance's attributes: + + Subgraph.[attribute name], i.e. + subgraph_instance.label, subgraph_instance.fontname + """ + + attributes = Graph.attributes+['rank'] + + # RMF: subgraph should have all the attributes of graph so it can be passed + # as a graph to all methods + def __init__(self, graph_name='subG', suppress_disconnected=False, \ + simplify=False, **attrs): + + self.graph_type = 'subgraph' + self.graph_name = graph_name + self.suppress_disconnected = suppress_disconnected + self.simplify = simplify + self.node_list = [] + self.edge_list = [] + self.edge_src_list = [] + self.edge_dst_list = [] + self.subgraph_list = [] + for attr in self.attributes: + # Set all the attributes to None. + self.__setattr__(attr, None) + # Generate all the Setter methods. + self.__setattr__('set_'+attr, lambda x, a=attr : self.__setattr__(a, x)) + # Generate all the Getter methods. + self.__setattr__('get_'+attr, lambda a=attr : self.__getattribute__(a)) + for attr, val in attrs.items(): + self.__setattr__(attr, val) + class Cluster(Graph): - """Class representing a cluster in Graphviz's dot language. + """Class representing a cluster in Graphviz's dot language. - This class implements the methods to work on a representation - of a cluster in Graphviz's dot language. - - cluster(graph_name='subG', suppress_disconnected=False, attribute=value, ...) - - graph_name: - the cluster's name (the string 'cluster' will be always prepended) - suppress_disconnected: - defaults to false, which will remove from the - cluster any disconnected nodes. - All the attributes defined in the Graphviz dot language should - be supported. - - Attributes can be set through the dynamically generated methods: - - set_[attribute name], i.e. set_color, set_fontname - - or using the instance's attributes: - - Cluster.[attribute name], i.e. - cluster_instance.color, cluster_instance.fontname - """ - - attributes = ['pencolor', 'bgcolor', 'labeljust', 'labelloc', 'URL', 'fontcolor', \ - 'fontsize', 'label', 'fontname', 'lp', 'style', 'target', 'color', \ - 'peripheries', 'fillcolor'] + This class implements the methods to work on a representation + of a cluster in Graphviz's dot language. + + cluster(graph_name='subG', suppress_disconnected=False, attribute=value, ...) + + graph_name: + the cluster's name (the string 'cluster' will be always prepended) + suppress_disconnected: + defaults to false, which will remove from the + cluster any disconnected nodes. + All the attributes defined in the Graphviz dot language should + be supported. + + Attributes can be set through the dynamically generated methods: + + set_[attribute name], i.e. set_color, set_fontname + + or using the instance's attributes: + + Cluster.[attribute name], i.e. + cluster_instance.color, cluster_instance.fontname + """ + + attributes = ['pencolor', 'bgcolor', 'labeljust', 'labelloc', 'URL', 'fontcolor', \ + 'fontsize', 'label', 'fontname', 'lp', 'style', 'target', 'color', \ + 'peripheries', 'fillcolor'] - def __init__(self, graph_name='subG', suppress_disconnected=False, \ - simplify=False, **attrs): - - #if type not in ['subgraph']: - # raise Error, 'Invalid type. Accepted graph types are: subgraph' - self.graph_type = 'subgraph' - self.graph_name = 'cluster_'+graph_name - self.suppress_disconnected = suppress_disconnected - self.simplify = simplify - self.node_list = [] - self.edge_list = [] - self.edge_src_list = [] - self.edge_dst_list = [] - self.subgraph_list = [] - for attr in self.attributes: - # Set all the attributes to None. - self.__setattr__(attr, None) - # Generate all the Setter methods. - self.__setattr__('set_'+attr, lambda x, a=attr : self.__setattr__(a, x)) - # Generate all the Getter methods. - self.__setattr__('get_'+attr, lambda a=attr : self.__getattribute__(a)) - for attr, val in attrs.items(): - self.__setattr__(attr, val) + def __init__(self, graph_name='subG', suppress_disconnected=False, \ + simplify=False, **attrs): + + #if type not in ['subgraph']: + # raise Error, 'Invalid type. Accepted graph types are: subgraph' + self.graph_type = 'subgraph' + self.graph_name = 'cluster_'+graph_name + self.suppress_disconnected = suppress_disconnected + self.simplify = simplify + self.node_list = [] + self.edge_list = [] + self.edge_src_list = [] + self.edge_dst_list = [] + self.subgraph_list = [] + for attr in self.attributes: + # Set all the attributes to None. + self.__setattr__(attr, None) + # Generate all the Setter methods. + self.__setattr__('set_'+attr, lambda x, a=attr : self.__setattr__(a, x)) + # Generate all the Getter methods. + self.__setattr__('get_'+attr, lambda a=attr : self.__getattribute__(a)) + for attr, val in attrs.items(): + self.__setattr__(attr, val) class Dot(Graph): - """A container for handling a dot language file. + """A container for handling a dot language file. - This class implements methods to write and process - a dot language file. It is a derived class of - the base class 'Graph'. - """ - - progs = None - - formats = ['ps', 'ps2', 'hpgl', 'pcl', 'mif', 'pic', 'gd', 'gd2', 'gif', 'jpg', \ - 'jpeg', 'png', 'wbmp', 'ismap', 'imap', 'cmap', 'vrml', 'vtx', 'mp', \ - 'fig', 'svg', 'svgz', 'dia', 'dot', 'canon', 'plain', 'plain-ext', 'xdot'] + This class implements methods to write and process + a dot language file. It is a derived class of + the base class 'Graph'. + """ + + progs = None + + formats = ['ps', 'ps2', 'hpgl', 'pcl', 'mif', 'pic', 'gd', 'gd2', 'gif', 'jpg', \ + 'jpeg', 'png', 'wbmp', 'ismap', 'imap', 'cmap', 'vrml', 'vtx', 'mp', \ + 'fig', 'svg', 'svgz', 'dia', 'dot', 'canon', 'plain', 'plain-ext', 'xdot'] - def __init__(self, prog='dot', **args): - Graph.__init__(self, **args) - - self.prog = prog - - # Automatically creates all the methods enabling the creation - # of output in any of the supported formats. - for frmt in self.formats: - self.__setattr__('create_'+frmt, lambda f=frmt, prog=self.prog : self.create(format=f, prog=prog)) - f = self.__dict__['create_'+frmt] - f.__doc__ = '''Refer to docstring from 'create' for more information.''' - - for frmt in self.formats+['raw']: - self.__setattr__('write_'+frmt, lambda path, f=frmt, prog=self.prog : self.write(path, format=f, prog=prog)) - f = self.__dict__['write_'+frmt] - f.__doc__ = '''Refer to docstring from 'write' for more information.''' - - def set_prog(self, prog): - """Sets the default program. - - Sets the default program in charge of processing - the dot file into a graph. - """ - self.prog = prog + def __init__(self, prog='dot', **args): + Graph.__init__(self, **args) + + self.prog = prog + + # Automatically creates all the methods enabling the creation + # of output in any of the supported formats. + for frmt in self.formats: + self.__setattr__('create_'+frmt, lambda f=frmt, prog=self.prog : self.create(format=f, prog=prog)) + f = self.__dict__['create_'+frmt] + f.__doc__ = '''Refer to docstring from 'create' for more information.''' + + for frmt in self.formats+['raw']: + self.__setattr__('write_'+frmt, lambda path, f=frmt, prog=self.prog : self.write(path, format=f, prog=prog)) + f = self.__dict__['write_'+frmt] + f.__doc__ = '''Refer to docstring from 'write' for more information.''' + + def set_prog(self, prog): + """Sets the default program. + + Sets the default program in charge of processing + the dot file into a graph. + """ + self.prog = prog - def write(self, path, prog=None, format='raw'): - """Writes a graph to a file. + def write(self, path, prog=None, format='raw'): + """Writes a graph to a file. - Given a filename 'path' it will open/create and truncate - such file and write on it a representation of the graph - defined by the dot object and in the format specified by - 'format'. - The format 'raw' is used to dump the string representation - of the Dot object, without further processing. - The output can be processed by any of graphviz tools, defined - in 'prog', which defaults to 'dot' - Returns True or False according to the success of the write - operation. - - There's also the preferred possibility of using: - - write_'format'(path, prog='program') - - which are automatically defined for all the supported formats. - [write_ps(), write_gif(), write_dia(), ...] - """ + Given a filename 'path' it will open/create and truncate + such file and write on it a representation of the graph + defined by the dot object and in the format specified by + 'format'. + The format 'raw' is used to dump the string representation + of the Dot object, without further processing. + The output can be processed by any of graphviz tools, defined + in 'prog', which defaults to 'dot' + Returns True or False according to the success of the write + operation. + + There's also the preferred possibility of using: + + write_'format'(path, prog='program') + + which are automatically defined for all the supported formats. + [write_ps(), write_gif(), write_dia(), ...] + """ - if prog is None: - prog = self.prog - - dot_fd = file(path, "w+b") - if format == 'raw': - dot_fd.write(self.to_string()) - else: - dot_fd.write(self.create(prog, format)) - dot_fd.close() + if prog is None: + prog = self.prog + + dot_fd = file(path, "w+b") + if format == 'raw': + dot_fd.write(self.to_string()) + else: + dot_fd.write(self.create(prog, format)) + dot_fd.close() - return True + return True - def create(self, prog=None, format='ps'): - """Creates and returns a Postscript representation of the graph. + def create(self, prog=None, format='ps'): + """Creates and returns a Postscript representation of the graph. - create will write the graph to a temporary dot file and process - it with the program given by 'prog' (which defaults to 'twopi'), - reading the Postscript output and returning it as a string is the - operation is successful. - On failure None is returned. - - There's also the preferred possibility of using: - - create_'format'(prog='program') - - which are automatically defined for all the supported formats. - [create_ps(), create_gif(), create_dia(), ...] - """ - if prog is None: - prog = self.prog - - if self.progs is None: - self.progs = find_graphviz() - if self.progs is None: - return None - if not self.progs.has_key(prog): - # Program not found ?!?! - return None - - tmp_fd, tmp_name = tempfile.mkstemp() - os.close(tmp_fd) - self.write(tmp_name) - stdin, stdout, stderr = os.popen3(self.progs[prog]+' -T'+format+' '+tmp_name, 'b') - stdin.close() - stderr.close() - data = stdout.read() - stdout.close() - os.unlink(tmp_name) - return data + create will write the graph to a temporary dot file and process + it with the program given by 'prog' (which defaults to 'twopi'), + reading the Postscript output and returning it as a string is the + operation is successful. + On failure None is returned. + + There's also the preferred possibility of using: + + create_'format'(prog='program') + + which are automatically defined for all the supported formats. + [create_ps(), create_gif(), create_dia(), ...] + """ + if prog is None: + prog = self.prog + + if self.progs is None: + self.progs = find_graphviz() + if self.progs is None: + return None + if not self.progs.has_key(prog): + # Program not found ?!?! + return None + + tmp_fd, tmp_name = tempfile.mkstemp() + os.close(tmp_fd) + self.write(tmp_name) + stdin, stdout, stderr = os.popen3(self.progs[prog]+' -T'+format+' '+tmp_name, 'b') + stdin.close() + stderr.close() + data = stdout.read() + stdout.close() + os.unlink(tmp_name) + return data diff --git a/bin/addons/base/ir/workflow/pydot/setup.py b/bin/addons/base/ir/workflow/pydot/setup.py old mode 100755 new mode 100644 index cd8956bebbd..5209f242d81 --- a/bin/addons/base/ir/workflow/pydot/setup.py +++ b/bin/addons/base/ir/workflow/pydot/setup.py @@ -3,21 +3,21 @@ from distutils.core import setup import pydot -setup( name = 'pydot', - version = pydot.__version__, - description = 'Python interface to Graphiz\'s Dot', - author = 'Ero Carrera', - author_email = 'ero@dkbza.org', - url = 'http://dkbza.org/pydot.html', - license = 'MIT', - platforms = ["any"], - classifiers = ['Development Status :: 5 - Production/Stable', \ - 'Intended Audience :: Science/Research', \ - 'License :: OSI Approved :: MIT License',\ - 'Natural Language :: English', \ - 'Operating System :: OS Independent', \ - 'Programming Language :: Python', \ - 'Topic :: Scientific/Engineering :: Visualization',\ - 'Topic :: Software Development :: Libraries :: Python Modules'], - long_description = "\n".join(pydot.__doc__.split('\n')), - py_modules = ['pydot', 'dot_parser']) +setup( name = 'pydot', + version = pydot.__version__, + description = 'Python interface to Graphiz\'s Dot', + author = 'Ero Carrera', + author_email = 'ero@dkbza.org', + url = 'http://dkbza.org/pydot.html', + license = 'MIT', + platforms = ["any"], + classifiers = ['Development Status :: 5 - Production/Stable', \ + 'Intended Audience :: Science/Research', \ + 'License :: OSI Approved :: MIT License',\ + 'Natural Language :: English', \ + 'Operating System :: OS Independent', \ + 'Programming Language :: Python', \ + 'Topic :: Scientific/Engineering :: Visualization',\ + 'Topic :: Software Development :: Libraries :: Python Modules'], + long_description = "\n".join(pydot.__doc__.split('\n')), + py_modules = ['pydot', 'dot_parser']) diff --git a/bin/addons/base/ir/workflow/workflow.py b/bin/addons/base/ir/workflow/workflow.py index 6aebf7262ec..24a8e315570 100644 --- a/bin/addons/base/ir/workflow/workflow.py +++ b/bin/addons/base/ir/workflow/workflow.py @@ -32,157 +32,157 @@ from tools import graph import netsvc class workflow(osv.osv): - _name = "workflow" - _table = "wkf" - _log_access = False - _columns = { - 'name': fields.char('Name', size=64, required=True), - 'osv': fields.char('Resource Model', size=64, required=True), - 'on_create': fields.boolean('On Create'), - 'activities': fields.one2many('workflow.activity', 'wkf_id', 'Activities'), - } - _defaults = { - 'on_create': lambda *a: True - } + _name = "workflow" + _table = "wkf" + _log_access = False + _columns = { + 'name': fields.char('Name', size=64, required=True), + 'osv': fields.char('Resource Model', size=64, required=True), + 'on_create': fields.boolean('On Create'), + 'activities': fields.one2many('workflow.activity', 'wkf_id', 'Activities'), + } + _defaults = { + 'on_create': lambda *a: True + } - def write(self, cr, user, ids, vals, context=None): - if not context: - context={} - wf_service = netsvc.LocalService("workflow") - wf_service.clear_cache(cr, user) - return super(workflow, self).write(cr, user, ids, vals, context=context) + def write(self, cr, user, ids, vals, context=None): + if not context: + context={} + wf_service = netsvc.LocalService("workflow") + wf_service.clear_cache(cr, user) + return super(workflow, self).write(cr, user, ids, vals, context=context) - # - # scale = [stepx, stepy, posx, posy ] - # + # + # scale = [stepx, stepy, posx, posy ] + # - def graph_get(self, cr, uid, id, scale, context={}): + def graph_get(self, cr, uid, id, scale, context={}): - nodes= [] - transitions = [] - start = [] - tres = {} - workflow = self.browse(cr, uid, id, context) - for a in workflow.activities: - nodes.append((a.id,a.name)) - if a.flow_start: - start.append((a.id,a.name)) - for t in a.out_transitions: - transitions.append( ((a.id,a.name), (t.act_to.id,t.act_to.name)) ) - tres[t.id] = (a.id,t.act_to.id) - g = graph(nodes, transitions) - g.process(start) - g.scale(*scale) - result = g.result_get() - results = {} + nodes= [] + transitions = [] + start = [] + tres = {} + workflow = self.browse(cr, uid, id, context) + for a in workflow.activities: + nodes.append((a.id,a.name)) + if a.flow_start: + start.append((a.id,a.name)) + for t in a.out_transitions: + transitions.append( ((a.id,a.name), (t.act_to.id,t.act_to.name)) ) + tres[t.id] = (a.id,t.act_to.id) + g = graph(nodes, transitions) + g.process(start) + g.scale(*scale) + result = g.result_get() + results = {} - for r in result.items(): - r[1]['name'] = r[0][1] - results[str(r[0][0])] = r[1] - return {'node': results, 'transition': tres} + for r in result.items(): + r[1]['name'] = r[0][1] + results[str(r[0][0])] = r[1] + return {'node': results, 'transition': tres} - def create(self, cr, user, vals, context=None): - if not context: - context={} - wf_service = netsvc.LocalService("workflow") - wf_service.clear_cache(cr, user) - return super(workflow, self).create(cr, user, vals, context=context) + def create(self, cr, user, vals, context=None): + if not context: + context={} + wf_service = netsvc.LocalService("workflow") + wf_service.clear_cache(cr, user) + return super(workflow, self).create(cr, user, vals, context=context) workflow() class wkf_activity(osv.osv): - _name = "workflow.activity" - _table = "wkf_activity" - _log_access = False - _columns = { - 'name': fields.char('Name', size=64, required=True), - 'wkf_id': fields.many2one('workflow', 'Workflow', required=True, select=True, ondelete='cascade'), - 'split_mode': fields.selection([('XOR', 'Xor'), ('OR','Or'), ('AND','And')], 'Split Mode', size=3, required=True), - 'join_mode': fields.selection([('XOR', 'Xor'), ('AND', 'And')], 'Join Mode', size=3, required=True), - 'kind': fields.selection([('dummy', 'Dummy'), ('function', 'Function'), ('subflow', 'Subflow'), ('stopall', 'Stop All')], 'Kind', size=64, required=True), - 'action': fields.text('Python Action'), - 'action_id': fields.many2one('ir.actions.server', 'Server Action', ondelete='set null'), - 'flow_start': fields.boolean('Flow Start'), - 'flow_stop': fields.boolean('Flow Stop'), - 'subflow_id': fields.many2one('workflow', 'Subflow'), - 'signal_send': fields.char('Signal (subflow.*)', size=32), - 'out_transitions': fields.one2many('workflow.transition', 'act_from', 'Outgoing transitions'), - 'in_transitions': fields.one2many('workflow.transition', 'act_to', 'Incoming transitions'), - } - _defaults = { - 'kind': lambda *a: 'dummy', - 'join_mode': lambda *a: 'XOR', - 'split_mode': lambda *a: 'XOR', - } + _name = "workflow.activity" + _table = "wkf_activity" + _log_access = False + _columns = { + 'name': fields.char('Name', size=64, required=True), + 'wkf_id': fields.many2one('workflow', 'Workflow', required=True, select=True, ondelete='cascade'), + 'split_mode': fields.selection([('XOR', 'Xor'), ('OR','Or'), ('AND','And')], 'Split Mode', size=3, required=True), + 'join_mode': fields.selection([('XOR', 'Xor'), ('AND', 'And')], 'Join Mode', size=3, required=True), + 'kind': fields.selection([('dummy', 'Dummy'), ('function', 'Function'), ('subflow', 'Subflow'), ('stopall', 'Stop All')], 'Kind', size=64, required=True), + 'action': fields.text('Python Action'), + 'action_id': fields.many2one('ir.actions.server', 'Server Action', ondelete='set null'), + 'flow_start': fields.boolean('Flow Start'), + 'flow_stop': fields.boolean('Flow Stop'), + 'subflow_id': fields.many2one('workflow', 'Subflow'), + 'signal_send': fields.char('Signal (subflow.*)', size=32), + 'out_transitions': fields.one2many('workflow.transition', 'act_from', 'Outgoing transitions'), + 'in_transitions': fields.one2many('workflow.transition', 'act_to', 'Incoming transitions'), + } + _defaults = { + 'kind': lambda *a: 'dummy', + 'join_mode': lambda *a: 'XOR', + 'split_mode': lambda *a: 'XOR', + } wkf_activity() class wkf_transition(osv.osv): - _table = "wkf_transition" - _name = "workflow.transition" - _log_access = False - _rec_name = 'signal' #TODO: pas top mais bon... - _columns = { - 'trigger_model': fields.char('Trigger Type', size=128), - 'trigger_expr_id': fields.char('Trigger Expr ID', size=128), - 'signal': fields.char('Signal (button Name)', size=64), - 'role_id': fields.many2one('res.roles', 'Role Required'), - 'condition': fields.char('Condition', required=True, size=128), - 'act_from': fields.many2one('workflow.activity', 'Source Activity', required=True, select=True, ondelete='cascade'), - 'act_to': fields.many2one('workflow.activity', 'Destination Activity', required=True, select=True, ondelete='cascade'), - } - _defaults = { - 'condition': lambda *a: 'True', - } + _table = "wkf_transition" + _name = "workflow.transition" + _log_access = False + _rec_name = 'signal' #TODO: pas top mais bon... + _columns = { + 'trigger_model': fields.char('Trigger Type', size=128), + 'trigger_expr_id': fields.char('Trigger Expr ID', size=128), + 'signal': fields.char('Signal (button Name)', size=64), + 'role_id': fields.many2one('res.roles', 'Role Required'), + 'condition': fields.char('Condition', required=True, size=128), + 'act_from': fields.many2one('workflow.activity', 'Source Activity', required=True, select=True, ondelete='cascade'), + 'act_to': fields.many2one('workflow.activity', 'Destination Activity', required=True, select=True, ondelete='cascade'), + } + _defaults = { + 'condition': lambda *a: 'True', + } wkf_transition() class wkf_instance(osv.osv): - _table = "wkf_instance" - _name = "workflow.instance" - _rec_name = 'res_type' - _log_access = False - _columns = { - 'wkf_id': fields.many2one('workflow', 'Workflow', ondelete='restrict'), - 'uid': fields.integer('User ID'), - 'res_id': fields.integer('Resource ID'), - 'res_type': fields.char('Resource Model', size=64), - 'state': fields.char('State', size=32), - } - def _auto_init(self, cr, context={}): - super(wkf_instance, self)._auto_init(cr, context) - cr.execute('SELECT indexname FROM pg_indexes WHERE indexname = \'wkf_instance_res_id_res_type_state_index\'') - if not cr.fetchone(): - cr.execute('CREATE INDEX wkf_instance_res_id_res_type_state_index ON wkf_instance (res_id, res_type, state)') - cr.commit() + _table = "wkf_instance" + _name = "workflow.instance" + _rec_name = 'res_type' + _log_access = False + _columns = { + 'wkf_id': fields.many2one('workflow', 'Workflow', ondelete='restrict'), + 'uid': fields.integer('User ID'), + 'res_id': fields.integer('Resource ID'), + 'res_type': fields.char('Resource Model', size=64), + 'state': fields.char('State', size=32), + } + def _auto_init(self, cr, context={}): + super(wkf_instance, self)._auto_init(cr, context) + cr.execute('SELECT indexname FROM pg_indexes WHERE indexname = \'wkf_instance_res_id_res_type_state_index\'') + if not cr.fetchone(): + cr.execute('CREATE INDEX wkf_instance_res_id_res_type_state_index ON wkf_instance (res_id, res_type, state)') + cr.commit() wkf_instance() class wkf_workitem(osv.osv): - _table = "wkf_workitem" - _name = "workflow.workitem" - _log_access = False - _rec_name = 'state' - _columns = { - 'act_id': fields.many2one('workflow.activity', 'Activity', required=True, ondelete="cascade"), - 'subflow_id': fields.many2one('workflow.instance', 'Subflow', ondelete="cascade"), - 'inst_id': fields.many2one('workflow.instance', 'Instance', required=True, ondelete="cascade", select=1), - 'state': fields.char('State', size=64), - } + _table = "wkf_workitem" + _name = "workflow.workitem" + _log_access = False + _rec_name = 'state' + _columns = { + 'act_id': fields.many2one('workflow.activity', 'Activity', required=True, ondelete="cascade"), + 'subflow_id': fields.many2one('workflow.instance', 'Subflow', ondelete="cascade"), + 'inst_id': fields.many2one('workflow.instance', 'Instance', required=True, ondelete="cascade", select=1), + 'state': fields.char('State', size=64), + } wkf_workitem() class wkf_triggers(osv.osv): - _table = "wkf_triggers" - _name = "workflow.triggers" - _log_access = False - _columns = { - 'res_id': fields.integer('Resource ID', size=128), - 'model': fields.char('Model', size=128), - 'instance_id': fields.many2one('workflow.instance', 'Destination Instance', ondelete="cascade"), - 'workitem_id': fields.many2one('workflow.workitem', 'Workitem', required=True, ondelete="cascade"), - } - def _auto_init(self, cr, context={}): - super(wkf_triggers, self)._auto_init(cr, context) - cr.execute('SELECT indexname FROM pg_indexes WHERE indexname = \'wkf_triggers_res_id_model_index\'') - if not cr.fetchone(): - cr.execute('CREATE INDEX wkf_triggers_res_id_model_index ON wkf_triggers (res_id, model)') - cr.commit() + _table = "wkf_triggers" + _name = "workflow.triggers" + _log_access = False + _columns = { + 'res_id': fields.integer('Resource ID', size=128), + 'model': fields.char('Model', size=128), + 'instance_id': fields.many2one('workflow.instance', 'Destination Instance', ondelete="cascade"), + 'workitem_id': fields.many2one('workflow.workitem', 'Workitem', required=True, ondelete="cascade"), + } + def _auto_init(self, cr, context={}): + super(wkf_triggers, self)._auto_init(cr, context) + cr.execute('SELECT indexname FROM pg_indexes WHERE indexname = \'wkf_triggers_res_id_model_index\'') + if not cr.fetchone(): + cr.execute('CREATE INDEX wkf_triggers_res_id_model_index ON wkf_triggers (res_id, model)') + cr.commit() wkf_triggers() diff --git a/bin/addons/base/module/module.py b/bin/addons/base/module/module.py index 1ad9a844ea0..76ead57fdbd 100644 --- a/bin/addons/base/module/module.py +++ b/bin/addons/base/module/module.py @@ -44,609 +44,609 @@ ver_regexp = re.compile("^(\\d+)((\\.\\d+)*)([a-z]?)((_(pre|p|beta|alpha|rc)\\d* suffix_regexp = re.compile("^(alpha|beta|rc|pre|p)(\\d*)$") def vercmp(ver1, ver2): - """ - Compare two versions - Take from portage_versions.py - @param ver1: version to compare with - @type ver1: string (example "1.2-r3") - @param ver2: version to compare again - @type ver2: string (example "2.1-r1") - @rtype: None or float - @return: - 1. position if ver1 is greater than ver2 - 2. negative if ver1 is less than ver2 - 3. 0 if ver1 equals ver2 - 4. None if ver1 or ver2 are invalid - """ + """ + Compare two versions + Take from portage_versions.py + @param ver1: version to compare with + @type ver1: string (example "1.2-r3") + @param ver2: version to compare again + @type ver2: string (example "2.1-r1") + @rtype: None or float + @return: + 1. position if ver1 is greater than ver2 + 2. negative if ver1 is less than ver2 + 3. 0 if ver1 equals ver2 + 4. None if ver1 or ver2 are invalid + """ - match1 = ver_regexp.match(ver1) - match2 = ver_regexp.match(ver2) + match1 = ver_regexp.match(ver1) + match2 = ver_regexp.match(ver2) - if not match1 or not match1.groups(): - return None - if not match2 or not match2.groups(): - return None + if not match1 or not match1.groups(): + return None + if not match2 or not match2.groups(): + return None - list1 = [int(match1.group(1))] - list2 = [int(match2.group(1))] + list1 = [int(match1.group(1))] + list2 = [int(match2.group(1))] - if len(match1.group(2)) or len(match2.group(2)): - vlist1 = match1.group(2)[1:].split(".") - vlist2 = match2.group(2)[1:].split(".") - for i in range(0, max(len(vlist1), len(vlist2))): - # Implicit .0 is given -1, so 1.0.0 > 1.0 - # would be ambiguous if two versions that aren't literally equal - # are given the same value (in sorting, for example). - if len(vlist1) <= i or len(vlist1[i]) == 0: - list1.append(-1) - list2.append(int(vlist2[i])) - elif len(vlist2) <= i or len(vlist2[i]) == 0: - list1.append(int(vlist1[i])) - list2.append(-1) - # Let's make life easy and use integers unless we're forced to use floats - elif (vlist1[i][0] != "0" and vlist2[i][0] != "0"): - list1.append(int(vlist1[i])) - list2.append(int(vlist2[i])) - # now we have to use floats so 1.02 compares correctly against 1.1 - else: - list1.append(float("0."+vlist1[i])) - list2.append(float("0."+vlist2[i])) - # and now the final letter - if len(match1.group(4)): - list1.append(ord(match1.group(4))) - if len(match2.group(4)): - list2.append(ord(match2.group(4))) + if len(match1.group(2)) or len(match2.group(2)): + vlist1 = match1.group(2)[1:].split(".") + vlist2 = match2.group(2)[1:].split(".") + for i in range(0, max(len(vlist1), len(vlist2))): + # Implicit .0 is given -1, so 1.0.0 > 1.0 + # would be ambiguous if two versions that aren't literally equal + # are given the same value (in sorting, for example). + if len(vlist1) <= i or len(vlist1[i]) == 0: + list1.append(-1) + list2.append(int(vlist2[i])) + elif len(vlist2) <= i or len(vlist2[i]) == 0: + list1.append(int(vlist1[i])) + list2.append(-1) + # Let's make life easy and use integers unless we're forced to use floats + elif (vlist1[i][0] != "0" and vlist2[i][0] != "0"): + list1.append(int(vlist1[i])) + list2.append(int(vlist2[i])) + # now we have to use floats so 1.02 compares correctly against 1.1 + else: + list1.append(float("0."+vlist1[i])) + list2.append(float("0."+vlist2[i])) + # and now the final letter + if len(match1.group(4)): + list1.append(ord(match1.group(4))) + if len(match2.group(4)): + list2.append(ord(match2.group(4))) - for i in range(0, max(len(list1), len(list2))): - if len(list1) <= i: - return -1 - elif len(list2) <= i: - return 1 - elif list1[i] != list2[i]: - return list1[i] - list2[i] + for i in range(0, max(len(list1), len(list2))): + if len(list1) <= i: + return -1 + elif len(list2) <= i: + return 1 + elif list1[i] != list2[i]: + return list1[i] - list2[i] - # main version is equal, so now compare the _suffix part - list1 = match1.group(5).split("_")[1:] - list2 = match2.group(5).split("_")[1:] + # main version is equal, so now compare the _suffix part + list1 = match1.group(5).split("_")[1:] + list2 = match2.group(5).split("_")[1:] - for i in range(0, max(len(list1), len(list2))): - # Implicit _p0 is given a value of -1, so that 1 < 1_p0 - if len(list1) <= i: - s1 = ("p","-1") - else: - s1 = suffix_regexp.match(list1[i]).groups() - if len(list2) <= i: - s2 = ("p","-1") - else: - s2 = suffix_regexp.match(list2[i]).groups() - if s1[0] != s2[0]: - return suffix_value[s1[0]] - suffix_value[s2[0]] - if s1[1] != s2[1]: - # it's possible that the s(1|2)[1] == '' - # in such a case, fudge it. - try: - r1 = int(s1[1]) - except ValueError: - r1 = 0 - try: - r2 = int(s2[1]) - except ValueError: - r2 = 0 - if r1 - r2: - return r1 - r2 + for i in range(0, max(len(list1), len(list2))): + # Implicit _p0 is given a value of -1, so that 1 < 1_p0 + if len(list1) <= i: + s1 = ("p","-1") + else: + s1 = suffix_regexp.match(list1[i]).groups() + if len(list2) <= i: + s2 = ("p","-1") + else: + s2 = suffix_regexp.match(list2[i]).groups() + if s1[0] != s2[0]: + return suffix_value[s1[0]] - suffix_value[s2[0]] + if s1[1] != s2[1]: + # it's possible that the s(1|2)[1] == '' + # in such a case, fudge it. + try: + r1 = int(s1[1]) + except ValueError: + r1 = 0 + try: + r2 = int(s2[1]) + except ValueError: + r2 = 0 + if r1 - r2: + return r1 - r2 - # the suffix part is equal to, so finally check the revision - if match1.group(9): - r1 = int(match1.group(9)) - else: - r1 = 0 - if match2.group(9): - r2 = int(match2.group(9)) - else: - r2 = 0 - return r1 - r2 + # the suffix part is equal to, so finally check the revision + if match1.group(9): + r1 = int(match1.group(9)) + else: + r1 = 0 + if match2.group(9): + r2 = int(match2.group(9)) + else: + r2 = 0 + return r1 - r2 class module_repository(osv.osv): - _name = "ir.module.repository" - _description = "Module Repository" - _columns = { - 'name': fields.char('Name', size=128), - 'url': fields.char('Url', size=256, required=True), - 'sequence': fields.integer('Sequence', required=True), - 'filter': fields.char('Filter', size=128, required=True, - help='Regexp to search module on the repository webpage:\n' - '- The first parenthesis must match the name of the module.\n' - '- The second parenthesis must match all the version number.\n' - '- The last parenthesis must match the extension of the module.'), - 'active': fields.boolean('Active'), - } - _defaults = { - 'sequence': lambda *a: 5, - 'filter': lambda *a: 'href="([a-zA-Z0-9_]+)-('+release.version.rsplit('.', 1)[0]+'.(\\d+)((\\.\\d+)*)([a-z]?)((_(pre|p|beta|alpha|rc)\\d*)*)(-r(\\d+))?)(\.zip)"', - 'active': lambda *a: 1, - } - _order = "sequence" + _name = "ir.module.repository" + _description = "Module Repository" + _columns = { + 'name': fields.char('Name', size=128), + 'url': fields.char('Url', size=256, required=True), + 'sequence': fields.integer('Sequence', required=True), + 'filter': fields.char('Filter', size=128, required=True, + help='Regexp to search module on the repository webpage:\n' + '- The first parenthesis must match the name of the module.\n' + '- The second parenthesis must match all the version number.\n' + '- The last parenthesis must match the extension of the module.'), + 'active': fields.boolean('Active'), + } + _defaults = { + 'sequence': lambda *a: 5, + 'filter': lambda *a: 'href="([a-zA-Z0-9_]+)-('+release.version.rsplit('.', 1)[0]+'.(\\d+)((\\.\\d+)*)([a-z]?)((_(pre|p|beta|alpha|rc)\\d*)*)(-r(\\d+))?)(\.zip)"', + 'active': lambda *a: 1, + } + _order = "sequence" module_repository() class module_category(osv.osv): - _name = "ir.module.category" - _description = "Module Category" + _name = "ir.module.category" + _description = "Module Category" - def _module_nbr(self,cr,uid, ids, prop, unknow_none,context): - cr.execute('select category_id,count(*) from ir_module_module where category_id in ('+','.join(map(str,ids))+') or category_id in (select id from ir_module_category where parent_id in ('+','.join(map(str,ids))+')) group by category_id') - result = dict(cr.fetchall()) - for id in ids: - cr.execute('select id from ir_module_category where parent_id=%d', (id,)) - childs = [c for c, in cr.fetchall()] - result[id] = reduce(lambda x,y:x+y, [result.get(c, 0) for c in childs], result.get(id, 0)) - return result + def _module_nbr(self,cr,uid, ids, prop, unknow_none,context): + cr.execute('select category_id,count(*) from ir_module_module where category_id in ('+','.join(map(str,ids))+') or category_id in (select id from ir_module_category where parent_id in ('+','.join(map(str,ids))+')) group by category_id') + result = dict(cr.fetchall()) + for id in ids: + cr.execute('select id from ir_module_category where parent_id=%d', (id,)) + childs = [c for c, in cr.fetchall()] + result[id] = reduce(lambda x,y:x+y, [result.get(c, 0) for c in childs], result.get(id, 0)) + return result - _columns = { - 'name': fields.char("Name", size=128, required=True), - 'parent_id': fields.many2one('ir.module.category', 'Parent Category', select=True), - 'child_ids': fields.one2many('ir.module.category', 'parent_id', 'Parent Category'), - 'module_nr': fields.function(_module_nbr, method=True, string='# of Modules', type='integer') - } - _order = 'name' + _columns = { + 'name': fields.char("Name", size=128, required=True), + 'parent_id': fields.many2one('ir.module.category', 'Parent Category', select=True), + 'child_ids': fields.one2many('ir.module.category', 'parent_id', 'Parent Category'), + 'module_nr': fields.function(_module_nbr, method=True, string='# of Modules', type='integer') + } + _order = 'name' module_category() class module(osv.osv): - _name = "ir.module.module" - _description = "Module" + _name = "ir.module.module" + _description = "Module" - def get_module_info(self, name): - try: - f = tools.file_open(os.path.join(name, '__terp__.py')) - data = f.read() - info = eval(data) - if 'version' in info: - info['version'] = release.version.rsplit('.', 1)[0] + '.' + info['version'] - f.close() - except: - return {} - return info + def get_module_info(self, name): + try: + f = tools.file_open(os.path.join(name, '__terp__.py')) + data = f.read() + info = eval(data) + if 'version' in info: + info['version'] = release.version.rsplit('.', 1)[0] + '.' + info['version'] + f.close() + except: + return {} + return info - def _get_installed_version(self, cr, uid, ids, field_name=None, arg=None, context={}): - res = {} - for m in self.browse(cr, uid, ids): - if m.state in ('installed', 'to upgrade', 'to remove'): - res[m.id] = self.get_module_info(m.name).get('version', '') - else: - res[m.id] = '' - return res + def _get_installed_version(self, cr, uid, ids, field_name=None, arg=None, context={}): + res = {} + for m in self.browse(cr, uid, ids): + if m.state in ('installed', 'to upgrade', 'to remove'): + res[m.id] = self.get_module_info(m.name).get('version', '') + else: + res[m.id] = '' + return res - _columns = { - 'name': fields.char("Name", size=128, readonly=True, required=True), - 'category_id': fields.many2one('ir.module.category', 'Category', readonly=True), - 'shortdesc': fields.char('Short description', size=256, readonly=True), - 'description': fields.text("Description", readonly=True), - 'author': fields.char("Author", size=128, readonly=True), - 'website': fields.char("Website", size=256, readonly=True), - 'installed_version': fields.function(_get_installed_version, method=True, - string='Installed version', type='char'), - 'latest_version': fields.char('Latest version', size=64, readonly=True), - 'published_version': fields.char('Published Version', size=64, readonly=True), - 'url': fields.char('URL', size=128), - 'dependencies_id': fields.one2many('ir.module.module.dependency', - 'module_id', 'Dependencies', readonly=True), - 'state': fields.selection([ - ('uninstallable','Not Installable'), - ('uninstalled','Not Installed'), - ('installed','Installed'), - ('to upgrade','To be upgraded'), - ('to remove','To be removed'), - ('to install','To be installed') - ], string='State', readonly=True), - 'demo': fields.boolean('Demo data'), - 'license': fields.selection([('GPL-2', 'GPL-2'), - ('Other proprietary', 'Other proprietary')], string='License', - readonly=True), - } + _columns = { + 'name': fields.char("Name", size=128, readonly=True, required=True), + 'category_id': fields.many2one('ir.module.category', 'Category', readonly=True), + 'shortdesc': fields.char('Short description', size=256, readonly=True), + 'description': fields.text("Description", readonly=True), + 'author': fields.char("Author", size=128, readonly=True), + 'website': fields.char("Website", size=256, readonly=True), + 'installed_version': fields.function(_get_installed_version, method=True, + string='Installed version', type='char'), + 'latest_version': fields.char('Latest version', size=64, readonly=True), + 'published_version': fields.char('Published Version', size=64, readonly=True), + 'url': fields.char('URL', size=128), + 'dependencies_id': fields.one2many('ir.module.module.dependency', + 'module_id', 'Dependencies', readonly=True), + 'state': fields.selection([ + ('uninstallable','Not Installable'), + ('uninstalled','Not Installed'), + ('installed','Installed'), + ('to upgrade','To be upgraded'), + ('to remove','To be removed'), + ('to install','To be installed') + ], string='State', readonly=True), + 'demo': fields.boolean('Demo data'), + 'license': fields.selection([('GPL-2', 'GPL-2'), + ('Other proprietary', 'Other proprietary')], string='License', + readonly=True), + } - _defaults = { - 'state': lambda *a: 'uninstalled', - 'demo': lambda *a: False, - 'license': lambda *a: 'GPL-2', - } - _order = 'name' + _defaults = { + 'state': lambda *a: 'uninstalled', + 'demo': lambda *a: False, + 'license': lambda *a: 'GPL-2', + } + _order = 'name' - _sql_constraints = [ - ('name_uniq', 'unique (name)', 'The name of the module must be unique !') - ] + _sql_constraints = [ + ('name_uniq', 'unique (name)', 'The name of the module must be unique !') + ] - def unlink(self, cr, uid, ids, context=None): - if not ids: - return True - if isinstance(ids, (int, long)): - ids = [ids] - for mod in self.read(cr, uid, ids, ['state'], context): - if mod['state'] in ('installed', 'to upgrade', 'to remove', 'to install'): - raise orm.except_orm(_('Error'), - _('You try to remove a module that is installed or will be installed')) - return super(module, self).unlink(cr, uid, ids, context=context) + def unlink(self, cr, uid, ids, context=None): + if not ids: + return True + if isinstance(ids, (int, long)): + ids = [ids] + for mod in self.read(cr, uid, ids, ['state'], context): + if mod['state'] in ('installed', 'to upgrade', 'to remove', 'to install'): + raise orm.except_orm(_('Error'), + _('You try to remove a module that is installed or will be installed')) + return super(module, self).unlink(cr, uid, ids, context=context) - def state_change(self, cr, uid, ids, newstate, context={}, level=50): - if level<1: - raise Exception, _('Recursion error in modules dependencies !') - demo = True - for module in self.browse(cr, uid, ids): - mdemo = True - for dep in module.dependencies_id: - ids2 = self.search(cr, uid, [('name','=',dep.name)]) - mdemo = self.state_change(cr, uid, ids2, newstate, context, level-1,)\ - and mdemo - if not module.dependencies_id: - mdemo = module.demo - if module.state == 'uninstalled': - self.write(cr, uid, [module.id], {'state': newstate, 'demo':mdemo}) - demo = demo and mdemo - return demo + def state_change(self, cr, uid, ids, newstate, context={}, level=50): + if level<1: + raise Exception, _('Recursion error in modules dependencies !') + demo = True + for module in self.browse(cr, uid, ids): + mdemo = True + for dep in module.dependencies_id: + ids2 = self.search(cr, uid, [('name','=',dep.name)]) + mdemo = self.state_change(cr, uid, ids2, newstate, context, level-1,)\ + and mdemo + if not module.dependencies_id: + mdemo = module.demo + if module.state == 'uninstalled': + self.write(cr, uid, [module.id], {'state': newstate, 'demo':mdemo}) + demo = demo and mdemo + return demo - def state_upgrade(self, cr, uid, ids, newstate, context=None, level=50): - dep_obj = self.pool.get('ir.module.module.dependency') - if level<1: - raise Exception, _('Recursion error in modules dependencies !') - for module in self.browse(cr, uid, ids): - dep_ids = dep_obj.search(cr, uid, [('name', '=', module.name)]) - if dep_ids: - ids2 = [] - for dep in dep_obj.browse(cr, uid, dep_ids): - if dep.module_id.state != 'to upgrade': - ids2.append(dep.module_id.id) - self.state_upgrade(cr, uid, ids2, newstate, context, level) - if module.state == 'installed': - self.write(cr, uid, module.id, {'state': newstate}) - return True + def state_upgrade(self, cr, uid, ids, newstate, context=None, level=50): + dep_obj = self.pool.get('ir.module.module.dependency') + if level<1: + raise Exception, _('Recursion error in modules dependencies !') + for module in self.browse(cr, uid, ids): + dep_ids = dep_obj.search(cr, uid, [('name', '=', module.name)]) + if dep_ids: + ids2 = [] + for dep in dep_obj.browse(cr, uid, dep_ids): + if dep.module_id.state != 'to upgrade': + ids2.append(dep.module_id.id) + self.state_upgrade(cr, uid, ids2, newstate, context, level) + if module.state == 'installed': + self.write(cr, uid, module.id, {'state': newstate}) + return True - def button_install(self, cr, uid, ids, context={}): - return self.state_change(cr, uid, ids, 'to install', context) + def button_install(self, cr, uid, ids, context={}): + return self.state_change(cr, uid, ids, 'to install', context) - def button_install_cancel(self, cr, uid, ids, context={}): - self.write(cr, uid, ids, {'state': 'uninstalled', 'demo':False}) - return True + def button_install_cancel(self, cr, uid, ids, context={}): + self.write(cr, uid, ids, {'state': 'uninstalled', 'demo':False}) + return True - def button_uninstall(self, cr, uid, ids, context={}): - for module in self.browse(cr, uid, ids): - cr.execute('''select m.state,m.name - from - ir_module_module_dependency d - join - ir_module_module m on (d.module_id=m.id) - where - d.name=%s and - m.state not in ('uninstalled','uninstallable','to remove')''', (module.name,)) - res = cr.fetchall() - if res: - raise orm.except_orm(_('Error'), _('The module you are trying to remove depends on installed modules :\n %s') % '\n'.join(map(lambda x: '\t%s: %s' % (x[0], x[1]), res))) - self.write(cr, uid, ids, {'state': 'to remove'}) - return True + def button_uninstall(self, cr, uid, ids, context={}): + for module in self.browse(cr, uid, ids): + cr.execute('''select m.state,m.name + from + ir_module_module_dependency d + join + ir_module_module m on (d.module_id=m.id) + where + d.name=%s and + m.state not in ('uninstalled','uninstallable','to remove')''', (module.name,)) + res = cr.fetchall() + if res: + raise orm.except_orm(_('Error'), _('The module you are trying to remove depends on installed modules :\n %s') % '\n'.join(map(lambda x: '\t%s: %s' % (x[0], x[1]), res))) + self.write(cr, uid, ids, {'state': 'to remove'}) + return True - def button_uninstall_cancel(self, cr, uid, ids, context={}): - self.write(cr, uid, ids, {'state': 'installed'}) - return True - def button_upgrade(self, cr, uid, ids, context=None): - return self.state_upgrade(cr, uid, ids, 'to upgrade', context) - def button_upgrade_cancel(self, cr, uid, ids, context={}): - self.write(cr, uid, ids, {'state': 'installed'}) - return True - def button_update_translations(self, cr, uid, ids, context={}): - cr.execute('select code from res_lang where translatable=TRUE') - langs = [l[0] for l in cr.fetchall()] - modules = self.read(cr, uid, ids, ['name']) - for module in modules: - files = self.get_module_info(module['name']).get('translations', {}) - for lang in langs: - if files.has_key(lang): - filepath = files[lang] - # if filepath does not contain :// we prepend the path of the module - if filepath.find('://') == -1: - filepath = addons.get_module_resource(module['name'], filepath) - tools.trans_load(filepath, lang) - return True + def button_uninstall_cancel(self, cr, uid, ids, context={}): + self.write(cr, uid, ids, {'state': 'installed'}) + return True + def button_upgrade(self, cr, uid, ids, context=None): + return self.state_upgrade(cr, uid, ids, 'to upgrade', context) + def button_upgrade_cancel(self, cr, uid, ids, context={}): + self.write(cr, uid, ids, {'state': 'installed'}) + return True + def button_update_translations(self, cr, uid, ids, context={}): + cr.execute('select code from res_lang where translatable=TRUE') + langs = [l[0] for l in cr.fetchall()] + modules = self.read(cr, uid, ids, ['name']) + for module in modules: + files = self.get_module_info(module['name']).get('translations', {}) + for lang in langs: + if files.has_key(lang): + filepath = files[lang] + # if filepath does not contain :// we prepend the path of the module + if filepath.find('://') == -1: + filepath = addons.get_module_resource(module['name'], filepath) + tools.trans_load(filepath, lang) + return True - # update the list of available packages - def update_list(self, cr, uid, context={}): - robj = self.pool.get('ir.module.repository') - res = [0, 0] # [update, add] + # update the list of available packages + def update_list(self, cr, uid, context={}): + robj = self.pool.get('ir.module.repository') + res = [0, 0] # [update, add] - # iterate through installed modules and mark them as being so - for name in addons.get_modules(): - mod_name = name - if name[-4:]=='.zip': - mod_name=name[:-4] - ids = self.search(cr, uid, [('name','=',mod_name)]) - if ids: - id = ids[0] - mod = self.browse(cr, uid, id) - terp = self.get_module_info(mod_name) - if terp.get('installable', True) and mod.state == 'uninstallable': - self.write(cr, uid, id, {'state': 'uninstalled'}) - if vercmp(terp.get('version', ''), mod.latest_version or '0') > 0: - self.write(cr, uid, id, { - 'latest_version': terp.get('version'), - 'url': ''}) - res[0] += 1 - self.write(cr, uid, id, { - 'description': terp.get('description', ''), - 'shortdesc': terp.get('name', ''), - 'author': terp.get('author', 'Unknown'), - 'website': terp.get('website', ''), - 'license': terp.get('license', 'GPL-2'), - }) - cr.execute('DELETE FROM ir_module_module_dependency\ - WHERE module_id = %d', (id,)) - self._update_dependencies(cr, uid, ids[0], terp.get('depends', - [])) - self._update_category(cr, uid, ids[0], terp.get('category', - 'Uncategorized')) - continue - terp_file = addons.get_module_resource(name, '__terp__.py') - mod_path = addons.get_module_path(name) - if os.path.isdir(mod_path) or os.path.islink(mod_path) or zipfile.is_zipfile(mod_path): - terp = self.get_module_info(mod_name) - if not terp or not terp.get('installable', True): - continue - if not os.path.isfile(mod_path+'.zip'): - import imp - # XXX must restrict to only addons paths - imp.load_module(name, *imp.find_module(mod_name)) - else: - import zipimport - zimp = zipimport.zipimporter(mod_path+'.zip') - zimp.load_module(mod_name) - id = self.create(cr, uid, { - 'name': mod_name, - 'state': 'uninstalled', - 'description': terp.get('description', ''), - 'shortdesc': terp.get('name', ''), - 'author': terp.get('author', 'Unknown'), - 'website': terp.get('website', ''), - 'latest_version': terp.get('version', ''), - 'license': terp.get('license', 'GPL-2'), - }) - res[1] += 1 - self._update_dependencies(cr, uid, id, terp.get('depends', [])) - self._update_category(cr, uid, id, terp.get('category', 'Uncategorized')) + # iterate through installed modules and mark them as being so + for name in addons.get_modules(): + mod_name = name + if name[-4:]=='.zip': + mod_name=name[:-4] + ids = self.search(cr, uid, [('name','=',mod_name)]) + if ids: + id = ids[0] + mod = self.browse(cr, uid, id) + terp = self.get_module_info(mod_name) + if terp.get('installable', True) and mod.state == 'uninstallable': + self.write(cr, uid, id, {'state': 'uninstalled'}) + if vercmp(terp.get('version', ''), mod.latest_version or '0') > 0: + self.write(cr, uid, id, { + 'latest_version': terp.get('version'), + 'url': ''}) + res[0] += 1 + self.write(cr, uid, id, { + 'description': terp.get('description', ''), + 'shortdesc': terp.get('name', ''), + 'author': terp.get('author', 'Unknown'), + 'website': terp.get('website', ''), + 'license': terp.get('license', 'GPL-2'), + }) + cr.execute('DELETE FROM ir_module_module_dependency\ + WHERE module_id = %d', (id,)) + self._update_dependencies(cr, uid, ids[0], terp.get('depends', + [])) + self._update_category(cr, uid, ids[0], terp.get('category', + 'Uncategorized')) + continue + terp_file = addons.get_module_resource(name, '__terp__.py') + mod_path = addons.get_module_path(name) + if os.path.isdir(mod_path) or os.path.islink(mod_path) or zipfile.is_zipfile(mod_path): + terp = self.get_module_info(mod_name) + if not terp or not terp.get('installable', True): + continue + if not os.path.isfile(mod_path+'.zip'): + import imp + # XXX must restrict to only addons paths + imp.load_module(name, *imp.find_module(mod_name)) + else: + import zipimport + zimp = zipimport.zipimporter(mod_path+'.zip') + zimp.load_module(mod_name) + id = self.create(cr, uid, { + 'name': mod_name, + 'state': 'uninstalled', + 'description': terp.get('description', ''), + 'shortdesc': terp.get('name', ''), + 'author': terp.get('author', 'Unknown'), + 'website': terp.get('website', ''), + 'latest_version': terp.get('version', ''), + 'license': terp.get('license', 'GPL-2'), + }) + res[1] += 1 + self._update_dependencies(cr, uid, id, terp.get('depends', [])) + self._update_category(cr, uid, id, terp.get('category', 'Uncategorized')) - import socket - socket.setdefaulttimeout(10) - for repository in robj.browse(cr, uid, robj.search(cr, uid, [])): - try: - index_page = urllib.urlopen(repository.url).read() - except IOError, e: - if e.errno == 21: - raise orm.except_orm(_('Error'), - _("This url '%s' must provide an html file with links to zip modules") % (repository.url)) - else: - raise - modules = re.findall(repository.filter, index_page, re.I+re.M) - mod_sort = {} - for m in modules: - name = m[0] - version = m[1] - extension = m[-1] - if version == 'x': # 'x' version was a mistake - version = '0' - if name in mod_sort: - if vercmp(version, mod_sort[name][0]) <= 0: - continue - mod_sort[name] = [version, extension] - for name in mod_sort.keys(): - version, extension = mod_sort[name] - url = repository.url+'/'+name+'-'+version+extension - ids = self.search(cr, uid, [('name','=',name)]) - if not ids: - self.create(cr, uid, { - 'name': name, - 'latest_version': version, - 'published_version': version, - 'url': url, - 'state': 'uninstalled', - }) - res[1] += 1 - else: - id = ids[0] - latest_version = self.read(cr, uid, id, ['latest_version'])\ - ['latest_version'] - if latest_version == 'x': # 'x' version was a mistake - latest_version = '0' - c = vercmp(version, latest_version) - if c > 0: - self.write(cr, uid, id, - {'latest_version': version, 'url': url}) - res[0] += 1 - published_version = self.read(cr, uid, id, ['published_version'])\ - ['published_version'] - if published_version == 'x' or not published_version: - published_version = '0' - c = vercmp(version, published_version) - if c > 0: - self.write(cr, uid, id, - {'published_version': version}) - return res + import socket + socket.setdefaulttimeout(10) + for repository in robj.browse(cr, uid, robj.search(cr, uid, [])): + try: + index_page = urllib.urlopen(repository.url).read() + except IOError, e: + if e.errno == 21: + raise orm.except_orm(_('Error'), + _("This url '%s' must provide an html file with links to zip modules") % (repository.url)) + else: + raise + modules = re.findall(repository.filter, index_page, re.I+re.M) + mod_sort = {} + for m in modules: + name = m[0] + version = m[1] + extension = m[-1] + if version == 'x': # 'x' version was a mistake + version = '0' + if name in mod_sort: + if vercmp(version, mod_sort[name][0]) <= 0: + continue + mod_sort[name] = [version, extension] + for name in mod_sort.keys(): + version, extension = mod_sort[name] + url = repository.url+'/'+name+'-'+version+extension + ids = self.search(cr, uid, [('name','=',name)]) + if not ids: + self.create(cr, uid, { + 'name': name, + 'latest_version': version, + 'published_version': version, + 'url': url, + 'state': 'uninstalled', + }) + res[1] += 1 + else: + id = ids[0] + latest_version = self.read(cr, uid, id, ['latest_version'])\ + ['latest_version'] + if latest_version == 'x': # 'x' version was a mistake + latest_version = '0' + c = vercmp(version, latest_version) + if c > 0: + self.write(cr, uid, id, + {'latest_version': version, 'url': url}) + res[0] += 1 + published_version = self.read(cr, uid, id, ['published_version'])\ + ['published_version'] + if published_version == 'x' or not published_version: + published_version = '0' + c = vercmp(version, published_version) + if c > 0: + self.write(cr, uid, id, + {'published_version': version}) + return res - def download(self, cr, uid, ids, download=True, context=None): - res = [] - for mod in self.browse(cr, uid, ids, context=context): - if not mod.url: - continue - match = re.search('-([a-zA-Z0-9\._-]+)(\.zip)', mod.url, re.I) - version = '0' - if match: - version = match.group(1) - if vercmp(mod.installed_version or '0', version) >= 0: - continue - res.append(mod.url) - if not download: - continue - zipfile = urllib.urlopen(mod.url).read() - fname = addons.get_module_path(mod.name+'.zip') - try: - fp = file(fname, 'wb') - fp.write(zipfile) - fp.close() - except IOError, e: - raise orm.except_orm(_('Error'), _('Can not create the module file:\n %s') % (fname,)) - terp = self.get_module_info(mod.name) - self.write(cr, uid, mod.id, { - 'description': terp.get('description', ''), - 'shortdesc': terp.get('name', ''), - 'author': terp.get('author', 'Unknown'), - 'website': terp.get('website', ''), - 'license': terp.get('license', 'GPL-2'), - }) - cr.execute('DELETE FROM ir_module_module_dependency ' \ - 'WHERE module_id = %d', (mod.id,)) - self._update_dependencies(cr, uid, mod.id, terp.get('depends', - [])) - self._update_category(cr, uid, mod.id, terp.get('category', - 'Uncategorized')) - # Import module - zimp = zipimport.zipimporter(fname) - zimp.load_module(mod.name) - return res + def download(self, cr, uid, ids, download=True, context=None): + res = [] + for mod in self.browse(cr, uid, ids, context=context): + if not mod.url: + continue + match = re.search('-([a-zA-Z0-9\._-]+)(\.zip)', mod.url, re.I) + version = '0' + if match: + version = match.group(1) + if vercmp(mod.installed_version or '0', version) >= 0: + continue + res.append(mod.url) + if not download: + continue + zipfile = urllib.urlopen(mod.url).read() + fname = addons.get_module_path(mod.name+'.zip') + try: + fp = file(fname, 'wb') + fp.write(zipfile) + fp.close() + except IOError, e: + raise orm.except_orm(_('Error'), _('Can not create the module file:\n %s') % (fname,)) + terp = self.get_module_info(mod.name) + self.write(cr, uid, mod.id, { + 'description': terp.get('description', ''), + 'shortdesc': terp.get('name', ''), + 'author': terp.get('author', 'Unknown'), + 'website': terp.get('website', ''), + 'license': terp.get('license', 'GPL-2'), + }) + cr.execute('DELETE FROM ir_module_module_dependency ' \ + 'WHERE module_id = %d', (mod.id,)) + self._update_dependencies(cr, uid, mod.id, terp.get('depends', + [])) + self._update_category(cr, uid, mod.id, terp.get('category', + 'Uncategorized')) + # Import module + zimp = zipimport.zipimporter(fname) + zimp.load_module(mod.name) + return res - def _update_dependencies(self, cr, uid, id, depends=[]): - for d in depends: - cr.execute('INSERT INTO ir_module_module_dependency (module_id, name) values (%d, %s)', (id, d)) + def _update_dependencies(self, cr, uid, id, depends=[]): + for d in depends: + cr.execute('INSERT INTO ir_module_module_dependency (module_id, name) values (%d, %s)', (id, d)) - def _update_category(self, cr, uid, id, category='Uncategorized'): - categs = category.split('/') - p_id = None - while categs: - if p_id is not None: - cr.execute('select id from ir_module_category where name=%s and parent_id=%d', (categs[0], p_id)) - else: - cr.execute('select id from ir_module_category where name=%s and parent_id is NULL', (categs[0],)) - c_id = cr.fetchone() - if not c_id: - cr.execute('select nextval(\'ir_module_category_id_seq\')') - c_id = cr.fetchone()[0] - cr.execute('insert into ir_module_category (id, name, parent_id) values (%d, %s, %d)', (c_id, categs[0], p_id)) - else: - c_id = c_id[0] - p_id = c_id - categs = categs[1:] - self.write(cr, uid, [id], {'category_id': p_id}) + def _update_category(self, cr, uid, id, category='Uncategorized'): + categs = category.split('/') + p_id = None + while categs: + if p_id is not None: + cr.execute('select id from ir_module_category where name=%s and parent_id=%d', (categs[0], p_id)) + else: + cr.execute('select id from ir_module_category where name=%s and parent_id is NULL', (categs[0],)) + c_id = cr.fetchone() + if not c_id: + cr.execute('select nextval(\'ir_module_category_id_seq\')') + c_id = cr.fetchone()[0] + cr.execute('insert into ir_module_category (id, name, parent_id) values (%d, %s, %d)', (c_id, categs[0], p_id)) + else: + c_id = c_id[0] + p_id = c_id + categs = categs[1:] + self.write(cr, uid, [id], {'category_id': p_id}) module() class module_dependency(osv.osv): - _name = "ir.module.module.dependency" - _description = "Module dependency" + _name = "ir.module.module.dependency" + _description = "Module dependency" - def _state(self, cr, uid, ids, name, args, context={}): - result = {} - mod_obj = self.pool.get('ir.module.module') - for md in self.browse(cr, uid, ids): - ids = mod_obj.search(cr, uid, [('name', '=', md.name)]) - if ids: - result[md.id] = mod_obj.read(cr, uid, [ids[0]], ['state'])[0]['state'] - else: - result[md.id] = 'unknown' - return result + def _state(self, cr, uid, ids, name, args, context={}): + result = {} + mod_obj = self.pool.get('ir.module.module') + for md in self.browse(cr, uid, ids): + ids = mod_obj.search(cr, uid, [('name', '=', md.name)]) + if ids: + result[md.id] = mod_obj.read(cr, uid, [ids[0]], ['state'])[0]['state'] + else: + result[md.id] = 'unknown' + return result - _columns = { - 'name': fields.char('Name', size=128), - 'module_id': fields.many2one('ir.module.module', 'Module', select=True, ondelete='cascade'), - 'state': fields.function(_state, method=True, type='selection', selection=[ - ('uninstallable','Uninstallable'), - ('uninstalled','Not Installed'), - ('installed','Installed'), - ('to upgrade','To be upgraded'), - ('to remove','To be removed'), - ('to install','To be installed'), - ('unknown', 'Unknown'), - ], string='State', readonly=True), - } + _columns = { + 'name': fields.char('Name', size=128), + 'module_id': fields.many2one('ir.module.module', 'Module', select=True, ondelete='cascade'), + 'state': fields.function(_state, method=True, type='selection', selection=[ + ('uninstallable','Uninstallable'), + ('uninstalled','Not Installed'), + ('installed','Installed'), + ('to upgrade','To be upgraded'), + ('to remove','To be removed'), + ('to install','To be installed'), + ('unknown', 'Unknown'), + ], string='State', readonly=True), + } module_dependency() class module_config_wizard_step(osv.osv): - _name = 'ir.module.module.configuration.step' - _columns={ - 'name':fields.char('Name',size=64,required=True, select=True), - 'note':fields.text('Text'), - 'action_id':fields.many2one('ir.actions.act_window', 'Action', select=True,required=True, ondelete='cascade'), - 'sequence':fields.integer('Sequence'), - 'state':fields.selection([('open', 'Open'),('done', 'Done'),('skip','Skip')], string='State', required=True) - } - _defaults={ - 'state': lambda *a: 'open', - 'sequence': lambda *a: 10, - } - _order="sequence" + _name = 'ir.module.module.configuration.step' + _columns={ + 'name':fields.char('Name',size=64,required=True, select=True), + 'note':fields.text('Text'), + 'action_id':fields.many2one('ir.actions.act_window', 'Action', select=True,required=True, ondelete='cascade'), + 'sequence':fields.integer('Sequence'), + 'state':fields.selection([('open', 'Open'),('done', 'Done'),('skip','Skip')], string='State', required=True) + } + _defaults={ + 'state': lambda *a: 'open', + 'sequence': lambda *a: 10, + } + _order="sequence" module_config_wizard_step() class module_configuration(osv.osv_memory): - _name='ir.module.module.configuration.wizard' - def _get_action_name(self, cr, uid, context={}): - item_obj = self.pool.get('ir.module.module.configuration.step') - item_ids = item_obj.search(cr, uid, [ - ('state', '=', 'open'), - ], limit=1, context=context) - if item_ids and len(item_ids): - item = item_obj.browse(cr, uid, item_ids[0], context=context) - return item.note - else: - return "Your database is now fully configured.\n\nClick 'Continue' and enyoy your OpenERP experience..." - return False + _name='ir.module.module.configuration.wizard' + def _get_action_name(self, cr, uid, context={}): + item_obj = self.pool.get('ir.module.module.configuration.step') + item_ids = item_obj.search(cr, uid, [ + ('state', '=', 'open'), + ], limit=1, context=context) + if item_ids and len(item_ids): + item = item_obj.browse(cr, uid, item_ids[0], context=context) + return item.note + else: + return "Your database is now fully configured.\n\nClick 'Continue' and enyoy your OpenERP experience..." + return False - def _get_action(self, cr, uid, context={}): - item_obj = self.pool.get('ir.module.module.configuration.step') - item_ids = item_obj.search(cr, uid, [ - ('state', '=', 'open'), - ], limit=1, context=context) - if item_ids: - item = item_obj.browse(cr, uid, item_ids[0], context=context) - return item.id - return False + def _get_action(self, cr, uid, context={}): + item_obj = self.pool.get('ir.module.module.configuration.step') + item_ids = item_obj.search(cr, uid, [ + ('state', '=', 'open'), + ], limit=1, context=context) + if item_ids: + item = item_obj.browse(cr, uid, item_ids[0], context=context) + return item.id + return False - _columns = { - 'name': fields.text('Next Wizard',readonly=True), - 'item_id':fields.many2one('ir.module.module.configuration.step', 'Next Configuration Wizard',invisible=True, readonly=True), + _columns = { + 'name': fields.text('Next Wizard',readonly=True), + 'item_id':fields.many2one('ir.module.module.configuration.step', 'Next Configuration Wizard',invisible=True, readonly=True), - } - _defaults={ - 'item_id':_get_action, - 'name':_get_action_name, + } + _defaults={ + 'item_id':_get_action, + 'name':_get_action_name, - } - def button_skip(self,cr,uid,ids,context=None): - item_obj = self.pool.get('ir.module.module.configuration.step') - item_id=self.read(cr,uid,ids)[0]['item_id'] - if item_id: - item = item_obj.browse(cr, uid, item_id, context=context) - item_obj.write(cr, uid, item.id, { - 'state': 'skip', - }, context=context) - return{ - 'view_type': 'form', - "view_mode": 'form', - 'res_model': 'ir.module.module.configuration.wizard', - 'type': 'ir.actions.act_window', - 'target':'new', - } - return {'type':'ir.actions.act_window_close'} + } + def button_skip(self,cr,uid,ids,context=None): + item_obj = self.pool.get('ir.module.module.configuration.step') + item_id=self.read(cr,uid,ids)[0]['item_id'] + if item_id: + item = item_obj.browse(cr, uid, item_id, context=context) + item_obj.write(cr, uid, item.id, { + 'state': 'skip', + }, context=context) + return{ + 'view_type': 'form', + "view_mode": 'form', + 'res_model': 'ir.module.module.configuration.wizard', + 'type': 'ir.actions.act_window', + 'target':'new', + } + return {'type':'ir.actions.act_window_close'} - def button_continue(self, cr, uid, ids, context=None): - item_obj = self.pool.get('ir.module.module.configuration.step') - item_id=self.read(cr,uid,ids)[0]['item_id'] - if item_id: - item = item_obj.browse(cr, uid, item_id, context=context) - item_obj.write(cr, uid, item.id, { - 'state': 'done', - }, context=context) - return{ - 'view_type': item.action_id.view_type, - 'view_id':item.action_id.view_id and [item.action_id.view_id.id] or False, - 'res_model': item.action_id.res_model, - 'type': item.action_id.type, - 'target':item.action_id.target, - } - return {'type':'ir.actions.act_window_close' } + def button_continue(self, cr, uid, ids, context=None): + item_obj = self.pool.get('ir.module.module.configuration.step') + item_id=self.read(cr,uid,ids)[0]['item_id'] + if item_id: + item = item_obj.browse(cr, uid, item_id, context=context) + item_obj.write(cr, uid, item.id, { + 'state': 'done', + }, context=context) + return{ + 'view_type': item.action_id.view_type, + 'view_id':item.action_id.view_id and [item.action_id.view_id.id] or False, + 'res_model': item.action_id.res_model, + 'type': item.action_id.type, + 'target':item.action_id.target, + } + return {'type':'ir.actions.act_window_close' } module_configuration() diff --git a/bin/addons/base/module/report/ir_module_reference_print.py b/bin/addons/base/module/report/ir_module_reference_print.py index f934803e862..57ffc71bdc4 100644 --- a/bin/addons/base/module/report/ir_module_reference_print.py +++ b/bin/addons/base/module/report/ir_module_reference_print.py @@ -31,33 +31,33 @@ import time from report import report_sxw class ir_module_reference_print(report_sxw.rml_parse): - def __init__(self, cr, uid, name, context): - super(ir_module_reference_print, self).__init__(cr, uid, name, context) - self.localcontext.update({ - 'time': time, - 'findobj': self._object_find, - 'objdoc': self._object_doc, - 'findflds': self._fields_find, - }) - def _object_doc(self, obj): - modobj = self.pool.get(obj) - return modobj.__doc__ + def __init__(self, cr, uid, name, context): + super(ir_module_reference_print, self).__init__(cr, uid, name, context) + self.localcontext.update({ + 'time': time, + 'findobj': self._object_find, + 'objdoc': self._object_doc, + 'findflds': self._fields_find, + }) + def _object_doc(self, obj): + modobj = self.pool.get(obj) + return modobj.__doc__ - def _object_find(self, module): - modobj = self.pool.get('ir.model') - if module=='base': - ids = modobj.search(self.cr, self.uid, [('model','=like','res%')]) - ids += modobj.search(self.cr, self.uid, [('model','=like','ir%')]) - else: - ids = modobj.search(self.cr, self.uid, [('model','=like',module+'%')]) - return modobj.browse(self.cr, self.uid, ids) + def _object_find(self, module): + modobj = self.pool.get('ir.model') + if module=='base': + ids = modobj.search(self.cr, self.uid, [('model','=like','res%')]) + ids += modobj.search(self.cr, self.uid, [('model','=like','ir%')]) + else: + ids = modobj.search(self.cr, self.uid, [('model','=like',module+'%')]) + return modobj.browse(self.cr, self.uid, ids) - def _fields_find(self, obj): - modobj = self.pool.get(obj) - res = modobj.fields_get(self.cr, self.uid).items() - return res + def _fields_find(self, obj): + modobj = self.pool.get(obj) + res = modobj.fields_get(self.cr, self.uid).items() + return res report_sxw.report_sxw('report.ir.module.reference', 'ir.module.module', - 'addons/base/module/report/ir_module_reference.rml', - parser=ir_module_reference_print, header=False) + 'addons/base/module/report/ir_module_reference.rml', + parser=ir_module_reference_print, header=False) diff --git a/bin/addons/base/module/wizard/add_new.py b/bin/addons/base/module/wizard/add_new.py index 0b5ec6a2f2f..39465dff970 100644 --- a/bin/addons/base/module/wizard/add_new.py +++ b/bin/addons/base/module/wizard/add_new.py @@ -49,48 +49,48 @@ _info_arch = ''' _info_fields = {} class wizard_install_module(wizard.interface): - def watch_dir(self, cr, uid, data, context): - mod_obj = pooler.get_pool(cr.dbname).get('ir.module.module') - all_mods = mod_obj.read(cr, uid, mod_obj.search(cr, uid, []), ['name', 'state']) - known_modules = [x['name'] for x in all_mods] - ls_ad = glob.glob(os.path.join(tools.config['addons_path'], '*', '__terp__.py')) - modules = [module_name_re.match(name).group(1) for name in ls_ad] - for fname in os.listdir(tools.config['addons_path']): - if zipfile.is_zipfile(fname): - modules.append( fname.split('.')[0]) - for module in modules: - if module in known_modules: - continue - terp = mod_obj.get_module_info(module) - if not terp.get('installable', True): - continue - imp.load_module(module, *imp.find_module(module)) - mod_id = mod_obj.create(cr, uid, { - 'name': module, - 'state': 'uninstalled', - 'description': terp.get('description', ''), - 'shortdesc': terp.get('name', ''), - 'author': terp.get('author', 'Unknown')}) - dependencies = terp.get('depends', []) - for d in dependencies: - cr.execute('insert into ir_module_module_dependency (module_id,name) values (%s, %s)', (mod_id, d)) - for module in known_modules: - terp = mod_obj.get_module_info(module) - if terp.get('installable', True): - for mod in all_mods: - if mod['name'] == module and mod['state'] == 'uninstallable': - mod_obj.write(cr, uid, [mod['id']], {'state': 'uninstalled'}) - return {} + def watch_dir(self, cr, uid, data, context): + mod_obj = pooler.get_pool(cr.dbname).get('ir.module.module') + all_mods = mod_obj.read(cr, uid, mod_obj.search(cr, uid, []), ['name', 'state']) + known_modules = [x['name'] for x in all_mods] + ls_ad = glob.glob(os.path.join(tools.config['addons_path'], '*', '__terp__.py')) + modules = [module_name_re.match(name).group(1) for name in ls_ad] + for fname in os.listdir(tools.config['addons_path']): + if zipfile.is_zipfile(fname): + modules.append( fname.split('.')[0]) + for module in modules: + if module in known_modules: + continue + terp = mod_obj.get_module_info(module) + if not terp.get('installable', True): + continue + imp.load_module(module, *imp.find_module(module)) + mod_id = mod_obj.create(cr, uid, { + 'name': module, + 'state': 'uninstalled', + 'description': terp.get('description', ''), + 'shortdesc': terp.get('name', ''), + 'author': terp.get('author', 'Unknown')}) + dependencies = terp.get('depends', []) + for d in dependencies: + cr.execute('insert into ir_module_module_dependency (module_id,name) values (%s, %s)', (mod_id, d)) + for module in known_modules: + terp = mod_obj.get_module_info(module) + if terp.get('installable', True): + for mod in all_mods: + if mod['name'] == module and mod['state'] == 'uninstallable': + mod_obj.write(cr, uid, [mod['id']], {'state': 'uninstalled'}) + return {} - states = { - 'init': { - 'actions': [], - 'result': {'type':'form', 'arch': _info_arch, 'fields': _info_fields, 'state':[('end','Cancel','gtk-cancel'),('addmod','Check new modules','gtk-ok')]} - }, - 'addmod': { - 'actions': [watch_dir], - 'result': {'type':'state', 'state':'end'} - }, - } + states = { + 'init': { + 'actions': [], + 'result': {'type':'form', 'arch': _info_arch, 'fields': _info_fields, 'state':[('end','Cancel','gtk-cancel'),('addmod','Check new modules','gtk-ok')]} + }, + 'addmod': { + 'actions': [watch_dir], + 'result': {'type':'state', 'state':'end'} + }, + } wizard_install_module('module.module.scan') diff --git a/bin/addons/base/module/wizard/wizard_export_lang.py b/bin/addons/base/module/wizard/wizard_export_lang.py index 3f7fa8f99df..3a4a4e82ae9 100644 --- a/bin/addons/base/module/wizard/wizard_export_lang.py +++ b/bin/addons/base/module/wizard/wizard_export_lang.py @@ -40,114 +40,114 @@ from osv import fields,osv ''' view_form_init="""
- - - - + + + +
""" view_form_finish="""
- - - - - + + + + +
""" class wizard_export_lang(wizard.interface): - def _get_language(self, cr, uid, context): - lang_obj=pooler.get_pool(cr.dbname).get('res.lang') - ids=lang_obj.search(cr, uid, [('active', '=', True),]) - langs=lang_obj.browse(cr, uid, ids) - return [(lang.code, lang.translatable and lang.name or _('New language')) for lang in langs] + def _get_language(self, cr, uid, context): + lang_obj=pooler.get_pool(cr.dbname).get('res.lang') + ids=lang_obj.search(cr, uid, [('active', '=', True),]) + langs=lang_obj.browse(cr, uid, ids) + return [(lang.code, lang.translatable and lang.name or _('New language')) for lang in langs] - def _get_file(self, cr, uid, data, context): - file=tools.trans_generate(data['form']['lang'], 'all', dbname=cr.dbname) - buf=StringIO.StringIO() - writer=csv.writer(buf, 'UNIX') - for row in file: - writer.writerow(row) - del file - out=base64.encodestring(buf.getvalue()) - buf.close() - return {'data': out} + def _get_file(self, cr, uid, data, context): + file=tools.trans_generate(data['form']['lang'], 'all', dbname=cr.dbname) + buf=StringIO.StringIO() + writer=csv.writer(buf, 'UNIX') + for row in file: + writer.writerow(row) + del file + out=base64.encodestring(buf.getvalue()) + buf.close() + return {'data': out} - fields_form={ - 'lang': {'string':'Language', 'type':'selection', 'selection':_get_language,}, - } - fields_form_finish={ - 'data': {'string':'File', 'type':'binary', 'readonly': True,}, - } - states={ - 'init':{ - 'actions': [], - 'result': {'type': 'form', 'arch': view_form_init, 'fields': fields_form, - 'state': [ - ('end', 'Cancel', 'gtk-cancel'), - ('finish', 'Ok', 'gtk-ok', True) - ] - } - }, - 'finish':{ - 'actions': [_get_file], - 'result': {'type': 'form', 'arch': view_form_finish, - 'fields': fields_form_finish, - 'state': [ - ('end', 'Close', 'gtk-cancel', True) - ] - } - }, - } + fields_form={ + 'lang': {'string':'Language', 'type':'selection', 'selection':_get_language,}, + } + fields_form_finish={ + 'data': {'string':'File', 'type':'binary', 'readonly': True,}, + } + states={ + 'init':{ + 'actions': [], + 'result': {'type': 'form', 'arch': view_form_init, 'fields': fields_form, + 'state': [ + ('end', 'Cancel', 'gtk-cancel'), + ('finish', 'Ok', 'gtk-ok', True) + ] + } + }, + 'finish':{ + 'actions': [_get_file], + 'result': {'type': 'form', 'arch': view_form_finish, + 'fields': fields_form_finish, + 'state': [ + ('end', 'Close', 'gtk-cancel', True) + ] + } + }, + } wizard_export_lang('module.lang.export') ''' class wizard_export_lang(osv.osv_memory): - def _get_languages(self, cr, uid, context): - lang_obj=pooler.get_pool(cr.dbname).get('res.lang') - ids=lang_obj.search(cr, uid, [('active', '=', True),]) - langs=lang_obj.browse(cr, uid, ids) - return [(lang.code, lang.translatable and lang.name or _('New language')) for lang in langs] - + def _get_languages(self, cr, uid, context): + lang_obj=pooler.get_pool(cr.dbname).get('res.lang') + ids=lang_obj.search(cr, uid, [('active', '=', True),]) + langs=lang_obj.browse(cr, uid, ids) + return [(lang.code, lang.translatable and lang.name or _('New language')) for lang in langs] + - def act_cancel(self, cr, uid, ids, context=None): - #self.unlink(cr, uid, ids, context) - return {'type':'ir.actions.act_window_close' } + def act_cancel(self, cr, uid, ids, context=None): + #self.unlink(cr, uid, ids, context) + return {'type':'ir.actions.act_window_close' } - def act_destroy(self, *args): - return {'type':'ir.actions.act_window_close' } + def act_destroy(self, *args): + return {'type':'ir.actions.act_window_close' } - def act_getfile(self, cr, uid, ids, context=None): - this = self.browse(cr, uid, ids)[0] - mods = map(lambda m: m.name, this.modules) - mods.sort() - buf=StringIO.StringIO() - - tools.trans_export(this.lang, mods, buf, this.format, dbname=cr.dbname) + def act_getfile(self, cr, uid, ids, context=None): + this = self.browse(cr, uid, ids)[0] + mods = map(lambda m: m.name, this.modules) + mods.sort() + buf=StringIO.StringIO() + + tools.trans_export(this.lang, mods, buf, this.format, dbname=cr.dbname) - if this.format == 'csv': - this.advice = _("Save this document to a .CSV file and open it with your favourite spreadsheet software. The file encoding is UTF-8. You have to translate the latest column before reimporting it.") - elif this.format == 'po': - this.advice = _("Save this document to a .po file and edit it with a specific software or a text editor. The file encoding is UTF-8.") - - out=base64.encodestring(buf.getvalue()) - buf.close() - return self.write(cr, uid, ids, {'state':'get', 'data':out, 'advice':this.advice}, context=context) + if this.format == 'csv': + this.advice = _("Save this document to a .CSV file and open it with your favourite spreadsheet software. The file encoding is UTF-8. You have to translate the latest column before reimporting it.") + elif this.format == 'po': + this.advice = _("Save this document to a .po file and edit it with a specific software or a text editor. The file encoding is UTF-8.") + + out=base64.encodestring(buf.getvalue()) + buf.close() + return self.write(cr, uid, ids, {'state':'get', 'data':out, 'advice':this.advice}, context=context) - _name = "wizard.module.lang.export" - _columns = { - 'lang': fields.selection(_get_languages, 'Language',required=True), - 'format': fields.selection( ( ('csv','CSV File'), ('po','PO File') ), 'File Format', required=True), - 'modules': fields.many2many('ir.module.module', 'rel_modules_langexport', 'wiz_id', 'module_id', 'Modules', domain=[('state','=','installed')]), - 'data': fields.binary('File', readonly=True), - 'advice': fields.text('', readonly=True), - 'state': fields.selection( ( ('choose','choose'), # choose language - ('get','get'), # get the file - ) ), - } - _defaults = { 'state': lambda *a: 'choose', } + _name = "wizard.module.lang.export" + _columns = { + 'lang': fields.selection(_get_languages, 'Language',required=True), + 'format': fields.selection( ( ('csv','CSV File'), ('po','PO File') ), 'File Format', required=True), + 'modules': fields.many2many('ir.module.module', 'rel_modules_langexport', 'wiz_id', 'module_id', 'Modules', domain=[('state','=','installed')]), + 'data': fields.binary('File', readonly=True), + 'advice': fields.text('', readonly=True), + 'state': fields.selection( ( ('choose','choose'), # choose language + ('get','get'), # get the file + ) ), + } + _defaults = { 'state': lambda *a: 'choose', } wizard_export_lang() diff --git a/bin/addons/base/module/wizard/wizard_import_lang.py b/bin/addons/base/module/wizard/wizard_import_lang.py index 9134e64433a..df0bee1310c 100644 --- a/bin/addons/base/module/wizard/wizard_import_lang.py +++ b/bin/addons/base/module/wizard/wizard_import_lang.py @@ -36,53 +36,53 @@ from tempfile import TemporaryFile view_form="""
- - - - - - - + + + + + + +
""" fields_form={ - 'name':{'string':'Language name', 'type':'char', 'size':64, 'required':True}, - 'code':{'string':'Code (eg:en__US)', 'type':'char', 'size':5, 'required':True}, - 'data':{'string':'File', 'type':'binary', 'required':True}, + 'name':{'string':'Language name', 'type':'char', 'size':64, 'required':True}, + 'code':{'string':'Code (eg:en__US)', 'type':'char', 'size':5, 'required':True}, + 'data':{'string':'File', 'type':'binary', 'required':True}, } class wizard_import_lang(wizard.interface): - def _import_lang(self, cr, uid, data, context): - form=data['form'] - fileobj = TemporaryFile('w+') - fileobj.write( base64.decodestring(form['data']) ) + def _import_lang(self, cr, uid, data, context): + form=data['form'] + fileobj = TemporaryFile('w+') + fileobj.write( base64.decodestring(form['data']) ) - # now we determine the file format - fileobj.seek(0) - first_line = fileobj.readline().strip() - fileformat = first_line.endswith("type,name,res_id,src,value") and 'csv' or 'po' - fileobj.seek(0) + # now we determine the file format + fileobj.seek(0) + first_line = fileobj.readline().strip() + fileformat = first_line.endswith("type,name,res_id,src,value") and 'csv' or 'po' + fileobj.seek(0) - tools.trans_load_data(cr.dbname, fileobj, fileformat, form['code'], lang_name=form['name']) - fileobj.close() - return {} + tools.trans_load_data(cr.dbname, fileobj, fileformat, form['code'], lang_name=form['name']) + fileobj.close() + return {} - states={ - 'init':{ - 'actions': [], - 'result': {'type': 'form', 'arch': view_form, 'fields': fields_form, - 'state':[ - ('end', 'Cancel', 'gtk-cancel'), - ('finish', 'Ok', 'gtk-ok', True) - ] - } - }, - 'finish':{ - 'actions':[], - 'result':{'type':'action', 'action':_import_lang, 'state':'end'} - }, - } + states={ + 'init':{ + 'actions': [], + 'result': {'type': 'form', 'arch': view_form, 'fields': fields_form, + 'state':[ + ('end', 'Cancel', 'gtk-cancel'), + ('finish', 'Ok', 'gtk-ok', True) + ] + } + }, + 'finish':{ + 'actions':[], + 'result':{'type':'action', 'action':_import_lang, 'state':'end'} + }, + } wizard_import_lang('module.lang.import') diff --git a/bin/addons/base/module/wizard/wizard_module_import.py b/bin/addons/base/module/wizard/wizard_module_import.py index d59c635cd30..394389dd68f 100644 --- a/bin/addons/base/module/wizard/wizard_module_import.py +++ b/bin/addons/base/module/wizard/wizard_module_import.py @@ -40,82 +40,82 @@ import base64 finish_form ='''
-