| # Copyright 2008 Google Inc. |
| # |
| # Licensed under the Apache License, Version 2.0 (the "License"); |
| # you may not use this file except in compliance with the License. |
| # You may obtain a copy of the License at |
| # |
| # http://www.apache.org/licenses/LICENSE-2.0 |
| # |
| # Unless required by applicable law or agreed to in writing, software |
| # distributed under the License is distributed on an "AS IS" BASIS, |
| # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| # See the License for the specific language governing permissions and |
| # limitations under the License. |
| |
| from django.utils import safestring |
| from django.utils import html |
| from django.template import defaultfilters |
| |
| import logging |
| import operator |
| import library |
| |
| class FieldRendererException(Exception): |
| def __init__(self, msg): |
| self.msg = msg |
| def __str__(self): |
| return "FieldRendererException('%s')" % self.msg |
| |
| def _render_star(change, current_user): |
| id = change.key().id() |
| |
| list = [] |
| list.append("""<span id="change-star-%d">""" % id) |
| if change.is_starred: |
| list.append("""<a href="javascript:M_removeChangeStar(%d)"><img src="/static/star-lite.gif" width="15" height="15" border="0"></a>""" |
| % id) |
| else: |
| if current_user: |
| list.append("""<a href="javascript:M_addChangeStar(%d)"><img src="/static/star-dark.gif" width="15" height="15" border="0"></a>""" |
| % id) |
| list.append("</span>") |
| return "".join(list) |
| |
| |
| class BaseFieldRenderer(object): |
| """Base class for renderers for particular fields. |
| |
| Implement the render_title() and render_contents() methods. |
| """ |
| def column_count(self): |
| raise FieldRendererException, "column_count not implemented" |
| |
| def render_title(self): |
| """Render the title for a column in the table. |
| |
| Returns: |
| The string of the rendered title. |
| """ |
| raise FieldRendererException, "render_title not implemented" |
| def render_contents(self, change, current_user): |
| raise FieldRendererException, "render_contents not implemented" |
| |
| |
| class IdFieldRenderer(BaseFieldRenderer): |
| def column_count(self): |
| return 3 |
| |
| def render_title(self): |
| return """<th class="header-columns" colspan="3" style="text-align: right;">Id</th> |
| """ |
| |
| def render_contents(self, change, current_user): |
| return """<td class="selection"><img src="/static/closedtriangle.gif" style="visibility: hidden;" width="12" height="9" /></td> |
| <td class="star" width="17" align="center">%(star)s</td> |
| <td class="id" align="right"><a href="/%(id)d">%(id)d</a></td>""" % { |
| 'id': change.key().id(), |
| 'star': _render_star(change, current_user) |
| } |
| |
| |
| class FieldRenderer(BaseFieldRenderer): |
| def __init__(self, cell_class, title, func): |
| self.cell_class = cell_class |
| self.title = title |
| self.func = func |
| |
| def column_count(self): |
| return 1 |
| |
| def render_title(self): |
| return """<th class="header-columns %(cell_class)s">%(title)s</th>""" % { |
| 'title': self.title, |
| 'cell_class': self.cell_class, |
| } |
| |
| def render_contents(self, change, current_user): |
| return """<td class="%(cell_class)s">%(cell_contents)s</td>""" % { |
| 'cell_contents': self.func(change), |
| 'cell_class': self.cell_class, |
| } |
| |
| |
| class SubjectFieldRenderer(FieldRenderer): |
| def __init__(self): |
| FieldRenderer.__init__(self, 'subject', 'Subject', |
| lambda c: """<a href="/%(id)d">%(subject)s</a> %(closed)s""" % { |
| 'id': c.key().id(), |
| 'subject': html.escape(defaultfilters.truncatewords(c.subject, 11)), |
| 'closed': library.closed_label(c), |
| }) |
| |
| def render_title(self): |
| return """<th class="header-columns %(class)s">%(title)s</th>""" % { |
| 'title': self.title, |
| 'class': self.cell_class, |
| } |
| |
| |
| |
| class UserListFieldRenderer(FieldRenderer): |
| def __init__(self, cell_class, title, func): |
| FieldRenderer.__init__(self, cell_class, title, |
| lambda c: ", ".join(map(library.show_user, func(c)))) |
| |
| |
| FIELD_ID = IdFieldRenderer() |
| FIELD_SUBJECT = SubjectFieldRenderer() |
| FIELD_OWNER = UserListFieldRenderer('owner', 'Owner', lambda c: [c.owner]) |
| FIELD_REVIEWERS = UserListFieldRenderer('reviewers', 'Reviewers', |
| lambda c: c.reviewers) |
| FIELD_PROJECT = FieldRenderer('project', 'Project', lambda c: html.escape(c.dest_project.name)) |
| FIELD_MODIFIED = FieldRenderer('modified', 'Last Update', |
| lambda c: library.abbrevtimesince(c.modified)) |
| |
| # this one should be change so that it's what they see in repo |
| FIELD_BRANCH = FieldRenderer('branch', 'Branch', lambda c: html.escape(c.dest_branch.short_name)) |
| |
| class ChangeTable(object): |
| """An object to help render a list of changes as a table. |
| |
| Generally, changes are grouped into sections. If a section's title is |
| None, then the section header won't be rendered, and it will appear to |
| be merged with the last section. |
| """ |
| |
| def __init__(self, current_user, fields): |
| """Construct a ChangeTable object. |
| |
| Args: |
| fields - A list of BaseFieldRenderer objects. See the FIELD_ constants |
| in this module for the common ones. |
| """ |
| self.current_user = current_user |
| self.fields = fields |
| self.sections = [] |
| |
| def add_section(self, title, changes): |
| self.sections.append({'title': title, 'changes': changes}) |
| |
| def render(self): |
| column_count = reduce(operator.add, |
| map(lambda x: x.column_count(), self.fields)) |
| def _render_none(): |
| return ("""<tr><td colspan="%d" class="disabled">(None)</td></tr>""" |
| % column_count) |
| lines = [] |
| lines.append("""<table class="change-list" id="user-queues">""") |
| lines.append("""<tr>""") |
| for field in self.fields: |
| lines.append(field.render_title()) |
| lines.append("""</tr>""") |
| if len(self.sections) == 0: |
| lines.append(_render_none()) |
| else: |
| for section in self.sections: |
| title = section['title'] |
| if not title is None: |
| lines.append("""<tr><th class="header-title" colspan="%d">%s</th></tr>""" |
| % (column_count, html.escape(title))) |
| changes = section['changes'] |
| if not changes: |
| lines.append(_render_none()) |
| else: |
| for change in section['changes']: |
| lines.append("""<tr name="change">""") |
| for field in self.fields: |
| lines.append(field.render_contents(change, self.current_user)) |
| lines.append("</tr>") |
| lines.append("""</table>""") |
| return safestring.mark_safe("\n".join(lines)) |
| |