Drop iprogress code (closes #2777628)
authorRémi Cardona <remi.cardona@logilab.fr>
Wed, 27 Mar 2013 16:58:13 +0100
changeset 8801 86c1a5afbe4e
parent 8800 8ca1a0da5a29
child 8802 d92919c995cc
Drop iprogress code (closes #2777628)
doc/3.17.rst
doc/tools/pyjsrest.py
entities/adapters.py
test/unittest_vregistry.py
web/data/cubicweb.iprogress.css
web/data/cubicweb.iprogress.js
web/views/iprogress.py
--- a/doc/3.17.rst	Wed Mar 27 16:36:47 2013 +0100
+++ b/doc/3.17.rst	Wed Mar 27 16:58:13 2013 +0100
@@ -6,3 +6,11 @@
 
 * The SIOC views and adapters have been removed from CubicWeb and moved to the
   `sioc` cube.
+
+
+Deprecated Code Drops
+----------------------
+
+* The progress views and adapters have been removed from CubicWeb. These
+  classes were deprecated since 3.14.0. They are still available in the
+  `iprogress` cube.
--- a/doc/tools/pyjsrest.py	Wed Mar 27 16:36:47 2013 +0100
+++ b/doc/tools/pyjsrest.py	Wed Mar 27 16:58:13 2013 +0100
@@ -136,7 +136,6 @@
     'cubicweb.preferences',
     'cubicweb.edition',
     'cubicweb.reledit',
-    'cubicweb.iprogress',
     'cubicweb.rhythm',
     'cubicweb.gmap',
     'cubicweb.timeline-ext',
--- a/entities/adapters.py	Wed Mar 27 16:36:47 2013 +0100
+++ b/entities/adapters.py	Wed Mar 27 16:58:13 2013 +0100
@@ -404,117 +404,3 @@
                       "%(cls)s is deprecated") % {'cls': cls.__name__}
         warn(msg, DeprecationWarning, stacklevel=2)
         return type.__call__(cls, *args, **kwargs)
-
-
-class IProgressAdapter(view.EntityAdapter):
-    """something that has a cost, a state and a progression.
-
-    You should at least override progress_info an in_progress methods on
-    concrete implementations.
-    """
-    __metaclass__ = adapter_deprecated
-    __deprecation_warning__ = '[3.14] IProgressAdapter has been moved to iprogress cube'
-    __needs_bw_compat__ = True
-    __regid__ = 'IProgress'
-    __select__ = implements(IProgress, warn=False) # XXX for bw compat, should be abstract
-
-    @property
-    @view.implements_adapter_compat('IProgress')
-    def cost(self):
-        """the total cost"""
-        return self.progress_info()['estimated']
-
-    @property
-    @view.implements_adapter_compat('IProgress')
-    def revised_cost(self):
-        return self.progress_info().get('estimatedcorrected', self.cost)
-
-    @property
-    @view.implements_adapter_compat('IProgress')
-    def done(self):
-        """what is already done"""
-        return self.progress_info()['done']
-
-    @property
-    @view.implements_adapter_compat('IProgress')
-    def todo(self):
-        """what remains to be done"""
-        return self.progress_info()['todo']
-
-    @view.implements_adapter_compat('IProgress')
-    def progress_info(self):
-        """returns a dictionary describing progress/estimated cost of the
-        version.
-
-        - mandatory keys are (''estimated', 'done', 'todo')
-
-        - optional keys are ('notestimated', 'notestimatedcorrected',
-          'estimatedcorrected')
-
-        'noestimated' and 'notestimatedcorrected' should default to 0
-        'estimatedcorrected' should default to 'estimated'
-        """
-        raise NotImplementedError
-
-    @view.implements_adapter_compat('IProgress')
-    def finished(self):
-        """returns True if status is finished"""
-        return not self.in_progress()
-
-    @view.implements_adapter_compat('IProgress')
-    def in_progress(self):
-        """returns True if status is not finished"""
-        raise NotImplementedError
-
-    @view.implements_adapter_compat('IProgress')
-    def progress(self):
-        """returns the % progress of the task item"""
-        try:
-            return 100. * self.done / self.revised_cost
-        except ZeroDivisionError:
-            # total cost is 0 : if everything was estimated, task is completed
-            if self.progress_info().get('notestimated'):
-                return 0.
-            return 100
-
-    @view.implements_adapter_compat('IProgress')
-    def progress_class(self):
-        return ''
-
-
-class IMileStoneAdapter(IProgressAdapter):
-    __metaclass__ = adapter_deprecated
-    __deprecation_warning__ = '[3.14] IMileStoneAdapter has been moved to iprogress cube'
-    __needs_bw_compat__ = True
-    __regid__ = 'IMileStone'
-    __select__ = implements(IMileStone, warn=False) # XXX for bw compat, should be abstract
-
-    parent_type = None # specify main task's type
-
-    @view.implements_adapter_compat('IMileStone')
-    def get_main_task(self):
-        """returns the main ITask entity"""
-        raise NotImplementedError
-
-    @view.implements_adapter_compat('IMileStone')
-    def initial_prevision_date(self):
-        """returns the initial expected end of the milestone"""
-        raise NotImplementedError
-
-    @view.implements_adapter_compat('IMileStone')
-    def eta_date(self):
-        """returns expected date of completion based on what remains
-        to be done
-        """
-        raise NotImplementedError
-
-    @view.implements_adapter_compat('IMileStone')
-    def completion_date(self):
-        """returns date on which the subtask has been completed"""
-        raise NotImplementedError
-
-    @view.implements_adapter_compat('IMileStone')
-    def contractors(self):
-        """returns the list of persons supposed to work on this task"""
-        raise NotImplementedError
-
--- a/test/unittest_vregistry.py	Wed Mar 27 16:36:47 2013 +0100
+++ b/test/unittest_vregistry.py	Wed Mar 27 16:58:13 2013 +0100
@@ -54,23 +54,23 @@
 
 
     def test_load_subinterface_based_appobjects(self):
-        self.vreg.register_objects([join(BASE, 'web', 'views', 'iprogress.py')])
-        # check progressbar was kicked
-        self.assertFalse(self.vreg['views'].get('progressbar'))
+        self.vreg.register_objects([join(BASE, 'web', 'views', 'idownloadable.py')])
+        # check downloadlink was kicked
+        self.assertFalse(self.vreg['views'].get('downloadlink'))
         # we've to emulate register_objects to add custom MyCard objects
         path = [join(BASE, 'entities', '__init__.py'),
                 join(BASE, 'entities', 'adapters.py'),
-                join(BASE, 'web', 'views', 'iprogress.py')]
+                join(BASE, 'web', 'views', 'idownloadable.py')]
         filemods = self.vreg.init_registration(path, None)
         for filepath, modname in filemods:
             self.vreg.load_file(filepath, modname)
-        class CardIProgressAdapter(EntityAdapter):
-            __regid__ = 'IProgress'
+        class CardIDownloadableAdapter(EntityAdapter):
+            __regid__ = 'IDownloadable'
         self.vreg._loadedmods[__name__] = {}
-        self.vreg.register(CardIProgressAdapter)
+        self.vreg.register(CardIDownloadableAdapter)
         self.vreg.initialization_completed()
         # check progressbar isn't kicked
-        self.assertEqual(len(self.vreg['views']['progressbar']), 1)
+        self.assertEqual(len(self.vreg['views']['downloadlink']), 1)
 
     def test_properties(self):
         self.vreg.reset()
--- a/web/data/cubicweb.iprogress.css	Wed Mar 27 16:36:47 2013 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,78 +0,0 @@
-/*
- *  :organization: Logilab
- *  :copyright: 2003-2010 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
- *  :contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr
- */
-
-/******************************************************************************/
-/* progressbar                                                                */
-/******************************************************************************/
-
-.done { background:red }
-
-.inprogress { background:green }
-
-.overpassed { background: yellow}
-
-
-canvas.progressbar {
-  border:1px solid black;
-}
-
-.progressbarback {
-  border: 1px solid #000000;
-  background: transparent;
-  height: 10px;
-  width: 100px;
-}
-
-/******************************************************************************/
-/* progress table                                                             */
-/******************************************************************************/
-
-table.progress {
- /* The default table view */
-  margin: 10px 0px 1em;
-  width: 100%;
-  font-size: 0.9167em;
-}
-
-table.progress th {
-  white-space: nowrap;
-  font-weight: bold;
-  background: %(listingHeaderBgColor)s;
-  padding: 2px 4px;
-  font-size:8pt;
-}
-
-table.progress th,
-table.progress td {
-  border: 1px solid %(listingBorderColor)s;
-}
-
-table.progress td {
-  text-align: right;
-  padding: 2px 3px;
-}
-
-table.progress th.tdleft,
-table.progress td.tdleft {
-  text-align: left;
-  padding: 2px 3px 2px 5px;
-}
-
-table.progress tr.highlighted {
-  background-color: %(listingHighlightedBgColor)s;
-}
-
-table.progress tr.highlighted .progressbarback {
-  border: 1px solid %(listingHighlightedBgColor)s;
-}
-
-table.progress .progressbarback {
-  border: 1px solid #777;
-}
-
-.progress_data {
-  padding-right: 3px;
-}
\ No newline at end of file
--- a/web/data/cubicweb.iprogress.js	Wed Mar 27 16:36:47 2013 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,63 +0,0 @@
-function ProgressBar() {
-    this.budget = 100;
-    this.todo = 100;
-    this.done = 100;
-    this.color_done = "green";
-    this.color_budget = "blue";
-    this.color_todo = "#cccccc"; //  grey
-    this.height = 16;
-    this.middle = this.height / 2;
-    this.radius = 4;
-}
-
-ProgressBar.prototype.draw_one_rect = function(ctx, pos, color, fill) {
-    ctx.beginPath();
-    ctx.lineWidth = 1;
-    ctx.strokeStyle = color;
-    if (fill) {
-        ctx.fillStyle = color;
-        ctx.fillRect(0, 0, pos, this.middle * 2);
-    } else {
-        ctx.lineWidth = 2;
-        ctx.strokeStyle = "black";
-        ctx.moveTo(pos, 0);
-        ctx.lineTo(pos, this.middle * 2);
-        ctx.stroke();
-    }
-};
-
-ProgressBar.prototype.draw_one_circ = function(ctx, pos, color) {
-    ctx.beginPath();
-    ctx.lineWidth = 2;
-    ctx.strokeStyle = color;
-    ctx.moveTo(0, this.middle);
-    ctx.lineTo(pos, this.middle);
-    ctx.arc(pos, this.middle, this.radius, 0, Math.PI * 2, true);
-    ctx.stroke();
-};
-
-ProgressBar.prototype.draw_circ = function(ctx) {
-    this.draw_one_circ(ctx, this.budget, this.color_budget);
-    this.draw_one_circ(ctx, this.todo, this.color_todo);
-    this.draw_one_circ(ctx, this.done, this.color_done);
-};
-
-ProgressBar.prototype.draw_rect = function(ctx) {
-    this.draw_one_rect(ctx, this.todo, this.color_todo, true);
-    this.draw_one_rect(ctx, this.done, this.color_done, true);
-    this.draw_one_rect(ctx, this.budget, this.color_budget, false);
-};
-
-function draw_progressbar(cid, done, todo, budget, color) {
-    var canvas = document.getElementById(cid);
-    if (canvas.getContext) {
-        var ctx = canvas.getContext("2d");
-        var bar = new ProgressBar();
-        bar.budget = budget;
-        bar.todo = todo;
-        bar.done = done;
-        bar.color_done = color;
-        bar.draw_rect(ctx);
-    }
-}
-
--- a/web/views/iprogress.py	Wed Mar 27 16:36:47 2013 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,260 +0,0 @@
-# copyright 2003-2012 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"
-_ = unicode
-
-from math import floor
-
-from logilab.common.deprecation import class_deprecated
-from logilab.mtconverter import xml_escape
-
-from cubicweb.utils import make_uid
-from cubicweb.predicates import adaptable
-from cubicweb.schema import display_name
-from cubicweb.view import EntityView
-from cubicweb.web.views.tableview import EntityAttributesTableView
-
-
-class ProgressTableView(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 table
-    columns = (_('project'), _('milestone'), _('state'), _('eta_date'),
-               _('cost'), _('progress'), _('todo_by'))
-
-    def cell_call(self, row, col):
-        _ = self._cw._
-        entity = self.cw_rset.get_entity(row, col)
-        infos = {}
-        for col in self.columns:
-            meth = getattr(self, 'build_%s_cell' % col, None)
-            # find the build method or try to find matching attribute
-            if meth:
-                content = meth(entity)
-            else:
-                content = entity.printable_value(col)
-            infos[col] = content
-        cssclass = 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>' % col for col in self.columns)
-        self.w(line % infos)
-        self.w(u'</tr>\n')
-
-    ## header management ######################################################
-
-    def header_for_project(self, sample):
-        """use entity's parent type as label"""
-        return display_name(self._cw, sample.cw_adapt_to('IMileStone').parent_type)
-
-    def header_for_milestone(self, sample):
-        """use entity's type as label"""
-        return display_name(self._cw, sample.__regid__)
-
-    ## cell management ########################################################
-    def build_project_cell(self, entity):
-        """``project`` column cell renderer"""
-        project = entity.cw_adapt_to('IMileStone').get_main_task()
-        if project:
-            return project.view('incontext')
-        return self._cw._('no related project')
-
-    def build_milestone_cell(self, entity):
-        """``milestone`` column cell renderer"""
-        return entity.view('incontext')
-
-    def build_state_cell(self, entity):
-        """``state`` column cell renderer"""
-        return xml_escape(entity.cw_adapt_to('IWorkflowable').printable_state)
-
-    def build_eta_date_cell(self, entity):
-        """``eta_date`` column cell renderer"""
-        imilestone = entity.cw_adapt_to('IMileStone')
-        if imilestone.finished():
-            return self._cw.format_date(imilestone.completion_date())
-        formated_date = self._cw.format_date(imilestone.initial_prevision_date())
-        if imilestone.in_progress():
-            eta_date = self._cw.format_date(imilestone.eta_date())
-            _ = self._cw._
-            if formated_date:
-                formated_date += u' (%s %s)' % (_('expected:'), eta_date)
-            else:
-                formated_date = u'%s %s' % (_('expected:'), eta_date)
-        return formated_date
-
-    def build_todo_by_cell(self, entity):
-        """``todo_by`` column cell renderer"""
-        imilestone = entity.cw_adapt_to('IMileStone')
-        return u', '.join(p.view('outofcontext') for p in imilestone.contractors())
-
-    def build_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 = []
-        if missing:
-            # XXX: link to unestimated entities
-            costdescr.append(_('%s not estimated') % missing)
-        estimated = pinfo['estimated']
-        if estimated and estimated != totalcost:
-            costdescr.append(_('initial estimation %s') % estimated)
-        if costdescr:
-            return u'%s (%s)' % (totalcost, ', '.join(costdescr))
-        return unicode(totalcost)
-
-    def build_progress_cell(self, entity):
-        """``progress`` column cell renderer"""
-        return entity.view('progressbar')
-
-
-class InContextProgressTableView(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'
-
-    def call(self, columns=None):
-        view = self._cw.vreg['views'].select('progress_table_view', self._cw,
-                                         rset=self.cw_rset)
-        columns = list(columns or view.columns)
-        try:
-            columns.remove('project')
-        except ValueError:
-            self.info('[ic_progress_table_view] could not remove project from columns')
-        view.render(w=self.w, columns=columns)
-
-
-class ProgressBarView(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.1
-    red_threshold = 1.1
-    orange_threshold = 1.05
-    yellow_threshold = 1
-
-    @classmethod
-    def overrun(cls, iprogress):
-        done = iprogress.done or 0
-        todo = iprogress.todo or 0
-        budget = iprogress.revised_cost or 0
-        if done + todo > budget:
-            overrun = done + todo - budget
-        else:
-            overrun = 0
-        if overrun < cls.precision:
-            overrun = 0
-        return overrun
-
-    @classmethod
-    def overrun_percentage(cls, iprogress):
-        budget = iprogress.revised_cost or 0
-        if budget == 0:
-            return 0
-        return cls.overrun(iprogress) * 100. / budget
-
-    def cell_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.done or 0
-        todo = iprogress.todo or 0
-        budget = iprogress.revised_cost or 0
-        if budget == 0:
-            pourcent = 100
-        else:
-            pourcent = done*100./budget
-        if pourcent > 100.1:
-            color = 'red'
-        elif todo+done > self.red_threshold*budget:
-            color = 'red'
-        elif todo+done > self.orange_threshold*budget:
-            color = 'orange'
-        elif todo+done > self.yellow_threshold*budget:
-            color = 'yellow'
-        else:
-            color = 'green'
-        if pourcent < 0:
-            pourcent = 0
-
-        if floor(done) == done or done>100:
-            done_str = '%i' % done
-        else:
-            done_str = '%.1f' % done
-        if floor(budget) == budget or budget>100:
-            budget_str = '%i' % budget
-        else:
-            budget_str = '%.1f' % budget
-
-        title = u'%s/%s = %i%%' % (done_str, budget_str, pourcent)
-        short_title = title
-        overrunpercent = self.overrun_percentage(iprogress)
-        if overrunpercent:
-            overrun = self.overrun(iprogress)
-            title += u' overrun +%sj (+%i%%)' % (overrun, overrunpercent)
-            if floor(overrun) == overrun or overrun > 100:
-                short_title += u' +%i' % overrun
-            else:
-                short_title += u' +%.1f' % overrun
-        # write bars
-        maxi = max(done+todo, budget)
-        if maxi == 0:
-            maxi = 1
-        cid = 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))