From aece567bf3727498eab43f0189242875b44e434d Mon Sep 17 00:00:00 2001 From: Shanta Kabra Date: Fri, 29 Aug 2008 14:53:03 +0530 Subject: [PATCH 01/17] * Graph algorithm updations bzr revid: shanta.kabra@gmail.com-20080829092303-4qn1f85o9p25trap --- bin/addons/base/ir/workflow/workflow.py | 31 +- bin/tools/graph.py | 548 +++++++++++++++++++----- 2 files changed, 464 insertions(+), 115 deletions(-) diff --git a/bin/addons/base/ir/workflow/workflow.py b/bin/addons/base/ir/workflow/workflow.py index 8b90cfee140..45d2c752661 100644 --- a/bin/addons/base/ir/workflow/workflow.py +++ b/bin/addons/base/ir/workflow/workflow.py @@ -57,31 +57,42 @@ class workflow(osv.osv): # scale = [stepx, stepy, posx, posy ] # + def graph_get(self, cr, uid, id, scale, context={}): nodes= [] + nodes_name = [] transitions = [] start = [] tres = {} + no_ancester = [] workflow = self.browse(cr, uid, id, context) for a in workflow.activities: - nodes.append((a.id,a.name)) + nodes_name.append((a.id,a.name)) + nodes.append(a.id) if a.flow_start: - start.append((a.id,a.name)) + start.append(a.id) + else: + if not a.in_transitions: + no_ancester.append(a.id) + for t in a.out_transitions: - transitions.append( ((a.id,a.name), (t.act_to.id,t.act_to.name)) ) - tres[t.id] = (a.id,t.act_to.id) - g = graph(nodes, transitions) + transitions.append((a.id, t.act_to.id)) + tres[t.id] = (a.id, t.act_to.id) + + + g = graph(nodes, transitions, no_ancester) g.process(start) g.scale(*scale) result = g.result_get() results = {} - - - for r in result.items(): - r[1]['name'] = r[0][1] - results[str(r[0][0])] = r[1] + + for node in nodes_name: + results[str(node[0])] = result[node[0]] + results[str(node[0])]['name'] = node[1] + return {'node': results, 'transition': tres} + def create(self, cr, user, vals, context=None): if not context: diff --git a/bin/tools/graph.py b/bin/tools/graph.py index f07f8d5aa0d..9e419690ec9 100644 --- a/bin/tools/graph.py +++ b/bin/tools/graph.py @@ -27,12 +27,22 @@ # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ############################################################################### +import operator class graph(object): - def __init__(self, nodes, transitions): - self.nodes = nodes - self.links = transitions + def __init__(self, nodes, transitions, no_ancester=None): + """Initailize graph's object + + @param nodes: list of ids of nodes in the graph + @param transitions: list of edges in the graph in the form (source_node, destination_node) + @param no_ancester: list of nodes with no incoming edges + """ + + self.nodes = nodes or [] + self.edges = transitions or [] + self.no_ancester = no_ancester or {} trans = {} + for t in transitions: trans.setdefault(t[0], []) trans[t[0]].append(t[1]) @@ -40,23 +50,21 @@ class graph(object): self.result = {} self.levels = {} - def get_parent(self,node): - count = 0 - for item in self.transitions: - if self.transitions[item].__contains__(node): - count +=1 - return count def init_rank(self): - self.temp = {} + """Computes rank of the nodes of the graph by finding initial feasible tree + """ + self.edge_wt = {} for link in self.links: - self.temp[link] = self.result[link[1]]['y'] - self.result[link[0]]['y'] + self.edge_wt[link] = self.result[link[1]]['y'] - self.result[link[0]]['y'] cnt = 0 list_node = [] list_edge = [] - - while self.tight_tree()self.temp[edge]-1): - slack = self.temp[edge]-1 + if(slack>self.edge_wt[edge]-1): + slack = self.edge_wt[edge]-1 new_edge = edge if new_edge[0] not in self.reachable_nodes: - delta = -(self.temp[new_edge]-1) + delta = -(self.edge_wt[new_edge]-1) else: - delta = self.temp[new_edge]-1 + delta = self.edge_wt[new_edge]-1 for node in self.result: if node in self.reachable_nodes: self.result[node]['y'] += delta - for link in self.temp: - self.temp[link] = self.result[link[1]]['y'] - self.result[link[0]]['y'] - - self.init_cutvalues() - + for link in self.edge_wt: + self.edge_wt[link] = self.result[link[1]]['y'] - self.result[link[0]]['y'] + self.init_cutvalues() def tight_tree(self,): @@ -100,13 +106,15 @@ class graph(object): self.reachable_node(self.start) return self.reachable_nodes.__len__() - def reachable_node(self,node): + def reachable_node(self, node): + """Find the nodes of the graph which are only 1 rank apart from each other + """ + if node not in self.reachable_nodes: self.reachable_nodes.append(node) - for link in self.temp: + for link in self.edge_wt: if link[0]==node: -# print link[0] - if self.temp[link]==1: + if self.edge_wt[link]==1: self.tree_edges.append(link) if link[1] not in self.reachable_nodes: self.reachable_nodes.append(link[1]) @@ -114,15 +122,19 @@ class graph(object): def init_cutvalues(self): + """Initailize cut values of edges of the feasible tree. + Edges with negative cut-values are removed from the tree to optimize rank assignment + """ self.cut_edges = {} self.head_nodes = [] i=0; + for edge in self.tree_edges: self.head_nodes = [] rest_edges = [] rest_edges += self.tree_edges rest_edges.__delitem__(i) - self.head_component(self.start,rest_edges) + self.head_component(self.start, rest_edges) i+=1 positive = 0 negative = 0 @@ -137,11 +149,11 @@ class graph(object): positive+=1 self.cut_edges[edge] = positive - negative - - def head_component(self, node, rest_edges): + """Find nodes which are reachable from the starting node, after removing an edge + """ if node not in self.head_nodes: self.head_nodes.append(node) for link in rest_edges: @@ -150,6 +162,9 @@ class graph(object): def process_ranking(self, node, level=0): + """Computes initial feasible ranking after making graph acyclic with depth-first search + """ + if node not in self.result: self.result[node] = {'x': None, 'y':level, 'mark':0} else: @@ -160,104 +175,437 @@ class graph(object): for t in self.transitions.get(node, []): self.process_ranking(t, level+1) + def make_acyclic(self, parent, node, level, tree): + """Computes Partial-order of the nodes with depth-first search + """ + + if node not in self.partial_order: + self.partial_order[node] = {'level':level, 'mark':0} + if parent: + tree.append((parent, node)) + + if self.partial_order[node]['mark']==0: + self.partial_order[node]['mark'] = 1 + for t in self.transitions.get(node, []): + self.links.append((node, t)) + self.make_acyclic(node, t, level+1, tree) - def preprocess_order(self): - levels = {} - for r in self.result: - l = self.result[r]['y'] - levels.setdefault(l,[]) - levels[l].append(r) - self.levels = levels + return tree - def process_order(self, level): - self.levels[level].sort(lambda x,y: cmp(self.result[x]['x'], self.result[y]['x'])) - for nodepos in range(len(self.levels[level])): - node = self.levels[level][nodepos] - if nodepos == 0: - left = self.result[node]['x']- 0.5 - else: - left = (self.result[node]['x'] + self.result[self.levels[level][nodepos-1]]['x']) / 2.0 - - if nodepos == (len(self.levels[level])-1): - right = self.result[node]['x'] + 0.5 - else: - right = (self.result[node]['x'] + self.result[self.levels[level][nodepos+1]]['x']) / 2.0 - - - if self.transitions.get(node, False): - if len(self.transitions[node])==1: - pos = (left+right)/2.0 - step = 0 - else: - pos = left - step = (-left+right) / (len(self.transitions[node])-1) - - for n2 in self.transitions[node]: - self.result[n2]['x'] = pos - pos += step - - def exchange(self,e,f): + + def rev_edges(self, tree): + """reverse the direction of the edges whose source-node-partail_order> destination-node-partail_order + to make the graph acyclic + """ + Is_Cyclic = False + i=0 + for link in self.links: + src = link[0] + des = link[1] + edge_len = self.partial_order[des]['level'] - self.partial_order[src]['level'] + if edge_len < 0: + self.links.__delitem__(i) + self.links.insert(i, (des, src)) + self.transitions[src].remove(des) + self.transitions.setdefault(des, []).append(src) + Is_Cyclic = True + elif edge_len > 1: + Is_Cyclic = True + i += 1 + + return Is_Cyclic + + def exchange(self, e, f): + """Exchange edges to make feasible-tree optimized + @param edge: edge with negative cut-value + @param edge: new edge with minimum slack-value + """ self.tree_edges.__delitem__(self.tree_edges.index(e)) self.tree_edges.append(f) self.init_cutvalues() - def enter_edge(self,edge): + def enter_edge(self, edge): + """Finds a new_edge with minimum slack value to replace an edge with negative cut-value + + @param edge: edge with negative cut-value + """ + self.head_nodes = [] rest_edges = [] rest_edges += self.tree_edges rest_edges.__delitem__(rest_edges.index(edge)) - self.head_component(self.start,rest_edges) + self.head_component(self.start, rest_edges) + + if self.head_nodes.__contains__(edge[1]): + list = [] + for node in self.result: + if not self.head_nodes.__contains__(node): + list.append(node) + self.head_nodes = list + slack = 100 + new_edge = edge for source_node in self.transitions: if source_node in self.head_nodes: for dest_node in self.transitions[source_node]: if dest_node not in self.head_nodes: - if(slack>(self.temp[edge]-1)): - slack = self.temp[edge]-1 + if(slack>(self.edge_wt[edge]-1)): + slack = self.edge_wt[edge]-1 new_edge = (source_node,dest_node) return new_edge def leave_edge(self): + """Returns the edge with negative cut_value(if exists) + """ + if self.critical_edges: + for edge in self.critical_edges: + self.cut_edges[edge] = 0 + for edge in self.cut_edges: if self.cut_edges[edge]<0: return edge - return () - - def process(self, starting_node): - pos = (len(starting_node) - 1.0)/2.0 - self.start = starting_node[0] - for s in starting_node: - self.process_ranking(s) - self.result[s]['x'] = pos - pos += 1.0 - self.init_rank() - #normalize + return None + + def normalize(self): + """The ranks are normalized by setting the least rank to zero. + """ + least_rank=100 - #normalization for node in self.result: if least_rank>self.result[node]['y']: least_rank = self.result[node]['y'] if(least_rank!=0): - diff = least_rank for node in self.result: - self.result[node]['y']-=least_rank + self.result[node]['y']-=least_rank - e = self.leave_edge() - #while e: - f = self.enter_edge(e) - self.exchange(e,f) - e = self.leave_edge() + def make_chain(self): + """Edges between nodes more than one rank apart are replaced by chains of unit + length edges between temporary nodes. + """ + for edge in self.edge_wt: + if self.edge_wt[edge]>1: + self.transitions[edge[0]].remove(edge[1]) + start = self.result[edge[0]]['y'] + end = self.result[edge[1]]['y'] + + for rank in range(start+1, end): + if not self.result.get((rank, 'temp'), False): + self.result[(rank, 'temp')] = {'x': None, 'y': rank, 'mark': 0} + + for rank in range(start, end): + if start==rank: + self.transitions[edge[0]].append((rank+1, 'temp')) + elif rank==end-1: + self.transitions.setdefault((rank, 'temp'), []).append(edge[1]) + else: + self.transitions.setdefault((rank, 'temp'), []).append((rank+1, 'temp')) + + + def init_order(self, node, level): + """Initialize orders the nodes in each rank with depth-first search + """ + if not self.result[node]['x']: + if self.order.get(level)==0: + self.result[node]['x'] = self.order[level] + self.order[level] = self.order[level]+1 + else: + self.result[node]['x'] = self.order[level-1] + self.order[level-1] = self.order[level-1]+1 + + for sec_end in self.transitions.get(node, []): + self.init_order(sec_end, level+1) + + + def order_heuristic(self): + for i in range(12): + self.wmedian() + + + def wmedian(self): + """Applies median heuristic to find optimzed order of the nodes with in their ranks + """ + for level in self.levels: + + node_median = [] + for node in self.levels[level]: + node_median.append((node, self.median_value(node, level-1))) + + sort_list = sorted(node_median, key=operator.itemgetter(1)) + + new_list = [tuple[0] for tuple in sort_list] + + self.levels[level] = new_list + order = 0 + for node in self.levels[level]: + self.result[node]['x'] = order + order +=1 + + + + + def median_value(self, node, adj_rank): + """Returns median value of a vertex , defined as the median position of the adjacent vertices + + @param node: node to process + @param adj_rank: rank 1 less than the node's rank + """ + adj_nodes = self.adj_position(node, adj_rank) + l = len(adj_nodes) + m = l/2 + if l==0: + return -1.0 + elif l%2 == 1: + return adj_nodes[m]#median of the middle element + elif l==2: + return (adj_nodes[0]+adj_nodes[1])/2 + else: + left = adj_nodes[m-1] - adj_nodes[0] + right = adj_nodes[l-1] - adj_nodes[m] + return ((adj_nodes[m-1]*right) + (adj_nodes[m]*left))/(left+right) + + + def adj_position(self, node, adj_rank): + """Returns list of the present positions of the nodes adjacent to node in the given adjacent rank. + + @param node: node to process + @param adj_rank: rank 1 less than the node's rank + """ + + pre_level_nodes = self.levels.get(adj_rank) + + adj_nodes = [] + if pre_level_nodes: + for n in pre_level_nodes: + if (self.transitions.get(n) and self.transitions[n].__contains__(node)): + adj_nodes.append(self.result[n]['x']) + + return adj_nodes + + + def preprocess_order(self): + levels = {} + for r in self.partial_order: + l = self.result[r]['y'] + levels.setdefault(l,[]) + levels[l].append(r) + self.levels = levels + + + def graph_order(self): + """Finds actual-order of the nodes with respect to maximum number of nodes in a rank in component + """ + mid_pos = None + max_level = max(map(lambda x: len(x), self.levels.values())) + + for level in self.levels: + if level: + no = len(self.levels[level]) + factor = (max_level - no) * 0.10 + self.levels[level].reverse() + list = self.levels[level] + + if no%2==0: + first_half = list[no/2:] + factor = -factor + else: + first_half = list[no/2+1:] + if max_level==1: + self.result[list[no/2]]['x'] = mid_pos + (self.result[list[no/2]]['y']%2 * 0.5) + else: + self.result[list[no/2]]['x'] = mid_pos + factor + + last_half = list[:no/2] + i=1 + for node in first_half: + self.result[node]['x'] = mid_pos - (i + factor) + i += 1 + + i=1 + for node in last_half: + self.result[node]['x'] = mid_pos + (i + factor) + i += 1 + else: + self.max_order += max_level+1 + mid_pos = self.result[self.start]['x'] + + def tree_order(self, node): + mid_pos = self.result[node]['x'] + l = self.transitions[node] + l.reverse() + no = len(l) + if no%2==0: + first_half = l[no/2:] + else: + first_half = l[no/2+1:] + self.result[l[no/2]]['x'] = mid_pos + if self.transitions.get((l[no/2]), False): + self.tree_order(l[no/2]) + last_half = l[:no/2] + + i=1 + for child in first_half: + self.result[child]['x'] = mid_pos - i + i += 1 + if self.transitions.get(child, False): + self.tree_order(child) + i=1 + for child in last_half: + self.result[child]['x'] = mid_pos + i + i += 1 + if self.transitions.get(child, False): + self.tree_order(child) + + def process_order(self): + """Finds actual-order of the nodes with respect to maximum number of nodes in a rank in component + """ + max_level = max(map(lambda x: len(x), self.levels.values())) + if max_level%2: + self.result[self.start]['x'] = (max_level+1)/2 + self.max_order + else: + self.result[self.start]['x'] = (max_level)/2 + self.max_order + + if self.Is_Cyclic: + self.graph_order() + else: + self.tree_order(self.start) + + def find_starts(self): + """Finds other start nodes of the graph in the case when graph is disconneted + """ + rem_nodes = [] + for node in self.nodes: + if not self.partial_order.get(node): + rem_nodes.append(node) + cnt = 0 + while True: + if len(rem_nodes)==1: + self.start_nodes.append(rem_nodes[0]) + break + else: + count = 0 + new_start = rem_nodes[0] + largest_tree = [] + for node in rem_nodes: + self.partial_order = {} + tree = self.make_acyclic(None, node, 0, []) + if len(tree)+1 > count: + count = len(tree) + 1 + new_start = node + largest_tree = tree + + self.start_nodes.append(new_start) + for edge in largest_tree: + if rem_nodes.__contains__(edge[0]): + rem_nodes.remove(edge[0]) + if rem_nodes.__contains__(edge[1]): + rem_nodes.remove(edge[1]) + if not rem_nodes: + break + + + + def rank(self): + """Finds the optimized rank of the nodes using Network-simplex algorithm + + @param start: starting node of the component + """ + + self.levels = {} + self.order = {} + self.critical_edges = [] + self.partial_order = {} + self.links = [] + self.Is_Cyclic = False + + tree = self.make_acyclic(None, self.start, 0, []) + self.Is_Cyclic = self.rev_edges(tree) + self.process_ranking(self.start) + self.init_rank() + + #make cut values of all tree edges to 0 to optimize ranking + e = self.leave_edge() + + while e : + f = self.enter_edge(e) + if e==f: + self.critical_edges.append(e) + else: + self.exchange(e,f) + e = self.leave_edge() + + #normalization + self.normalize() + for edge in self.edge_wt: + self.edge_wt[edge] = self.result[edge[1]]['y'] - self.result[edge[0]]['y'] + + def order_in_rank(self): + """Finds optimized order of the nodes within their ranks using median heuristic + + @param start: starting node of the component + """ + + self.make_chain() self.preprocess_order() - for n in self.levels: - self.process_order(n) + + self.order = {} + for i in self.levels: + self.order[i] = 0 + + self.init_order(self.start, 0) + + for level in self.levels: + self.levels[level].sort(lambda x,y: cmp(self.result[x]['x'], self.result[y]['x'])) + + self.order_heuristic() + + for level in self.levels: + for node in self.levels[level]: + try: + if int(node): + continue + except e: + self.levels[level].remove(node) + self.result.__delitem__(node) + self.process_order() + + + def process(self, starting_node): + """Process the graph to find ranks and order of the nodes + + @param starting_node: node from where to start the graph search + """ + + self.start_nodes = starting_node or [] + self.partial_order = {} + self.links = [] + + if self.start_nodes: + #add dummy edges to the nodes which does not have any incoming edges + for node in self.no_ancester: + self.transitions[self.start_nodes[0]].append(node) + + tree = self.make_acyclic(None, self.start_nodes[0], 0, []) + + # if graph is disconnected than to find starting_node for each component of the node + if len(self.nodes) > len(self.partial_order): + self.find_starts() + + self.max_order = 0 + + #for each component of the graph find ranks and order of the nodes + for s in self.start_nodes: + self.start = s + self.rank() # First step:Netwoek simplex algorithm + self.order_in_rank() #Second step: ordering nodes within ranks + @@ -270,22 +618,12 @@ class graph(object): return result def scale(self, maxx, maxy, plusx2=0, plusy2=0): - plusx = - min(map(lambda x: x['x'],self.result.values())) - plusy = - min(map(lambda x: x['y'],self.result.values())) - - maxcurrent = 1.0 - diff = 1.0 - for l in self.levels: - for n in range(1, len(self.levels[l])): - n1 = self.levels[l][n] - n2 = self.levels[l][n-1] - diff = abs(self.result[n2]['x']-self.result[n1]['x']) - if diff Date: Tue, 2 Sep 2008 11:34:09 +0530 Subject: [PATCH 02/17] * Improvement in tree ordering to avoid overlaping bzr revid: shanta.kabra@gmail.com-20080902060409-6o8q476t246dlf4s --- bin/tools/graph.py | 69 ++++++++++++++++++++++++++++++++-------------- 1 file changed, 48 insertions(+), 21 deletions(-) diff --git a/bin/tools/graph.py b/bin/tools/graph.py index 9e419690ec9..2942f0b78e4 100644 --- a/bin/tools/graph.py +++ b/bin/tools/graph.py @@ -28,6 +28,7 @@ # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ############################################################################### import operator +import math class graph(object): def __init__(self, nodes, transitions, no_ancester=None): @@ -100,7 +101,7 @@ class graph(object): self.init_cutvalues() - def tight_tree(self,): + def tight_tree(self): self.reachable_nodes = [] self.tree_edges = [] self.reachable_node(self.start) @@ -175,6 +176,7 @@ class graph(object): for t in self.transitions.get(node, []): self.process_ranking(t, level+1) + def make_acyclic(self, parent, node, level, tree): """Computes Partial-order of the nodes with depth-first search """ @@ -209,7 +211,7 @@ class graph(object): self.transitions[src].remove(des) self.transitions.setdefault(des, []).append(src) Is_Cyclic = True - elif edge_len > 1: + elif math.fabs(edge_len) > 1: Is_Cyclic = True i += 1 @@ -433,35 +435,56 @@ class graph(object): i += 1 else: self.max_order += max_level+1 - mid_pos = self.result[self.start]['x'] - - def tree_order(self, node): + mid_pos = self.result[self.start]['x'] + + + def tree_order(self, node, last=0): mid_pos = self.result[node]['x'] l = self.transitions[node] l.reverse() - no = len(l) + no = len(l) if no%2==0: first_half = l[no/2:] else: first_half = l[no/2+1:] - self.result[l[no/2]]['x'] = mid_pos - if self.transitions.get((l[no/2]), False): - self.tree_order(l[no/2]) + last_half = l[:no/2] i=1 for child in first_half: - self.result[child]['x'] = mid_pos - i + self.result[child]['x'] = mid_pos - i i += 1 + if self.transitions.get(child, False): - self.tree_order(child) - i=1 - for child in last_half: - self.result[child]['x'] = mid_pos + i - i += 1 - if self.transitions.get(child, False): - self.tree_order(child) + if last: + self.result[child]['x'] = last + len(self.transitions[child])/2 + 1 + last = self.tree_order(child, last) + if no%2: + self.result[l[no/2]]['x'] = mid_pos + if self.transitions.get((l[no/2]), False): + self.result[l[no/2]]['x'] = last + len(self.transitions[child])/2 + 1 + last = self.tree_order(l[no/2]) + else: + if last: + self.result[l[no/2]]['x'] = last + 1 + self.result[node]['x'] = self.result[l[no/2]]['x'] + mid_pos = self.result[node]['x'] + + i=1 + temp = None + for child in last_half: + self.result[child]['x'] = mid_pos + i + temp = child + i += 1 + if self.transitions.get(child, False): + if last: + self.result[child]['x'] = last + len(self.transitions[child])/2 + 1 + last = self.tree_order(child, last) + last = self.result[temp]['x'] + return last + + def process_order(self): """Finds actual-order of the nodes with respect to maximum number of nodes in a rank in component """ @@ -473,8 +496,13 @@ class graph(object): if self.Is_Cyclic: self.graph_order() - else: - self.tree_order(self.start) + else: + self.result[self.start]['x'] = 0 + self.tree_order(self.start, 0) + min_order = math.fabs(min(map(lambda x: x['x'], self.result.values()))) + for node in self.result: + self.result[node]['x'] += min_order + def find_starts(self): """Finds other start nodes of the graph in the case when graph is disconneted @@ -517,8 +545,7 @@ class graph(object): @param start: starting node of the component """ - self.levels = {} - self.order = {} + self.levels = {} self.critical_edges = [] self.partial_order = {} self.links = [] From 0f3033108bbeb935fe5597e949837e15b9aa8a3b Mon Sep 17 00:00:00 2001 From: Shanta Kabra Date: Tue, 2 Sep 2008 17:13:30 +0530 Subject: [PATCH 03/17] * Improved graph rankin using optimal feasible tree bzr revid: shanta.kabra@gmail.com-20080902114330-8rz4nanbmwm1s742 --- bin/tools/graph.py | 113 ++++++++++++++++++++++++++------------------- 1 file changed, 66 insertions(+), 47 deletions(-) diff --git a/bin/tools/graph.py b/bin/tools/graph.py index 2942f0b78e4..0a756010aaa 100644 --- a/bin/tools/graph.py +++ b/bin/tools/graph.py @@ -270,6 +270,13 @@ class graph(object): return edge return None + + def finalize_rank(self, node, level): + self.result[node]['y'] = level + for destination in self.optimal_edges.get(node, []): + self.finalize_rank(destination, level+1) + + def normalize(self): """The ranks are normalized by setting the least rank to zero. """ @@ -312,16 +319,12 @@ class graph(object): def init_order(self, node, level): """Initialize orders the nodes in each rank with depth-first search """ - if not self.result[node]['x']: - if self.order.get(level)==0: - self.result[node]['x'] = self.order[level] - self.order[level] = self.order[level]+1 - else: - self.result[node]['x'] = self.order[level-1] - self.order[level-1] = self.order[level-1]+1 - + if not self.result[node]['x']: + self.result[node]['x'] = self.order[level] + self.order[level] = self.order[level]+1 + for sec_end in self.transitions.get(node, []): - self.init_order(sec_end, level+1) + self.init_order(sec_end, self.result[sec_end]['y']) def order_heuristic(self): @@ -444,15 +447,17 @@ class graph(object): l.reverse() no = len(l) if no%2==0: - first_half = l[no/2:] + first_half = l[no/2:] + factor = 1 else: first_half = l[no/2+1:] + factor = 0 last_half = l[:no/2] i=1 for child in first_half: - self.result[child]['x'] = mid_pos - i + self.result[child]['x'] = mid_pos - (i - (factor * 0.5)) i += 1 if self.transitions.get(child, False): @@ -461,27 +466,31 @@ class graph(object): last = self.tree_order(child, last) if no%2: - self.result[l[no/2]]['x'] = mid_pos - if self.transitions.get((l[no/2]), False): - self.result[l[no/2]]['x'] = last + len(self.transitions[child])/2 + 1 - last = self.tree_order(l[no/2]) + mid_node = l[no/2] + self.result[mid_node]['x'] = mid_pos + + if self.transitions.get((mid_node), False): + if last: + self.result[mid_node]['x'] = last + len(self.transitions[mid_node])/2 + 1 + last = self.tree_order(mid_node) else: if last: - self.result[l[no/2]]['x'] = last + 1 - self.result[node]['x'] = self.result[l[no/2]]['x'] + self.result[mid_node]['x'] = last + 1 + self.result[node]['x'] = self.result[mid_node]['x'] mid_pos = self.result[node]['x'] i=1 - temp = None + last_child = None for child in last_half: - self.result[child]['x'] = mid_pos + i - temp = child + self.result[child]['x'] = mid_pos + (i - (factor * 0.5)) + last_child = child i += 1 if self.transitions.get(child, False): if last: self.result[child]['x'] = last + len(self.transitions[child])/2 + 1 last = self.tree_order(child, last) - last = self.result[temp]['x'] + if last_child: + last = self.result[last_child]['x'] return last @@ -528,35 +537,35 @@ class graph(object): new_start = node largest_tree = tree - self.start_nodes.append(new_start) + self.start_nodes.append(new_start) + for edge in largest_tree: if rem_nodes.__contains__(edge[0]): rem_nodes.remove(edge[0]) if rem_nodes.__contains__(edge[1]): rem_nodes.remove(edge[1]) + if not rem_nodes: break - - + def rank(self): """Finds the optimized rank of the nodes using Network-simplex algorithm @param start: starting node of the component """ - self.levels = {} self.critical_edges = [] self.partial_order = {} self.links = [] self.Is_Cyclic = False - tree = self.make_acyclic(None, self.start, 0, []) + tree = self.make_acyclic(None, self.start, 0, []) self.Is_Cyclic = self.rev_edges(tree) self.process_ranking(self.start) self.init_rank() - #make cut values of all tree edges to 0 to optimize ranking + #make cut values of all tree edges to 0 to optimize feasible tree e = self.leave_edge() while e : @@ -566,9 +575,17 @@ class graph(object): else: self.exchange(e,f) e = self.leave_edge() - + + #finalize rank using optimum feasible tree + self.optimal_edges = {} + for edge in self.tree_edges: + source = self.optimal_edges.setdefault(edge[0], []) + source.append(edge[1]) + + self.finalize_rank(self.start, 0) + #normalization - self.normalize() +# self.normalize() for edge in self.edge_wt: self.edge_wt[edge] = self.result[edge[1]]['y'] - self.result[edge[0]]['y'] @@ -580,12 +597,12 @@ class graph(object): self.make_chain() self.preprocess_order() - self.order = {} - for i in self.levels: + max_rank = max(map(lambda x: x, self.levels.keys())) + for i in range(max_rank+1): self.order[i] = 0 - - self.init_order(self.start, 0) + + self.init_order(self.start, self.result[self.start]['y']) for level in self.levels: self.levels[level].sort(lambda x,y: cmp(self.result[x]['x'], self.result[y]['x'])) @@ -597,7 +614,7 @@ class graph(object): try: if int(node): continue - except e: + except ValueError: self.levels[level].remove(node) self.result.__delitem__(node) self.process_order() @@ -612,28 +629,30 @@ class graph(object): self.start_nodes = starting_node or [] self.partial_order = {} self.links = [] - - if self.start_nodes: - #add dummy edges to the nodes which does not have any incoming edges - for node in self.no_ancester: - self.transitions[self.start_nodes[0]].append(node) + + if self.nodes: + if self.start_nodes: + #add dummy edges to the nodes which does not have any incoming edges + for node in self.no_ancester: + self.transitions[self.start_nodes[0]].append(node) + + + tree = self.make_acyclic(None, self.start_nodes[0], 0, []) - - tree = self.make_acyclic(None, self.start_nodes[0], 0, []) - - # if graph is disconnected than to find starting_node for each component of the node + + # if graph is disconnected or no start-node is given + #than to find starting_node for each component of the node if len(self.nodes) > len(self.partial_order): self.find_starts() - + + self.max_order = 0 #for each component of the graph find ranks and order of the nodes for s in self.start_nodes: self.start = s self.rank() # First step:Netwoek simplex algorithm - self.order_in_rank() #Second step: ordering nodes within ranks - - + self.order_in_rank() #Second step: ordering nodes within ranks def __str__(self): From b08ade33568577c6fbb8c5021cc6cc1728486eb3 Mon Sep 17 00:00:00 2001 From: Shanta Kabra Date: Wed, 3 Sep 2008 16:44:25 +0530 Subject: [PATCH 04/17] * Code improvement bzr revid: shanta.kabra@gmail.com-20080903111425-x8hb38nbaqofxdvu --- bin/tools/graph.py | 151 +++++++++++++++++++++++---------------------- 1 file changed, 78 insertions(+), 73 deletions(-) diff --git a/bin/tools/graph.py b/bin/tools/graph.py index 0a756010aaa..aeafe405e97 100644 --- a/bin/tools/graph.py +++ b/bin/tools/graph.py @@ -49,7 +49,6 @@ class graph(object): trans[t[0]].append(t[1]) self.transitions = trans self.result = {} - self.levels = {} def init_rank(self): @@ -59,29 +58,25 @@ class graph(object): for link in self.links: self.edge_wt[link] = self.result[link[1]]['y'] - self.result[link[0]]['y'] - cnt = 0 - list_node = [] - list_edge = [] - tot_node = self.partial_order.__len__() - #do until all the nodes in the components are searched + #do until all the nodes in the component are searched while self.tight_tree()self.edge_wt[edge]-1): slack = self.edge_wt[edge]-1 new_edge = edge @@ -95,8 +90,8 @@ class graph(object): if node in self.reachable_nodes: self.result[node]['y'] += delta - for link in self.edge_wt: - self.edge_wt[link] = self.result[link[1]]['y'] - self.result[link[0]]['y'] + for edge in self.edge_wt: + self.edge_wt[edge] = self.result[edge[1]]['y'] - self.result[edge[0]]['y'] self.init_cutvalues() @@ -107,19 +102,20 @@ class graph(object): self.reachable_node(self.start) return self.reachable_nodes.__len__() + def reachable_node(self, node): """Find the nodes of the graph which are only 1 rank apart from each other """ if node not in self.reachable_nodes: self.reachable_nodes.append(node) - for link in self.edge_wt: - if link[0]==node: - if self.edge_wt[link]==1: - self.tree_edges.append(link) - if link[1] not in self.reachable_nodes: - self.reachable_nodes.append(link[1]) - self.reachable_node(link[1]) + for edge in self.edge_wt: + if edge[0]==node: + if self.edge_wt[edge]==1: + self.tree_edges.append(edge) + if edge[1] not in self.reachable_nodes: + self.reachable_nodes.append(edge[1]) + self.reachable_node(edge[1]) def init_cutvalues(self): @@ -157,9 +153,10 @@ class graph(object): """ if node not in self.head_nodes: self.head_nodes.append(node) - for link in rest_edges: - if link[0]==node: - self.head_component(link[1],rest_edges) + + for edge in rest_edges: + if edge[0]==node: + self.head_component(edge[1],rest_edges) def process_ranking(self, node, level=0): @@ -171,10 +168,11 @@ class graph(object): else: if level > self.result[node]['y']: self.result[node]['y'] = level + if self.result[node]['mark']==0: self.result[node]['mark'] = 1 - for t in self.transitions.get(node, []): - self.process_ranking(t, level+1) + for sec_end in self.transitions.get(node, []): + self.process_ranking(sec_end, level+1) def make_acyclic(self, parent, node, level, tree): @@ -188,9 +186,9 @@ class graph(object): if self.partial_order[node]['mark']==0: self.partial_order[node]['mark'] = 1 - for t in self.transitions.get(node, []): - self.links.append((node, t)) - self.make_acyclic(node, t, level+1, tree) + for sec_end in self.transitions.get(node, []): + self.links.append((node, sec_end)) + self.make_acyclic(node, sec_end, level+1, tree) return tree @@ -240,11 +238,11 @@ class graph(object): self.head_component(self.start, rest_edges) if self.head_nodes.__contains__(edge[1]): - list = [] + l = [] for node in self.result: if not self.head_nodes.__contains__(node): - list.append(node) - self.head_nodes = list + l.append(node) + self.head_nodes = l slack = 100 new_edge = edge @@ -254,7 +252,8 @@ class graph(object): if dest_node not in self.head_nodes: if(slack>(self.edge_wt[edge]-1)): slack = self.edge_wt[edge]-1 - new_edge = (source_node,dest_node) + new_edge = (source_node, dest_node) + return new_edge @@ -268,6 +267,7 @@ class graph(object): for edge in self.cut_edges: if self.cut_edges[edge]<0: return edge + return None @@ -337,8 +337,9 @@ class graph(object): """ for level in self.levels: - node_median = [] - for node in self.levels[level]: + node_median = [] + nodes = self.levels[level] + for node in nodes: node_median.append((node, self.median_value(node, level-1))) sort_list = sorted(node_median, key=operator.itemgetter(1)) @@ -347,7 +348,7 @@ class graph(object): self.levels[level] = new_list order = 0 - for node in self.levels[level]: + for node in nodes: self.result[node]['x'] = order order +=1 @@ -383,23 +384,25 @@ class graph(object): @param adj_rank: rank 1 less than the node's rank """ - pre_level_nodes = self.levels.get(adj_rank) - + pre_level_nodes = self.levels.get(adj_rank, []) adj_nodes = [] + if pre_level_nodes: - for n in pre_level_nodes: - if (self.transitions.get(n) and self.transitions[n].__contains__(node)): - adj_nodes.append(self.result[n]['x']) + for src in pre_level_nodes: + if (self.transitions.get(src) and self.transitions[src].__contains__(node)): + adj_nodes.append(self.result[src]['x']) return adj_nodes def preprocess_order(self): levels = {} + for r in self.partial_order: l = self.result[r]['y'] levels.setdefault(l,[]) - levels[l].append(r) + levels[l].append(r) + self.levels = levels @@ -412,21 +415,22 @@ class graph(object): for level in self.levels: if level: no = len(self.levels[level]) - factor = (max_level - no) * 0.10 - self.levels[level].reverse() + factor = (max_level - no) * 0.10 list = self.levels[level] + list.reverse() if no%2==0: first_half = list[no/2:] factor = -factor else: first_half = list[no/2+1:] - if max_level==1: + if max_level==1:#for the case when horizontal graph is there self.result[list[no/2]]['x'] = mid_pos + (self.result[list[no/2]]['y']%2 * 0.5) else: self.result[list[no/2]]['x'] = mid_pos + factor - last_half = list[:no/2] + last_half = list[:no/2] + i=1 for node in first_half: self.result[node]['x'] = mid_pos - (i + factor) @@ -443,9 +447,10 @@ class graph(object): def tree_order(self, node, last=0): mid_pos = self.result[node]['x'] - l = self.transitions[node] + l = self.transitions.get(node, []) l.reverse() - no = len(l) + no = len(l) + if no%2==0: first_half = l[no/2:] factor = 1 @@ -498,6 +503,7 @@ class graph(object): """Finds actual-order of the nodes with respect to maximum number of nodes in a rank in component """ max_level = max(map(lambda x: len(x), self.levels.values())) + if max_level%2: self.result[self.start]['x'] = (max_level+1)/2 + self.max_order else: @@ -505,13 +511,19 @@ class graph(object): if self.Is_Cyclic: self.graph_order() + #for flat edges ie sorce an destination nodes are on the same rank + for src in self.transitions: + for des in self.transitions[src]: + if (self.result[des]['y'] - self.result[src]['y'] == 0): + self.result[src]['y'] += 0.08 + self.result[des]['y'] -= 0.08 else: - self.result[self.start]['x'] = 0 + self.result[self.start]['x'] = 1 + self.max_order self.tree_order(self.start, 0) min_order = math.fabs(min(map(lambda x: x['x'], self.result.values()))) for node in self.result: self.result[node]['x'] += min_order - + self.max_order = max(map(lambda x: x['x'], self.result.values())) def find_starts(self): """Finds other start nodes of the graph in the case when graph is disconneted @@ -529,6 +541,7 @@ class graph(object): count = 0 new_start = rem_nodes[0] largest_tree = [] + for node in rem_nodes: self.partial_order = {} tree = self.make_acyclic(None, node, 0, []) @@ -560,11 +573,11 @@ class graph(object): self.links = [] self.Is_Cyclic = False - tree = self.make_acyclic(None, self.start, 0, []) + tree = self.make_acyclic(None, self.start, 0, []) self.Is_Cyclic = self.rev_edges(tree) self.process_ranking(self.start) self.init_rank() - + #make cut values of all tree edges to 0 to optimize feasible tree e = self.leave_edge() @@ -577,15 +590,15 @@ class graph(object): e = self.leave_edge() #finalize rank using optimum feasible tree - self.optimal_edges = {} - for edge in self.tree_edges: - source = self.optimal_edges.setdefault(edge[0], []) - source.append(edge[1]) +# self.optimal_edges = {} +# for edge in self.tree_edges: +# source = self.optimal_edges.setdefault(edge[0], []) +# source.append(edge[1]) - self.finalize_rank(self.start, 0) +# self.finalize_rank(self.start, 0) #normalization -# self.normalize() + self.normalize() for edge in self.edge_wt: self.edge_wt[edge] = self.result[edge[1]]['y'] - self.result[edge[0]]['y'] @@ -599,24 +612,16 @@ class graph(object): self.preprocess_order() self.order = {} max_rank = max(map(lambda x: x, self.levels.keys())) + for i in range(max_rank+1): self.order[i] = 0 self.init_order(self.start, self.result[self.start]['y']) for level in self.levels: - self.levels[level].sort(lambda x,y: cmp(self.result[x]['x'], self.result[y]['x'])) + self.levels[level].sort(lambda x, y: cmp(self.result[x]['x'], self.result[y]['x'])) - self.order_heuristic() - - for level in self.levels: - for node in self.levels[level]: - try: - if int(node): - continue - except ValueError: - self.levels[level].remove(node) - self.result.__delitem__(node) + self.order_heuristic() self.process_order() @@ -647,7 +652,6 @@ class graph(object): self.max_order = 0 - #for each component of the graph find ranks and order of the nodes for s in self.start_nodes: self.start = s @@ -667,9 +671,10 @@ class graph(object): """Computes actual co-ordiantes of the nodes """ - for r in self.result: - self.result[r]['x'] = (self.result[r]['x']) * maxx + plusx2 - self.result[r]['y'] = (self.result[r]['y']) * maxy + plusy2 + for node in self.result: + self.result[node]['x'] = (self.result[node]['x']) * maxx + plusx2 + self.result[node]['y'] = (self.result[node]['y']) * maxy + plusy2 + def result_get(self): return self.result From 8c725d3cfe237218d09bd30c538fd44d33d92fb8 Mon Sep 17 00:00:00 2001 From: Shanta Kabra Date: Thu, 4 Sep 2008 11:06:14 +0530 Subject: [PATCH 05/17] * Imrovement in tree ordering and finding starts of the components (when graph is a forest) bzr revid: shanta.kabra@gmail.com-20080904053614-bqwxe32uyp6t731c --- bin/tools/graph.py | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/bin/tools/graph.py b/bin/tools/graph.py index aeafe405e97..fd4f3c28052 100644 --- a/bin/tools/graph.py +++ b/bin/tools/graph.py @@ -494,8 +494,10 @@ class graph(object): if last: self.result[child]['x'] = last + len(self.transitions[child])/2 + 1 last = self.tree_order(child, last) + if last_child: last = self.result[last_child]['x'] + return last @@ -511,18 +513,22 @@ class graph(object): if self.Is_Cyclic: self.graph_order() - #for flat edges ie sorce an destination nodes are on the same rank + #for flat edges ie. source an destination nodes are on the same rank for src in self.transitions: for des in self.transitions[src]: if (self.result[des]['y'] - self.result[src]['y'] == 0): self.result[src]['y'] += 0.08 self.result[des]['y'] -= 0.08 else: - self.result[self.start]['x'] = 1 + self.max_order + self.result[self.start]['x'] = 0 self.tree_order(self.start, 0) min_order = math.fabs(min(map(lambda x: x['x'], self.result.values()))) - for node in self.result: - self.result[node]['x'] += min_order + min_order += self.max_order + 1 + + for level in self.levels: + for node in self.levels[level]: + self.result[node]['x'] += min_order + self.max_order = max(map(lambda x: x['x'], self.result.values())) def find_starts(self): @@ -549,15 +555,20 @@ class graph(object): count = len(tree) + 1 new_start = node largest_tree = tree + else: + if not largest_tree: + new_start = rem_nodes[0] + rem_nodes.remove(new_start) self.start_nodes.append(new_start) - + + for edge in largest_tree: if rem_nodes.__contains__(edge[0]): rem_nodes.remove(edge[0]) if rem_nodes.__contains__(edge[1]): rem_nodes.remove(edge[1]) - + if not rem_nodes: break @@ -648,8 +659,7 @@ class graph(object): # if graph is disconnected or no start-node is given #than to find starting_node for each component of the node if len(self.nodes) > len(self.partial_order): - self.find_starts() - + self.find_starts() self.max_order = 0 #for each component of the graph find ranks and order of the nodes From fd8f74ca728d9adc3d09f4788ec3d0c6e178570b Mon Sep 17 00:00:00 2001 From: Shanta Kabra Date: Fri, 5 Sep 2008 15:15:46 +0530 Subject: [PATCH 06/17] * Modifications in the strategy to add edge for the nodes with no ancesters bzr revid: shanta.kabra@gmail.com-20080905094546-oj9xbxoiykwk541k --- bin/tools/graph.py | 34 ++++++++++++++++++++-------------- 1 file changed, 20 insertions(+), 14 deletions(-) diff --git a/bin/tools/graph.py b/bin/tools/graph.py index fd4f3c28052..d1fe2d50c57 100644 --- a/bin/tools/graph.py +++ b/bin/tools/graph.py @@ -507,18 +507,13 @@ class graph(object): max_level = max(map(lambda x: len(x), self.levels.values())) if max_level%2: - self.result[self.start]['x'] = (max_level+1)/2 + self.max_order + self.result[self.start]['x'] = (max_level+1)/2 + self.max_order +1 else: - self.result[self.start]['x'] = (max_level)/2 + self.max_order + self.result[self.start]['x'] = (max_level)/2 + self.max_order + 1 if self.Is_Cyclic: self.graph_order() - #for flat edges ie. source an destination nodes are on the same rank - for src in self.transitions: - for des in self.transitions[src]: - if (self.result[des]['y'] - self.result[src]['y'] == 0): - self.result[src]['y'] += 0.08 - self.result[des]['y'] -= 0.08 + else: self.result[self.start]['x'] = 0 self.tree_order(self.start, 0) @@ -634,7 +629,6 @@ class graph(object): self.order_heuristic() self.process_order() - def process(self, starting_node): """Process the graph to find ranks and order of the nodes @@ -649,18 +643,22 @@ class graph(object): if self.nodes: if self.start_nodes: #add dummy edges to the nodes which does not have any incoming edges + tree = self.make_acyclic(None, self.start_nodes[0], 0, []) + for node in self.no_ancester: - self.transitions[self.start_nodes[0]].append(node) - - + for sec_node in self.transitions.get(node, []): + if sec_node in self.partial_order.keys(): + self.transitions[self.start_nodes[0]].append(node) + break + self.partial_order = {} tree = self.make_acyclic(None, self.start_nodes[0], 0, []) # if graph is disconnected or no start-node is given #than to find starting_node for each component of the node if len(self.nodes) > len(self.partial_order): - self.find_starts() - + self.find_starts() + self.max_order = 0 #for each component of the graph find ranks and order of the nodes for s in self.start_nodes: @@ -668,6 +666,7 @@ class graph(object): self.rank() # First step:Netwoek simplex algorithm self.order_in_rank() #Second step: ordering nodes within ranks + def __str__(self): result = '' @@ -681,6 +680,13 @@ class graph(object): """Computes actual co-ordiantes of the nodes """ + #for flat edges ie. source an destination nodes are on the same rank + for src in self.transitions: + for des in self.transitions[src]: + if (self.result[des]['y'] - self.result[src]['y'] == 0): + self.result[src]['y'] += 0.08 + self.result[des]['y'] -= 0.08 + for node in self.result: self.result[node]['x'] = (self.result[node]['x']) * maxx + plusx2 self.result[node]['y'] = (self.result[node]['y']) * maxy + plusy2 From 34b0ce0abd575b5632ddde9af9342dd9742e5eaf Mon Sep 17 00:00:00 2001 From: "mga@tinyerp.com" <> Date: Fri, 5 Sep 2008 18:40:02 +0530 Subject: [PATCH 07/17] * Test Change bzr revid: mga@tinyerp.com-20080905131002-2zkx9x32k8nzruix --- setup.py | 1 + 1 file changed, 1 insertion(+) diff --git a/setup.py b/setup.py index a781f7a0c5c..40e1d96309f 100644 --- a/setup.py +++ b/setup.py @@ -1,3 +1,4 @@ + #!/usr/bin/env python # -*- encoding: utf-8 -*- ############################################################################## From f6bd3ada8a59c86697107222dfcf41e5f67ce084 Mon Sep 17 00:00:00 2001 From: Shanta Kabra Date: Tue, 9 Sep 2008 15:01:42 +0530 Subject: [PATCH 08/17] * Change in scale strategy bzr revid: shanta.kabra@gmail.com-20080909093142-urjd701pvlysw4na --- bin/addons/base/ir/workflow/workflow.py | 4 ++-- bin/tools/graph.py | 14 +++++++++----- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/bin/addons/base/ir/workflow/workflow.py b/bin/addons/base/ir/workflow/workflow.py index 45d2c752661..35b594812d7 100644 --- a/bin/addons/base/ir/workflow/workflow.py +++ b/bin/addons/base/ir/workflow/workflow.py @@ -54,7 +54,7 @@ class workflow(osv.osv): return super(workflow, self).write(cr, user, ids, vals, context=context) # - # scale = [stepx, stepy, posx, posy ] + # scale = (vertical-distance, horizontal-distance, min-node-width(optional), min-node-height(optional), margin(default=20)) # @@ -91,7 +91,7 @@ class workflow(osv.osv): results[str(node[0])] = result[node[0]] results[str(node[0])]['name'] = node[1] - return {'node': results, 'transition': tres} + return {'nodes': results, 'transitions': tres} def create(self, cr, user, vals, context=None): diff --git a/bin/tools/graph.py b/bin/tools/graph.py index d1fe2d50c57..8508f10ce42 100644 --- a/bin/tools/graph.py +++ b/bin/tools/graph.py @@ -650,6 +650,7 @@ class graph(object): if sec_node in self.partial_order.keys(): self.transitions[self.start_nodes[0]].append(node) break + self.partial_order = {} tree = self.make_acyclic(None, self.start_nodes[0], 0, []) @@ -665,8 +666,7 @@ class graph(object): self.start = s self.rank() # First step:Netwoek simplex algorithm self.order_in_rank() #Second step: ordering nodes within ranks - - + def __str__(self): result = '' @@ -676,7 +676,8 @@ class graph(object): result += '\tPosX: '+ str(self.result[node]['x']) + ' - Node:' + node + "\n" return result - def scale(self, maxx, maxy, plusx2=0, plusy2=0): + + def scale(self, maxx, maxy, nwidth=0, nheight=0, margin=20): """Computes actual co-ordiantes of the nodes """ @@ -687,9 +688,12 @@ class graph(object): self.result[src]['y'] += 0.08 self.result[des]['y'] -= 0.08 + factorX = maxx + nheight + factorY = maxy + nwidth + for node in self.result: - self.result[node]['x'] = (self.result[node]['x']) * maxx + plusx2 - self.result[node]['y'] = (self.result[node]['y']) * maxy + plusy2 + self.result[node]['x'] = (self.result[node]['x']) * factorX + margin + self.result[node]['y'] = (self.result[node]['y']) * factorY + margin def result_get(self): From eae3463b99db115288a8472f3b8d35e723055c75 Mon Sep 17 00:00:00 2001 From: Fabien Pinckaers Date: Tue, 9 Sep 2008 11:40:23 +0200 Subject: [PATCH 09/17] Bugfix bzr revid: fp@tinyerp.com-20080909094023-owi3zbiaokilfmi3 --- bin/addons/base/module/module.py | 6 +----- bin/addons/base/res/res_user.py | 4 ++-- bin/addons/mrp | 1 + 3 files changed, 4 insertions(+), 7 deletions(-) create mode 120000 bin/addons/mrp diff --git a/bin/addons/base/module/module.py b/bin/addons/base/module/module.py index 15b9a1fe820..2ff220a4c98 100644 --- a/bin/addons/base/module/module.py +++ b/bin/addons/base/module/module.py @@ -656,6 +656,7 @@ class module_configuration(osv.osv_memory): 'state': 'done', }, context=context) return{ + 'view_mode': item.action_id.view_mode, 'view_type': item.action_id.view_type, 'view_id':item.action_id.view_id and [item.action_id.view_id.id] or False, 'res_model': item.action_id.res_model, @@ -665,8 +666,3 @@ class module_configuration(osv.osv_memory): return {'type':'ir.actions.act_window_close' } module_configuration() - - - -# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: - diff --git a/bin/addons/base/res/res_user.py b/bin/addons/base/res/res_user.py index f9e8ab42986..95397a85a02 100644 --- a/bin/addons/base/res/res_user.py +++ b/bin/addons/base/res/res_user.py @@ -203,7 +203,7 @@ class users(osv.osv): return dataobj.browse(cr, uid, data_id, context).res_id def action_next(self,cr,uid,ids,context=None): - return{ + return { 'view_type': 'form', "view_mode": 'form', 'res_model': 'ir.module.module.configuration.wizard', @@ -218,7 +218,7 @@ class users(osv.osv): 'res_model': 'ir.module.module.configuration.wizard', 'type': 'ir.actions.act_window', 'target':'new', - } + } def action_new(self,cr,uid,ids,context={}): return { 'view_type': 'form', diff --git a/bin/addons/mrp b/bin/addons/mrp new file mode 120000 index 00000000000..b68eb83c463 --- /dev/null +++ b/bin/addons/mrp @@ -0,0 +1 @@ +/home/fp/code/terp/trunk/addons/mrp \ No newline at end of file From 31af6245dade5a299c4913d88f3f6779d27954de Mon Sep 17 00:00:00 2001 From: Christophe Simonis Date: Tue, 9 Sep 2008 15:22:10 +0200 Subject: [PATCH 10/17] enable get_binary_size for function field witch return binary bzr revid: christophe@tinyerp.com-20080909132210-gvgq8qovgh7updez --- bin/addons/base/ir/ir_actions.py | 2 +- bin/addons/mrp | 2 +- bin/osv/fields.py | 9 +++++++-- 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/bin/addons/base/ir/ir_actions.py b/bin/addons/base/ir/ir_actions.py index 3977e11f35c..fad22ec5ee1 100755 --- a/bin/addons/base/ir/ir_actions.py +++ b/bin/addons/base/ir/ir_actions.py @@ -155,7 +155,7 @@ class act_window(osv.osv): if (not act.view_ids): modes = act.view_mode.split(',') find = False - if act.view_id.id: + if act.view_id: res[act.id].append((act.view_id.id, act.view_id.type)) for t in modes: if act.view_id and (t == act.view_id.type) and not find: diff --git a/bin/addons/mrp b/bin/addons/mrp index b68eb83c463..eb5a02276e8 120000 --- a/bin/addons/mrp +++ b/bin/addons/mrp @@ -1 +1 @@ -/home/fp/code/terp/trunk/addons/mrp \ No newline at end of file +../../../addons/mrp \ No newline at end of file diff --git a/bin/osv/fields.py b/bin/osv/fields.py index 9044c7f1929..7c1a3034770 100644 --- a/bin/osv/fields.py +++ b/bin/osv/fields.py @@ -612,9 +612,14 @@ class function(_column): values = {} res = {} if self._method: - return self._fnct(obj, cr, user, ids, name, self._arg, context) + res = self._fnct(obj, cr, user, ids, name, self._arg, context) else: - return self._fnct(cr, obj._table, ids, name, self._arg, context) + res = self._fnct(cr, obj._table, ids, name, self._arg, context) + + if self._type == 'binary' and context.get('get_binary_size', True): + # convert the data returned by the function with the size of that data... + res = dict(map(lambda (x, y): (x, tools.human_size(len(y))), res.items())) + return res def set(self, cr, obj, id, name, value, user=None, context=None): if not context: From 16e0d0d7e3ab00d5eb72d59e59ab79c48cd9666e Mon Sep 17 00:00:00 2001 From: Christophe Simonis Date: Tue, 9 Sep 2008 15:44:53 +0200 Subject: [PATCH 11/17] remove symlink bzr revid: christophe@tinyerp.com-20080909134453-eevp0psteo67ytop --- bin/addons/mrp | 1 - 1 file changed, 1 deletion(-) delete mode 120000 bin/addons/mrp diff --git a/bin/addons/mrp b/bin/addons/mrp deleted file mode 120000 index eb5a02276e8..00000000000 --- a/bin/addons/mrp +++ /dev/null @@ -1 +0,0 @@ -../../../addons/mrp \ No newline at end of file From 40e61100135082c1e3f277ff8f9673521eb89137 Mon Sep 17 00:00:00 2001 From: Stephane Wirtel Date: Tue, 9 Sep 2008 18:15:17 +0200 Subject: [PATCH 12/17] Add a new decorator to log the res, args of a function bzr revid: stephane@tinyerp.com-20080909161517-nx1s1u2fzdbv52p1 --- bin/tools/misc.py | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/bin/tools/misc.py b/bin/tools/misc.py index 4d9458206f4..b08465403fa 100644 --- a/bin/tools/misc.py +++ b/bin/tools/misc.py @@ -702,6 +702,39 @@ def human_size(sz): i = i + 1 return "%0.2f %s" % (s, units[i]) +def logged(when): + def log(f, res, *args, **kwargs): + vector = ['Call -> function: %s' % f] + for i, arg in enumerate(args): + vector.append( ' arg %02d: %r' % ( i, arg ) ) + for key, value in kwargs.items(): + vector.append( ' kwarg %10s: %r' % ( key, value ) ) + vector.append( ' result: %r' % res ) + print "\n".join(vector) + + def pre_logged(f): + def wrapper(*args, **kwargs): + res = f(*args, **kwargs) + log(f, res, *args, **kwargs) + return res + return wrapper + + def post_logged(f): + def wrapper(*args, **kwargs): + now = time.time() + res = None + try: + res = f(*args, **kwargs) + return res + finally: + log(f, res, *args, **kwargs) + print " time delta: %s" % (time.time() - now) + return wrapper + + try: + return { "pre" : pre_logged, "post" : post_logged}[when] + except KeyError, e: + raise ValueError(e), "must to be 'pre' or 'post'" if __name__ == '__main__': import doctest From f20613721db626e800beeb8de8468bb295922cff Mon Sep 17 00:00:00 2001 From: Stephane Wirtel Date: Wed, 10 Sep 2008 09:13:12 +0200 Subject: [PATCH 13/17] Add some package Change svn to bzr bzr revid: stephane@tinyerp.com-20080910071312-hvziijv2slvg8zaw --- setup.py | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/setup.py b/setup.py index a781f7a0c5c..a9a5353167b 100644 --- a/setup.py +++ b/setup.py @@ -76,8 +76,8 @@ def check_modules(): def find_addons(): for (dp, dn, names) in os.walk(opj('bin', 'addons')): - if '.svn' in dn: - dn.remove('.svn') + if '.bzr' in dn: + dn.remove('.bzr') for dirpath, dirnames, filenames in os.walk(dp): if '__init__.py' in filenames: modname = dirpath.replace(os.path.sep, '.') @@ -89,17 +89,17 @@ def data_files(): if os.name == 'nt': os.chdir('bin') for (dp,dn,names) in os.walk('addons'): - if '.svn' in dn: - dn.remove('.svn') + if '.bzr' in dn: + dn.remove('.bzr') files.append((dp, map(lambda x: os.path.join('bin', dp,x), names))) for (dp,dn,names) in os.walk('i18n'): - if '.svn' in dn: - dn.remove('.svn') + if '.bzr' in dn: + dn.remove('.bzr') files.append((dp, map(lambda x: os.path.join('bin', dp,x), names))) os.chdir('..') for (dp,dn,names) in os.walk('doc'): - if '.svn' in dn: - dn.remove('.svn') + if '.bzr' in dn: + dn.remove('.bzr') files.append((dp, map(lambda x: os.path.join(dp,x), names))) else: files.append((opj('share', 'man', 'man1'), ['man/tinyerp-server.1'])) @@ -154,7 +154,7 @@ f.close() options = {"py2exe": { "compressed": 0, "optimize": 2, - "packages": ["encodings","mx.DateTime","wizard","pychart","PIL", "pyparsing", "pydot"], + "packages": ["decimal", "xml", "xml.dom", "xml.xpath", "encodings","mx.DateTime","wizard","pychart","PIL", "pyparsing", "pydot"], "excludes" : ["Tkconstants","Tkinter","tcl"], }} From fe3b8926a5227430caedd5a158e1e43314ac91ab Mon Sep 17 00:00:00 2001 From: Stephane Wirtel Date: Wed, 10 Sep 2008 09:42:21 +0200 Subject: [PATCH 14/17] rename tinyerp to openerp bzr revid: stephane@tinyerp.com-20080910074221-6cu9fn1eog4y5ciu --- ...taller.nsi => openerp-server-installer.nsi | 58 +++++++++---------- 1 file changed, 29 insertions(+), 29 deletions(-) rename tinyerp-server-installer.nsi => openerp-server-installer.nsi (75%) diff --git a/tinyerp-server-installer.nsi b/openerp-server-installer.nsi similarity index 75% rename from tinyerp-server-installer.nsi rename to openerp-server-installer.nsi index 6cdcd6703bd..3947879ef6a 100644 --- a/tinyerp-server-installer.nsi +++ b/openerp-server-installer.nsi @@ -11,14 +11,14 @@ ;General ;Name and file - Name "TinyERP Server" - OutFile "tinyerp-server-setup.exe" + Name "OpenERP Server" + OutFile "openerp-server-setup.exe" ;Default installation folder - InstallDir "$PROGRAMFILES\TinyERP Server" + InstallDir "$PROGRAMFILES\OpenERP Server" ;Get installation folder from registry if available - InstallDirRegKey HKCU "Software\TinyERP Server" "" + InstallDirRegKey HKCU "Software\OpenERP Server" "" ;Vista redirects $SMPROGRAMS to all users without this RequestExecutionLevel admin @@ -37,11 +37,11 @@ ;-------------------------------- ;Pages - !define MUI_ICON ".\pixmaps\tinyerp.ico" - !define MUI_UNICON ".\pixmaps\tinyerp.ico" - !define MUI_WELCOMEFINISHPAGE_BITMAP ".\pixmaps\tinyerp-intro.bmp" + !define MUI_ICON ".\pixmaps\openerp.ico" + !define MUI_UNICON ".\pixmaps\openerp.ico" + !define MUI_WELCOMEFINISHPAGE_BITMAP ".\pixmaps\openerp-intro.bmp" !define MUI_HEADERIMAGE - !define MUI_HEADERIMAGE_BITMAP ".\pixmaps\tinyerp-header.bmp" + !define MUI_HEADERIMAGE_BITMAP ".\pixmaps\openerp-header.bmp" !insertmacro MUI_PAGE_WELCOME !insertmacro MUI_PAGE_LICENSE "doc\\License.rtf" @@ -50,8 +50,8 @@ ;Start Menu Folder Page Configuration !define MUI_STARTMENUPAGE_REGISTRY_ROOT "HKCU" - !define MUI_STARTMENUPAGE_REGISTRY_KEY "Software\TinyERP Server" - !define MUI_STARTMENUPAGE_REGISTRY_VALUENAME "TinyERP Server" + !define MUI_STARTMENUPAGE_REGISTRY_KEY "Software\OpenERP Server" + !define MUI_STARTMENUPAGE_REGISTRY_VALUENAME "OpenERP Server" !insertmacro MUI_PAGE_STARTMENU Application $STARTMENU_FOLDER @@ -60,7 +60,7 @@ !define MUI_FINISHPAGE_NOAUTOCLOSE !define MUI_FINISHPAGE_RUN !define MUI_FINISHPAGE_RUN_CHECKED - !define MUI_FINISHPAGE_RUN_TEXT "Start TinyERP Server" + !define MUI_FINISHPAGE_RUN_TEXT "Start OpenERP Server" !define MUI_FINISHPAGE_RUN_FUNCTION "LaunchLink" !define MUI_FINISHPAGE_SHOWREADME_NOTCHECKED !define MUI_FINISHPAGE_SHOWREADME $INSTDIR\README.txt @@ -79,9 +79,9 @@ ;-------------------------------- ;Installer Sections -Section "TinyERP Server" SecTinyERPServer +Section "OpenERP Server" SecOpenERPServer - nsExec::Exec "net stop tinyerp-service" + nsExec::Exec "net stop openerp-service" sleep 2 SetOutPath "$INSTDIR" @@ -95,11 +95,11 @@ Section "TinyERP Server" SecTinyERPServer File "win32\\stop.bat" ;Store installation folder - WriteRegStr HKCU "Software\TinyERP Server" "" $INSTDIR + WriteRegStr HKCU "Software\OpenERP Server" "" $INSTDIR ;Create uninstaller - WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\TinyERP Server" "DisplayName" "TinyERP Server (remove only)" - WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\TinyERP Server" "UninstallString" "$INSTDIR\Uninstall.exe" + WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\OpenERP Server" "DisplayName" "OpenERP Server (remove only)" + WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\OpenERP Server" "UninstallString" "$INSTDIR\Uninstall.exe" WriteUninstaller "$INSTDIR\Uninstall.exe" @@ -107,27 +107,27 @@ Section "TinyERP Server" SecTinyERPServer ;Create shortcuts CreateDirectory "$SMPROGRAMS\$STARTMENU_FOLDER" - CreateShortCut "$SMPROGRAMS\$STARTMENU_FOLDER\TinyERP Server.lnk" "$INSTDIR\tinyerp-server.exe" + CreateShortCut "$SMPROGRAMS\$STARTMENU_FOLDER\OpenERP Server.lnk" "$INSTDIR\openerp-server.exe" CreateShortCut "$SMPROGRAMS\$STARTMENU_FOLDER\Start service.lnk" "$INSTDIR\service\start.bat" CreateShortCut "$SMPROGRAMS\$STARTMENU_FOLDER\Stop service.lnk" "$INSTDIR\service\stop.bat" - CreateShortCut "$SMPROGRAMS\$STARTMENU_FOLDER\Edit config.lnk" "notepad.exe" "$INSTDIR\tinyerp-server.conf" - CreateShortCut "$SMPROGRAMS\$STARTMENU_FOLDER\View log.lnk" "notepad.exe" "$INSTDIR\tinyerp-server.log" + CreateShortCut "$SMPROGRAMS\$STARTMENU_FOLDER\Edit config.lnk" "notepad.exe" "$INSTDIR\openerp-server.conf" + CreateShortCut "$SMPROGRAMS\$STARTMENU_FOLDER\View log.lnk" "notepad.exe" "$INSTDIR\openerp-server.log" !insertmacro MUI_STARTMENU_WRITE_END - nsExec::Exec '"$INSTDIR\\tinyerp-server.exe" --stop-after-init --logfile "$INSTDIR\\tinyerp-server.log" -s' - nsExec::Exec '"$INSTDIR\\service\\TinyERPServerService.exe" -auto -install' + nsExec::Exec '"$INSTDIR\\openerp-server.exe" --stop-after-init --logfile "$INSTDIR\\openerp-server.log" -s' + nsExec::Exec '"$INSTDIR\\service\\OpenERPServerService.exe" -auto -install' SectionEnd ;Descriptions ;Language strings - LangString DESC_SecTinyERPServer ${LANG_ENGLISH} "TinyERP Server." + LangString DESC_SecOpenERPServer ${LANG_ENGLISH} "OpenERP Server." ;Assign language strings to sections !insertmacro MUI_FUNCTION_DESCRIPTION_BEGIN - !insertmacro MUI_DESCRIPTION_TEXT ${SecTinyERPServer} $(DESC_SecTinyERPServer) + !insertmacro MUI_DESCRIPTION_TEXT ${SecOpenERPServer} $(DESC_SecOpenERPServer) !insertmacro MUI_FUNCTION_DESCRIPTION_END ;-------------------------------- @@ -135,9 +135,9 @@ SectionEnd Section "Uninstall" - nsExec::Exec "net stop tinyerp-service" + nsExec::Exec "net stop openerp-service" sleep 2 - nsExec::Exec '"$INSTDIR\\service\\TinyERPServerService.exe" -remove' + nsExec::Exec '"$INSTDIR\\service\\OpenERPServerService.exe" -remove' sleep 2 ;ADD YOUR OWN FILES HERE... @@ -172,7 +172,7 @@ Section "Uninstall" !insertmacro MUI_STARTMENU_GETFOLDER Application $MUI_TEMP - Delete "$SMPROGRAMS\$MUI_TEMP\TinyERP Server.lnk" + Delete "$SMPROGRAMS\$MUI_TEMP\OpenERP Server.lnk" Delete "$SMPROGRAMS\$MUI_TEMP\Uninstall.lnk" Delete "$SMPROGRAMS\$MUI_TEMP\Start service.lnk" Delete "$SMPROGRAMS\$MUI_TEMP\Stop service.lnk" @@ -192,13 +192,13 @@ Section "Uninstall" StrCmp $MUI_TEMP $SMPROGRAMS startMenuDeleteLoopDone startMenuDeleteLoop startMenuDeleteLoopDone: - DeleteRegKey HKEY_LOCAL_MACHINE "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\TinyERP Server" - DeleteRegKey /ifempty HKCU "Software\TinyERP Server" + DeleteRegKey HKEY_LOCAL_MACHINE "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\OpenERP Server" + DeleteRegKey /ifempty HKCU "Software\OpenERP Server" SectionEnd Function LaunchLink - nsExec::Exec "net start tinyerp-service" + nsExec::Exec "net start openerp-service" FunctionEnd Function un.RmDirsButOne From d4538e04380528fd0556851d99ab9ce7cdacb612 Mon Sep 17 00:00:00 2001 From: Stephane Wirtel Date: Wed, 10 Sep 2008 09:55:47 +0200 Subject: [PATCH 15/17] rename the files with tinyerp in the name bzr revid: stephane@tinyerp.com-20080910075547-6iifqe6w6kw2u3v4 --- bin/{tinyerp-server.py => openerp-server.py} | 0 man/{tinyerp-server.1 => openerp-server.1} | 22 ++++++++---------- man/{terp_serverrc.5 => openerp_serverrc.5} | 12 ++++------ ...{tinyerp-header.bmp => openerp-header.bmp} | Bin .../{tinyerp-icon.png => openerp-icon.png} | Bin .../{tinyerp-intro.bmp => openerp-intro.bmp} | Bin pixmaps/{tinyerp.ico => openerp.ico} | Bin ...rverService.py => OpenERPServerService.py} | 0 8 files changed, 14 insertions(+), 20 deletions(-) rename bin/{tinyerp-server.py => openerp-server.py} (100%) rename man/{tinyerp-server.1 => openerp-server.1} (83%) rename man/{terp_serverrc.5 => openerp_serverrc.5} (85%) rename pixmaps/{tinyerp-header.bmp => openerp-header.bmp} (100%) rename pixmaps/{tinyerp-icon.png => openerp-icon.png} (100%) rename pixmaps/{tinyerp-intro.bmp => openerp-intro.bmp} (100%) rename pixmaps/{tinyerp.ico => openerp.ico} (100%) rename win32/{TinyERPServerService.py => OpenERPServerService.py} (100%) diff --git a/bin/tinyerp-server.py b/bin/openerp-server.py similarity index 100% rename from bin/tinyerp-server.py rename to bin/openerp-server.py diff --git a/man/tinyerp-server.1 b/man/openerp-server.1 similarity index 83% rename from man/tinyerp-server.1 rename to man/openerp-server.1 index 1bb935953f9..0d0275b31d6 100644 --- a/man/tinyerp-server.1 +++ b/man/openerp-server.1 @@ -1,20 +1,20 @@ -.TH tinyerp_server 1 +.TH openerp_server 1 .SH NAME -tinyerp_server \- Server for Tiny ERP +openerp_server \- Server for OpenERP .SH SYNOPSIS -.B tinyerp_server.py [options] +.B openerp_server.py [options] .SH DESCRIPTION -TinyERP is an Enterprise Resource Planning and Customer Relationship +OpenERP is an Enterprise Resource Planning and Customer Relationship Management software package. It is developed to meet changing needs. The main functional features are: CRM and SRM, analytic and financial accounting, double-entry stock management, sales and purchases management, tasks automation, a help desk, marketing campaigns, and vertical modules for very specific businesses. Technical features include a distributed server, flexible workflows, an object database, a dynamic GUI, customizable -reports, and a SOAP and XML-RPC interface. +reports, and a NET-RPC and XML-RPC interface. .SH OPTIONS @@ -28,7 +28,7 @@ Print the program's version number and exit. .TP .B \-c \fIFILE\fB, \-\-config=\fIFILE\fB -Specify an alternate config file. By default, tinyerp server uses ~/.terp_serverrc +Specify an alternate config file. By default, openerp server uses ~/.terp_serverrc .TP .B \-s, \-\-save @@ -87,14 +87,12 @@ Import the CSV file at \fIFILEPATH\fR. It should contain the translations for th .SH AUTHORS -Tiny ERP is a product of \fBTiny.be\fR (\fIhttp://www.tiny.be\fR) +OpenERP is a product of \fBTiny.be\fR (\fIhttp://www.tiny.be\fR) .SH SEE ALSO -terp_serverrc(5) -tinyerp(1) +openerp_serverrc(5) +openerp(1) .br -\fIhttp://www.tinyerp.com\fR : Tiny ERP functional description -.br -\fIhttp://www.tinyerp.org\fR : Tiny ERP developer zone +\fIhttp://www.openerp.com\fR : Tiny ERP functional description diff --git a/man/terp_serverrc.5 b/man/openerp_serverrc.5 similarity index 85% rename from man/terp_serverrc.5 rename to man/openerp_serverrc.5 index 9959509f4d0..9337bc370a1 100644 --- a/man/terp_serverrc.5 +++ b/man/openerp_serverrc.5 @@ -1,7 +1,7 @@ -.TH terp_serverrc 5 +.TH openerp_serverrc 5 .SH NAME -terp_serverrc \- configuration file for Tiny ERP +openerp_serverrc \- configuration file for OpenERP .SH SYNOPSIS [options] @@ -71,8 +71,6 @@ Specify the SMTP password for sending email. .TP .IR db_name Specify the database name. -.br -(default terp) .TP .IR db_user Specify the database user name. @@ -105,11 +103,9 @@ Specify the price accuracy. .SH AUTHORS -Tiny ERP is a product of \fBTiny.be\fR (\fIhttp://www.tiny.be\fR) +OpenERP is a product of \fBTiny.be\fR (\fIhttp://www.tiny.be\fR) .SH SEE ALSO tinyerp-server(1) .br -\fIhttp://www.tinyerp.com\fR : Tiny ERP functional description -.br -\fIhttp://www.tinyerp.org\fR : Tiny ERP developer zone +\fIhttp://www.openerp.com\fR : OpenERP functional description diff --git a/pixmaps/tinyerp-header.bmp b/pixmaps/openerp-header.bmp similarity index 100% rename from pixmaps/tinyerp-header.bmp rename to pixmaps/openerp-header.bmp diff --git a/pixmaps/tinyerp-icon.png b/pixmaps/openerp-icon.png similarity index 100% rename from pixmaps/tinyerp-icon.png rename to pixmaps/openerp-icon.png diff --git a/pixmaps/tinyerp-intro.bmp b/pixmaps/openerp-intro.bmp similarity index 100% rename from pixmaps/tinyerp-intro.bmp rename to pixmaps/openerp-intro.bmp diff --git a/pixmaps/tinyerp.ico b/pixmaps/openerp.ico similarity index 100% rename from pixmaps/tinyerp.ico rename to pixmaps/openerp.ico diff --git a/win32/TinyERPServerService.py b/win32/OpenERPServerService.py similarity index 100% rename from win32/TinyERPServerService.py rename to win32/OpenERPServerService.py From dbe1e8ca98abebcb6045614d6ced335e3edb9bf6 Mon Sep 17 00:00:00 2001 From: Stephane Wirtel Date: Wed, 10 Sep 2008 10:46:40 +0200 Subject: [PATCH 16/17] Rename Tiny ERP to OpenERP Rename tinyerp to openerp bzr revid: stephane@tinyerp.com-20080910084640-bg1h1bre7mwky8s0 --- bin/PKG-INFO | 12 ++-- bin/addons/base/__terp__.py | 4 +- bin/addons/base/i18n/cs_CZ.po | 2 +- bin/addons/base/i18n/de_DE.po | 2 +- bin/addons/base/i18n/es_AR.po | 2 +- bin/addons/base/i18n/es_ES.po | 2 +- bin/addons/base/i18n/fr_FR.po | 2 +- bin/addons/base/i18n/hu_HU.po | 2 +- bin/addons/base/i18n/it_IT.po | 2 +- bin/addons/base/i18n/nl_NL.po | 2 +- bin/addons/base/i18n/pt_BR.po | 2 +- bin/addons/base/i18n/pt_PT.po | 2 +- bin/addons/base/i18n/ro_RO.po | 2 +- bin/addons/base/i18n/ru_RU.po | 2 +- bin/addons/base/i18n/sv_SE.po | 2 +- bin/addons/base/i18n/zh_CN.po | 2 +- bin/addons/base/i18n/zh_TW.po | 2 +- bin/addons/base/ir/ir_report_custom.py | 2 +- bin/addons/base/module/module_data.xml | 6 +- bin/addons/base/report/custom.xsl | 5 +- bin/addons/base/report/custom_default.xsl | 2 +- bin/addons/base/report/custom_rml.xsl | 2 +- bin/addons/base/report/rml_template.xsl | 2 +- bin/addons/base/res/partner/partner_demo.xml | 4 +- .../base/res/partner/report/business_card.xsl | 3 +- .../res/partner/report/partner_address.xsl | 3 +- bin/openerp-server.py | 12 ++-- bin/osv/orm.py | 2 +- bin/report/render/simple.py | 2 +- bin/service/web_services.py | 4 +- bin/tools/config.py | 12 ++-- bin/tools/import_email.py | 2 +- bin/tools/misc.py | 4 +- bin/tools/translate.py | 2 +- doc/INSTALL | 6 +- doc/README.txt | 10 ++-- doc/tests/check_profile_l10n_all.py | 2 +- man/openerp-server.1 | 10 ++-- man/openerp_serverrc.5 | 2 +- setup.py | 60 +++++++++---------- win32/OpenERPServerService.py | 24 ++++---- win32/setup.py | 2 +- win32/start.bat | 4 +- win32/stop.bat | 2 +- 44 files changed, 120 insertions(+), 117 deletions(-) diff --git a/bin/PKG-INFO b/bin/PKG-INFO index eab85ed9001..c74326a1493 100644 --- a/bin/PKG-INFO +++ b/bin/PKG-INFO @@ -1,18 +1,18 @@ Metadata-Version: 1.1 -Name: Tiny ERP -Version: 4.3.0 +Name: OpenERP +Version: 4.3.99 Author: Tiny.be Author-email: fp at tiny be Maintainer: Tiny.be Maintainer-email: fp at tiny be Home-page: http://tiny.be -Download-url: http://tinyerp.org/download.php -Summary: TinyERP is an Enterprise Resource Management written entirely in python. +Download-url: http://openerp.com/downloads.html +Summary: OpenERP is an Enterprise Resource Management written entirely in python. License: GPL -Description: Tiny ERP is a complete ERP and CRM. The main features are accounting (analytic +Description: OpenERP is a complete ERP and CRM. The main features are accounting (analytic and financial), stock management, sales and purchases management, tasks automation, marketing campaigns, help desk, POS, etc. Technical features include a distributed server, flexible workflows, an object database, a dynamic GUI, - customizable reports, and SOAP and XML-RPC interfaces. + customizable reports, and NET-RPC and XML-RPC interfaces. Keywords: ERP, Accounting, Stock, CRM, Enterprise, Logistics, Management, Sales, Purchases Platform: Linux, Win32 diff --git a/bin/addons/base/__terp__.py b/bin/addons/base/__terp__.py index 5ba01da68b6..917a0ff3541 100644 --- a/bin/addons/base/__terp__.py +++ b/bin/addons/base/__terp__.py @@ -31,9 +31,9 @@ "name" : "Base", "version" : "1.0", "author" : "Tiny", - "website" : "http://tinyerp.com", + "website" : "http://openerp.com", "category" : "Generic Modules/Base", - "description": "The kernel of Tiny ERP, needed for all installation.", + "description": "The kernel of OpenERP, needed for all installation.", "depends" : [], "init_xml" : [ "base_data.xml", diff --git a/bin/addons/base/i18n/cs_CZ.po b/bin/addons/base/i18n/cs_CZ.po index 95f8ebbb3b4..cebcb8a4b47 100644 --- a/bin/addons/base/i18n/cs_CZ.po +++ b/bin/addons/base/i18n/cs_CZ.po @@ -5,7 +5,7 @@ msgid "" msgstr "" "Project-Id-Version: OpenERP Server 4.3.0" -"Report-Msgid-Bugs-To: support@tinyerp.com" +"Report-Msgid-Bugs-To: support@openerp.com" "POT-Creation-Date: 2008-09-04 08:32:29+0000" "PO-Revision-Date: 2008-09-04 08:32:29+0000" "Last-Translator: <>" diff --git a/bin/addons/base/i18n/de_DE.po b/bin/addons/base/i18n/de_DE.po index 796ad959f45..7a62e651c63 100644 --- a/bin/addons/base/i18n/de_DE.po +++ b/bin/addons/base/i18n/de_DE.po @@ -5,7 +5,7 @@ msgid "" msgstr "" "Project-Id-Version: OpenERP Server 4.3.0" -"Report-Msgid-Bugs-To: support@tinyerp.com" +"Report-Msgid-Bugs-To: support@openerp.com" "POT-Creation-Date: 2008-09-04 08:33:13+0000" "PO-Revision-Date: 2008-09-04 08:33:13+0000" "Last-Translator: <>" diff --git a/bin/addons/base/i18n/es_AR.po b/bin/addons/base/i18n/es_AR.po index f3414aa1ee8..f00d642000f 100644 --- a/bin/addons/base/i18n/es_AR.po +++ b/bin/addons/base/i18n/es_AR.po @@ -5,7 +5,7 @@ msgid "" msgstr "" "Project-Id-Version: OpenERP Server 4.3.0" -"Report-Msgid-Bugs-To: support@tinyerp.com" +"Report-Msgid-Bugs-To: support@openerp.com" "POT-Creation-Date: 2008-09-04 08:34:02+0000" "PO-Revision-Date: 2008-09-04 08:34:02+0000" "Last-Translator: <>" diff --git a/bin/addons/base/i18n/es_ES.po b/bin/addons/base/i18n/es_ES.po index e0b7026bf45..bf2e8a57a6e 100644 --- a/bin/addons/base/i18n/es_ES.po +++ b/bin/addons/base/i18n/es_ES.po @@ -5,7 +5,7 @@ msgid "" msgstr "" "Project-Id-Version: OpenERP Server 4.3.0" -"Report-Msgid-Bugs-To: support@tinyerp.com" +"Report-Msgid-Bugs-To: support@openerp.com" "POT-Creation-Date: 2008-09-04 08:34:48+0000" "PO-Revision-Date: 2008-09-04 08:34:48+0000" "Last-Translator: <>" diff --git a/bin/addons/base/i18n/fr_FR.po b/bin/addons/base/i18n/fr_FR.po index 6b0a938841d..13dc60cef9d 100644 --- a/bin/addons/base/i18n/fr_FR.po +++ b/bin/addons/base/i18n/fr_FR.po @@ -5,7 +5,7 @@ msgid "" msgstr "" "Project-Id-Version: OpenERP Server 4.3.0" -"Report-Msgid-Bugs-To: support@tinyerp.com" +"Report-Msgid-Bugs-To: support@openerp.com" "POT-Creation-Date: 2008-09-04 08:35:53+0000" "PO-Revision-Date: 2008-09-04 08:35:53+0000" "Last-Translator: <>" diff --git a/bin/addons/base/i18n/hu_HU.po b/bin/addons/base/i18n/hu_HU.po index be29b43097b..065fabee0e9 100644 --- a/bin/addons/base/i18n/hu_HU.po +++ b/bin/addons/base/i18n/hu_HU.po @@ -5,7 +5,7 @@ msgid "" msgstr "" "Project-Id-Version: OpenERP Server 4.3.0" -"Report-Msgid-Bugs-To: support@tinyerp.com" +"Report-Msgid-Bugs-To: support@openerp.com" "POT-Creation-Date: 2008-09-04 08:36:32+0000" "PO-Revision-Date: 2008-09-04 08:36:32+0000" "Last-Translator: <>" diff --git a/bin/addons/base/i18n/it_IT.po b/bin/addons/base/i18n/it_IT.po index 20332511512..d656bb36514 100644 --- a/bin/addons/base/i18n/it_IT.po +++ b/bin/addons/base/i18n/it_IT.po @@ -5,7 +5,7 @@ msgid "" msgstr "" "Project-Id-Version: OpenERP Server 4.3.0" -"Report-Msgid-Bugs-To: support@tinyerp.com" +"Report-Msgid-Bugs-To: support@openerp.com" "POT-Creation-Date: 2008-09-04 08:37:25+0000" "PO-Revision-Date: 2008-09-04 08:37:25+0000" "Last-Translator: <>" diff --git a/bin/addons/base/i18n/nl_NL.po b/bin/addons/base/i18n/nl_NL.po index e152a5eab0a..7a57a286cdb 100644 --- a/bin/addons/base/i18n/nl_NL.po +++ b/bin/addons/base/i18n/nl_NL.po @@ -5,7 +5,7 @@ msgid "" msgstr "" "Project-Id-Version: OpenERP Server 4.3.0" -"Report-Msgid-Bugs-To: support@tinyerp.com" +"Report-Msgid-Bugs-To: support@openerp.com" "POT-Creation-Date: 2008-09-04 08:38:11+0000" "PO-Revision-Date: 2008-09-04 08:38:11+0000" "Last-Translator: <>" diff --git a/bin/addons/base/i18n/pt_BR.po b/bin/addons/base/i18n/pt_BR.po index 89b21f1cff4..a1a632e58a4 100644 --- a/bin/addons/base/i18n/pt_BR.po +++ b/bin/addons/base/i18n/pt_BR.po @@ -5,7 +5,7 @@ msgid "" msgstr "" "Project-Id-Version: OpenERP Server 4.3.0" -"Report-Msgid-Bugs-To: support@tinyerp.com" +"Report-Msgid-Bugs-To: support@openerp.com" "POT-Creation-Date: 2008-09-04 08:38:52+0000" "PO-Revision-Date: 2008-09-04 08:38:52+0000" "Last-Translator: <>" diff --git a/bin/addons/base/i18n/pt_PT.po b/bin/addons/base/i18n/pt_PT.po index 0878619590a..8e86560093c 100644 --- a/bin/addons/base/i18n/pt_PT.po +++ b/bin/addons/base/i18n/pt_PT.po @@ -5,7 +5,7 @@ msgid "" msgstr "" "Project-Id-Version: OpenERP Server 4.3.0" -"Report-Msgid-Bugs-To: support@tinyerp.com" +"Report-Msgid-Bugs-To: support@openerp.com" "POT-Creation-Date: 2008-09-04 08:39:40+0000" "PO-Revision-Date: 2008-09-04 08:39:40+0000" "Last-Translator: <>" diff --git a/bin/addons/base/i18n/ro_RO.po b/bin/addons/base/i18n/ro_RO.po index 4e3049c65d9..a56056d51a5 100644 --- a/bin/addons/base/i18n/ro_RO.po +++ b/bin/addons/base/i18n/ro_RO.po @@ -5,7 +5,7 @@ msgid "" msgstr "" "Project-Id-Version: OpenERP Server 4.3.0" -"Report-Msgid-Bugs-To: support@tinyerp.com" +"Report-Msgid-Bugs-To: support@openerp.com" "POT-Creation-Date: 2008-09-04 08:40:19+0000" "PO-Revision-Date: 2008-09-04 08:40:19+0000" "Last-Translator: <>" diff --git a/bin/addons/base/i18n/ru_RU.po b/bin/addons/base/i18n/ru_RU.po index 20ecb44fe01..13c1c714a26 100644 --- a/bin/addons/base/i18n/ru_RU.po +++ b/bin/addons/base/i18n/ru_RU.po @@ -5,7 +5,7 @@ msgid "" msgstr "" "Project-Id-Version: OpenERP Server 4.3.0" -"Report-Msgid-Bugs-To: support@tinyerp.com" +"Report-Msgid-Bugs-To: support@openerp.com" "POT-Creation-Date: 2008-09-04 08:41:03+0000" "PO-Revision-Date: 2008-09-04 08:41:03+0000" "Last-Translator: <>" diff --git a/bin/addons/base/i18n/sv_SE.po b/bin/addons/base/i18n/sv_SE.po index 9e65d004140..7b49d38198b 100644 --- a/bin/addons/base/i18n/sv_SE.po +++ b/bin/addons/base/i18n/sv_SE.po @@ -5,7 +5,7 @@ msgid "" msgstr "" "Project-Id-Version: OpenERP Server 4.3.0" -"Report-Msgid-Bugs-To: support@tinyerp.com" +"Report-Msgid-Bugs-To: support@openerp.com" "POT-Creation-Date: 2008-09-04 08:41:45+0000" "PO-Revision-Date: 2008-09-04 08:41:45+0000" "Last-Translator: <>" diff --git a/bin/addons/base/i18n/zh_CN.po b/bin/addons/base/i18n/zh_CN.po index 9fe9773b0a8..80708aff4ae 100644 --- a/bin/addons/base/i18n/zh_CN.po +++ b/bin/addons/base/i18n/zh_CN.po @@ -5,7 +5,7 @@ msgid "" msgstr "" "Project-Id-Version: OpenERP Server 4.3.0" -"Report-Msgid-Bugs-To: support@tinyerp.com" +"Report-Msgid-Bugs-To: support@openerp.com" "POT-Creation-Date: 2008-09-04 08:42:44+0000" "PO-Revision-Date: 2008-09-04 08:42:44+0000" "Last-Translator: <>" diff --git a/bin/addons/base/i18n/zh_TW.po b/bin/addons/base/i18n/zh_TW.po index 2e3e6c54493..791cd0df416 100644 --- a/bin/addons/base/i18n/zh_TW.po +++ b/bin/addons/base/i18n/zh_TW.po @@ -5,7 +5,7 @@ msgid "" msgstr "" "Project-Id-Version: OpenERP Server 4.3.0" -"Report-Msgid-Bugs-To: support@tinyerp.com" +"Report-Msgid-Bugs-To: support@openerp.com" "POT-Creation-Date: 2008-09-04 08:43:25+0000" "PO-Revision-Date: 2008-09-04 08:43:25+0000" "Last-Translator: <>" diff --git a/bin/addons/base/ir/ir_report_custom.py b/bin/addons/base/ir/ir_report_custom.py index 1d0dddd3a37..3a7ca1dd07e 100644 --- a/bin/addons/base/ir/ir_report_custom.py +++ b/bin/addons/base/ir/ir_report_custom.py @@ -58,7 +58,7 @@ class report_custom(osv.osv): 'print_orientation': lambda *a: 'portrait', 'state': lambda *a: 'unsubscribed', 'type': lambda *a: 'table', - 'footer': lambda *a: 'Generated by Tiny ERP' + 'footer': lambda *a: 'Generated by OpenERP' } def onchange_model_id(self, cr, uid, ids, model_id): diff --git a/bin/addons/base/module/module_data.xml b/bin/addons/base/module/module_data.xml index 1f632c7ef08..940dd3833c9 100644 --- a/bin/addons/base/module/module_data.xml +++ b/bin/addons/base/module/module_data.xml @@ -1,11 +1,11 @@ - - Tiny ERP + + OpenERP http://www.openerp.com/download/modules/ - \ No newline at end of file + diff --git a/bin/addons/base/report/custom.xsl b/bin/addons/base/report/custom.xsl index e40c62ddb2a..1e5fd740c0f 100644 --- a/bin/addons/base/report/custom.xsl +++ b/bin/addons/base/report/custom.xsl @@ -7,7 +7,8 @@ -