Index: roundup/cgi/templating.py =================================================================== --- roundup/cgi/templating.py (Revision 4543) +++ roundup/cgi/templating.py (Arbeitskopie) @@ -27,6 +27,8 @@ from roundup import i18n from roundup.i18n import _ +from KeywordsExpr import render_keywords_expression_editor + try: import cPickle as pickle except ImportError: @@ -2848,6 +2850,9 @@ raise AttributeError, name return self.client.instance.templating_utils[name] + def keywords_expressions(self, request): + return render_keywords_expression_editor(request) + def html_calendar(self, request): """Generate a HTML calendar. Index: roundup/cgi/KeywordsExpr.py =================================================================== --- roundup/cgi/KeywordsExpr.py (Revision 0) +++ roundup/cgi/KeywordsExpr.py (Revision 0) @@ -0,0 +1,273 @@ +# This module is free software, you may redistribute it +# and/or modify under the same terms as Python. + +WINDOW_CONTENT = '''\ +

Keyword Expression Editor:

+
+
+ +''' + +def list_nodes(request): + prop = request.form.getfirst("property") + cls = request.client.db.getclass(prop) + items = [] + for nodeid in cls.getnodeids(): + l = cls.getnode(nodeid).items() + l = dict([x for x in l if len(x) == 2]) + try: + items.append((l['id'], l['name'])) + except KeyError: + pass + items.sort(key=lambda x: int(x[0])) + return items + +def items_to_keywords(items): + return ',\n '.join(['["%s", "%s"]' % x for x in items]) + + +def render_keywords_expression_editor(request): + prop = request.form.getfirst("property") + + window_content = WINDOW_CONTENT % { + 'prop' : prop, + 'keywords': items_to_keywords(list_nodes(request)), + 'original': '' + } + + return window_content + +# vim: set et sts=4 sw=4 : Index: roundup/backends/back_anydbm.py =================================================================== --- roundup/backends/back_anydbm.py (Revision 4543) +++ roundup/backends/back_anydbm.py (Arbeitskopie) @@ -49,6 +49,60 @@ def db_nuke(config): shutil.rmtree(config.DATABASE) +class Equals: + def __init__(self, x): + self.x = x + + def evaluate(self, v): + return self.x in v + +class Not: + def __init__(self, x): + self.x = x + + def evaluate(self, v): + return not self.x.evaluate(v) + +class Or: + def __init__(self, x, y): + self.x = x + self.y = y + + def evaluate(self, v): + return self.x.evaluate(v) or self.y.evaluate(v) + +class And: + def __init__(self, x, y): + self.x = x + self.y = y + + def evaluate(self, v): + return self.x.evaluate(v) and self.y.evaluate(v) + + +class Expression: + + def __init__(self, v): + try: + opcodes = [int(x) for x in v] + if min(opcodes) >= -1: raise ValueError() + + stack = [] + for opcode in opcodes: + if opcode == -2: # not + stack.append(Not(stack.pop())) + elif opcode == -3: # and + stack.append(And(stack.pop(), stack.pop())) + elif opcode == -4: # or + stack.append(Or(stack.pop(), stack.pop())) + else: # = + stack.append(Equals(opcode)) + + compiled = stack.pop() + self.evaluate = lambda x: compiled.evaluate([int(y) for y in x]) + except: + self.evaluate = lambda x: bool(set(x) & set(v)) + # # Now the database # @@ -1700,12 +1754,10 @@ if not v: match = not nv else: - # othewise, make sure this node has each of the + # otherwise, make sure this node has each of the # required values - for want in v: - if want in nv: - match = 1 - break + expr = Expression(v) + if expr.evaluate(nv): match = 1 elif t == STRING: if nv is None: nv = '' Index: share/roundup/templates/devel/html/page.html =================================================================== --- share/roundup/templates/devel/html/page.html (Revision 4543) +++ share/roundup/templates/devel/html/page.html (Arbeitskopie) @@ -307,6 +307,20 @@ + + + (edit) + + Index: share/roundup/templates/classic/html/_generic.keywords_expr.html =================================================================== --- share/roundup/templates/classic/html/_generic.keywords_expr.html (Revision 0) +++ share/roundup/templates/classic/html/_generic.keywords_expr.html (Revision 0) @@ -0,0 +1,11 @@ + + + + + + + + + + Index: share/roundup/templates/classic/html/page.html =================================================================== --- share/roundup/templates/classic/html/page.html (Revision 4543) +++ share/roundup/templates/classic/html/page.html (Arbeitskopie) @@ -247,6 +247,22 @@ + +
+ + (expr) +
+ + Index: share/roundup/templates/classic/html/issue.search.html =================================================================== --- share/roundup/templates/classic/html/issue.search.html (Revision 4543) +++ share/roundup/templates/classic/html/issue.search.html (Arbeitskopie) @@ -23,6 +23,7 @@ sort_input templates/page/macros/sort_input; group_input templates/page/macros/group_input; search_select templates/page/macros/search_select; + search_select_keywords templates/page/macros/search_select_keywords; search_select_translated templates/page/macros/search_select_translated; search_multiselect templates/page/macros/search_multiselect;"> @@ -54,7 +55,7 @@ db_klass string:keyword; db_content string:name;"> Keyword: - +