Drop iprogress code (closes #2777628)

authorR?mi Cardona <remi.cardona@logilab.fr>
changeset87d24907ca99
branchdefault
phasedraft
hiddenyes
parent revision#f404f3e4ccea [web/views] extract cube sioc (closes #1916018)
child revision<not specified>
files modified by this revision
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
# HG changeset patch
# User RĂ©mi Cardona <remi.cardona@logilab.fr>
# Date 1364398731 -3600
# Wed Mar 27 16:38:51 2013 +0100
# Node ID 87d24907ca99be9cabfcb2b1ba2ad985148bf369
# Parent f404f3e4ccea032f85639904c644293e1b19749c
Drop iprogress code (closes #2777628)

diff --git a/doc/3.17.rst b/doc/3.17.rst
@@ -7,5 +7,9 @@
1  * The web page embedding views and adapters have been removed from CubicWeb and
2    moved to the `embed` cube.
3 
4  * The SIOC views and adapters have been removed from CubicWeb and moved to the
5    `sioc` cube.
6 +
7 +* The progress views and adapters have been removed from CubicWeb. These
8 +  classes were deprecated since 3.14.0. They are still available in the
9 +  `iprogress` cube.
diff --git a/doc/tools/pyjsrest.py b/doc/tools/pyjsrest.py
@@ -134,11 +134,10 @@
10      'cubicweb.flot',
11      'cubicweb.calendar',
12      'cubicweb.preferences',
13      'cubicweb.edition',
14      'cubicweb.reledit',
15 -    'cubicweb.iprogress',
16      'cubicweb.rhythm',
17      'cubicweb.gmap',
18      'cubicweb.timeline-ext',
19  ]
20 
diff --git a/entities/adapters.py b/entities/adapters.py
@@ -402,119 +402,5 @@
21      def __call__(cls, *args, **kwargs):
22          msg = getattr(cls, "__deprecation_warning__",
23                        "%(cls)s is deprecated") % {'cls': cls.__name__}
24          warn(msg, DeprecationWarning, stacklevel=2)
25          return type.__call__(cls, *args, **kwargs)
26 -
27 -
28 -class IProgressAdapter(view.EntityAdapter):
29 -    """something that has a cost, a state and a progression.
30 -
31 -    You should at least override progress_info an in_progress methods on
32 -    concrete implementations.
33 -    """
34 -    __metaclass__ = adapter_deprecated
35 -    __deprecation_warning__ = '[3.14] IProgressAdapter has been moved to iprogress cube'
36 -    __needs_bw_compat__ = True
37 -    __regid__ = 'IProgress'
38 -    __select__ = implements(IProgress, warn=False) # XXX for bw compat, should be abstract
39 -
40 -    @property
41 -    @view.implements_adapter_compat('IProgress')
42 -    def cost(self):
43 -        """the total cost"""
44 -        return self.progress_info()['estimated']
45 -
46 -    @property
47 -    @view.implements_adapter_compat('IProgress')
48 -    def revised_cost(self):
49 -        return self.progress_info().get('estimatedcorrected', self.cost)
50 -
51 -    @property
52 -    @view.implements_adapter_compat('IProgress')
53 -    def done(self):
54 -        """what is already done"""
55 -        return self.progress_info()['done']
56 -
57 -    @property
58 -    @view.implements_adapter_compat('IProgress')
59 -    def todo(self):
60 -        """what remains to be done"""
61 -        return self.progress_info()['todo']
62 -
63 -    @view.implements_adapter_compat('IProgress')
64 -    def progress_info(self):
65 -        """returns a dictionary describing progress/estimated cost of the
66 -        version.
67 -
68 -        - mandatory keys are (''estimated', 'done', 'todo')
69 -
70 -        - optional keys are ('notestimated', 'notestimatedcorrected',
71 -          'estimatedcorrected')
72 -
73 -        'noestimated' and 'notestimatedcorrected' should default to 0
74 -        'estimatedcorrected' should default to 'estimated'
75 -        """
76 -        raise NotImplementedError
77 -
78 -    @view.implements_adapter_compat('IProgress')
79 -    def finished(self):
80 -        """returns True if status is finished"""
81 -        return not self.in_progress()
82 -
83 -    @view.implements_adapter_compat('IProgress')
84 -    def in_progress(self):
85 -        """returns True if status is not finished"""
86 -        raise NotImplementedError
87 -
88 -    @view.implements_adapter_compat('IProgress')
89 -    def progress(self):
90 -        """returns the % progress of the task item"""
91 -        try:
92 -            return 100. * self.done / self.revised_cost
93 -        except ZeroDivisionError:
94 -            # total cost is 0 : if everything was estimated, task is completed
95 -            if self.progress_info().get('notestimated'):
96 -                return 0.
97 -            return 100
98 -
99 -    @view.implements_adapter_compat('IProgress')
100 -    def progress_class(self):
101 -        return ''
102 -
103 -
104 -class IMileStoneAdapter(IProgressAdapter):
105 -    __metaclass__ = adapter_deprecated
106 -    __deprecation_warning__ = '[3.14] IMileStoneAdapter has been moved to iprogress cube'
107 -    __needs_bw_compat__ = True
108 -    __regid__ = 'IMileStone'
109 -    __select__ = implements(IMileStone, warn=False) # XXX for bw compat, should be abstract
110 -
111 -    parent_type = None # specify main task's type
112 -
113 -    @view.implements_adapter_compat('IMileStone')
114 -    def get_main_task(self):
115 -        """returns the main ITask entity"""
116 -        raise NotImplementedError
117 -
118 -    @view.implements_adapter_compat('IMileStone')
119 -    def initial_prevision_date(self):
120 -        """returns the initial expected end of the milestone"""
121 -        raise NotImplementedError
122 -
123 -    @view.implements_adapter_compat('IMileStone')
124 -    def eta_date(self):
125 -        """returns expected date of completion based on what remains
126 -        to be done
127 -        """
128 -        raise NotImplementedError
129 -
130 -    @view.implements_adapter_compat('IMileStone')
131 -    def completion_date(self):
132 -        """returns date on which the subtask has been completed"""
133 -        raise NotImplementedError
134 -
135 -    @view.implements_adapter_compat('IMileStone')
136 -    def contractors(self):
137 -        """returns the list of persons supposed to work on this task"""
138 -        raise NotImplementedError
139 -
diff --git a/test/unittest_vregistry.py b/test/unittest_vregistry.py
@@ -52,27 +52,27 @@
140          self.vreg.initialization_completed()
141          self.assertEqual(len(self.vreg['views']['primary']), 1)
142 
143 
144      def test_load_subinterface_based_appobjects(self):
145 -        self.vreg.register_objects([join(BASE, 'web', 'views', 'iprogress.py')])
146 -        # check progressbar was kicked
147 -        self.assertFalse(self.vreg['views'].get('progressbar'))
148 +        self.vreg.register_objects([join(BASE, 'web', 'views', 'idownloadable.py')])
149 +        # check downloadlink was kicked
150 +        self.assertFalse(self.vreg['views'].get('downloadlink'))
151          # we've to emulate register_objects to add custom MyCard objects
152          path = [join(BASE, 'entities', '__init__.py'),
153                  join(BASE, 'entities', 'adapters.py'),
154 -                join(BASE, 'web', 'views', 'iprogress.py')]
155 +                join(BASE, 'web', 'views', 'idownloadable.py')]
156          filemods = self.vreg.init_registration(path, None)
157          for filepath, modname in filemods:
158              self.vreg.load_file(filepath, modname)
159 -        class CardIProgressAdapter(EntityAdapter):
160 -            __regid__ = 'IProgress'
161 +        class CardIDownloadableAdapter(EntityAdapter):
162 +            __regid__ = 'IDownloadable'
163          self.vreg._loadedmods[__name__] = {}
164 -        self.vreg.register(CardIProgressAdapter)
165 +        self.vreg.register(CardIDownloadableAdapter)
166          self.vreg.initialization_completed()
167          # check progressbar isn't kicked
168 -        self.assertEqual(len(self.vreg['views']['progressbar']), 1)
169 +        self.assertEqual(len(self.vreg['views']['downloadlink']), 1)
170 
171      def test_properties(self):
172          self.vreg.reset()
173          self.assertFalse('system.version.cubicweb' in self.vreg['propertydefs'])
174          self.assertTrue(self.vreg.property_info('system.version.cubicweb'))
diff --git a/web/data/cubicweb.iprogress.css b/web/data/cubicweb.iprogress.css
@@ -1,78 +0,0 @@
175 -/*
176 - *  :organization: Logilab
177 - *  :copyright: 2003-2010 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
178 - *  :contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr
179 - */
180 -
181 -/******************************************************************************/
182 -/* progressbar                                                                */
183 -/******************************************************************************/
184 -
185 -.done { background:red }
186 -
187 -.inprogress { background:green }
188 -
189 -.overpassed { background: yellow}
190 -
191 -
192 -canvas.progressbar {
193 -  border:1px solid black;
194 -}
195 -
196 -.progressbarback {
197 -  border: 1px solid #000000;
198 -  background: transparent;
199 -  height: 10px;
200 -  width: 100px;
201 -}
202 -
203 -/******************************************************************************/
204 -/* progress table                                                             */
205 -/******************************************************************************/
206 -
207 -table.progress {
208 - /* The default table view */
209 -  margin: 10px 0px 1em;
210 -  width: 100%;
211 -  font-size: 0.9167em;
212 -}
213 -
214 -table.progress th {
215 -  white-space: nowrap;
216 -  font-weight: bold;
217 -  background: %(listingHeaderBgColor)s;
218 -  padding: 2px 4px;
219 -  font-size:8pt;
220 -}
221 -
222 -table.progress th,
223 -table.progress td {
224 -  border: 1px solid %(listingBorderColor)s;
225 -}
226 -
227 -table.progress td {
228 -  text-align: right;
229 -  padding: 2px 3px;
230 -}
231 -
232 -table.progress th.tdleft,
233 -table.progress td.tdleft {
234 -  text-align: left;
235 -  padding: 2px 3px 2px 5px;
236 -}
237 -
238 -table.progress tr.highlighted {
239 -  background-color: %(listingHighlightedBgColor)s;
240 -}
241 -
242 -table.progress tr.highlighted .progressbarback {
243 -  border: 1px solid %(listingHighlightedBgColor)s;
244 -}
245 -
246 -table.progress .progressbarback {
247 -  border: 1px solid #777;
248 -}
249 -
250 -.progress_data {
251 -  padding-right: 3px;
252 -}
253 \ No newline at end of file
diff --git a/web/data/cubicweb.iprogress.js b/web/data/cubicweb.iprogress.js
@@ -1,63 +0,0 @@
254 -function ProgressBar() {
255 -    this.budget = 100;
256 -    this.todo = 100;
257 -    this.done = 100;
258 -    this.color_done = "green";
259 -    this.color_budget = "blue";
260 -    this.color_todo = "#cccccc"; //  grey
261 -    this.height = 16;
262 -    this.middle = this.height / 2;
263 -    this.radius = 4;
264 -}
265 -
266 -ProgressBar.prototype.draw_one_rect = function(ctx, pos, color, fill) {
267 -    ctx.beginPath();
268 -    ctx.lineWidth = 1;
269 -    ctx.strokeStyle = color;
270 -    if (fill) {
271 -        ctx.fillStyle = color;
272 -        ctx.fillRect(0, 0, pos, this.middle * 2);
273 -    } else {
274 -        ctx.lineWidth = 2;
275 -        ctx.strokeStyle = "black";
276 -        ctx.moveTo(pos, 0);
277 -        ctx.lineTo(pos, this.middle * 2);
278 -        ctx.stroke();
279 -    }
280 -};
281 -
282 -ProgressBar.prototype.draw_one_circ = function(ctx, pos, color) {
283 -    ctx.beginPath();
284 -    ctx.lineWidth = 2;
285 -    ctx.strokeStyle = color;
286 -    ctx.moveTo(0, this.middle);
287 -    ctx.lineTo(pos, this.middle);
288 -    ctx.arc(pos, this.middle, this.radius, 0, Math.PI * 2, true);
289 -    ctx.stroke();
290 -};
291 -
292 -ProgressBar.prototype.draw_circ = function(ctx) {
293 -    this.draw_one_circ(ctx, this.budget, this.color_budget);
294 -    this.draw_one_circ(ctx, this.todo, this.color_todo);
295 -    this.draw_one_circ(ctx, this.done, this.color_done);
296 -};
297 -
298 -ProgressBar.prototype.draw_rect = function(ctx) {
299 -    this.draw_one_rect(ctx, this.todo, this.color_todo, true);
300 -    this.draw_one_rect(ctx, this.done, this.color_done, true);
301 -    this.draw_one_rect(ctx, this.budget, this.color_budget, false);
302 -};
303 -
304 -function draw_progressbar(cid, done, todo, budget, color) {
305 -    var canvas = document.getElementById(cid);
306 -    if (canvas.getContext) {
307 -        var ctx = canvas.getContext("2d");
308 -        var bar = new ProgressBar();
309 -        bar.budget = budget;
310 -        bar.todo = todo;
311 -        bar.done = done;
312 -        bar.color_done = color;
313 -        bar.draw_rect(ctx);
314 -    }
315 -}
316 -
diff --git a/web/views/iprogress.py b/web/views/iprogress.py
@@ -1,260 +0,0 @@
317 -# copyright 2003-2012 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
318 -# contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
319 -#
320 -# This file is part of CubicWeb.
321 -#
322 -# CubicWeb is free software: you can redistribute it and/or modify it under the
323 -# terms of the GNU Lesser General Public License as published by the Free
324 -# Software Foundation, either version 2.1 of the License, or (at your option)
325 -# any later version.
326 -#
327 -# CubicWeb is distributed in the hope that it will be useful, but WITHOUT
328 -# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
329 -# FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more
330 -# details.
331 -#
332 -# You should have received a copy of the GNU Lesser General Public License along
333 -# with CubicWeb.  If not, see <http://www.gnu.org/licenses/>.
334 -"""Specific views for entities implementing IProgress/IMileStone"""
335 -
336 -__docformat__ = "restructuredtext en"
337 -_ = unicode
338 -
339 -from math import floor
340 -
341 -from logilab.common.deprecation import class_deprecated
342 -from logilab.mtconverter import xml_escape
343 -
344 -from cubicweb.utils import make_uid
345 -from cubicweb.predicates import adaptable
346 -from cubicweb.schema import display_name
347 -from cubicweb.view import EntityView
348 -from cubicweb.web.views.tableview import EntityAttributesTableView
349 -
350 -
351 -class ProgressTableView(EntityAttributesTableView):
352 -    """The progress table view is able to display progress information
353 -    of any object implement IMileStone.
354 -
355 -    The default layout is composoed of 7 columns : parent task,
356 -    milestone, state, estimated date, cost, progressbar, and todo_by
357 -
358 -    The view accepts an optional ``columns`` paramater that lets you
359 -    remove or reorder some of those columns.
360 -
361 -    To add new columns, you should extend this class, define a new
362 -    ``columns`` class attribute and implement corresponding
363 -    build_COLNAME_cell methods
364 -
365 -    header_for_COLNAME methods allow to customize header's label
366 -    """
367 -    __metaclass__ = class_deprecated
368 -    __deprecation_warning__ = '[3.14] %(cls)s is deprecated'
369 -
370 -    __regid__ = 'progress_table_view'
371 -    __select__ = adaptable('IMileStone')
372 -    title = _('task progression')
373 -    table_css = "progress"
374 -    css_files = ('cubicweb.iprogress.css',)
375 -
376 -    # default columns of the table
377 -    columns = (_('project'), _('milestone'), _('state'), _('eta_date'),
378 -               _('cost'), _('progress'), _('todo_by'))
379 -
380 -    def cell_call(self, row, col):
381 -        _ = self._cw._
382 -        entity = self.cw_rset.get_entity(row, col)
383 -        infos = {}
384 -        for col in self.columns:
385 -            meth = getattr(self, 'build_%s_cell' % col, None)
386 -            # find the build method or try to find matching attribute
387 -            if meth:
388 -                content = meth(entity)
389 -            else:
390 -                content = entity.printable_value(col)
391 -            infos[col] = content
392 -        cssclass = entity.cw_adapt_to('IMileStone').progress_class()
393 -        self.w(u"""<tr class="%s" onmouseover="$(this).addClass('highlighted');"
394 -            onmouseout="$(this).removeClass('highlighted')">""" % cssclass)
395 -        line = u''.join(u'<td>%%(%s)s</td>' % col for col in self.columns)
396 -        self.w(line % infos)
397 -        self.w(u'</tr>\n')
398 -
399 -    ## header management ######################################################
400 -
401 -    def header_for_project(self, sample):
402 -        """use entity's parent type as label"""
403 -        return display_name(self._cw, sample.cw_adapt_to('IMileStone').parent_type)
404 -
405 -    def header_for_milestone(self, sample):
406 -        """use entity's type as label"""
407 -        return display_name(self._cw, sample.__regid__)
408 -
409 -    ## cell management ########################################################
410 -    def build_project_cell(self, entity):
411 -        """``project`` column cell renderer"""
412 -        project = entity.cw_adapt_to('IMileStone').get_main_task()
413 -        if project:
414 -            return project.view('incontext')
415 -        return self._cw._('no related project')
416 -
417 -    def build_milestone_cell(self, entity):
418 -        """``milestone`` column cell renderer"""
419 -        return entity.view('incontext')
420 -
421 -    def build_state_cell(self, entity):
422 -        """``state`` column cell renderer"""
423 -        return xml_escape(entity.cw_adapt_to('IWorkflowable').printable_state)
424 -
425 -    def build_eta_date_cell(self, entity):
426 -        """``eta_date`` column cell renderer"""
427 -        imilestone = entity.cw_adapt_to('IMileStone')
428 -        if imilestone.finished():
429 -            return self._cw.format_date(imilestone.completion_date())
430 -        formated_date = self._cw.format_date(imilestone.initial_prevision_date())
431 -        if imilestone.in_progress():
432 -            eta_date = self._cw.format_date(imilestone.eta_date())
433 -            _ = self._cw._
434 -            if formated_date:
435 -                formated_date += u' (%s %s)' % (_('expected:'), eta_date)
436 -            else:
437 -                formated_date = u'%s %s' % (_('expected:'), eta_date)
438 -        return formated_date
439 -
440 -    def build_todo_by_cell(self, entity):
441 -        """``todo_by`` column cell renderer"""
442 -        imilestone = entity.cw_adapt_to('IMileStone')
443 -        return u', '.join(p.view('outofcontext') for p in imilestone.contractors())
444 -
445 -    def build_cost_cell(self, entity):
446 -        """``cost`` column cell renderer"""
447 -        _ = self._cw._
448 -        imilestone = entity.cw_adapt_to('IMileStone')
449 -        pinfo = imilestone.progress_info()
450 -        totalcost = pinfo.get('estimatedcorrected', pinfo['estimated'])
451 -        missing = pinfo.get('notestimatedcorrected', pinfo.get('notestimated', 0))
452 -        costdescr = []
453 -        if missing:
454 -            # XXX: link to unestimated entities
455 -            costdescr.append(_('%s not estimated') % missing)
456 -        estimated = pinfo['estimated']
457 -        if estimated and estimated != totalcost:
458 -            costdescr.append(_('initial estimation %s') % estimated)
459 -        if costdescr:
460 -            return u'%s (%s)' % (totalcost, ', '.join(costdescr))
461 -        return unicode(totalcost)
462 -
463 -    def build_progress_cell(self, entity):
464 -        """``progress`` column cell renderer"""
465 -        return entity.view('progressbar')
466 -
467 -
468 -class InContextProgressTableView(ProgressTableView):
469 -    """this views redirects to ``progress_table_view`` but removes
470 -    the ``project`` column
471 -    """
472 -    __metaclass__ = class_deprecated
473 -    __deprecation_warning__ = '[3.14] %(cls)s is deprecated'
474 -    __regid__ = 'ic_progress_table_view'
475 -
476 -    def call(self, columns=None):
477 -        view = self._cw.vreg['views'].select('progress_table_view', self._cw,
478 -                                         rset=self.cw_rset)
479 -        columns = list(columns or view.columns)
480 -        try:
481 -            columns.remove('project')
482 -        except ValueError:
483 -            self.info('[ic_progress_table_view] could not remove project from columns')
484 -        view.render(w=self.w, columns=columns)
485 -
486 -
487 -class ProgressBarView(EntityView):
488 -    """displays a progress bar"""
489 -    __metaclass__ = class_deprecated
490 -    __deprecation_warning__ = '[3.14] %(cls)s is deprecated'
491 -    __regid__ = 'progressbar'
492 -    __select__ = adaptable('IProgress')
493 -
494 -    title = _('progress bar')
495 -
496 -    precision = 0.1
497 -    red_threshold = 1.1
498 -    orange_threshold = 1.05
499 -    yellow_threshold = 1
500 -
501 -    @classmethod
502 -    def overrun(cls, iprogress):
503 -        done = iprogress.done or 0
504 -        todo = iprogress.todo or 0
505 -        budget = iprogress.revised_cost or 0
506 -        if done + todo > budget:
507 -            overrun = done + todo - budget
508 -        else:
509 -            overrun = 0
510 -        if overrun < cls.precision:
511 -            overrun = 0
512 -        return overrun
513 -
514 -    @classmethod
515 -    def overrun_percentage(cls, iprogress):
516 -        budget = iprogress.revised_cost or 0
517 -        if budget == 0:
518 -            return 0
519 -        return cls.overrun(iprogress) * 100. / budget
520 -
521 -    def cell_call(self, row, col):
522 -        self._cw.add_css('cubicweb.iprogress.css')
523 -        self._cw.add_js('cubicweb.iprogress.js')
524 -        entity = self.cw_rset.get_entity(row, col)
525 -        iprogress = entity.cw_adapt_to('IProgress')
526 -        done = iprogress.done or 0
527 -        todo = iprogress.todo or 0
528 -        budget = iprogress.revised_cost or 0
529 -        if budget == 0:
530 -            pourcent = 100
531 -        else:
532 -            pourcent = done*100./budget
533 -        if pourcent > 100.1:
534 -            color = 'red'
535 -        elif todo+done > self.red_threshold*budget:
536 -            color = 'red'
537 -        elif todo+done > self.orange_threshold*budget:
538 -            color = 'orange'
539 -        elif todo+done > self.yellow_threshold*budget:
540 -            color = 'yellow'
541 -        else:
542 -            color = 'green'
543 -        if pourcent < 0:
544 -            pourcent = 0
545 -
546 -        if floor(done) == done or done>100:
547 -            done_str = '%i' % done
548 -        else:
549 -            done_str = '%.1f' % done
550 -        if floor(budget) == budget or budget>100:
551 -            budget_str = '%i' % budget
552 -        else:
553 -            budget_str = '%.1f' % budget
554 -
555 -        title = u'%s/%s = %i%%' % (done_str, budget_str, pourcent)
556 -        short_title = title
557 -        overrunpercent = self.overrun_percentage(iprogress)
558 -        if overrunpercent:
559 -            overrun = self.overrun(iprogress)
560 -            title += u' overrun +%sj (+%i%%)' % (overrun, overrunpercent)
561 -            if floor(overrun) == overrun or overrun > 100:
562 -                short_title += u' +%i' % overrun
563 -            else:
564 -                short_title += u' +%.1f' % overrun
565 -        # write bars
566 -        maxi = max(done+todo, budget)
567 -        if maxi == 0:
568 -            maxi = 1
569 -        cid = make_uid('progress_bar')
570 -        self._cw.html_headers.add_onload(
571 -            'draw_progressbar("canvas%s", %i, %i, %i, "%s");' %
572 -            (cid, int(100.*done/maxi), int(100.*(done+todo)/maxi),
573 -             int(100.*budget/maxi), color))
574 -        self.w(u'%s<br/>'
575 -               u'<canvas class="progressbar" id="canvas%s" width="100" height="10"></canvas>'
576 -               % (xml_escape(short_title), cid))