[MERGE] merge from trunk addons
[odoo/odoo.git] / addons / base_module_doc_rst / base_module_doc_rst.py
1 # -*- encoding: utf-8 -*-
2 ##############################################################################
3 #
4 #    OpenERP, Open Source Management Solution
5 #    Copyright (C) 2004-2009 Tiny SPRL (<http://tiny.be>).
6 #
7 #    This program is free software: you can redistribute it and/or modify
8 #    it under the terms of the GNU Affero General Public License as
9 #    published by the Free Software Foundation, either version 3 of the
10 #    License, or (at your option) any later version.
11 #
12 #    This program is distributed in the hope that it will be useful,
13 #    but WITHOUT ANY WARRANTY; without even the implied warranty of
14 #    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 #    GNU Affero General Public License for more details.
16 #
17 #    You should have received a copy of the GNU Affero General Public License
18 #    along with this program.  If not, see <http://www.gnu.org/licenses/>.
19 #
20 ##############################################################################
21 import os
22 import pydot
23 import base64
24
25 import report
26 from osv import fields, osv, orm
27 import tools
28 from tools.translate import _
29 import addons
30
31 class module(osv.osv):
32     _inherit = 'ir.module.module'
33     _description = 'Module With Relationship Graph'
34     _columns = {
35         'file_graph': fields.binary('Relationship Graph'),
36             }
37
38     def _get_graphical_representation(self, cr, uid, model_ids, level=1, context={}):
39         obj_model = self.pool.get('ir.model')
40         if level == 0:
41             return tuple()
42         relation = []
43         for id in model_ids:
44             model_data = obj_model.browse(cr, uid, id, context=context)
45             for field in (f for f in model_data.field_id if f.ttype in ('many2many', 'many2one', 'one2many')):
46                 relation.append((model_data.model, field.name, field.ttype, field.relation, field.field_description))
47                 new_model_ids = obj_model.search(cr, uid, [('model', '=', field.relation)], context=context)
48                 if new_model_ids:
49                     model = obj_model.read(cr, uid, new_model_ids, ['id', 'name'], context=context)[0]
50                     relation.extend(self._get_graphical_representation(cr, uid, model['id'], level - 1))
51         return tuple(relation)
52
53     def _get_structure(self, relations, main_element):
54         res = {}
55         for rel in relations:
56             # if we have to display the string along with field name then uncomment the first line n comment the second line
57             res.setdefault(rel[0], set()).add(rel[1])
58             res.setdefault(rel[3], set())
59         val = []
60         for obj, fields in res.items():
61             val.append('"%s" [%s label="{<id>%s|%s}"];' % (obj,
62                                                        obj in main_element and 'fillcolor=yellow, style="filled,rounded"' or "",
63                                                        obj,
64                                                        "|".join(["<%s> %s" % (fn, fn) for fn in fields])))
65         return "\n".join(val)
66
67     def _get_arrow(self, field_type='many2one'):
68         return {
69             'many2one': 'arrowtail="none" arrowhead="normal" color="red" label="m2o"',
70             'many2many': 'arrowtail="crow" arrowhead="crow" color="green" label="m2m"',
71             'one2many': 'arrowtail="none" arrowhead="crow" color="blue" label="o2m"',
72         }[field_type]
73
74     def get_graphical_representation(self, cr, uid, model_ids, context=None):
75         obj_model = self.pool.get('ir.model')
76         if context is None:
77             context = {}
78         res = {}
79         models = []
80         for obj in obj_model.browse(cr, uid, model_ids, context=context):
81             models.append(obj.model)
82         relations = set(self._get_graphical_representation(cr, uid, model_ids, context.get('level', 1)))
83         res[obj.model] = "digraph G {\nnode [style=rounded, shape=record];\n%s\n%s }" % (
84                 self._get_structure(relations, models),
85                 ''.join('"%s":%s -> "%s":id:n [%s]; // %s\n' % (m, fn, fr, self._get_arrow(ft),ft) for m, fn, ft, fr, fl in relations),
86             )
87         return res
88
89     def _get_module_objects(self, cr, uid, module, context={}):
90         obj_model = self.pool.get('ir.model')
91         obj_mod_data = self.pool.get('ir.model.data')
92         obj_ids = []
93         model_data_ids = obj_mod_data.search(cr, uid, [('module', '=', module), ('model', '=', 'ir.model')], context=context)
94         model_ids = []
95         for mod in obj_mod_data.browse(cr, uid, model_data_ids, context=context):
96             model_ids.append(mod.res_id)
97         models = obj_model.browse(cr, uid, model_ids, context=context)
98         map(lambda x: obj_ids.append(x.id),models)
99         return obj_ids
100
101     def get_relation_graph(self, cr, uid, module_name, context=None):
102         object_ids = self._get_module_objects(cr, uid, module_name, context=context)
103         if not object_ids:
104             return {'module_file': False}
105         context.update({'level': 1})
106         dots = self.get_graphical_representation(cr, uid, object_ids, context=context)
107         # todo: use os.realpath
108         file_path = addons.get_module_resource('base_module_doc_rst')
109         path_png = file_path + "/module.png"
110         for key, val in dots.items():
111            path_dotfile = file_path + "/%s.dot" % (key,)
112            fp = file(path_dotfile, "w")
113            fp.write(val)
114            fp.close()
115         os.popen('dot -Tpng' +' '+ path_dotfile + ' '+ '-o' +' ' + path_png)
116         fp = file(path_png, "r")
117         x = fp.read()
118         fp.close()
119         os.popen('rm ' + path_dotfile + ' ' + path_png)
120         return {'module_file': base64.encodestring(x)}
121
122 module()
123
124
125 # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
126