Index: trac/ticket/query.py =================================================================== --- trac/ticket/query.py (revision 4209) +++ trac/ticket/query.py (working copy) @@ -20,6 +20,7 @@ from StringIO import StringIO from trac.core import * +from trac.config import ListOption from trac.db import get_column_names from trac.mimeview.api import Mimeview, IContentConverter from trac.perm import IPermissionRequestor @@ -42,7 +43,7 @@ class Query(object): def __init__(self, env, constraints=None, order=None, desc=0, group=None, - groupdesc = 0, verbose=0): + groupdesc = 0, verbose=0, columns=None): self.env = env self.constraints = constraints or {} self.order = order @@ -51,10 +52,12 @@ self.groupdesc = groupdesc self.verbose = verbose self.fields = TicketSystem(self.env).get_ticket_fields() - self.cols = [] # lazily initialized + self.cols = columns # lazily initialized if empty - if self.order != 'id' \ - and self.order not in [f['name'] for f in self.fields]: + self.valid_cols = ['id', 'changetime', 'time'] + \ + [f['name'] for f in self.fields] + + if self.order not in self.valid_cols: # order by priority by default self.order = 'priority' @@ -94,6 +97,8 @@ kw[field] = processed_values[0] elif field in kw_bools: kw[field] = True + elif field == 'columns': + kw[field] = processed_values[0].split(',') else: constraints[field] = processed_values except UnicodeError: @@ -108,7 +113,14 @@ # FIXME: the user should be able to configure which columns should # be displayed cols = ['id'] - cols += [f['name'] for f in self.fields if f['type'] != 'textarea'] + cols += [f['name'] for f in self.fields if f['type'] != 'textarea' + and f['name'] not in cols] + default_columns = QueryModule(self.env).default_columns + for col in default_columns: + if col not in cols: + cols.append(col) + # Filter out invalid column names from config or URL + cols = [c for c in cols if c in self.valid_cols] for col in ('reporter', 'keywords', 'cc'): if col in cols: cols.remove(col) @@ -139,6 +151,8 @@ # Constrained columns appear before other columns elif col1 in constrained_fields or col2 in constrained_fields: return col1 in constrained_fields and -1 or 1 + elif col1 in default_columns or col2 in default_columns: + return col1 in default_columns and -1 or 1 return 0 cols.sort(sort_columns) @@ -168,7 +182,7 @@ for row in cursor: id = int(row[0]) result = {'id': id, 'href': req.href.ticket(id)} - for i in range(1, len(columns)): + for i in xrange(1, len(columns)): name, val = columns[i], row[i] if name == self.group: val = val or 'None' @@ -369,6 +383,8 @@ cols = self.get_columns() labels = dict([(f['name'], f['label']) for f in self.fields]) + labels['changetime'] = 'Modified' + labels['time'] = 'Created' headers = [{ 'name': col, 'label': labels.get(col, 'Ticket'), 'href': self.get_href(req, order=col, desc=(col == self.order and @@ -429,6 +445,9 @@ implements(IRequestHandler, INavigationContributor, IWikiSyntaxProvider, IContentConverter) + _default_columns = ListOption('ticket-query', 'default_columns', 'id', + keep_empty=False) + # IContentConverter methods def get_supported_conversions(self): yield ('rss', 'RSS Feed', 'xml', @@ -480,10 +499,13 @@ if email or name: constraints['cc'] = ('~%s' % email or name,) + columns = [c.strip() for c in req.args.get('columns', '').split(',') + if c.strip()] query = Query(self.env, constraints, req.args.get('order'), req.args.has_key('desc'), req.args.get('group'), req.args.has_key('groupdesc'), - req.args.has_key('verbose')) + req.args.has_key('verbose'), + self.expand_aliases(columns)) if req.args.has_key('update'): # Reset session vars @@ -506,6 +528,24 @@ return self.display_html(req, query) + def expand_aliases(self, cols, aliases=None): + if aliases is None: + section = self.config['ticket-query-column-aliases'] + aliases = {} + for key in section: + aliases[key] = section.getlist(key, keep_empty=False) + expanded = [] + for c in cols: + if c in aliases: + expanded.extend(self.expand_aliases(aliases[c], aliases)) + else: + expanded.append(c) + return expanded + + def default_columns(self): + return self.expand_aliases(self._default_columns) + default_columns = property(default_columns) + # Internal methods def _get_constraints(self, req): Index: templates/query_div.html =================================================================== --- templates/query_div.html (revision 4209) +++ templates/query_div.html (working copy) @@ -48,6 +48,7 @@