# HG changeset patch # User Stephanie Marcu # Date 1281449428 -7200 # Node ID 9001a74fcc821db364f7071112c7436148130dbb # Parent 560df423149aaf084b164c5ed45e8329f48736fe more generic dot graph generator diff -r 560df423149a -r 9001a74fcc82 web/views/dotgraphview.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/web/views/dotgraphview.py Tue Aug 10 16:10:28 2010 +0200 @@ -0,0 +1,80 @@ +# copyright 2003-2010 LOGILAB S.A. (Paris, FRANCE), all rights reserved. +# contact http://www.logilab.fr/ -- mailto:contact@logilab.fr +# +# This file is part of CubicWeb. +# +# CubicWeb is free software: you can redistribute it and/or modify it under the +# terms of the GNU Lesser General Public License as published by the Free +# Software Foundation, either version 2.1 of the License, or (at your option) +# any later version. +# +# CubicWeb 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 Lesser General Public License for more +# details. +# +# You should have received a copy of the GNU Lesser General Public License along +# with CubicWeb. If not, see . +"""some basic stuff to build dot generated graph images""" + +__docformat__ = "restructuredtext en" +_ = unicode + +import tempfile +import os + +from logilab.mtconverter import xml_escape +from logilab.common.graph import GraphGenerator, DotBackend + +from cubicweb.view import EntityView +from cubicweb.utils import make_uid + +class DotGraphView(EntityView): + __abstract__ = True + + def cell_call(self, row, col): + entity = self.cw_rset.get_entity(row, col) + visitor = self.build_visitor(entity) + prophdlr = self.build_dotpropshandler() + graphname = 'dotgraph%s' % str(entity.eid) + generator = GraphGenerator(DotBackend(graphname, None, + ratio='compress', size='30,10')) + # map file + pmap, mapfile = tempfile.mkstemp(".map", graphname) + os.close(pmap) + # image file + fd, tmpfile = tempfile.mkstemp('.png') + os.close(fd) + generator.generate(visitor, prophdlr, tmpfile, mapfile) + filekeyid = make_uid() + self._cw.session.data[filekeyid] = tmpfile + self.w(u'%s' % ( + xml_escape(entity.absolute_url(vid='tmppng', tmpfile=filekeyid)), + xml_escape(self._cw._('Data connection graph for %s') % entity.name), + graphname)) + stream = open(mapfile, 'r').read() + stream = stream.decode(self._cw.encoding) + self.w(stream) + os.unlink(mapfile) + + def build_visitor(self, entity): + raise NotImplementedError + + def build_dotpropshandler(self): + return DotGraphPropsHandler(self._cw) + + +class DotPropsHandler(object): + def __init__(self, req): + self._ = req._ + + def node_properties(self, entity): + """return default DOT drawing options for a state or transition""" + return {'label': entity.printable_value('name'), + 'href': entity.absolute_url(), + 'fontname': 'Courier', 'fontsize': 10, 'shape':'box', + } + + def edge_properties(self, transition, fromstate, tostate): + return {'label': '', 'dir': 'forward', + 'color': 'black', 'style': 'filled'} diff -r 560df423149a -r 9001a74fcc82 web/views/primary.py --- a/web/views/primary.py Tue Aug 10 18:27:02 2010 +0200 +++ b/web/views/primary.py Tue Aug 10 16:10:28 2010 +0200 @@ -285,6 +285,7 @@ return label return u'' + class RelatedView(EntityView): __regid__ = 'autolimited' diff -r 560df423149a -r 9001a74fcc82 web/views/workflow.py --- a/web/views/workflow.py Tue Aug 10 18:27:02 2010 +0200 +++ b/web/views/workflow.py Tue Aug 10 16:10:28 2010 +0200 @@ -24,17 +24,15 @@ __docformat__ = "restructuredtext en" _ = unicode -import tempfile import os from logilab.mtconverter import xml_escape -from logilab.common.graph import escape, GraphGenerator, DotBackend +from logilab.common.graph import escape from cubicweb import Unauthorized, view from cubicweb.selectors import (has_related_entities, one_line_rset, relation_possible, match_form_params, score_entity, is_instance, adaptable) -from cubicweb.utils import make_uid from cubicweb.view import EntityView from cubicweb.schema import display_name from cubicweb.web import uicfg, stdmsgs, action, component, form, action @@ -42,6 +40,7 @@ from cubicweb.web.views import TmpFileViewMixin from cubicweb.web.views import forms, primary, autoform, ibreadcrumbs from cubicweb.web.views.tabs import TabbedPrimaryView, PrimaryTab +from cubicweb.web.views.dotgraphview import DotGraphView, DotPropsHandler _pvs = uicfg.primaryview_section _pvs.tag_subject_of(('Workflow', 'initial_state', '*'), 'hidden') @@ -374,16 +373,11 @@ # workflow images ############################################################## -class WorkflowDotPropsHandler(object): - def __init__(self, req): - self._ = req._ +class WorkflowDotPropsHandler(DotPropsHandler): def node_properties(self, stateortransition): """return default DOT drawing options for a state or transition""" - props = {'label': stateortransition.printable_value('name'), - 'fontname': 'Courier', 'fontsize':10, - 'href': stateortransition.absolute_url(), - } + props = super(WorkflowDotPropsHandler, self).node_properties(stateortransition) if hasattr(stateortransition, 'state_of'): props['shape'] = 'box' props['style'] = 'filled' @@ -397,10 +391,6 @@ props['label'] += escape('\n'.join(descr)) return props - def edge_properties(self, transition, fromstate, tostate): - return {'label': '', 'dir': 'forward', - 'color': 'black', 'style': 'filled'} - class WorkflowVisitor: def __init__(self, entity): @@ -421,35 +411,15 @@ for outgoingstate in transition.potential_destinations(): yield transition.eid, outgoingstate.eid, transition - -class WorkflowGraphView(view.EntityView): +class WorkflowGraphView(DotGraphView): __regid__ = 'wfgraph' __select__ = EntityView.__select__ & one_line_rset() & is_instance('Workflow') - def cell_call(self, row, col): - entity = self.cw_rset.get_entity(row, col) - visitor = WorkflowVisitor(entity) - prophdlr = WorkflowDotPropsHandler(self._cw) - wfname = 'workflow%s' % str(entity.eid) - generator = GraphGenerator(DotBackend(wfname, None, - ratio='compress', size='30,10')) - # map file - pmap, mapfile = tempfile.mkstemp(".map", wfname) - os.close(pmap) - # image file - fd, tmpfile = tempfile.mkstemp('.png') - os.close(fd) - generator.generate(visitor, prophdlr, tmpfile, mapfile) - filekeyid = make_uid() - self._cw.session.data[filekeyid] = tmpfile - self.w(u'%s' % ( - xml_escape(entity.absolute_url(vid='tmppng', tmpfile=filekeyid)), - xml_escape(self._cw._('graphical workflow for %s') % entity.name), - wfname)) - stream = open(mapfile, 'r').read() - stream = stream.decode(self._cw.encoding) - self.w(stream) - os.unlink(mapfile) + def build_visitor(self, entity): + return WorkflowVisitor(entity) + + def build_dotpropshandler(self): + return WorkflowPropsHandler(self._cw) class TmpPngView(TmpFileViewMixin, view.EntityView):