web/views/workflow.py
changeset 5224 34e669b6fd95
parent 5174 78438ad513ca
child 5239 471554b842d2
--- a/web/views/workflow.py	Tue Apr 13 12:19:24 2010 +0200
+++ b/web/views/workflow.py	Tue Apr 13 13:21:10 2010 +0200
@@ -11,6 +11,9 @@
 __docformat__ = "restructuredtext en"
 _ = unicode
 
+import tempfile
+import os
+
 from logilab.mtconverter import xml_escape
 from logilab.common.graph import escape, GraphGenerator, DotBackend
 
@@ -24,6 +27,7 @@
 from cubicweb.web import uicfg, stdmsgs, action, component, form, action
 from cubicweb.web import formfields as ff, formwidgets as fwdgs
 from cubicweb.web.views import TmpFileViewMixin, forms, primary, autoform
+from cubicweb.web.views.tabs import TabbedPrimaryView, PrimaryTab
 
 _pvs = uicfg.primaryview_section
 _pvs.tag_subject_of(('Workflow', 'initial_state', '*'), 'hidden')
@@ -187,6 +191,7 @@
 _pvs.tag_subject_of(('Workflow', 'initial_state', '*'), 'hidden')
 _pvs.tag_object_of(('*', 'state_of', 'Workflow'), 'hidden')
 _pvs.tag_object_of(('*', 'transition_of', 'Workflow'), 'hidden')
+_pvs.tag_object_of(('*', 'default_workflow', 'Workflow'), 'hidden')
 
 _abaa = uicfg.actionbox_appearsin_addmenu
 _abaa.tag_subject_of(('BaseTransition', 'condition', 'RQLExpression'), False)
@@ -198,14 +203,10 @@
 _abaa.tag_object_of(('Transition', 'transition_of', 'Workflow'), True)
 _abaa.tag_object_of(('WorkflowTransition', 'transition_of', 'Workflow'), True)
 
-class WorkflowPrimaryView(primary.PrimaryView):
+class WorkflowPrimaryView(TabbedPrimaryView):
     __select__ = implements('Workflow')
-
-    def render_entity_attributes(self, entity):
-        self.w(entity.view('reledit', rtype='description'))
-        self.w(u'<img src="%s" alt="%s"/>' % (
-            xml_escape(entity.absolute_url(vid='wfgraph')),
-            xml_escape(self._cw._('graphical workflow for %s') % entity.name)))
+    tabs = [  _('wf_tab_info'), _('wfgraph'),]
+    default_tab = 'wf_tab_info'
 
 
 class CellView(view.EntityView):
@@ -225,6 +226,59 @@
         self.w(xml_escape(self._cw.view('textincontext', self.cw_rset,
                                         row=row, col=col)))
 
+class WorkflowTabTextView(PrimaryTab):
+    __regid__ = 'wf_tab_info'
+    __select__ = PrimaryTab.__select__ & one_line_rset() & implements('Workflow')
+
+    def render_entity_attributes(self, entity):
+        _ = self._cw._
+        self.w(u'<div>%s</div>' % (entity.printable_value('description')))
+        self.w(u'<span>%s%s</span>' % (_("workflow_of").capitalize(), _(" :")))
+        html = []
+        for e in  entity.workflow_of:
+            view = e.view('outofcontext')
+            if entity.eid == e.default_workflow[0].eid:
+                view += u' <span>[%s]</span>' % _('default_workflow')
+            html.append(view)
+        self.w(', '.join(v for v in html))
+        self.w(u'<h2>%s</h2>' % _("Transition_plural"))
+        rset = self._cw.execute(
+            'Any T,T,DS,T,TT ORDERBY TN WHERE T transition_of WF, WF eid %(x)s,'
+            'T type TT, T name TN, T destination_state DS?', {'x': entity.eid})
+        self.wview('editable-table', rset, 'null',
+                   cellvids={ 1: 'trfromstates', 2: 'outofcontext', 3:'trsecurity',},
+                   headers = (_('Transition'),  _('from_state'),
+                              _('to_state'), _('permissions'), _('type') ),
+                   )
+
+
+class TransitionSecurityTextView(view.EntityView):
+    __regid__ = 'trsecurity'
+    __select__ = implements('Transition')
+
+    def cell_call(self, row, col):
+        _ = self._cw._
+        entity = self.cw_rset.get_entity(self.cw_row, self.cw_col)
+        if entity.require_group:
+            self.w(u'<div>%s%s %s</div>' %
+                   (_('groups'), _(" :"),
+                    u', '.join((g.view('incontext') for g
+                               in entity.require_group))))
+        if entity.condition:
+            self.w(u'<div>%s%s %s</div>' %
+                   ( _('conditions'), _(" :"),
+                     u'<br/>'.join((e.dc_title() for e
+                                in entity.condition))))
+
+class TransitionAllowedTextView(view.EntityView):
+    __regid__ = 'trfromstates'
+    __select__ = implements('Transition')
+
+    def cell_call(self, row, col):
+        entity = self.cw_rset.get_entity(self.cw_row, self.cw_col)
+        self.w(u', '.join((e.view('outofcontext') for e
+                           in entity.reverse_allowed_transition)))
+
 
 # workflow entity types edition ################################################
 
@@ -284,24 +338,18 @@
     def node_properties(self, stateortransition):
         """return default DOT drawing options for a state or transition"""
         props = {'label': stateortransition.printable_value('name'),
-                 'fontname': 'Courier'}
+                 'fontname': 'Courier', 'fontsize':10,
+                 'href': stateortransition.absolute_url(),
+                 }
         if hasattr(stateortransition, 'state_of'):
             props['shape'] = 'box'
             props['style'] = 'filled'
             if stateortransition.reverse_initial_state:
-                props['color'] = '#88CC88'
+                props['fillcolor'] = '#88CC88'
         else:
             props['shape'] = 'ellipse'
             descr = []
             tr = stateortransition
-            if tr.require_group:
-                descr.append('%s %s'% (
-                    self._('groups:'),
-                    ','.join(g.printable_value('name') for g in tr.require_group)))
-            if tr.condition:
-                descr.append('%s %s'% (
-                    self._('condition:'),
-                    ' | '.join(e.expression for e in tr.condition)))
             if descr:
                 props['label'] += escape('\n'.join(descr))
         return props
@@ -331,17 +379,39 @@
                 yield transition.eid, outgoingstate.eid, transition
 
 
+class WorkflowGraphView(view.EntityView):
+    __regid__ = 'wfgraph'
+    __select__ = EntityView.__select__ & one_line_rset() & implements('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)
+        self.w(u'<img src="%s" alt="%s" usemap="#%s" />' % (
+            xml_escape(entity.absolute_url(vid='wfimage', tmpfile=tmpfile)),
+            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)
+
 class WorkflowImageView(TmpFileViewMixin, view.EntityView):
-    __regid__ = 'wfgraph'
+    __regid__ = 'wfimage'
     __select__ = implements('Workflow')
     content_type = 'image/png'
 
-    def _generate(self, tmpfile):
-        """display schema information for an entity"""
-        entity = self.cw_rset.get_entity(self.cw_row, self.cw_col)
-        visitor = WorkflowVisitor(entity)
-        prophdlr = WorkflowDotPropsHandler(self._cw)
-        generator = GraphGenerator(DotBackend('workflow', 'LR',
-                                              ratio='compress', size='30,12'))
-        return generator.generate(visitor, prophdlr, tmpfile)
-
+    def cell_call(self, row=0, col=0):
+        tmpfile = self._cw.form.get('tmpfile', None)
+        self.w(open(tmpfile, 'rb').read())
+        os.unlink(tmpfile)