Merged from diagram branch
bzr revid: hda@tinyerp.com-20100312073053-9fq87tnzmbd37mg7
This commit is contained in:
@@ -7,13 +7,13 @@ msgstr ""
|
||||
"Project-Id-Version: OpenERP Server 5.0.4\n"
|
||||
"Report-Msgid-Bugs-To: support@openerp.com\n"
|
||||
"POT-Creation-Date: 2009-12-18 08:39+0000\n"
|
||||
"PO-Revision-Date: 2010-03-10 05:22+0000\n"
|
||||
"PO-Revision-Date: 2010-03-11 05:23+0000\n"
|
||||
"Last-Translator: goranc <goranc@gmail.com>\n"
|
||||
"Language-Team: openerp-translators\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Launchpad-Export-Date: 2010-03-11 04:37+0000\n"
|
||||
"X-Launchpad-Export-Date: 2010-03-12 04:50+0000\n"
|
||||
"X-Generator: Launchpad (build Unknown)\n"
|
||||
"Language: hr\n"
|
||||
|
||||
|
||||
+19
-15
@@ -7,13 +7,13 @@ msgstr ""
|
||||
"Project-Id-Version: OpenERP Server 5.0.4\n"
|
||||
"Report-Msgid-Bugs-To: support@openerp.com\n"
|
||||
"POT-Creation-Date: 2009-12-18 08:39+0000\n"
|
||||
"PO-Revision-Date: 2010-02-15 05:46+0000\n"
|
||||
"Last-Translator: Luigi Grilli <luigi.grilli@gmail.com>\n"
|
||||
"PO-Revision-Date: 2010-03-11 11:29+0000\n"
|
||||
"Last-Translator: Maurizio.Colella <m.colella88@gmail.com>\n"
|
||||
"Language-Team: \n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Launchpad-Export-Date: 2010-02-17 04:54+0000\n"
|
||||
"X-Launchpad-Export-Date: 2010-03-12 04:50+0000\n"
|
||||
"X-Generator: Launchpad (build Unknown)\n"
|
||||
|
||||
#. module: base
|
||||
@@ -3278,7 +3278,7 @@ msgstr "Test"
|
||||
#. module: base
|
||||
#: field:ir.report.custom.fields,groupby:0
|
||||
msgid "Group By"
|
||||
msgstr ""
|
||||
msgstr "Raggruppa per"
|
||||
|
||||
#. module: base
|
||||
#: code:addons/base/ir/ir_model.py:0
|
||||
@@ -3354,7 +3354,7 @@ msgstr ""
|
||||
#: code:addons/base/res/res_user.py:0
|
||||
#, python-format
|
||||
msgid "The name of the group can not start with \"-\""
|
||||
msgstr ""
|
||||
msgstr "Il nome del gruppo non può iniziare con '-'"
|
||||
|
||||
#. module: base
|
||||
#: wizard_view:module.upgrade,end:0
|
||||
@@ -3387,7 +3387,7 @@ msgstr "Sicurezza Gruppi"
|
||||
#. module: base
|
||||
#: view:res.partner.bank:0
|
||||
msgid "Bank Account Owner"
|
||||
msgstr ""
|
||||
msgstr "Titolare del conto"
|
||||
|
||||
#. module: base
|
||||
#: model:ir.actions.act_window,name:base.act_values_form
|
||||
@@ -3434,7 +3434,7 @@ msgstr "Nome Menu"
|
||||
#. module: base
|
||||
#: field:ir.report.custom,title:0
|
||||
msgid "Report Title"
|
||||
msgstr ""
|
||||
msgstr "Titolo del report"
|
||||
|
||||
#. module: base
|
||||
#: field:ir.report.custom.fields,fontcolor:0
|
||||
@@ -3763,6 +3763,8 @@ msgstr "Crea / Scrivi"
|
||||
#: help:res.partner.category,active:0
|
||||
msgid "The active field allows you to hide the category without removing it."
|
||||
msgstr ""
|
||||
"Il campo attivo ti permette di nascondere la categoria senza doverla "
|
||||
"rimuovere."
|
||||
|
||||
#. module: base
|
||||
#: rml:ir.module.reference:0
|
||||
@@ -3806,7 +3808,7 @@ msgstr "Oggetti di Lavoro"
|
||||
#. module: base
|
||||
#: field:wizard.module.lang.export,advice:0
|
||||
msgid "Advice"
|
||||
msgstr ""
|
||||
msgstr "Consiglio"
|
||||
|
||||
#. module: base
|
||||
#: selection:module.lang.install,init,lang:0
|
||||
@@ -3819,6 +3821,8 @@ msgid ""
|
||||
"Provide the field name where the record id is stored after the create "
|
||||
"operations. If it is empty, you can not track the new record."
|
||||
msgstr ""
|
||||
"Assegna un nome al campo in cui viene registrato l'identificativo del "
|
||||
"record. Se è vuoto, non potrai tracciare il nuovo record"
|
||||
|
||||
#. module: base
|
||||
#: field:ir.ui.view,inherit_id:0
|
||||
@@ -3862,7 +3866,7 @@ msgstr ""
|
||||
#: field:ir.model.fields,state:0
|
||||
#: field:ir.model.grid,state:0
|
||||
msgid "Manually Created"
|
||||
msgstr ""
|
||||
msgstr "Creato manualmente"
|
||||
|
||||
#. module: base
|
||||
#: selection:ir.report.custom.fields,operation:0
|
||||
@@ -3933,7 +3937,7 @@ msgstr "Firma"
|
||||
#. module: base
|
||||
#: field:res.partner.category,complete_name:0
|
||||
msgid "Full Name"
|
||||
msgstr ""
|
||||
msgstr "Nome Completo"
|
||||
|
||||
#. module: base
|
||||
#: model:res.country,name:base.mz
|
||||
@@ -3944,7 +3948,7 @@ msgstr "Mozambico"
|
||||
#: model:ir.actions.act_window,name:base.grant_menu_access
|
||||
#: model:ir.ui.menu,name:base.menu_grant_menu_access
|
||||
msgid "Manage Menus"
|
||||
msgstr ""
|
||||
msgstr "Gestisci i menu"
|
||||
|
||||
#. module: base
|
||||
#: field:ir.actions.server,message:0
|
||||
@@ -4048,7 +4052,7 @@ msgstr "Mongolia"
|
||||
#: code:addons/base/res/res_user.py:0
|
||||
#, python-format
|
||||
msgid "Error"
|
||||
msgstr ""
|
||||
msgstr "Errore"
|
||||
|
||||
#. module: base
|
||||
#: view:res.partner.som:0
|
||||
@@ -4098,7 +4102,7 @@ msgstr "Formato File"
|
||||
#. module: base
|
||||
#: field:res.lang,iso_code:0
|
||||
msgid "ISO code"
|
||||
msgstr ""
|
||||
msgstr "Codice ISO"
|
||||
|
||||
#. module: base
|
||||
#: model:ir.model,name:base.model_res_config_view
|
||||
@@ -4351,12 +4355,12 @@ msgstr "Email Mittente"
|
||||
#. module: base
|
||||
#: field:ir.default,field_name:0
|
||||
msgid "Object Field"
|
||||
msgstr ""
|
||||
msgstr "Campo Oggetto"
|
||||
|
||||
#. module: base
|
||||
#: selection:module.lang.install,init,lang:0
|
||||
msgid "French (CH) / Français (CH)"
|
||||
msgstr ""
|
||||
msgstr "Francese (CH) / Français (CH)"
|
||||
|
||||
#. module: base
|
||||
#: selection:ir.ui.menu,icon:0
|
||||
|
||||
@@ -8,13 +8,13 @@ msgstr ""
|
||||
"Project-Id-Version: openobject-server\n"
|
||||
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"POT-Creation-Date: 2009-12-18 08:39+0000\n"
|
||||
"PO-Revision-Date: 2010-03-10 05:18+0000\n"
|
||||
"PO-Revision-Date: 2010-03-11 05:20+0000\n"
|
||||
"Last-Translator: Harry (Open ERP) <hmo@tinyerp.com>\n"
|
||||
"Language-Team: Japanese <ja@li.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Launchpad-Export-Date: 2010-03-11 04:37+0000\n"
|
||||
"X-Launchpad-Export-Date: 2010-03-12 04:50+0000\n"
|
||||
"X-Generator: Launchpad (build Unknown)\n"
|
||||
|
||||
#. module: base
|
||||
|
||||
@@ -8,13 +8,13 @@ msgstr ""
|
||||
"Project-Id-Version: openobject-server\n"
|
||||
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"POT-Creation-Date: 2009-12-18 08:39+0000\n"
|
||||
"PO-Revision-Date: 2010-03-10 14:09+0000\n"
|
||||
"Last-Translator: Christian Stange <Unknown>\n"
|
||||
"PO-Revision-Date: 2010-03-11 05:06+0000\n"
|
||||
"Last-Translator: OpenERP Administrators <Unknown>\n"
|
||||
"Language-Team: Norwegian Bokmal <nb@li.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Launchpad-Export-Date: 2010-03-11 04:37+0000\n"
|
||||
"X-Launchpad-Export-Date: 2010-03-12 04:50+0000\n"
|
||||
"X-Generator: Launchpad (build Unknown)\n"
|
||||
|
||||
#. module: base
|
||||
|
||||
@@ -14,7 +14,7 @@ msgstr ""
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Launchpad-Export-Date: 2010-03-11 04:37+0000\n"
|
||||
"X-Launchpad-Export-Date: 2010-03-12 04:50+0000\n"
|
||||
"X-Generator: Launchpad (build Unknown)\n"
|
||||
|
||||
#. module: base
|
||||
|
||||
@@ -7,13 +7,13 @@ msgstr ""
|
||||
"Project-Id-Version: OpenERP Server 5.0.0\n"
|
||||
"Report-Msgid-Bugs-To: support@openerp.com\n"
|
||||
"POT-Creation-Date: 2009-12-18 08:39+0000\n"
|
||||
"PO-Revision-Date: 2010-03-10 17:44+0000\n"
|
||||
"PO-Revision-Date: 2010-03-11 05:02+0000\n"
|
||||
"Last-Translator: Anders Wallenquist <anders.wallenquist@vertel.se>\n"
|
||||
"Language-Team: <>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Launchpad-Export-Date: 2010-03-11 04:38+0000\n"
|
||||
"X-Launchpad-Export-Date: 2010-03-12 04:51+0000\n"
|
||||
"X-Generator: Launchpad (build Unknown)\n"
|
||||
|
||||
#. module: base
|
||||
|
||||
@@ -7,13 +7,13 @@ msgstr ""
|
||||
"Project-Id-Version: OpenERP Server 5.0.0\n"
|
||||
"Report-Msgid-Bugs-To: support@openerp.com\n"
|
||||
"POT-Creation-Date: 2009-12-18 08:39+0000\n"
|
||||
"PO-Revision-Date: 2010-03-10 05:23+0000\n"
|
||||
"PO-Revision-Date: 2010-03-11 05:11+0000\n"
|
||||
"Last-Translator: Fabien (Open ERP) <fp@tinyerp.com>\n"
|
||||
"Language-Team: \n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Launchpad-Export-Date: 2010-03-11 04:38+0000\n"
|
||||
"X-Launchpad-Export-Date: 2010-03-12 04:51+0000\n"
|
||||
"X-Generator: Launchpad (build Unknown)\n"
|
||||
|
||||
#. module: base
|
||||
|
||||
@@ -1252,9 +1252,10 @@
|
||||
<newline/>
|
||||
<label colspan="4" string="Access all the fields related to the current object using expression in double brackets, i.e. [[ object.partner_id.name ]]" align="0.0"/>
|
||||
</page>
|
||||
<page string="Create / Write" attrs="{'invisible':[('state','!=','object_create'),('state','!=','object_write')]}">
|
||||
<page string="Create / Write / Copy" attrs="{'invisible':[('state','!=','object_create'), ('state','!=','object_write'), ('state','!=','object_copy')]}">
|
||||
<separator colspan="4" string="Fields Mapping"/>
|
||||
<field name="srcmodel_id" select="2" attrs="{'required':[('state','!=','dummy'), ('state','!=','sms'), ('state','!=','code'), ('state','!=','loop'),('state','!=','trigger'), ('state','!=','client_action'), ('state','!=','email'), ('state','!=','sms'), ('state','!=','other')]}"/>
|
||||
<field name="srcmodel_id" select="2" attrs="{'required':[('state','!=','dummy'), ('state','!=','sms'), ('state','!=','code'), ('state','!=','loop'), ('state','!=','trigger'), ('state','!=','object_copy'), ('state','!=','client_action'), ('state','!=','email'), ('state','!=','sms'), ('state','!=','other')]}"/>
|
||||
<field name="copy_object" on_change="change_object(copy_object, state)" select="2" attrs="{'required':[('state','!=','dummy'), ('state','!=','sms'), ('state','!=','code'), ('state','!=','loop'), ('state','!=','trigger'), ('state','!=','object_write'), ('state','!=','object_create'), ('state','!=','client_action'), ('state','!=','email'), ('state','!=','sms'), ('state','!=','other')]}"/>
|
||||
<field name="fields_lines" nolabel="1" select="2" colspan="4">
|
||||
<tree string="Field Mappings" editable="top">
|
||||
<field name="col1" domain="[('model_id','=',parent.srcmodel_id or parent.model_id)]"/>
|
||||
|
||||
@@ -159,7 +159,7 @@ class act_window(osv.osv):
|
||||
]
|
||||
|
||||
def get_filters(self, cr, uid, model):
|
||||
cr.execute('select id from ir_act_window a where a.id not in (select act_id from ir_act_window_user_rel) and a.res_model=\''+model+'\' and a.filter=\'1\';')
|
||||
cr.execute('SELECT id FROM ir_act_window a WHERE a.id not in (SELECT act_id FROM ir_act_window_user_rel) AND a.res_model=\''+model+'\' and a.filter=\'1\';')
|
||||
all_ids = cr.fetchall()
|
||||
filter_ids = map(lambda x:x[0],all_ids)
|
||||
act_ids = self.search(cr,uid,[('res_model','=',model),('filter','=',1),('default_user_ids','in',(','.join(map(str,[uid,])),))])
|
||||
@@ -377,16 +377,34 @@ server_object_lines()
|
||||
class actions_server(osv.osv):
|
||||
|
||||
def _select_signals(self, cr, uid, context={}):
|
||||
cr.execute("select distinct t.signal as key, t.signal || ' - [ ' || w.osv || ' ] ' as val from wkf w, wkf_activity a, wkf_transition t "\
|
||||
" where w.id = a.wkf_id " \
|
||||
" and t.act_from = a.id " \
|
||||
" or t.act_to = a.id and t.signal not in (null, NULL)")
|
||||
cr.execute("SELECT distinct w.osv, t.signal FROM wkf w, wkf_activity a, wkf_transition t \
|
||||
WHERE w.id = a.wkf_id AND t.act_from = a.id OR t.act_to = a.id AND t.signal!='' \
|
||||
AND t.signal not in (null, NULL)")
|
||||
result = cr.fetchall() or []
|
||||
res = []
|
||||
for rs in result:
|
||||
if rs[0] is not None and rs[1] is not None:
|
||||
res.append(rs)
|
||||
line = rs[0], "%s - (%s)" % (rs[1], rs[0])
|
||||
res.append(line)
|
||||
return res
|
||||
|
||||
def _select_objects(self, cr, uid, context={}):
|
||||
model_pool = self.pool.get('ir.model')
|
||||
ids = model_pool.search(cr, uid, [('name','not ilike','.')])
|
||||
res = model_pool.read(cr, uid, ids, ['model', 'name'])
|
||||
return [(r['model'], r['name']) for r in res] + [('','')]
|
||||
|
||||
def change_object(self, cr, uid, ids, copy_object, state, context={}):
|
||||
if state == 'object_copy':
|
||||
model_pool = self.pool.get('ir.model')
|
||||
model = copy_object.split(',')[0]
|
||||
mid = model_pool.search(cr, uid, [('model','=',model)])
|
||||
return {
|
||||
'value':{'srcmodel_id':mid[0]},
|
||||
'context':context
|
||||
}
|
||||
else:
|
||||
return {}
|
||||
|
||||
_name = 'ir.actions.server'
|
||||
_table = 'ir_act_server'
|
||||
@@ -404,6 +422,7 @@ class actions_server(osv.osv):
|
||||
('email','Email'),
|
||||
('sms','SMS'),
|
||||
('object_create','Create Object'),
|
||||
('object_copy','Copy Object'),
|
||||
('object_write','Write Object'),
|
||||
('other','Multi Actions'),
|
||||
], 'Action Type', required=True, size=32, help="Type of the Action that is to be executed"),
|
||||
@@ -428,6 +447,7 @@ class actions_server(osv.osv):
|
||||
'write_id':fields.char('Write Id', size=256, help="Provide the field name that the record id refers to for the write operation. If it is empty it will refer to the active id of the object."),
|
||||
'loop_action':fields.many2one('ir.actions.server', 'Loop Action', help="Select the action that will be executed. Loop action will not be avaliable inside loop."),
|
||||
'expression':fields.char('Loop Expression', size=512, help="Enter the field/expression that will return the list. E.g. select the sale order in Object, and you can have loop on the sales order line. Expression = `object.order_line`."),
|
||||
'copy_object': fields.reference('Copy Of', selection=_select_objects, size=256),
|
||||
}
|
||||
_defaults = {
|
||||
'state': lambda *a: 'dummy',
|
||||
@@ -666,6 +686,26 @@ class actions_server(osv.osv):
|
||||
cr.commit()
|
||||
if action.record_id:
|
||||
self.pool.get(action.model_id.model).write(cr, uid, [context.get('active_id')], {action.record_id.name:res_id})
|
||||
|
||||
if action.state == 'object_copy':
|
||||
res = {}
|
||||
for exp in action.fields_lines:
|
||||
euq = exp.value
|
||||
if exp.type == 'equation':
|
||||
obj_pool = self.pool.get(action.model_id.model)
|
||||
obj = obj_pool.browse(cr, uid, context['active_id'], context=context)
|
||||
expr = eval(euq, {'context':context, 'object': obj, 'time':time})
|
||||
else:
|
||||
expr = exp.value
|
||||
res[exp.col1.name] = expr
|
||||
|
||||
obj_pool = None
|
||||
res_id = False
|
||||
|
||||
model = action.copy_object.split(',')[0]
|
||||
cid = action.copy_object.split(',')[1]
|
||||
obj_pool = self.pool.get(model)
|
||||
res_id = obj_pool.copy(cr, uid, int(cid), res)
|
||||
|
||||
return False
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
#
|
||||
# OpenERP, Open Source Management Solution
|
||||
# Copyright (C) 2004-2009 Tiny SPRL (<http://tiny.be>).
|
||||
#
|
||||
@@ -15,12 +15,13 @@
|
||||
# GNU Affero General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
##############################################################################
|
||||
|
||||
from osv import fields,osv
|
||||
from lxml import etree
|
||||
from tools import graph
|
||||
import tools
|
||||
import netsvc
|
||||
import os
|
||||
@@ -59,6 +60,7 @@ class view(osv.osv):
|
||||
('mdx','mdx'),
|
||||
('graph', 'Graph'),
|
||||
('calendar', 'Calendar'),
|
||||
('diagram','Diagram'),
|
||||
('gantt', 'Gantt'),
|
||||
('search','Search')), 'View Type', required=True),
|
||||
'arch': fields.text('View Architecture', required=True),
|
||||
@@ -129,6 +131,64 @@ class view(osv.osv):
|
||||
return result
|
||||
|
||||
return super(view, self).write(cr, uid, ids, vals, context)
|
||||
|
||||
def graph_get(self, cr, uid, id, model, node_obj, conn_obj, src_node, des_node,signal,scale,context={}):
|
||||
nodes=[]
|
||||
nodes_name=[]
|
||||
transitions=[]
|
||||
start=[]
|
||||
tres={}
|
||||
sig={}
|
||||
no_ancester=[]
|
||||
blank_nodes = []
|
||||
|
||||
_Model_Obj=self.pool.get(model)
|
||||
_Node_Obj=self.pool.get(node_obj)
|
||||
_Arrow_Obj=self.pool.get(conn_obj)
|
||||
|
||||
for model_key,model_value in _Model_Obj._columns.items():
|
||||
if model_value._type=='one2many':
|
||||
if model_value._obj==node_obj:
|
||||
_Node_Field=model_key
|
||||
_Model_Field=model_value._fields_id
|
||||
flag=False
|
||||
for node_key,node_value in _Node_Obj._columns.items():
|
||||
if node_value._type=='one2many':
|
||||
if node_value._obj==conn_obj:
|
||||
if src_node in _Arrow_Obj._columns and flag:
|
||||
_Source_Field=node_key
|
||||
if des_node in _Arrow_Obj._columns and not flag:
|
||||
_Destination_Field=node_key
|
||||
flag = True
|
||||
|
||||
datas = _Model_Obj.read(cr, uid, id, [],context)
|
||||
for a in _Node_Obj.read(cr,uid,datas[_Node_Field],[]):
|
||||
if a[_Source_Field] or a[_Destination_Field]:
|
||||
nodes_name.append((a['id'],a['name']))
|
||||
nodes.append(a['id'])
|
||||
else:
|
||||
blank_nodes.append({'id': a['id'],'name':a['name']})
|
||||
|
||||
if a.has_key('flow_start') and a['flow_start']:
|
||||
start.append(a['id'])
|
||||
else:
|
||||
if not a[_Source_Field]:
|
||||
no_ancester.append(a['id'])
|
||||
for t in _Arrow_Obj.read(cr,uid, a[_Destination_Field],[]):
|
||||
transitions.append((a['id'], t[des_node][0]))
|
||||
tres[str(t['id'])] = (a['id'],t[des_node][0])
|
||||
if t.has_key(str(signal)) and str(t[signal])=='False':
|
||||
t[signal]=' '
|
||||
sig[str(t['id'])] = (a['id'],t.get(signal,' '))
|
||||
g = graph(nodes, transitions, no_ancester)
|
||||
g.process(start)
|
||||
g.scale(*scale)
|
||||
result = g.result_get()
|
||||
results = {}
|
||||
for node in nodes_name:
|
||||
results[str(node[0])] = result[node[0]]
|
||||
results[str(node[0])]['name'] = node[1]
|
||||
return {'nodes': results, 'transitions': tres, 'signal' : sig, 'blank_nodes': blank_nodes}
|
||||
view()
|
||||
|
||||
class view_sc(osv.osv):
|
||||
|
||||
@@ -44,45 +44,64 @@ class workflow(osv.osv):
|
||||
wf_service.clear_cache(cr, user)
|
||||
return super(workflow, self).write(cr, user, ids, vals, context=context)
|
||||
|
||||
def get_active_workitems(self, cr, uid, res, res_id, context={}):
|
||||
|
||||
cr.execute('select * from wkf where osv=%s limit 1',(res,))
|
||||
wkfinfo = cr.dictfetchone()
|
||||
workitems = []
|
||||
|
||||
if wkfinfo:
|
||||
cr.execute('SELECT id FROM wkf_instance \
|
||||
WHERE res_id=%s AND wkf_id=%s \
|
||||
ORDER BY state LIMIT 1',
|
||||
(res_id, wkfinfo['id']))
|
||||
inst_id = cr.fetchone()
|
||||
|
||||
cr.execute('select act_id,count(*) from wkf_workitem where inst_id=%s group by act_id', (inst_id,))
|
||||
workitems = dict(cr.fetchall())
|
||||
|
||||
return {'wkf': wkfinfo, 'workitems': workitems}
|
||||
|
||||
|
||||
#
|
||||
# scale = (vertical-distance, horizontal-distance, min-node-width(optional), min-node-height(optional), margin(default=20))
|
||||
#
|
||||
|
||||
|
||||
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_name.append((a.id,a.name))
|
||||
nodes.append(a.id)
|
||||
if a.flow_start:
|
||||
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, 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 node in nodes_name:
|
||||
results[str(node[0])] = result[node[0]]
|
||||
results[str(node[0])]['name'] = node[1]
|
||||
|
||||
return {'nodes': results, 'transitions': tres}
|
||||
# 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_name.append((a.id,a.name))
|
||||
# nodes.append(a.id)
|
||||
# if a.flow_start:
|
||||
# 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, 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 node in nodes_name:
|
||||
# results[str(node[0])] = result[node[0]]
|
||||
# results[str(node[0])]['name'] = node[1]
|
||||
#
|
||||
# return {'nodes': results, 'transitions': tres}
|
||||
|
||||
|
||||
def create(self, cr, user, vals, context=None):
|
||||
|
||||
@@ -2,13 +2,13 @@
|
||||
<openerp>
|
||||
<data>
|
||||
<menuitem id="menu_workflow_root" name="Workflow Definitions" parent="menu_custom"/>
|
||||
|
||||
|
||||
<!--
|
||||
================================
|
||||
Workflows
|
||||
================================
|
||||
-->
|
||||
|
||||
|
||||
<record id="view_workflow_form" model="ir.ui.view">
|
||||
<field name="name">workflow.form</field>
|
||||
<field name="model">workflow</field>
|
||||
@@ -23,6 +23,25 @@
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="view_workflow_diagram" model="ir.ui.view">
|
||||
<field name="name">workflow.diagram</field>
|
||||
<field name="model">workflow</field>
|
||||
<field name="type">diagram</field>
|
||||
<field name="arch" type="xml">
|
||||
<diagram string="Workflow Editor">
|
||||
<node object="workflow.activity">
|
||||
<field name="name"/>
|
||||
<field name="kind"/>
|
||||
</node>
|
||||
<arrow object="workflow.transition" source="act_from" destination="act_to" signal="signal">
|
||||
<field name="act_from"/>
|
||||
<field name="act_to"/>
|
||||
<field name="signal"/>
|
||||
</arrow>
|
||||
</diagram>
|
||||
</field>
|
||||
</record>
|
||||
<record id="view_workflow_tree" model="ir.ui.view">
|
||||
<field name="name">workflow.tree</field>
|
||||
<field name="model">workflow</field>
|
||||
@@ -35,12 +54,13 @@
|
||||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
|
||||
<record id="action_workflow_form" model="ir.actions.act_window">
|
||||
<field name="name">Workflows</field>
|
||||
<field name="res_model">workflow</field>
|
||||
<field name="view_type">form</field>
|
||||
<field name="view_id" ref="view_workflow_tree"/>
|
||||
<field name="view_mode">tree,form,diagram</field>
|
||||
</record>
|
||||
<menuitem action="action_workflow_form" id="menu_workflow" parent="base.menu_workflow_root"/>
|
||||
|
||||
@@ -109,7 +129,7 @@
|
||||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
|
||||
<record id="action_workflow_activity_form" model="ir.actions.act_window">
|
||||
<field name="name">Activities</field>
|
||||
<field name="res_model">workflow.activity</field>
|
||||
@@ -117,14 +137,14 @@
|
||||
<field name="view_id" ref="view_workflow_activity_tree"/>
|
||||
</record>
|
||||
<menuitem action="action_workflow_activity_form" id="menu_workflow_activity" parent="base.menu_workflow_root"/>
|
||||
|
||||
|
||||
|
||||
|
||||
<!--
|
||||
================================
|
||||
Transitions
|
||||
================================
|
||||
-->
|
||||
|
||||
|
||||
<record id="view_workflow_transition_form" model="ir.ui.view">
|
||||
<field name="name">workflow.transition.form</field>
|
||||
<field name="model">workflow.transition</field>
|
||||
@@ -157,8 +177,8 @@
|
||||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
|
||||
|
||||
|
||||
<record id="action_workflow_transition_form" model="ir.actions.act_window">
|
||||
<field name="name">Transitions</field>
|
||||
<field name="res_model">workflow.transition</field>
|
||||
@@ -166,13 +186,13 @@
|
||||
<field name="view_id" ref="view_workflow_transition_tree"/>
|
||||
</record>
|
||||
<menuitem action="action_workflow_transition_form" id="menu_workflow_transition" parent="base.menu_workflow_root"/>
|
||||
|
||||
|
||||
<!--
|
||||
================================
|
||||
Instances
|
||||
================================
|
||||
-->
|
||||
|
||||
|
||||
<record id="view_workflow_instance_form" model="ir.ui.view">
|
||||
<field name="name">workflow.instance.form</field>
|
||||
<field name="model">workflow.instance</field>
|
||||
@@ -201,7 +221,7 @@
|
||||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
|
||||
<record id="action_workflow_instance_form" model="ir.actions.act_window">
|
||||
<field name="name">Instances</field>
|
||||
<field name="res_model">workflow.instance</field>
|
||||
@@ -209,13 +229,13 @@
|
||||
<field name="view_id" ref="view_workflow_instance_tree"/>
|
||||
</record>
|
||||
<menuitem action="action_workflow_instance_form" id="menu_workflow_instance" parent="base.menu_low_workflow"/>
|
||||
|
||||
|
||||
<!--
|
||||
================================
|
||||
Workitems
|
||||
================================
|
||||
-->
|
||||
|
||||
|
||||
<record id="view_workflow_workitem_form" model="ir.ui.view">
|
||||
<field name="name">workflow.workitem.form</field>
|
||||
<field name="model">workflow.workitem</field>
|
||||
@@ -242,7 +262,7 @@
|
||||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
|
||||
<record id="action_workflow_workitem_form" model="ir.actions.act_window">
|
||||
<field name="name">Workitems</field>
|
||||
<field name="res_model">workflow.workitem</field>
|
||||
@@ -250,6 +270,6 @@
|
||||
<field name="view_id" ref="view_workflow_workitem_tree"/>
|
||||
</record>
|
||||
<menuitem action="action_workflow_workitem_form" id="menu_workflow_workitem" parent="base.menu_low_workflow"/>
|
||||
|
||||
|
||||
</data>
|
||||
</openerp>
|
||||
|
||||
@@ -31,6 +31,45 @@
|
||||
</rng:element>
|
||||
</rng:define>
|
||||
|
||||
<rng:define name="diagram">
|
||||
<rng:element name="diagram">
|
||||
<rng:optional><rng:attribute name="string"/></rng:optional>
|
||||
<rng:zeroOrMore>
|
||||
<rng:choice>
|
||||
<rng:ref name="node"/>
|
||||
<rng:ref name="arrow"/>
|
||||
</rng:choice>
|
||||
</rng:zeroOrMore>
|
||||
</rng:element>
|
||||
</rng:define>
|
||||
|
||||
<rng:define name="node">
|
||||
<rng:element name="node">
|
||||
<rng:attribute name="object"/>
|
||||
<rng:optional><rng:attribute name="shape"/></rng:optional>
|
||||
<rng:optional><rng:attribute name="bgcolor"/></rng:optional>
|
||||
<rng:zeroOrMore>
|
||||
<rng:choice>
|
||||
<rng:ref name="field"/>
|
||||
</rng:choice>
|
||||
</rng:zeroOrMore>
|
||||
</rng:element>
|
||||
</rng:define>
|
||||
|
||||
<rng:define name="arrow">
|
||||
<rng:element name="arrow">
|
||||
<rng:attribute name="object" />
|
||||
<rng:attribute name="source" />
|
||||
<rng:attribute name="destination" />
|
||||
<rng:optional><rng:attribute name="signal"/></rng:optional>
|
||||
<rng:zeroOrMore>
|
||||
<rng:choice>
|
||||
<rng:ref name="field"/>
|
||||
</rng:choice>
|
||||
</rng:zeroOrMore>
|
||||
</rng:element>
|
||||
</rng:define>
|
||||
|
||||
<rng:define name="tree">
|
||||
<rng:element name="tree">
|
||||
<rng:optional><rng:attribute name="string"/></rng:optional>
|
||||
@@ -359,6 +398,7 @@
|
||||
<rng:optional><rng:attribute name="selection"/></rng:optional>
|
||||
<rng:zeroOrMore>
|
||||
<rng:choice>
|
||||
<rng:ref name="diagram"/>
|
||||
<rng:ref name="attribute" />
|
||||
<rng:ref name="form"/>
|
||||
<rng:ref name="data"/>
|
||||
@@ -545,6 +585,7 @@
|
||||
|
||||
<rng:start>
|
||||
<rng:choice>
|
||||
<rng:ref name="diagram" />
|
||||
<rng:ref name="form" />
|
||||
<rng:ref name="search" />
|
||||
<rng:ref name="group" />
|
||||
|
||||
@@ -193,6 +193,7 @@
|
||||
<rng:optional> <rng:attribute name="view_mode"/> </rng:optional>
|
||||
<rng:optional> <rng:attribute name="multi"/> </rng:optional>
|
||||
<rng:optional> <rng:attribute name="target"/> </rng:optional>
|
||||
<rng:optional> <rng:attribute name="key2"/> </rng:optional>
|
||||
<rng:optional> <rng:attribute name="groups"/> </rng:optional>
|
||||
<rng:empty />
|
||||
</rng:element>
|
||||
|
||||
+1
-3
@@ -151,9 +151,7 @@ def init_logger():
|
||||
if tools.config['syslog']:
|
||||
# SysLog Handler
|
||||
if os.name == 'nt':
|
||||
handler = logging.handlers.NTEventLogHandler("%s %s" %
|
||||
(release.description,
|
||||
release.version))
|
||||
handler = logging.handlers.NTEventLogHandler("%s %s" % (release.description, release.version))
|
||||
else:
|
||||
handler = logging.handlers.SysLogHandler('/dev/log')
|
||||
formatter = logging.Formatter("%s %s" % (release.description, release.version) + ':%(levelname)s:%(name)s:%(message)s')
|
||||
|
||||
@@ -66,6 +66,11 @@ for name, value in [('addons_path', tools.config['addons_path']),
|
||||
('database user', tools.config['db_user'])]:
|
||||
logger.notifyChannel("server", netsvc.LOG_INFO, "%s - %s" % ( name, value ))
|
||||
|
||||
# Don't allow if the connection to PostgreSQL done by postgres user
|
||||
if tools.config['db_user'] == 'postgres':
|
||||
logger.notifyChannel("server", netsvc.LOG_ERROR, "%s" % ("Attempted to connect database with postgres user. This is a security flaws, aborting."))
|
||||
sys.exit(1)
|
||||
|
||||
import time
|
||||
|
||||
#----------------------------------------------------------
|
||||
|
||||
+15
-2
@@ -1188,7 +1188,21 @@ class orm_template(object):
|
||||
button.set('readonly', str(int(not can_click)))
|
||||
|
||||
arch = etree.tostring(node, encoding="utf-8").replace('\t', '')
|
||||
fields = self.fields_get(cr, user, fields_def.keys(), context)
|
||||
|
||||
#code for diagram view.
|
||||
fields={}
|
||||
if node.tag=='diagram':
|
||||
if node.getchildren()[0].tag=='node':
|
||||
node_fields=self.pool.get(node.getchildren()[0].get('object')).fields_get(cr, user, fields_def.keys(), context)
|
||||
if node.getchildren()[1].tag=='arrow':
|
||||
arrow_fields = self.pool.get(node.getchildren()[1].get('object')).fields_get(cr, user, fields_def.keys(), context)
|
||||
for key,value in node_fields.items():
|
||||
fields[key]=value
|
||||
for key,value in arrow_fields.items():
|
||||
fields[key]=value
|
||||
else:
|
||||
fields = self.fields_get(cr, user, fields_def.keys(), context)
|
||||
|
||||
for field in fields_def:
|
||||
if field == 'id':
|
||||
# sometime, the view may containt the (invisible) field 'id' needed for a domain (when 2 objects have cross references)
|
||||
@@ -1204,7 +1218,6 @@ class orm_template(object):
|
||||
msg += "\n\nEither you wrongly customised this view, or some modules bringing those views are not compatible with your current data model"
|
||||
netsvc.Logger().notifyChannel('orm', netsvc.LOG_ERROR, msg)
|
||||
raise except_orm('View error', msg)
|
||||
|
||||
return arch, fields
|
||||
|
||||
def __get_default_calendar_view(self):
|
||||
|
||||
+1
-2
@@ -24,7 +24,7 @@ pool_dic = {}
|
||||
def get_db_and_pool(db_name, force_demo=False, status=None, update_module=False):
|
||||
if not status:
|
||||
status={}
|
||||
|
||||
|
||||
db = get_db_only(db_name)
|
||||
|
||||
if db_name in pool_dic:
|
||||
@@ -81,4 +81,3 @@ def get_pool(db_name, force_demo=False, status=None, update_module=False):
|
||||
return pool
|
||||
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||
|
||||
|
||||
+12
-3
@@ -25,12 +25,20 @@ import cStringIO
|
||||
import marshal
|
||||
|
||||
class Myexception(Exception):
|
||||
"""
|
||||
custome exception object store
|
||||
* faultcode
|
||||
* faulestring
|
||||
* args
|
||||
"""
|
||||
|
||||
def __init__(self, faultCode, faultString):
|
||||
self.faultCode = faultCode
|
||||
self.faultString = faultString
|
||||
self.args = (faultCode, faultString)
|
||||
|
||||
class mysocket:
|
||||
|
||||
def __init__(self, sock=None):
|
||||
if sock is None:
|
||||
self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
@@ -40,14 +48,17 @@ class mysocket:
|
||||
# prepare this socket for long operations: it may block for infinite
|
||||
# time, but should exit as soon as the net is down
|
||||
self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1)
|
||||
|
||||
def connect(self, host, port=False):
|
||||
if not port:
|
||||
protocol, buf = host.split('//')
|
||||
host, port = buf.split(':')
|
||||
self.sock.connect((host, int(port)))
|
||||
|
||||
def disconnect(self):
|
||||
self.sock.shutdown(socket.SHUT_RDWR)
|
||||
self.sock.close()
|
||||
|
||||
def mysend(self, msg, exception=False, traceback=None):
|
||||
msg = cPickle.dumps([msg,traceback])
|
||||
size = len(msg)
|
||||
@@ -59,6 +70,7 @@ class mysocket:
|
||||
if sent == 0:
|
||||
raise RuntimeError, "socket connection broken"
|
||||
totalsent = totalsent + sent
|
||||
|
||||
def myreceive(self):
|
||||
buf=''
|
||||
while len(buf) < 8:
|
||||
@@ -89,6 +101,3 @@ class mysocket:
|
||||
raise res[0]
|
||||
else:
|
||||
return res[0]
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -369,9 +369,10 @@ form: module.record_id""" % (xml_id,)
|
||||
domain = rec.get('domain','').encode('utf-8') or '{}'
|
||||
context = rec.get('context','').encode('utf-8') or '{}'
|
||||
res_model = rec.get('res_model','').encode('utf-8')
|
||||
src_model = rec.get('src_model','').encode('utf-8')
|
||||
src_model = rec.get('src_model','').encode('utf-8')
|
||||
view_type = rec.get('view_type','').encode('utf-8') or 'form'
|
||||
view_mode = rec.get('view_mode','').encode('utf-8') or 'tree,form'
|
||||
|
||||
usage = rec.get('usage','').encode('utf-8')
|
||||
limit = rec.get('limit','').encode('utf-8')
|
||||
auto_refresh = rec.get('auto_refresh','').encode('utf-8')
|
||||
@@ -419,7 +420,8 @@ form: module.record_id""" % (xml_id,)
|
||||
self.idref[xml_id] = int(id)
|
||||
|
||||
if src_model:
|
||||
keyword = 'client_action_relate'
|
||||
#keyword = 'client_action_relate'
|
||||
keyword = rec.get('key2','').encode('utf-8') or 'client_action_relate'
|
||||
keys = [('action', keyword), ('res_model', res_model)]
|
||||
value = 'ir.actions.act_window,'+str(id)
|
||||
replace = rec.get('replace','') or True
|
||||
|
||||
+247
-247
@@ -1,7 +1,7 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
#
|
||||
# OpenERP, Open Source Management Solution
|
||||
# Copyright (C) 2004-2009 Tiny SPRL (<http://tiny.be>).
|
||||
#
|
||||
@@ -16,7 +16,7 @@
|
||||
# GNU Affero General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
##############################################################################
|
||||
|
||||
@@ -26,80 +26,80 @@ import math
|
||||
class graph(object):
|
||||
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
|
||||
@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])
|
||||
self.transitions = trans
|
||||
self.result = {}
|
||||
|
||||
|
||||
|
||||
|
||||
def init_rank(self):
|
||||
"""Computes rank of the nodes of the graph by finding initial feasible tree
|
||||
"""
|
||||
self.edge_wt = {}
|
||||
for link in self.links:
|
||||
self.edge_wt[link] = self.result[link[1]]['x'] - self.result[link[0]]['x']
|
||||
|
||||
|
||||
tot_node = self.partial_order.__len__()
|
||||
#do until all the nodes in the component are searched
|
||||
#do until all the nodes in the component are searched
|
||||
while self.tight_tree()<tot_node:
|
||||
list_node = []
|
||||
list_edge = []
|
||||
|
||||
|
||||
for node in self.nodes:
|
||||
if node not in self.reachable_nodes:
|
||||
list_node.append(node)
|
||||
|
||||
|
||||
for edge in self.edge_wt:
|
||||
if edge not in self.tree_edges:
|
||||
list_edge.append(edge)
|
||||
|
||||
|
||||
slack = 100
|
||||
|
||||
|
||||
for edge in list_edge:
|
||||
if ((self.reachable_nodes.__contains__(edge[0]) and edge[1] not in self.reachable_nodes) or
|
||||
if ((self.reachable_nodes.__contains__(edge[0]) and edge[1] not in self.reachable_nodes) or
|
||||
(self.reachable_nodes.__contains__(edge[1]) and edge[0] not in self.reachable_nodes)):
|
||||
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.edge_wt[new_edge]-1)
|
||||
else:
|
||||
delta = self.edge_wt[new_edge]-1
|
||||
|
||||
|
||||
for node in self.result:
|
||||
if node in self.reachable_nodes:
|
||||
self.result[node]['x'] += delta
|
||||
|
||||
|
||||
for edge in self.edge_wt:
|
||||
self.edge_wt[edge] = self.result[edge[1]]['x'] - self.result[edge[0]]['x']
|
||||
|
||||
self.init_cutvalues()
|
||||
|
||||
|
||||
self.edge_wt[edge] = self.result[edge[1]]['x'] - self.result[edge[0]]['x']
|
||||
|
||||
self.init_cutvalues()
|
||||
|
||||
|
||||
def tight_tree(self):
|
||||
self.reachable_nodes = []
|
||||
self.tree_edges = []
|
||||
self.reachable_node(self.start)
|
||||
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
|
||||
"""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 edge in self.edge_wt:
|
||||
@@ -109,27 +109,27 @@ class graph(object):
|
||||
if edge[1] not in self.reachable_nodes:
|
||||
self.reachable_nodes.append(edge[1])
|
||||
self.reachable_node(edge[1])
|
||||
|
||||
|
||||
|
||||
|
||||
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
|
||||
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
|
||||
for source_node in self.transitions:
|
||||
if source_node in self.head_nodes:
|
||||
if source_node in self.head_nodes:
|
||||
for dest_node in self.transitions[source_node]:
|
||||
if dest_node not in self.head_nodes:
|
||||
negative+=1
|
||||
@@ -140,62 +140,62 @@ class graph(object):
|
||||
|
||||
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 edge in rest_edges:
|
||||
if edge[0]==node:
|
||||
if edge[0]==node:
|
||||
self.head_component(edge[1],rest_edges)
|
||||
|
||||
|
||||
|
||||
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] = {'y': None, 'x':level, 'mark':0}
|
||||
else:
|
||||
if level > self.result[node]['x']:
|
||||
self.result[node]['x'] = level
|
||||
|
||||
|
||||
if self.result[node]['mark']==0:
|
||||
self.result[node]['mark'] = 1
|
||||
for sec_end in self.transitions.get(node, []):
|
||||
self.process_ranking(sec_end, 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 sec_end in self.transitions.get(node, []):
|
||||
self.links.append((node, sec_end))
|
||||
self.make_acyclic(node, sec_end, level+1, tree)
|
||||
|
||||
return tree
|
||||
return tree
|
||||
|
||||
|
||||
|
||||
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
|
||||
"""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
|
||||
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']
|
||||
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))
|
||||
@@ -205,9 +205,9 @@ class graph(object):
|
||||
elif math.fabs(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
|
||||
@@ -216,144 +216,144 @@ class graph(object):
|
||||
self.tree_edges.__delitem__(self.tree_edges.index(e))
|
||||
self.tree_edges.append(f)
|
||||
self.init_cutvalues()
|
||||
|
||||
|
||||
|
||||
|
||||
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
|
||||
"""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)
|
||||
|
||||
|
||||
if self.head_nodes.__contains__(edge[1]):
|
||||
l = []
|
||||
for node in self.result:
|
||||
if not self.head_nodes.__contains__(node):
|
||||
l.append(node)
|
||||
l.append(node)
|
||||
self.head_nodes = l
|
||||
|
||||
|
||||
slack = 100
|
||||
new_edge = edge
|
||||
for source_node in self.transitions:
|
||||
if source_node in self.head_nodes:
|
||||
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.edge_wt[edge]-1)):
|
||||
slack = self.edge_wt[edge]-1
|
||||
new_edge = (source_node, dest_node)
|
||||
|
||||
return new_edge
|
||||
|
||||
|
||||
return new_edge
|
||||
|
||||
|
||||
def leave_edge(self):
|
||||
"""Returns the edge with negative cut_value(if exists)
|
||||
"""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 None
|
||||
|
||||
|
||||
|
||||
return None
|
||||
|
||||
|
||||
def finalize_rank(self, node, level):
|
||||
self.result[node]['x'] = 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.
|
||||
"""
|
||||
|
||||
|
||||
least_rank = min(map(lambda x: x['x'], self.result.values()))
|
||||
|
||||
|
||||
if(least_rank!=0):
|
||||
for node in self.result:
|
||||
self.result[node]['x']-=least_rank
|
||||
|
||||
|
||||
def make_chain(self):
|
||||
"""Edges between nodes more than one rank apart are replaced by chains of unit
|
||||
self.result[node]['x']-=least_rank
|
||||
|
||||
|
||||
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]]['x']
|
||||
end = self.result[edge[1]]['x']
|
||||
|
||||
for rank in range(start+1, end):
|
||||
if not self.result.get((rank, 'temp'), False):
|
||||
|
||||
for rank in range(start+1, end):
|
||||
if not self.result.get((rank, 'temp'), False):
|
||||
self.result[(rank, 'temp')] = {'y': None, 'x': rank, 'mark': 0}
|
||||
|
||||
|
||||
for rank in range(start, end):
|
||||
if start==rank:
|
||||
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'))
|
||||
|
||||
|
||||
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]['y']:
|
||||
"""
|
||||
if not self.result[node]['y']:
|
||||
self.result[node]['y'] = self.order[level]
|
||||
self.order[level] = self.order[level]+1
|
||||
|
||||
self.order[level] = self.order[level]+1
|
||||
|
||||
for sec_end in self.transitions.get(node, []):
|
||||
self.init_order(sec_end, self.result[sec_end]['x'])
|
||||
|
||||
|
||||
|
||||
|
||||
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:
|
||||
|
||||
for level in self.levels:
|
||||
|
||||
node_median = []
|
||||
nodes = self.levels[level]
|
||||
for node in nodes:
|
||||
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))
|
||||
|
||||
new_list = [tuple[0] for tuple in sort_list]
|
||||
|
||||
|
||||
self.levels[level] = new_list
|
||||
order = 0
|
||||
for node in nodes:
|
||||
self.result[node]['y'] = order
|
||||
order +=1
|
||||
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
|
||||
"""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
|
||||
return -1.0
|
||||
elif l%2 == 1:
|
||||
return adj_nodes[m]#median of the middle element
|
||||
elif l==2:
|
||||
@@ -361,106 +361,106 @@ class graph(object):
|
||||
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)
|
||||
|
||||
|
||||
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
|
||||
|
||||
@param node: node to process
|
||||
@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 src in pre_level_nodes:
|
||||
if (self.transitions.get(src) and self.transitions[src].__contains__(node)):
|
||||
adj_nodes.append(self.result[src]['y'])
|
||||
|
||||
return adj_nodes
|
||||
|
||||
|
||||
|
||||
return adj_nodes
|
||||
|
||||
|
||||
def preprocess_order(self):
|
||||
levels = {}
|
||||
|
||||
|
||||
for r in self.partial_order:
|
||||
l = self.result[r]['x']
|
||||
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
|
||||
|
||||
|
||||
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
|
||||
mid_pos = 0.0
|
||||
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
|
||||
list = self.levels[level]
|
||||
factor = (max_level - no) * 0.10
|
||||
list = self.levels[level]
|
||||
list.reverse()
|
||||
|
||||
|
||||
if no%2==0:
|
||||
first_half = list[no/2:]
|
||||
factor = -factor
|
||||
factor = -factor
|
||||
else:
|
||||
first_half = list[no/2+1:]
|
||||
if max_level==1:#for the case when horizontal graph is there
|
||||
self.result[list[no/2]]['y'] = mid_pos + (self.result[list[no/2]]['x']%2 * 0.5)
|
||||
else:
|
||||
self.result[list[no/2]]['y'] = mid_pos + factor
|
||||
|
||||
last_half = list[:no/2]
|
||||
|
||||
|
||||
last_half = list[:no/2]
|
||||
|
||||
i=1
|
||||
for node in first_half:
|
||||
self.result[node]['y'] = mid_pos - (i + factor)
|
||||
i += 1
|
||||
|
||||
|
||||
i=1
|
||||
for node in last_half:
|
||||
self.result[node]['y'] = mid_pos + (i + factor)
|
||||
i += 1
|
||||
else:
|
||||
else:
|
||||
self.max_order += max_level+1
|
||||
mid_pos = self.result[self.start]['y']
|
||||
|
||||
mid_pos = self.result[self.start]['y']
|
||||
|
||||
|
||||
def tree_order(self, node, last=0):
|
||||
mid_pos = self.result[node]['y']
|
||||
l = self.transitions.get(node, [])
|
||||
l.reverse()
|
||||
no = len(l)
|
||||
|
||||
|
||||
if no%2==0:
|
||||
first_half = l[no/2:]
|
||||
factor = 1
|
||||
first_half = l[no/2:]
|
||||
factor = 1
|
||||
else:
|
||||
first_half = l[no/2+1:]
|
||||
factor = 0
|
||||
|
||||
last_half = l[:no/2]
|
||||
|
||||
|
||||
last_half = l[:no/2]
|
||||
|
||||
i=1
|
||||
for child in first_half:
|
||||
self.result[child]['y'] = mid_pos - (i - (factor * 0.5))
|
||||
i += 1
|
||||
|
||||
|
||||
if self.transitions.get(child, False):
|
||||
if last:
|
||||
self.result[child]['y'] = last + len(self.transitions[child])/2 + 1
|
||||
last = self.tree_order(child, last)
|
||||
|
||||
|
||||
if no%2:
|
||||
mid_node = l[no/2]
|
||||
self.result[mid_node]['y'] = mid_pos
|
||||
|
||||
self.result[mid_node]['y'] = mid_pos
|
||||
|
||||
if self.transitions.get((mid_node), False):
|
||||
if last:
|
||||
self.result[mid_node]['y'] = last + len(self.transitions[mid_node])/2 + 1
|
||||
@@ -469,51 +469,51 @@ class graph(object):
|
||||
if last:
|
||||
self.result[mid_node]['y'] = last + 1
|
||||
self.result[node]['y'] = self.result[mid_node]['y']
|
||||
mid_pos = self.result[node]['y']
|
||||
|
||||
i=1
|
||||
mid_pos = self.result[node]['y']
|
||||
|
||||
i=1
|
||||
last_child = None
|
||||
for child in last_half:
|
||||
for child in last_half:
|
||||
self.result[child]['y'] = mid_pos + (i - (factor * 0.5))
|
||||
last_child = child
|
||||
last_child = child
|
||||
i += 1
|
||||
if self.transitions.get(child, False):
|
||||
if last:
|
||||
self.result[child]['y'] = last + len(self.transitions[child])/2 + 1
|
||||
self.result[child]['y'] = last + len(self.transitions[child])/2 + 1
|
||||
last = self.tree_order(child, last)
|
||||
|
||||
|
||||
if last_child:
|
||||
last = self.result[last_child]['y']
|
||||
|
||||
return last
|
||||
|
||||
|
||||
def process_order(self):
|
||||
"""Finds actual-order of the nodes with respect to maximum number of nodes in a rank in component
|
||||
|
||||
return last
|
||||
|
||||
|
||||
def process_order(self):
|
||||
"""Finds actual-order of the nodes with respect to maximum number of nodes in a rank in component
|
||||
"""
|
||||
|
||||
|
||||
if self.Is_Cyclic:
|
||||
max_level = max(map(lambda x: len(x), self.levels.values()))
|
||||
|
||||
|
||||
if max_level%2:
|
||||
self.result[self.start]['y'] = (max_level+1)/2 + self.max_order + (self.max_order and 1)
|
||||
else:
|
||||
self.result[self.start]['y'] = (max_level)/2 + self.max_order + (self.max_order and 1)
|
||||
|
||||
|
||||
self.graph_order()
|
||||
|
||||
else:
|
||||
self.result[self.start]['y'] = 0
|
||||
|
||||
else:
|
||||
self.result[self.start]['y'] = 0
|
||||
self.tree_order(self.start, 0)
|
||||
min_order = math.fabs(min(map(lambda x: x['y'], self.result.values())))
|
||||
|
||||
index = self.start_nodes.index(self.start)
|
||||
|
||||
index = self.start_nodes.index(self.start)
|
||||
same = False
|
||||
|
||||
|
||||
roots = []
|
||||
if index>0:
|
||||
if index>0:
|
||||
for start in self.start_nodes[:index]:
|
||||
same = True
|
||||
same = True
|
||||
for edge in self.tree_list[start][1:]:
|
||||
if self.tree_list[self.start].__contains__(edge):
|
||||
continue
|
||||
@@ -522,46 +522,46 @@ class graph(object):
|
||||
break
|
||||
if same:
|
||||
roots.append(start)
|
||||
|
||||
if roots:
|
||||
min_order += self.max_order
|
||||
|
||||
if roots:
|
||||
min_order += self.max_order
|
||||
else:
|
||||
min_order += self.max_order + 1
|
||||
|
||||
|
||||
for level in self.levels:
|
||||
for node in self.levels[level]:
|
||||
self.result[node]['y'] += min_order
|
||||
|
||||
|
||||
if roots:
|
||||
roots.append(self.start)
|
||||
one_level_el = self.tree_list[self.start][0][1]
|
||||
base = self.result[one_level_el]['y']# * 2 / (index + 2)
|
||||
|
||||
|
||||
|
||||
|
||||
no = len(roots)
|
||||
first_half = roots[:no/2]
|
||||
|
||||
|
||||
if no%2==0:
|
||||
last_half = roots[no/2:]
|
||||
else:
|
||||
last_half = roots[no/2+1:]
|
||||
|
||||
|
||||
factor = -math.floor(no/2)
|
||||
for start in first_half:
|
||||
self.result[start]['y'] = base + factor
|
||||
self.result[start]['y'] = base + factor
|
||||
factor += 1
|
||||
|
||||
|
||||
if no%2:
|
||||
self.result[roots[no/2]]['y'] = base + factor
|
||||
factor +=1
|
||||
|
||||
|
||||
for start in last_half:
|
||||
self.result[start]['y'] = base + factor
|
||||
self.result[start]['y'] = base + factor
|
||||
factor += 1
|
||||
|
||||
|
||||
self.max_order = max(map(lambda x: x['y'], self.result.values()))
|
||||
|
||||
def find_starts(self):
|
||||
|
||||
def find_starts(self):
|
||||
"""Finds other start nodes of the graph in the case when graph is disconneted
|
||||
"""
|
||||
rem_nodes = []
|
||||
@@ -577,7 +577,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, [])
|
||||
@@ -589,120 +589,120 @@ class graph(object):
|
||||
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
|
||||
|
||||
|
||||
|
||||
def rank(self):
|
||||
"""Finds the optimized rank of the nodes using Network-simplex algorithm
|
||||
|
||||
|
||||
@param start: starting node of the component
|
||||
"""
|
||||
self.levels = {}
|
||||
self.levels = {}
|
||||
self.critical_edges = []
|
||||
self.partial_order = {}
|
||||
self.links = []
|
||||
self.Is_Cyclic = False
|
||||
|
||||
|
||||
self.tree_list[self.start] = self.make_acyclic(None, self.start, 0, [])
|
||||
self.Is_Cyclic = self.rev_edges(self.tree_list[self.start])
|
||||
self.Is_Cyclic = self.rev_edges(self.tree_list[self.start])
|
||||
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()
|
||||
|
||||
e = self.leave_edge()
|
||||
|
||||
while e :
|
||||
f = self.enter_edge(e)
|
||||
if e==f:
|
||||
self.critical_edges.append(e)
|
||||
else:
|
||||
self.exchange(e,f)
|
||||
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]]['x'] - self.result[edge[0]]['x']
|
||||
|
||||
|
||||
def order_in_rank(self):
|
||||
"""Finds optimized order of the nodes within their ranks using median heuristic
|
||||
|
||||
@param start: starting node of the component
|
||||
|
||||
@param start: starting node of the component
|
||||
"""
|
||||
|
||||
|
||||
self.make_chain()
|
||||
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]['x'])
|
||||
|
||||
|
||||
for level in self.levels:
|
||||
self.levels[level].sort(lambda x, y: cmp(self.result[x]['y'], self.result[y]['y']))
|
||||
|
||||
self.order_heuristic()
|
||||
|
||||
self.order_heuristic()
|
||||
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
|
||||
|
||||
@param starting_node: node from where to start the graph search
|
||||
"""
|
||||
|
||||
|
||||
self.start_nodes = starting_node or []
|
||||
self.partial_order = {}
|
||||
self.links = []
|
||||
self.tree_list = {}
|
||||
|
||||
self.partial_order = {}
|
||||
self.links = []
|
||||
self.tree_list = {}
|
||||
|
||||
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:
|
||||
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 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
|
||||
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:
|
||||
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):
|
||||
result = ''
|
||||
@@ -716,21 +716,21 @@ class graph(object):
|
||||
def scale(self, maxx, maxy, nwidth=0, nheight=0, margin=20):
|
||||
"""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]['x'] - self.result[src]['x'] == 0):
|
||||
if (self.result[des]['x'] - self.result[src]['x'] == 0):
|
||||
self.result[src]['x'] += 0.08
|
||||
self.result[des]['x'] -= 0.08
|
||||
|
||||
|
||||
factorX = maxx + nheight
|
||||
factorY = maxy + nwidth
|
||||
|
||||
factorY = maxy + nwidth
|
||||
|
||||
for node in self.result:
|
||||
self.result[node]['y'] = (self.result[node]['y']) * factorX + margin
|
||||
self.result[node]['x'] = (self.result[node]['x']) * factorY + margin
|
||||
|
||||
|
||||
|
||||
def result_get(self):
|
||||
return self.result
|
||||
@@ -763,14 +763,14 @@ if __name__=='__main__':
|
||||
import ImageDraw
|
||||
img = Image.new("RGB", (800, 600), "#ffffff")
|
||||
draw = ImageDraw.Draw(img)
|
||||
|
||||
|
||||
result = g.result_get()
|
||||
node_res = {}
|
||||
for node in nodes:
|
||||
node_res[node] = result[node]
|
||||
|
||||
|
||||
for name,node in node_res.items():
|
||||
|
||||
|
||||
draw.arc( (int(node['y']-radius), int(node['x']-radius),int(node['y']+radius), int(node['x']+radius) ), 0, 360, (128,128,128))
|
||||
draw.text( (int(node['y']), int(node['x'])), name, (128,128,128))
|
||||
|
||||
|
||||
+9
-9
@@ -2,17 +2,17 @@
|
||||
|
||||
ADMIN_PASSWD='admin'
|
||||
method_1() {
|
||||
cat '-' << EOF
|
||||
cat '-' << EOF
|
||||
<xml>
|
||||
<methodCall>
|
||||
<methodName>set_loglevel</methodName>
|
||||
<params>
|
||||
<param><value><string>$ADMIN_PASSWD</string></value>
|
||||
</param>
|
||||
<param>
|
||||
<value><string>$1</string></value>
|
||||
</param>
|
||||
</params>
|
||||
<methodName>set_loglevel</methodName>
|
||||
<params>
|
||||
<param><value><string>$ADMIN_PASSWD</string></value>
|
||||
</param>
|
||||
<param>
|
||||
<value><string>$1</string></value>
|
||||
</param>
|
||||
</params>
|
||||
</methodCall>
|
||||
EOF
|
||||
}
|
||||
|
||||
Vendored
+1
-1
@@ -14,7 +14,7 @@ msgstr ""
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Launchpad-Export-Date: 2010-03-11 04:38+0000\n"
|
||||
"X-Launchpad-Export-Date: 2010-03-12 04:51+0000\n"
|
||||
"X-Generator: Launchpad (build Unknown)\n"
|
||||
|
||||
#. Type: string
|
||||
|
||||
Vendored
+1
-1
@@ -14,7 +14,7 @@ msgstr ""
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Launchpad-Export-Date: 2010-03-11 04:38+0000\n"
|
||||
"X-Launchpad-Export-Date: 2010-03-12 04:51+0000\n"
|
||||
"X-Generator: Launchpad (build Unknown)\n"
|
||||
|
||||
#. Type: string
|
||||
|
||||
+4
-4
@@ -2,12 +2,12 @@
|
||||
|
||||
# ADMIN_PASSWD='admin'
|
||||
method_1() {
|
||||
cat '-' << EOF
|
||||
cat '-' << EOF
|
||||
<xml>
|
||||
<methodCall>
|
||||
<methodName>get_stats</methodName>
|
||||
<params>
|
||||
</params>
|
||||
<methodName>get_stats</methodName>
|
||||
<params>
|
||||
</params>
|
||||
</methodCall>
|
||||
EOF
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user