1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
|
"""This is temporary code to parse category
tree, stored in the settings.
The tree is plain text, with levels of branching
reflected by indentation (2 spaces per level).
example of desired structure, when input is parsed
cat_tree = [
['dummy',
[
['tires', [
['michelin', [
['trucks', []],
['cars', []],
['motorcycles', []]
]
],
['good year', []],
['honda', []],
]
],
['abandonment', []],
['chile', []],
['vulcanization', []],
]
]
]
"""
from askbot.conf import settings as askbot_settings
from django.utils import simplejson
def get_leaf_index(tree, leaf_name):
children = tree[1]
for index, child in enumerate(children):
if child[0] == leaf_name:
return index
return None
def _get_subtree(tree, path):
clevel = tree
for pace in path:
clevel = clevel[1][pace]
return clevel
def get_subtree(tree, path):
"""path always starts with 0,
and is a list of integers"""
assert(path[0] == 0)
if len(path) == 1:#special case
return tree[0]
else:
return _get_subtree(tree[0], path[1:])
def sort_tree(tree):
"""sorts contents of the nodes alphabetically"""
tree = sorted(tree, lambda x,y: cmp(x[0], y[0]))
for item in tree:
item[1] = sort_tree(item[1])
return tree
def get_data():
"""returns category tree data structure encoded as json
or None, if category_tree is disabled
"""
if askbot_settings.TAG_SOURCE == 'category-tree':
return simplejson.loads(askbot_settings.CATEGORY_TREE)
else:
return None
def _get_leaf_names(subtree):
leaf_names = set()
for leaf in subtree:
leaf_names.add(leaf[0])
leaf_names |= _get_leaf_names(leaf[1])
return leaf_names
def get_leaf_names(tree = None):
"""returns set of leaf names"""
data = tree or get_data()
if data is None:
return set()
return _get_leaf_names(data[0][1])
def path_is_valid(tree, path):
try:
get_subtree(tree, path)
return True
except IndexError:
return False
except AssertionError:
return False
def add_category(tree, category_name, path):
subtree = get_subtree(tree, path)
children = subtree[1]
children.append([category_name, []])
children = sorted(children, lambda x,y: cmp(x[0], y[0]))
subtree[1] = children
new_path = path[:]
#todo: reformulate all paths in terms of names?
new_item_index = get_leaf_index(subtree, category_name)
assert new_item_index != None
new_path.append(new_item_index)
return new_path
def _has_category(tree, category_name):
for item in tree:
if item[0] == category_name:
return True
if _has_category(item[1], category_name):
return True
return False
def has_category(tree, category_name):
"""true if category is in tree"""
#skip the dummy
return _has_category(tree[0][1], category_name)
def rename_category(
tree, from_name = None, to_name = None, path = None
):
if to_name == from_name:
return
subtree = get_subtree(tree, path[:-1])
from_index = get_leaf_index(subtree, from_name)
#todo possibly merge if to_name exists on the same level
#to_index = get_leaf_index(subtree, to_name)
child = subtree[1][from_index]
child[0] = to_name
return sort_tree(tree)
def _delete_category(tree, name):
for item in tree:
if item[0] == name:
tree.remove(item)
return True
if _delete_category(item[1], name):
return True
return False
def delete_category(tree, name, path):
subtree = get_subtree(tree, path[:-1])
del_index = get_leaf_index(subtree, name)
subtree[1].pop(del_index)
return sort_tree(tree)
def save_data(tree):
assert(askbot_settings.TAG_SOURCE == 'category-tree')
tree_json = simplejson.dumps(tree)
askbot_settings.update('CATEGORY_TREE', tree_json)
|