web/views/iprogress.py
changeset 0 b97547f5f1fa
child 431 18b4dd650ef8
equal deleted inserted replaced
-1:000000000000 0:b97547f5f1fa
       
     1 """Specific views for entities implementing IProgress
       
     2 
       
     3 :organization: Logilab
       
     4 :copyright: 2001-2008 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
       
     5 :contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr
       
     6 """
       
     7 
       
     8 __docformat__ = "restructuredtext en"
       
     9 
       
    10 from logilab.mtconverter import html_escape
       
    11 
       
    12 from cubicweb.interfaces import IProgress, IMileStone
       
    13 from cubicweb.schema import display_name
       
    14 from cubicweb.common.view import EntityView
       
    15 from cubicweb.common.selectors import interface_selector, accept_selector
       
    16 from cubicweb.web.htmlwidgets import ProgressBarWidget
       
    17 
       
    18 
       
    19 class ProgressTableView(EntityView):
       
    20     """The progress table view is able to display progress information
       
    21     of any object implement IMileStone.
       
    22 
       
    23     The default layout is composoed of 7 columns : parent task,
       
    24     milestone, state, estimated date, cost, progressbar, and todo_by
       
    25 
       
    26     The view accepts an optional ``columns`` paramater that lets you
       
    27     remove or reorder some of those columns.
       
    28 
       
    29     To add new columns, you should extend this class, define a new
       
    30     ``columns`` class attribute and implement corresponding
       
    31     build_COLNAME_cell methods
       
    32 
       
    33     header_for_COLNAME methods allow to customize header's label
       
    34     """
       
    35     
       
    36     id = 'progress_table_view'
       
    37     title = _('task progression')
       
    38     __selectors__ = (accept_selector, interface_selector)
       
    39 
       
    40     accepts_interfaces = (IMileStone,)
       
    41 
       
    42     # default columns of the table
       
    43     columns = (_('project'), _('milestone'), _('state'), _('eta_date'),
       
    44                _('cost'), _('progress'), _('todo_by'))
       
    45 
       
    46 
       
    47     def call(self, columns=None):
       
    48         """displays all versions in a table"""
       
    49         self.req.add_css('cubicweb.iprogress.css')
       
    50         _ = self.req._
       
    51         self.columns = columns or self.columns
       
    52         ecls = self.vreg.etype_class(self.rset.description[0][0])
       
    53         self.w(u'<table class="progress">')
       
    54         self.table_header(ecls)
       
    55         self.w(u'<tbody>')
       
    56         for row in xrange(self.rset.rowcount):
       
    57             self.cell_call(row=row, col=0)
       
    58         self.w(u'</tbody>')
       
    59         self.w(u'</table>')
       
    60 
       
    61     def cell_call(self, row, col):
       
    62         _ = self.req._
       
    63         entity = self.entity(row, col)
       
    64         infos = {}
       
    65         for col in self.columns:
       
    66             meth = getattr(self, 'build_%s_cell' % col, None)
       
    67             # find the build method or try to find matching attribute
       
    68             if meth:
       
    69                 content = meth(entity)
       
    70             else:
       
    71                 content = entity.printable_value(col)
       
    72             infos[col] = content
       
    73         if hasattr(entity, 'progress_class'):
       
    74             cssclass = entity.progress_class()
       
    75         else:
       
    76             cssclass = u''
       
    77         self.w(u"""<tr class="%s" onmouseover="addElementClass(this, 'highlighted');"
       
    78             onmouseout="removeElementClass(this, 'highlighted')">""" % cssclass)
       
    79         line = u''.join(u'<td>%%(%s)s</td>' % col for col in self.columns)
       
    80         self.w(line % infos)
       
    81         self.w(u'</tr>\n')
       
    82 
       
    83     ## header management ######################################################
       
    84 
       
    85     def header_for_project(self, ecls):
       
    86         """use entity's parent type as label"""
       
    87         return display_name(self.req, ecls.parent_type)
       
    88 
       
    89     def header_for_milestone(self, ecls):
       
    90         """use entity's type as label"""
       
    91         return display_name(self.req, ecls.id)
       
    92     
       
    93     def table_header(self, ecls):
       
    94         """builds the table's header"""
       
    95         self.w(u'<thead><tr>')
       
    96         _ = self.req._
       
    97         for column in self.columns:
       
    98             meth = getattr(self, 'header_for_%s' % column, None)
       
    99             if meth:
       
   100                 colname = meth(ecls)
       
   101             else:
       
   102                 colname = _(column)
       
   103             self.w(u'<th>%s</th>' % html_escape(colname))
       
   104         self.w(u'</tr></thead>\n')
       
   105 
       
   106     
       
   107     ## cell management ########################################################
       
   108     def build_project_cell(self, entity):
       
   109         """``project`` column cell renderer"""
       
   110         project = entity.get_main_task()
       
   111         if project:
       
   112             return project.view('incontext')
       
   113         return self.req._('no related project')
       
   114 
       
   115     def build_milestone_cell(self, entity):
       
   116         """``milestone`` column cell renderer"""
       
   117         return entity.view('incontext')
       
   118 
       
   119     def build_state_cell(self, entity):
       
   120         """``state`` column cell renderer"""
       
   121         return html_escape(self.req._(entity.state))
       
   122     
       
   123     def build_eta_date_cell(self, entity):
       
   124         """``eta_date`` column cell renderer"""
       
   125         if entity.finished():
       
   126             return self.format_date(entity.completion_date())
       
   127         formated_date = self.format_date(entity.initial_prevision_date())
       
   128         if entity.in_progress():
       
   129             eta_date = self.format_date(entity.eta_date())
       
   130             _ = self.req._
       
   131             if formated_date:
       
   132                 formated_date += u' (%s %s)' % (_('expected:'), eta_date)
       
   133             else:
       
   134                 formated_date = u'%s %s' % (_('expected:'), eta_date)
       
   135         return formated_date
       
   136     
       
   137     def build_todo_by_cell(self, entity):
       
   138         """``todo_by`` column cell renderer"""
       
   139         return u', '.join(p.view('outofcontext') for p in entity.contractors())
       
   140 
       
   141     def build_cost_cell(self, entity):
       
   142         """``cost`` column cell renderer"""
       
   143         _ = self.req._
       
   144         pinfo = entity.progress_info()
       
   145         totalcost = pinfo.get('estimatedcorrected', pinfo['estimated'])
       
   146         missing = pinfo.get('notestimatedcorrected', pinfo.get('notestimated', 0))
       
   147         costdescr = []
       
   148         if missing:
       
   149             # XXX: link to unestimated entities
       
   150             costdescr.append(_('%s not estimated') % missing)
       
   151         estimated = pinfo['estimated']
       
   152         if estimated and estimated != totalcost:
       
   153             costdescr.append(_('initial estimation %s') % estimated)
       
   154         if costdescr:
       
   155             return u'%s (%s)' % (totalcost, ', '.join(costdescr))
       
   156         return unicode(totalcost)
       
   157     
       
   158     def build_progress_cell(self, entity):
       
   159         """``progress`` column cell renderer"""
       
   160         progress =  u'<div class="progress_data">%s (%.2f%%)</div>' % (
       
   161             entity.done, entity.progress())
       
   162         return progress + entity.view('progressbar')
       
   163 
       
   164 
       
   165 class InContextProgressTableView(ProgressTableView):
       
   166     """this views redirects to ``progress_table_view`` but removes
       
   167     the ``project`` column
       
   168     """
       
   169     id = 'ic_progress_table_view'
       
   170     
       
   171     def call(self):
       
   172         view = self.vreg.select_view('progress_table_view', self.req, self.rset)
       
   173         columns = list(view.columns)
       
   174         try:
       
   175             columns.remove('project')
       
   176         except ValueError:
       
   177             self.info('[ic_progress_table_view] could not remove project from columns')
       
   178         view.dispatch(w=self.w, columns=columns)
       
   179 
       
   180 
       
   181 class ProgressBarView(EntityView):
       
   182     """displays a progress bar"""
       
   183     id = 'progressbar'
       
   184     title = _('progress bar')
       
   185     __selectors__ = (accept_selector, interface_selector)
       
   186 
       
   187     accepts_interfaces = (IProgress,)
       
   188 
       
   189     def cell_call(self, row, col):
       
   190         self.req.add_css('cubicweb.iprogress.css')
       
   191         entity = self.entity(row, col)
       
   192         widget = ProgressBarWidget(entity.done, entity.todo,
       
   193                                    entity.revised_cost)
       
   194         self.w(widget.render())
       
   195