# copyright 2003-2011 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 <http://www.gnu.org/licenses/>."""Specific views for entities implementing IProgress/IMileStone"""__docformat__="restructuredtext en"_=unicodefrommathimportfloorfromlogilab.common.deprecationimportclass_deprecatedfromlogilab.mtconverterimportxml_escapefromcubicweb.utilsimportmake_uidfromcubicweb.selectorsimportadaptablefromcubicweb.schemaimportdisplay_namefromcubicweb.viewimportEntityViewfromcubicweb.web.views.tableviewimportEntityAttributesTableViewclassProgressTableView(EntityAttributesTableView):"""The progress table view is able to display progress information of any object implement IMileStone. The default layout is composoed of 7 columns : parent task, milestone, state, estimated date, cost, progressbar, and todo_by The view accepts an optional ``columns`` paramater that lets you remove or reorder some of those columns. To add new columns, you should extend this class, define a new ``columns`` class attribute and implement corresponding build_COLNAME_cell methods header_for_COLNAME methods allow to customize header's label """__metaclass__=class_deprecated__deprecation_warning__='[3.14] %(cls)s is deprecated'__regid__='progress_table_view'__select__=adaptable('IMileStone')title=_('task progression')table_css="progress"css_files=('cubicweb.iprogress.css',)# default columns of the tablecolumns=(_('project'),_('milestone'),_('state'),_('eta_date'),_('cost'),_('progress'),_('todo_by'))defcell_call(self,row,col):_=self._cw._entity=self.cw_rset.get_entity(row,col)infos={}forcolinself.columns:meth=getattr(self,'build_%s_cell'%col,None)# find the build method or try to find matching attributeifmeth:content=meth(entity)else:content=entity.printable_value(col)infos[col]=contentcssclass=entity.cw_adapt_to('IMileStone').progress_class()self.w(u"""<tr class="%s" onmouseover="$(this).addClass('highlighted');" onmouseout="$(this).removeClass('highlighted')">"""%cssclass)line=u''.join(u'<td>%%(%s)s</td>'%colforcolinself.columns)self.w(line%infos)self.w(u'</tr>\n')## header management ######################################################defheader_for_project(self,sample):"""use entity's parent type as label"""returndisplay_name(self._cw,sample.cw_adapt_to('IMileStone').parent_type)defheader_for_milestone(self,sample):"""use entity's type as label"""returndisplay_name(self._cw,sample.__regid__)## cell management ########################################################defbuild_project_cell(self,entity):"""``project`` column cell renderer"""project=entity.cw_adapt_to('IMileStone').get_main_task()ifproject:returnproject.view('incontext')returnself._cw._('no related project')defbuild_milestone_cell(self,entity):"""``milestone`` column cell renderer"""returnentity.view('incontext')defbuild_state_cell(self,entity):"""``state`` column cell renderer"""returnxml_escape(entity.cw_adapt_to('IWorkflowable').printable_state)defbuild_eta_date_cell(self,entity):"""``eta_date`` column cell renderer"""imilestone=entity.cw_adapt_to('IMileStone')ifimilestone.finished():returnself._cw.format_date(imilestone.completion_date())formated_date=self._cw.format_date(imilestone.initial_prevision_date())ifimilestone.in_progress():eta_date=self._cw.format_date(imilestone.eta_date())_=self._cw._ifformated_date:formated_date+=u' (%s%s)'%(_('expected:'),eta_date)else:formated_date=u'%s%s'%(_('expected:'),eta_date)returnformated_datedefbuild_todo_by_cell(self,entity):"""``todo_by`` column cell renderer"""imilestone=entity.cw_adapt_to('IMileStone')returnu', '.join(p.view('outofcontext')forpinimilestone.contractors())defbuild_cost_cell(self,entity):"""``cost`` column cell renderer"""_=self._cw._imilestone=entity.cw_adapt_to('IMileStone')pinfo=imilestone.progress_info()totalcost=pinfo.get('estimatedcorrected',pinfo['estimated'])missing=pinfo.get('notestimatedcorrected',pinfo.get('notestimated',0))costdescr=[]ifmissing:# XXX: link to unestimated entitiescostdescr.append(_('%s not estimated')%missing)estimated=pinfo['estimated']ifestimatedandestimated!=totalcost:costdescr.append(_('initial estimation %s')%estimated)ifcostdescr:returnu'%s (%s)'%(totalcost,', '.join(costdescr))returnunicode(totalcost)defbuild_progress_cell(self,entity):"""``progress`` column cell renderer"""returnentity.view('progressbar')classInContextProgressTableView(ProgressTableView):"""this views redirects to ``progress_table_view`` but removes the ``project`` column """__metaclass__=class_deprecated__deprecation_warning__='[3.14] %(cls)s is deprecated'__regid__='ic_progress_table_view'defcall(self,columns=None):view=self._cw.vreg['views'].select('progress_table_view',self._cw,rset=self.cw_rset)columns=list(columnsorview.columns)try:columns.remove('project')exceptValueError:self.info('[ic_progress_table_view] could not remove project from columns')view.render(w=self.w,columns=columns)classProgressBarView(EntityView):"""displays a progress bar"""__metaclass__=class_deprecated__deprecation_warning__='[3.14] %(cls)s is deprecated'__regid__='progressbar'__select__=adaptable('IProgress')title=_('progress bar')precision=0.1red_threshold=1.1orange_threshold=1.05yellow_threshold=1@classmethoddefoverrun(cls,iprogress):done=iprogress.doneor0todo=iprogress.todoor0budget=iprogress.revised_costor0ifdone+todo>budget:overrun=done+todo-budgetelse:overrun=0ifoverrun<cls.precision:overrun=0returnoverrun@classmethoddefoverrun_percentage(cls,iprogress):budget=iprogress.revised_costor0ifbudget==0:return0returncls.overrun(iprogress)*100./budgetdefcell_call(self,row,col):self._cw.add_css('cubicweb.iprogress.css')self._cw.add_js('cubicweb.iprogress.js')entity=self.cw_rset.get_entity(row,col)iprogress=entity.cw_adapt_to('IProgress')done=iprogress.doneor0todo=iprogress.todoor0budget=iprogress.revised_costor0ifbudget==0:pourcent=100else:pourcent=done*100./budgetifpourcent>100.1:color='red'eliftodo+done>self.red_threshold*budget:color='red'eliftodo+done>self.orange_threshold*budget:color='orange'eliftodo+done>self.yellow_threshold*budget:color='yellow'else:color='green'ifpourcent<0:pourcent=0iffloor(done)==doneordone>100:done_str='%i'%doneelse:done_str='%.1f'%doneiffloor(budget)==budgetorbudget>100:budget_str='%i'%budgetelse:budget_str='%.1f'%budgettitle=u'%s/%s = %i%%'%(done_str,budget_str,pourcent)short_title=titleoverrunpercent=self.overrun_percentage(iprogress)ifoverrunpercent:overrun=self.overrun(iprogress)title+=u' overrun +%sj (+%i%%)'%(overrun,overrunpercent)iffloor(overrun)==overrunoroverrun>100:short_title+=u' +%i'%overrunelse:short_title+=u' +%.1f'%overrun# write barsmaxi=max(done+todo,budget)ifmaxi==0:maxi=1cid=make_uid('progress_bar')self._cw.html_headers.add_onload('draw_progressbar("canvas%s", %i, %i, %i, "%s");'%(cid,int(100.*done/maxi),int(100.*(done+todo)/maxi),int(100.*budget/maxi),color))self.w(u'%s<br/>'u'<canvas class="progressbar" id="canvas%s" width="100" height="10"></canvas>'%(xml_escape(short_title),cid))