You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
180 lines
6.4 KiB
180 lines
6.4 KiB
# -*- coding: utf-8 -*-
|
|
##############################################################################
|
|
#
|
|
# OpenERP, Open Source Management Solution
|
|
# Copyright (C) 2004-2009 Tiny SPRL (<http://tiny.be>).
|
|
#
|
|
# This program is free software: you can redistribute it and/or modify
|
|
# it under the terms of the GNU Affero General Public License as
|
|
# published by the Free Software Foundation, either version 3 of the
|
|
# License, or (at your option) any later version.
|
|
#
|
|
# This program is distributed in the hope that it will be useful,
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
# GNU Affero General Public License for more details.
|
|
#
|
|
# You should have received a copy of the GNU Affero General Public License
|
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
#
|
|
##############################################################################
|
|
import os
|
|
import base64
|
|
import openerp.modules.registry
|
|
from openerp import models, fields
|
|
|
|
|
|
class Module(models.Model):
|
|
_inherit = 'ir.module.module'
|
|
_description = 'Module With Relationship Graph'
|
|
|
|
file_graph = fields.Binary('Relationship Graph')
|
|
|
|
def _get_graphical_representation(
|
|
self, cr, uid, model_ids, level=1, context=None
|
|
):
|
|
obj_model = self.pool.get('ir.model')
|
|
if level == 0:
|
|
return tuple()
|
|
relation = []
|
|
for id in model_ids:
|
|
model_data = obj_model.browse(cr, uid, id, context=context)
|
|
for field in (
|
|
f for f in model_data.field_id if f.ttype in (
|
|
'many2many', 'many2one', 'one2many'
|
|
)
|
|
):
|
|
relation.append(
|
|
(
|
|
model_data.model,
|
|
field.name,
|
|
field.ttype,
|
|
field.relation,
|
|
field.field_description
|
|
)
|
|
)
|
|
new_model_ids = obj_model.search(
|
|
cr,
|
|
uid,
|
|
[('model', '=', field.relation)],
|
|
context=context
|
|
)
|
|
if new_model_ids:
|
|
model = obj_model.read(
|
|
cr,
|
|
uid,
|
|
new_model_ids,
|
|
['id', 'name'],
|
|
context=context
|
|
)[0]
|
|
relation.extend(
|
|
self._get_graphical_representation(
|
|
cr, uid, model['id'], level - 1
|
|
)
|
|
)
|
|
return tuple(relation)
|
|
|
|
def _get_structure(self, relations, main_element):
|
|
res = {}
|
|
for rel in relations:
|
|
# if we have to display the string along with field name,
|
|
# then uncomment the first line n comment the second line
|
|
res.setdefault(rel[0], set()).add(rel[1])
|
|
res.setdefault(rel[3], set())
|
|
val = []
|
|
for obj, fieldsx in res.items():
|
|
val.append('"%s" [%s label="{<id>%s|%s}"];' % (
|
|
obj,
|
|
obj in
|
|
main_element and
|
|
'fillcolor=yellow, style="filled,rounded"' or
|
|
"",
|
|
obj,
|
|
"|".join(["<%s> %s" % (fn, fn) for fn in fieldsx])
|
|
))
|
|
return "\n".join(val)
|
|
|
|
def _get_arrow(self, field_type='many2one'):
|
|
return {
|
|
'many2one': (
|
|
'arrowtail="none" arrowhead="normal" color="red" label="m2o"'
|
|
),
|
|
'many2many': (
|
|
'arrowtail="crow" arrowhead="crow" color="green" label="m2m"'
|
|
),
|
|
'one2many': (
|
|
'arrowtail="none" arrowhead="crow" color="blue" label="o2m"'
|
|
),
|
|
}[field_type]
|
|
|
|
def get_graphical_representation(self, cr, uid, model_ids, context=None):
|
|
obj_model = self.pool.get('ir.model')
|
|
if context is None:
|
|
context = {}
|
|
res = {}
|
|
models = []
|
|
for obj in obj_model.browse(cr, uid, model_ids, context=context):
|
|
models.append(obj.model)
|
|
relations = set(
|
|
self._get_graphical_representation(
|
|
cr, uid, model_ids, context.get('level', 1)
|
|
)
|
|
)
|
|
res[obj.model] = (
|
|
"digraph G {\nnode [style=rounded, shape=record];\n%s\n%s }" % (
|
|
self._get_structure(relations, models),
|
|
''.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),
|
|
)
|
|
)
|
|
return res
|
|
|
|
def _get_module_objects(self, cr, uid, module, context=None):
|
|
obj_model = self.pool.get('ir.model')
|
|
obj_mod_data = self.pool.get('ir.model.data')
|
|
obj_ids = []
|
|
model_data_ids = obj_mod_data.search(
|
|
cr, uid,
|
|
[('module', '=', module), ('model', '=', 'ir.model')],
|
|
context=context
|
|
)
|
|
model_ids = []
|
|
for mod in obj_mod_data.browse(
|
|
cr, uid, model_data_ids, context=context
|
|
):
|
|
model_ids.append(mod.res_id)
|
|
models = obj_model.browse(cr, uid, model_ids, context=context)
|
|
map(lambda x: obj_ids.append(x.id), models)
|
|
return obj_ids
|
|
|
|
def get_relation_graph(self, cr, uid, module_name, context=None):
|
|
if context is None:
|
|
context = {}
|
|
object_ids = self._get_module_objects(
|
|
cr, uid, module_name, context=context
|
|
)
|
|
if not object_ids:
|
|
return {'module_file': False}
|
|
# context.update({'level': 1})
|
|
dots = self.get_graphical_representation(
|
|
cr, uid, object_ids, context=context
|
|
)
|
|
# todo: use os.realpath
|
|
file_path = openerp.modules.module.get_module_path(
|
|
'base_module_doc_rst'
|
|
)
|
|
path_png = file_path + "/module.png"
|
|
for key, val in dots.items():
|
|
path_dotfile = file_path + "/%s.dot" % (key,)
|
|
fp = file(path_dotfile, "w")
|
|
fp.write(val)
|
|
fp.close()
|
|
os.popen(
|
|
'dot -Tpng' + ' ' + path_dotfile + ' ' + '-o' + ' ' + path_png
|
|
)
|
|
fp = file(path_png, "r")
|
|
x = fp.read()
|
|
fp.close()
|
|
os.popen('rm ' + path_dotfile + ' ' + path_png)
|
|
return {'module_file': base64.encodestring(x)}
|