From 8392b4d3d08809050a1238a3f6bbd0e6b7805839 Mon Sep 17 00:00:00 2001 From: Thibault Francois Date: Thu, 24 Feb 2011 15:22:16 +0100 Subject: [PATCH 001/259] [FIX] hard code template bzr revid: tfr@openerp.com-20110224142216-x61sd77ad269cquk --- addons/crm/wizard/crm_send_email.py | 3 +- .../wizard/crm_forward_to_partner.py | 56 +++++++++++-------- 2 files changed, 34 insertions(+), 25 deletions(-) diff --git a/addons/crm/wizard/crm_send_email.py b/addons/crm/wizard/crm_send_email.py index 3ce5942272d..8dff88296ab 100644 --- a/addons/crm/wizard/crm_send_email.py +++ b/addons/crm/wizard/crm_send_email.py @@ -57,7 +57,7 @@ class crm_send_new_email(osv.osv_memory): 'body': fields.text('Message Body', required=True), 'state': fields.selection(AVAILABLE_STATES, string='Set New State To', required=True), 'attachment_ids' : fields.one2many('crm.send.mail.attachment', 'wizard_id'), - 'html': fields.boolean('HTML formatting?', help="Select this if you want to send email with HTML formatting."), + 'html': fields.boolean('HTML formatting?', help="Select this if you want to send email with HTML formatting."), } def action_send(self, cr, uid, ids, context=None): @@ -180,7 +180,6 @@ class crm_send_new_email(osv.osv_memory): user_obj = self.pool.get('res.users') user_mail_from = user_obj._get_email_from(cr, uid, [uid], context=context)[uid] - for case in mod_obj.browse(cr, uid, res_id, context=context): if 'email_to' in fields: res.update({'email_to': case.email_from and tools.ustr(case.email_from) or ''}) diff --git a/addons/crm_partner_assign/wizard/crm_forward_to_partner.py b/addons/crm_partner_assign/wizard/crm_forward_to_partner.py index 7173f466148..b06881f6b60 100644 --- a/addons/crm_partner_assign/wizard/crm_forward_to_partner.py +++ b/addons/crm_partner_assign/wizard/crm_forward_to_partner.py @@ -44,9 +44,10 @@ class crm_lead_forward_to_partner(osv.osv_memory): _defaults = { 'name' : 'email', 'history': 'latest', - 'email_from': lambda self, cr, uid, *a: self.pool.get('res.users')._get_email_from(cr, uid, uid)[uid] + 'email_from': lambda self, cr, uid, *a: self.pool.get('res.users')._get_email_from(cr, uid, uid)[uid], } + def get_whole_history(self, cr, uid, ids, context=None): """This function gets whole communication history and returns as top posting style @param self: The object pointer @@ -87,7 +88,7 @@ class crm_lead_forward_to_partner(osv.osv_memory): @param uid: the current user’s ID for security checks, @param ids: List of Mail’s IDs @param user: Changed User id - @param partner: Changed Partner id + @param partner: Changed Partner id """ if not user: return {'value': {'email_to': False}} @@ -146,7 +147,7 @@ class crm_lead_forward_to_partner(osv.osv_memory): @param uid: the current user’s ID for security checks, @param ids: List of Mail’s IDs @param user: Changed User id - @param partner: Changed Partner id + @param partner: Changed Partner id """ if not partner_id: return {'value' : {'email_to' : False, 'address_id': False}} @@ -155,13 +156,13 @@ class crm_lead_forward_to_partner(osv.osv_memory): addr = partner_obj.address_get(cr, uid, [partner_id], ['contact']) data = {'address_id': addr['contact']} data.update(self.on_change_address(cr, uid, ids, addr['contact'])['value']) - + partner = partner_obj.browse(cr, uid, [partner_id]) user_id = partner and partner[0].user_id or False email = user_id and user_id.user_email or '' data.update({'email_cc' : email}) return { - 'value' : data, + 'value' : data, 'domain' : {'address_id' : partner_id and "[('partner_id', '=', partner_id)]" or "[]"} } @@ -207,7 +208,17 @@ class crm_lead_forward_to_partner(osv.osv_memory): return {'type': 'ir.actions.act_window_close'} def get_lead_details(self, cr, uid, lead_id, context=None): - body = [] + body = ["""Hello, + +OpenERP Leads are now forwarded to our trusted partners, through the CRM, we hope that they provide you with interesting projects, we know that they have shown keen interest in our software. +Below is an interesting lead for you. I have notified the lead that you would contact them. + +Please let us know about the advancements of this lead or if you are not able to answer to its requests by replying to this email. This way, we can keep track of closed leads or forward them to other partners. +Don't forget to propose our maintenance at the beginning of your implementation projects, together with your services quotation. The maintenance provides unlimited bugfixing that will avoid you waste time on bugs detected during the implementation. It also provides free migration services for the current stable version at the time of signature; otherwise if we released a new version during your implementation, the customer would not always be able to easily migrate to newer versions. + +Kind regards, OpenERP Team + + """, "\n\n"] lead_proxy = self.pool.get('crm.lead') lead = lead_proxy.browse(cr, uid, lead_id, context=context) if not lead.type or lead.type == 'lead' or not lead.partner_address_id: @@ -237,22 +248,22 @@ class crm_lead_forward_to_partner(osv.osv_memory): elif lead.type == 'opportunity': pa = lead.partner_address_id body = [ - "Partner: %s" % (lead.partner_id and lead.partner_id.name_get()[0][1]), - "Contact: %s" % (pa.name or ''), - "Title: %s" % (pa.title or ''), - "Function: %s" % (pa.function or ''), - "Street: %s" % (pa.street or ''), - "Street2: %s" % (pa.street2 or ''), - "Zip: %s" % (pa.zip or ''), - "City: %s" % (pa.city or ''), - "Country: %s" % (pa.country_id and pa.country_id.name_get()[0][1] or ''), - "State: %s" % (pa.state_id and pa.state_id.name_get()[0][1] or ''), - "Email: %s" % (pa.email or ''), - "Phone: %s" % (pa.phone or ''), - "Fax: %s" % (pa.fax or ''), - "Mobile: %s" % (pa.mobile or ''), - "Lead Category: %s" % (lead.categ_id and lead.categ_id.name or ''), - "Details: %s" % (lead.description or ''), + "Partner: %s" % (lead.partner_id and lead.partner_id.name_get()[0][1]), + "Contact: %s" % (pa.name or ''), + "Title: %s" % (pa.title or ''), + "Function: %s" % (pa.function or ''), + "Street: %s" % (pa.street or ''), + "Street2: %s" % (pa.street2 or ''), + "Zip: %s" % (pa.zip or ''), + "City: %s" % (pa.city or ''), + "Country: %s" % (pa.country_id and pa.country_id.name_get()[0][1] or ''), + "State: %s" % (pa.state_id and pa.state_id.name_get()[0][1] or ''), + "Email: %s" % (pa.email or ''), + "Phone: %s" % (pa.phone or ''), + "Fax: %s" % (pa.fax or ''), + "Mobile: %s" % (pa.mobile or ''), + "Lead Category: %s" % (lead.categ_id and lead.categ_id.name or ''), + "Details: %s" % (lead.description or ''), ] return "\n".join(body + ['---']) @@ -264,7 +275,6 @@ class crm_lead_forward_to_partner(osv.osv_memory): context = {} defaults = super(crm_lead_forward_to_partner, self).default_get(cr, uid, fields, context=context) - active_id = context.get('active_id') if not active_id: return defaults From 739dd7000e04030896c7f63c2a16426ef14ef966 Mon Sep 17 00:00:00 2001 From: Stephane Wirtel Date: Thu, 24 Feb 2011 16:28:50 +0100 Subject: [PATCH 002/259] [IMP] We use the analytic account associated to the project bzr revid: stephane@openerp.com-20110224152850-3poei06fhja3wm5w --- addons/project_issue_sheet/project_issue_sheet.py | 12 +++++++++++- .../project_issue_sheet/project_issue_sheet_view.xml | 9 ++++++++- 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/addons/project_issue_sheet/project_issue_sheet.py b/addons/project_issue_sheet/project_issue_sheet.py index f96ce9a4ac5..ed14fc99177 100644 --- a/addons/project_issue_sheet/project_issue_sheet.py +++ b/addons/project_issue_sheet/project_issue_sheet.py @@ -27,8 +27,18 @@ class project_issue(osv.osv): _description = 'project issue' _columns = { 'timesheet_ids': fields.one2many('hr.analytic.timesheet', 'issue_id', 'Timesheets'), - 'analytic_account_id': fields.related('project_id', 'analytic_account_id', type='many2one', relation='account.analytic.account',string='Analytic Account') + 'analytic_account_id': fields.many2one('account.analytic.account', 'Analytic Account'), } + + def on_change_project(self, cr, uid, ids, project_id, context=None): + if not project_id: + return {} + project = self.pool.get('project.project').browse(cr, uid, project_id, context=context) + account = project.analytic_account_id + if account: + return {'value' : {'analytic_account_id' : account.id}} + else: + return {} project_issue() diff --git a/addons/project_issue_sheet/project_issue_sheet_view.xml b/addons/project_issue_sheet/project_issue_sheet_view.xml index 2222ef12ea5..78950e5f749 100644 --- a/addons/project_issue_sheet/project_issue_sheet_view.xml +++ b/addons/project_issue_sheet/project_issue_sheet_view.xml @@ -7,9 +7,16 @@ form + + on_change_project(project_id) + + + + - From c0bee8c4e3924c33d66a20b7b47325fd8e3971e0 Mon Sep 17 00:00:00 2001 From: Stephane Wirtel Date: Thu, 24 Feb 2011 17:09:53 +0100 Subject: [PATCH 003/259] [IMP] The responsible of the project issue is the manager of the associated project. [IMP] There is a new domain on the resolution field, allow to select the project.task.type associated to the selected project. [IMP] The assigned_to field is the connected user, but can be changed by the user bzr revid: stephane@openerp.com-20110224160953-fv9p2qhkqdseh183 --- addons/project/project.py | 5 +++ addons/project_issue/project_issue.py | 9 +++--- addons/project_issue/project_issue_view.xml | 35 ++++++++++----------- 3 files changed, 27 insertions(+), 22 deletions(-) diff --git a/addons/project/project.py b/addons/project/project.py index bff63746d9a..d197da37709 100644 --- a/addons/project/project.py +++ b/addons/project/project.py @@ -26,6 +26,10 @@ from datetime import datetime, date from tools.translate import _ from osv import fields, osv +class project_project(osv.osv): + _name = 'project.project' + +project_project() class project_task_type(osv.osv): _name = 'project.task.type' @@ -35,6 +39,7 @@ class project_task_type(osv.osv): 'name': fields.char('Stage Name', required=True, size=64, translate=True), 'description': fields.text('Description'), 'sequence': fields.integer('Sequence'), + 'project_ids': fields.many2many('project.project', 'project_task_type_rel', 'type_id', 'project_id', 'Projects'), } _defaults = { diff --git a/addons/project_issue/project_issue.py b/addons/project_issue/project_issue.py index aaaff37305e..b4ec852a558 100644 --- a/addons/project_issue/project_issue.py +++ b/addons/project_issue/project_issue.py @@ -45,7 +45,7 @@ class project_issue(crm.crm_case, osv.osv): _description = "Project Issue" _order = "priority, id desc" _inherit = ['mailgate.thread'] - + def case_open(self, cr, uid, ids, *args): """ @param self: The object pointer @@ -175,7 +175,7 @@ class project_issue(crm.crm_case, osv.osv): 'section_id': fields.many2one('crm.case.section', 'Sales Team', \ select=True, help='Sales team to which Case belongs to.\ Define Responsible user and Email account for mail gateway.'), - 'user_id': fields.many2one('res.users', 'Responsible'), + 'user_id': fields.related('project_id', 'user_id', type='many2one', relation='res.users', store=True, select=1, string='Responsible'), 'partner_id': fields.many2one('res.partner', 'Partner'), 'partner_address_id': fields.many2one('res.partner.address', 'Partner Contact', \ domain="[('partner_id','=',partner_id)]"), @@ -200,7 +200,7 @@ class project_issue(crm.crm_case, osv.osv): 'partner_name': fields.char("Employee's Name", size=64), 'partner_mobile': fields.char('Mobile', size=32), 'partner_phone': fields.char('Phone', size=32), - 'type_id': fields.many2one ('project.task.type', 'Resolution'), + 'type_id': fields.many2one ('project.task.type', 'Resolution', domain="[('project_ids', '=', project_id)]"), 'project_id':fields.many2one('project.project', 'Project'), 'duration': fields.float('Duration'), 'task_id': fields.many2one('project.task', 'Task', domain="[('project_id','=',project_id)]"), @@ -208,7 +208,7 @@ class project_issue(crm.crm_case, osv.osv): method=True, multi='day_open', type="float", store=True), 'day_close': fields.function(_compute_day, string='Days to Close', \ method=True, multi='day_close', type="float", store=True), - 'assigned_to': fields.related('task_id', 'user_id', string = 'Assigned to', type="many2one", relation="res.users", store=True, help='This is the current user to whom the related task have been assigned'), + 'assigned_to': fields.many2one('res.users', 'Assigned to', required=True, select=1), 'working_hours_open': fields.function(_compute_day, string='Working Hours to Open the Issue', \ method=True, multi='working_days_open', type="float", store=True), 'working_hours_close': fields.function(_compute_day, string='Working Hours to Close the Issue', \ @@ -241,6 +241,7 @@ class project_issue(crm.crm_case, osv.osv): 'company_id': lambda s, cr, uid, c: s.pool.get('res.company')._company_default_get(cr, uid, 'crm.helpdesk', context=c), 'priority': crm.AVAILABLE_PRIORITIES[2][0], 'project_id':_get_project, + 'assigned_to' : lambda obj, cr, uid, context: uid, } def convert_issue_task(self, cr, uid, ids, context=None): diff --git a/addons/project_issue/project_issue_view.xml b/addons/project_issue/project_issue_view.xml index 23a361b0ff9..36fee3f661c 100644 --- a/addons/project_issue/project_issue_view.xml +++ b/addons/project_issue/project_issue_view.xml @@ -52,13 +52,14 @@
- - - - - + + + + + + - + + Forward to Partner crm.lead.forward.to.partner form form - + new + + + crm.new.mass.forward.mail.form + crm.lead.mass.forward.to.partner + form + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + -
+ + +
+ + + + + + + + + + + + + + + + + + + + + + + + +

@@ -320,7 +351,8 @@
+ +

+
+

diff --git a/addons/base_diagram/__init__.py b/addons/base_diagram/__init__.py new file mode 100644 index 00000000000..355939a4922 --- /dev/null +++ b/addons/base_diagram/__init__.py @@ -0,0 +1 @@ +import controllers \ No newline at end of file diff --git a/addons/base_diagram/__openerp__.py b/addons/base_diagram/__openerp__.py new file mode 100644 index 00000000000..fb2a849f630 --- /dev/null +++ b/addons/base_diagram/__openerp__.py @@ -0,0 +1,6 @@ +{ + "name" : "OpenERP Web base Diagram", + "version" : "2.0", + "depends" : [], + 'active': True, +} diff --git a/addons/base_diagram/controllers/__init__.py b/addons/base_diagram/controllers/__init__.py new file mode 100644 index 00000000000..039d9715fab --- /dev/null +++ b/addons/base_diagram/controllers/__init__.py @@ -0,0 +1 @@ +import main \ No newline at end of file diff --git a/addons/base_diagram/controllers/main.py b/addons/base_diagram/controllers/main.py new file mode 100644 index 00000000000..b742021b5d7 --- /dev/null +++ b/addons/base_diagram/controllers/main.py @@ -0,0 +1,125 @@ +from base.controllers.main import View +import openerpweb + +class DiagramView(View): + _cp_path = "/base_diagram/diagram" + + @openerpweb.jsonrequest + def load(self, req, model, view_id): + fields_view = self.fields_view_get(req.session, model, view_id, 'diagram') + return {'fields_view': fields_view} + + @openerpweb.jsonrequest + def get_diagram_info(self, req, **kw): + id = kw['id'] + model = kw['model'] + node = kw['node'] + connector = kw['connector'] + src_node = kw['src_node'] + des_node = kw['des_node'] + + visible_node_fields = kw.get('visible_node_fields',[]) + invisible_node_fields = kw.get('invisible_node_fields',[]) + node_fields_string = kw.get('node_fields_string',[]) + connector_fields = kw.get('connector_fields',[]) + connector_fields_string = kw.get('connector_fields_string',[]) + + bgcolors = {} + shapes = {} + bgcolor = kw.get('bgcolor','') + shape = kw.get('shape','') + + if bgcolor: + for color_spec in bgcolor.split(';'): + if color_spec: + colour, color_state = color_spec.split(':') + bgcolors[colour] = color_state + + if shape: + for shape_spec in shape.split(';'): + if shape_spec: + shape_colour, shape_color_state = shape_spec.split(':') + shapes[shape_colour] = shape_color_state + + ir_view = req.session.model('ir.ui.view') + graphs = ir_view.graph_get(id, model, node, connector, src_node, des_node, False, + (140, 180), req.session.context) + + nodes = graphs['nodes'] + transitions = graphs['transitions'] + isolate_nodes = {} + + for node in graphs['blank_nodes']: + isolate_nodes[node['id']] = node + else: + y = map(lambda t: t['y'],filter(lambda x: x['y'] if x['x']==20 else None, nodes.values())) + y_max = (y and max(y)) or 120 + + connectors = {} + list_tr = [] + + for tr in transitions: + list_tr.append(tr) + connectors.setdefault(tr, { + 'id': tr, + 's_id': transitions[tr][0], + 'd_id': transitions[tr][1] + }) + connector_tr = req.session.model(connector) + connector_ids = connector_tr.search([('id', 'in', list_tr)], 0, 0, 0, req.session.context) + + data_connectors =connector_tr.read(connector_ids, connector_fields, req.session.context) + + + for tr in data_connectors: + t = connectors.get(str(tr['id'])) + t.update({ + 'source': tr[src_node][1], + 'destination': tr[des_node][1], + 'options': {} + }) + + for i, fld in enumerate(connector_fields): + t['options'][connector_fields_string[i]] = tr[fld] + + fields = req.session.model('ir.model.fields') + field_ids = fields.search([('model', '=', model), ('relation', '=', node)], 0, 0, 0, req.session.context) + field_data = fields.read(field_ids, ['relation_field'], req.session.context) + + node_act = req.session.model(node) + search_acts = node_act.search([(field_data[0]['relation_field'], '=', id)], 0, 0, 0, req.session.context) + data_acts = node_act.read(search_acts, invisible_node_fields + visible_node_fields, req.session.context) + + for act in data_acts: + n = nodes.get(str(act['id'])) + if not n: + n = isolate_nodes.get(act['id'], {}) + y_max += 140 + n.update({'x': 20, 'y': y_max}) + nodes[act['id']] = n + + n.update( + id=act['id'], + color='white', + shape='ellipse', + options={} + ) + for color, expr in bgcolors.items(): + if eval(expr, act): + n['color'] = color + + for shape, expr in shapes.items(): + if eval(expr, act): + n['shape'] = shape + + for i, fld in enumerate(visible_node_fields): + n['options'][node_fields_string[i]] = act[fld] + + #to relate m2o field of transition to corresponding o2m in activity + in_transition_field_id = fields.search([('relation', '=', connector), ('relation_field', '=', des_node), ('model', '=', node)], 0, 0, 0, req.session.context) + in_transition_field = fields.read(in_transition_field_id[0], ['name'], req.session.context)['name'] + + out_transition_field_id = fields.search([('relation', '=', connector), ('relation_field', '=', src_node), ('model', '=', node)], 0, 0, 0, req.session.context) + out_transition_field = fields.read(out_transition_field_id[0], ['name'], req.session.context)['name'] + + return dict(nodes=nodes, conn=connectors, in_transition_field=in_transition_field, out_transition_field=out_transition_field) \ No newline at end of file diff --git a/addons/base_diagram/static/lib/js/Curry-1.0.1.js b/addons/base_diagram/static/lib/js/Curry-1.0.1.js new file mode 100644 index 00000000000..f5aa0f993a6 --- /dev/null +++ b/addons/base_diagram/static/lib/js/Curry-1.0.1.js @@ -0,0 +1,29 @@ +/** + * Curry - Function currying + * Copyright (c) 2008 Ariel Flesler - aflesler(at)gmail(dot)com | http://flesler.blogspot.com + * Licensed under BSD (http://www.opensource.org/licenses/bsd-license.php) + * Date: 10/4/2008 + * + * @author Ariel Flesler + * @version 1.0.1 + */ + +function curry( fn ){ + return function(){ + var args = curry.args(arguments), + master = arguments.callee, + self = this; + + return args.length >= fn.length ? fn.apply(self,args) : function(){ + return master.apply( self, args.concat(curry.args(arguments)) ); + }; + }; +}; + +curry.args = function( args ){ + return Array.prototype.slice.call(args); +}; + +Function.prototype.curry = function(){ + return curry(this); +}; \ No newline at end of file diff --git a/addons/base_diagram/static/lib/js/dracula_algorithms.js b/addons/base_diagram/static/lib/js/dracula_algorithms.js new file mode 100644 index 00000000000..0fbb0857fc8 --- /dev/null +++ b/addons/base_diagram/static/lib/js/dracula_algorithms.js @@ -0,0 +1,599 @@ +/* + * Various algorithms and data structures, licensed under the MIT-license. + * (c) 2010 by Johann Philipp Strathausen + * http://strathausen.eu + * + */ + + + +/* + Bellman-Ford + + Path-finding algorithm, finds the shortest paths from one node to all nodes. + + + Complexity + + O( |E| · |V| ), where E = edges and V = vertices (nodes) + + + Constraints + + Can run on graphs with negative edge weights as long as they do not have + any negative weight cycles. + + */ +function bellman_ford(g, source) { + + /* STEP 1: initialisation */ + for(var n in g.nodes) + g.nodes[n].distance = Infinity; + /* predecessors are implicitly null */ + source.distance = 0; + + step("Initially, all distances are infinite and all predecessors are null."); + + /* STEP 2: relax each edge (this is at the heart of Bellman-Ford) */ + /* repeat this for the number of nodes minus one */ + for(var i = 1; i < g.nodes.length; i++) + /* for each edge */ + for(var e in g.edges) { + var edge = g.edges[e]; + if(edge.source.distance + edge.weight < edge.target.distance) { + step("Relax edge between " + edge.source.id + " and " + edge.target.id + "."); + edge.target.distance = edge.source.distance + edge.weight; + edge.target.predecessor = edge.source; + } + //Added by Jake Stothard (Needs to be tested) + if(!edge.style.directed) { + if(edge.target.distance + edge.weight < edge.source.distance) { + g.snapShot("Relax edge between "+edge.target.id+" and "+edge.source.id+"."); + edge.source.distance = edge.target.distance + edge.weight; + edge.source.predecessor = edge.target; + } + } + } + step("Ready."); + + /* STEP 3: TODO Check for negative cycles */ + /* For now we assume here that the graph does not contain any negative + weights cycles. (this is left as an excercise to the reader[tm]) */ +} + + + +/* + Path-finding algorithm Dijkstra + + - worst-case running time is O((|E| + |V|) · log |V| ) thus better than + Bellman-Ford for sparse graphs (with less edges), but cannot handle + negative edge weights + */ +function dijkstra(g, source) { + + /* initially, all distances are infinite and all predecessors are null */ + for(var n in g.nodes) + g.nodes[n].distance = Infinity; + /* predecessors are implicitly null */ + + g.snapShot("Initially, all distances are infinite and all predecessors are null."); + + source.distance = 0; + /* set of unoptimized nodes, sorted by their distance (but a Fibonacci heap + would be better) */ + var q = new BinaryMinHeap(g.nodes, "distance"); + + /* pointer to the node in focus */ + var node; + + /* get the node with the smallest distance + as long as we have unoptimized nodes. q.min() can have O(log n). */ + while(q.min() != undefined) { + /* remove the latest */ + node = q.extractMin(); + node.optimized = true; + + /* no nodes accessible from this one, should not happen */ + if(node.distance == Infinity) + throw "Orphaned node!"; + + /* for each neighbour of node */ + for(e in node.edges) { + var other = (node == node.edges[e].target) ? node.edges[e].source : node.edges[e].target; + + if(other.optimized) + continue; + + /* look for an alternative route */ + var alt = node.distance + node.edges[e].weight; + + /* update distance and route if a better one has been found */ + if (alt < other.distance) { + + /* update distance of neighbour */ + other.distance = alt; + + /* update priority queue */ + q.heapify(); + + /* update path */ + other.predecessor = node; + g.snapShot("Enhancing node.") + } + } + } +} + + +/* All-Pairs-Shortest-Paths */ +/* Runs at worst in O(|V|³) and at best in Omega(|V|³) :-) + complexity Sigma(|V|²) */ +/* This implementation is not yet ready for general use, but works with the + Dracula graph library. */ +function floyd_warshall(g, source) { + + /* Step 1: initialising empty path matrix (second dimension is implicit) */ + var path = []; + var next = []; + var n = g.nodes.length; + + /* construct path matrix, initialize with Infinity */ + for(j in g.nodes) { + path[j] = []; + next[j] = []; + for(i in g.nodes) + path[j][i] = j == i ? 0 : Infinity; + } + + /* initialize path with edge weights */ + for(e in g.edges) + path[g.edges[e].source.id][g.edges[e].target.id] = g.edges[e].weight; + + /* Note: Usually, the initialisation is done by getting the edge weights + from a node matrix representation of the graph, not by iterating through + a list of edges as done here. */ + + /* Step 2: find best distances (the heart of Floyd-Warshall) */ + for(k in g.nodes){ + for(i in g.nodes) { + for(j in g.nodes) + if(path[i][j] > path[i][k] + path[k][j]) { + path[i][j] = path[i][k] + path[k][j]; + /* Step 2.b: remember the path */ + next[i][j] = k; + } + } + } + + /* Step 3: Path reconstruction, get shortest path */ + function getPath(i, j) { + if(path[i][j] == Infinity) + throw "There is no path."; + var intermediate = next[i][j]; + if(intermediate == undefined) + return null; + else + return getPath(i, intermediate) + .concat([intermediate]) + .concat(getPath(intermediate, j)); + } + + /* TODO use the knowledge, e.g. mark path in graph */ +} + +/* + Ford-Fulkerson + + Max-Flow-Min-Cut Algorithm finding the maximum flow through a directed + graph from source to sink. + + + Complexity + + O(E * max(f)), max(f) being the maximum flow + + + Description + + As long as there is an open path through the residual graph, send the + minimum of the residual capacities on the path. + + + Constraints + + The algorithm works only if all weights are integers. Otherwise it is + possible that the Ford–Fulkerson algorithm will not converge to the maximum + value. + + + Input + + g - Graph object + s - Source ID + t - Target (sink) ID + + + Output + + Maximum flow from Source s to Target t + + */ +/* + Edmonds-Karp + + Max-Flow-Min-Cut Algorithm finding the maximum flow through a directed + graph from source to sink. An implementation of the Ford-Fulkerson + algorithm. + + + Complexity + + O(|V|*|E|²) + + + Input + + g - Graph object (with node and edge lists, capacity is a property of edge) + s - source ID + t - sink ID + + */ +function edmonds_karp(g, s, t) { + +} + +/* + A simple binary min-heap serving as a priority queue + - takes an array as the input, with elements having a key property + - elements will look like this: + { + key: "... key property ...", + value: "... element content ..." + } + - provides insert(), min(), extractMin() and heapify() + - example usage (e.g. via the Firebug or Chromium console): + var x = {foo: 20, hui: "bla"}; + var a = new BinaryMinHeap([x,{foo:3},{foo:10},{foo:20},{foo:30},{foo:6},{foo:1},{foo:3}],"foo"); + console.log(a.extractMin()); + console.log(a.extractMin()); + x.foo = 0; // update key + a.heapify(); // call this always after having a key updated + console.log(a.extractMin()); + console.log(a.extractMin()); + - can also be used on a simple array, like [9,7,8,5] + */ +function BinaryMinHeap(array, key) { + + /* Binary tree stored in an array, no need for a complicated data structure */ + var tree = []; + + var key = key || 'key'; + + /* Calculate the index of the parent or a child */ + var parent = function(index) { return Math.floor((index - 1)/2); }; + var right = function(index) { return 2 * index + 2; }; + var left = function(index) { return 2 * index + 1; }; + + /* Helper function to swap elements with their parent + as long as the parent is bigger */ + function bubble_up(i) { + var p = parent(i); + while((p >= 0) && (tree[i][key] < tree[p][key])) { + /* swap with parent */ + tree[i] = tree.splice(p, 1, tree[i])[0]; + /* go up one level */ + i = p; + p = parent(i); + } + } + + /* Helper function to swap elements with the smaller of their children + as long as there is one */ + function bubble_down(i) { + var l = left(i); + var r = right(i); + + /* as long as there are smaller children */ + while(tree[l] && (tree[i][key] > tree[l][key]) || tree[r] && (tree[i][key] > tree[r][key])) { + + /* find smaller child */ + var child = tree[l] ? tree[r] ? tree[l][key] > tree[r][key] ? r : l : l : l; + + /* swap with smaller child with current element */ + tree[i] = tree.splice(child, 1, tree[i])[0]; + + /* go up one level */ + i = child; + l = left(i); + r = right(i); + } + } + + /* Insert a new element with respect to the heap property + 1. Insert the element at the end + 2. Bubble it up until it is smaller than its parent */ + this.insert = function(element) { + + /* make sure there's a key property */ + (element[key] == undefined) && (element = {key:element}); + + /* insert element at the end */ + tree.push(element); + + /* bubble up the element */ + bubble_up(tree.length - 1); + } + + /* Only show us the minimum */ + this.min = function() { + return tree.length == 1 ? undefined : tree[0]; + } + + /* Return and remove the minimum + 1. Take the root as the minimum that we are looking for + 2. Move the last element to the root (thereby deleting the root) + 3. Compare the new root with both of its children, swap it with the + smaller child and then check again from there (bubble down) + */ + this.extractMin = function() { + var result = this.min(); + + /* move the last element to the root or empty the tree completely */ + /* bubble down the new root if necessary */ + (tree.length == 1) && (tree = []) || (tree[0] = tree.pop()) && bubble_down(0); + + return result; + } + + /* currently unused, TODO implement */ + this.changeKey = function(index, key) { + throw "function not implemented"; + } + + this.heapify = function() { + for(var start = Math.floor((tree.length - 2) / 2); start >= 0; start--) { + bubble_down(start); + } + } + + /* insert the input elements one by one only when we don't have a key property (TODO can be done more elegant) */ + for(i in (array || [])) + this.insert(array[i]); +} + + + +/* + Quick Sort: + 1. Select some random value from the array, the median. + 2. Divide the array in three smaller arrays according to the elements + being less, equal or greater than the median. + 3. Recursively sort the array containg the elements less than the + median and the one containing elements greater than the median. + 4. Concatenate the three arrays (less, equal and greater). + 5. One or no element is always sorted. + TODO: This could be implemented more efficiently by using only one array object and several pointers. +*/ +function quickSort(arr) { + /* recursion anchor: one element is always sorted */ + if(arr.length <= 1) return arr; + /* randomly selecting some value */ + var median = arr[Math.floor(Math.random() * arr.length)]; + var arr1 = [], arr2 = [], arr3 = []; + for(var i in arr) { + arr[i] < median && arr1.push(arr[i]); + arr[i] == median && arr2.push(arr[i]); + arr[i] > median && arr3.push(arr[i]); + } + /* recursive sorting and assembling final result */ + return quickSort(arr1).concat(arr2).concat(quickSort(arr3)); +} + +/* + Selection Sort: + 1. Select the minimum and remove it from the array + 2. Sort the rest recursively + 3. Return the minimum plus the sorted rest + 4. An array with only one element is already sorted +*/ +function selectionSort(arr) { + /* recursion anchor: one element is always sorted */ + if(arr.length == 1) return arr; + var minimum = Infinity; + var index; + for(var i in arr) { + if(arr[i] < minimum) { + minimum = arr[i]; + index = i; /* remember the minimum index for later removal */ + } + } + /* remove the minimum */ + arr.splice(index, 1); + /* assemble result and sort recursively (could be easily done iteratively as well)*/ + return [minimum].concat(selectionSort(arr)); +} + +/* + Merge Sort: + 1. Cut the array in half + 2. Sort each of them recursively + 3. Merge the two sorted arrays + 4. An array with only one element is considered sorted + +*/ +function mergeSort(arr) { + /* merges two sorted arrays into one sorted array */ + function merge(a, b) { + /* result set */ + var c = []; + /* as long as there are elements in the arrays to be merged */ + while(a.length > 0 || b.length > 0){ + /* are there elements to be merged, if yes, compare them and merge */ + var n = a.length > 0 && b.length > 0 ? a[0] < b[0] ? a.shift() : b.shift() : b.length > 0 ? b.shift() : a.length > 0 ? a.shift() : null; + /* always push the smaller one onto the result set */ + n != null && c.push(n); + } + return c; + } + /* this mergeSort implementation cuts the array in half, wich should be fine with randomized arrays, but introduces the risk of a worst-case scenario */ + median = Math.floor(arr.length / 2); + var part1 = arr.slice(0, median); /* for some reason it doesn't work if inserted directly in the return statement (tried so with firefox) */ + var part2 = arr.slice(median - arr.length); + return arr.length <= 1 ? arr : merge( + mergeSort(part1), /* first half */ + mergeSort(part2) /* second half */ + ); +} + +/* Balanced Red-Black-Tree */ +function RedBlackTree(arr) { + +} + +function BTree(arr) { + +} + +function NaryTree(n, arr) { + +} + +/** + * Knuth-Morris-Pratt string matching algorithm - finds a pattern in a text. + * FIXME: Doesn't work correctly yet. + */ +function kmp(p, t) { + + /** + * PREFIX, OVERLAP or FALIURE function for KMP. Computes how many iterations + * the algorithm can skip after a mismatch. + * + * @input p - pattern (string) + * @result array of skippable iterations + */ + function prefix(p) { + /* pi contains the computed skip marks */ + var pi = [0], k = 0; + for(q = 1; q < p.length; q++) { + while(k > 0 && (p.charAt(k) != p.charAt(q))) + k = pi[k-1]; + + (p.charAt(k) == p.charAt(q)) && k++; + + pi[q] = k; + } + return pi; + } + + /* The actual KMP algorithm starts here. */ + + var pi = prefix(p), q = 0, result = []; + + for(var i = 0; i < t.length; i++) { + /* jump forward as long as the character doesn't match */ + while((q > 0) && (p.charAt(q) != t.charAt(i))) + q = pi[q]; + + (p.charAt(q) == t.charAt(i)) && q++; + + (q == p.length) && result.push(i - p.length) && (q = pi[q]); + } + + return result; +} + +/* step for algorithm visualisation */ +function step(comment, funct) { + //wait for input + //display comment (before or after waiting) +// next.wait(); + /* execute callback function */ + funct(); +} + +/** + * Curry - Function currying + * Copyright (c) 2008 Ariel Flesler - aflesler(at)gmail(dot)com | http://flesler.blogspot.com + * Licensed under BSD (http://www.opensource.org/licenses/bsd-license.php) + * Date: 10/4/2008 + * + * @author Ariel Flesler + * @version 1.0.1 + */ +function curry( fn ){ + return function(){ + var args = curry.args(arguments), + master = arguments.callee, + self = this; + + return args.length >= fn.length ? fn.apply(self,args) : function(){ + return master.apply( self, args.concat(curry.args(arguments)) ); + }; + }; +}; + +curry.args = function( args ){ + return Array.prototype.slice.call(args); +}; + +Function.prototype.curry = function(){ + return curry(this); +}; + +/** + * Topological Sort + * + * Sort a directed graph based on incoming edges + * + * Coded by Jake Stothard + */ +function topological_sort(g) { + //Mark nodes as "deleted" instead of actually deleting them + //That way we don't have to copy g + + for(i in g.nodes) + g.nodes[i].deleted = false; + + var ret = topological_sort_helper(g); + + //Cleanup: Remove the deleted property + for(i in g.nodes) + delete g.nodes[i].deleted + + return ret; +} +function topological_sort_helper(g) { + //Find node with no incoming edges + var node; + for(i in g.nodes) { + if(g.nodes[i].deleted) + continue; //Bad style, meh + + var incoming = false; + for(j in g.nodes[i].edges) { + if(g.nodes[i].edges[j].target == g.nodes[i] + && g.nodes[i].edges[j].source.deleted == false) { + incoming = true; + break; + } + } + if(!incoming) { + node = g.nodes[i]; + break; + } + } + + // Either unsortable or done. Either way, GTFO + if(node == undefined) + return []; + + //"Delete" node from g + node.deleted = true; + + var tail = topological_sort_helper(g); + + tail.unshift(node); + + return tail; +} diff --git a/addons/base_diagram/static/lib/js/dracula_graffle.js b/addons/base_diagram/static/lib/js/dracula_graffle.js new file mode 100644 index 00000000000..9d4fd2099e8 --- /dev/null +++ b/addons/base_diagram/static/lib/js/dracula_graffle.js @@ -0,0 +1,106 @@ +/** + * Originally grabbed from the official RaphaelJS Documentation + * http://raphaeljs.com/graffle.html + * Adopted (arrows) and commented by Philipp Strathausen http://blog.ameisenbar.de + * Licenced under the MIT licence. + */ + +/** + * Usage: + * connect two shapes + * parameters: + * source shape [or connection for redrawing], + * target shape, + * style with { fg : linecolor, bg : background color, directed: boolean } + * returns: + * connection { draw = function() } + */ +Raphael.fn.connection = function (obj1, obj2, style) { + var selfRef = this; + /* create and return new connection */ + var edge = {/* + from : obj1, + to : obj2, + style : style,*/ + draw : function() { + /* get bounding boxes of target and source */ + var bb1 = obj1.getBBox(); + var bb2 = obj2.getBBox(); + var off1 = 0; + var off2 = 0; + /* coordinates for potential connection coordinates from/to the objects */ + var p = [ + {x: bb1.x + bb1.width / 2, y: bb1.y - off1}, /* NORTH 1 */ + {x: bb1.x + bb1.width / 2, y: bb1.y + bb1.height + off1}, /* SOUTH 1 */ + {x: bb1.x - off1, y: bb1.y + bb1.height / 2}, /* WEST 1 */ + {x: bb1.x + bb1.width + off1, y: bb1.y + bb1.height / 2}, /* EAST 1 */ + {x: bb2.x + bb2.width / 2, y: bb2.y - off2}, /* NORTH 2 */ + {x: bb2.x + bb2.width / 2, y: bb2.y + bb2.height + off2}, /* SOUTH 2 */ + {x: bb2.x - off2, y: bb2.y + bb2.height / 2}, /* WEST 2 */ + {x: bb2.x + bb2.width + off2, y: bb2.y + bb2.height / 2} /* EAST 2 */ + ]; + + /* distances between objects and according coordinates connection */ + var d = {}, dis = []; + + /* + * find out the best connection coordinates by trying all possible ways + */ + /* loop the first object's connection coordinates */ + for (var i = 0; i < 4; i++) { + /* loop the seond object's connection coordinates */ + for (var j = 4; j < 8; j++) { + var dx = Math.abs(p[i].x - p[j].x), + dy = Math.abs(p[i].y - p[j].y); + if ((i == j - 4) || (((i != 3 && j != 6) || p[i].x < p[j].x) && ((i != 2 && j != 7) || p[i].x > p[j].x) && ((i != 0 && j != 5) || p[i].y > p[j].y) && ((i != 1 && j != 4) || p[i].y < p[j].y))) { + dis.push(dx + dy); + d[dis[dis.length - 1].toFixed(3)] = [i, j]; + } + } + } + var res = dis.length == 0 ? [0, 4] : d[Math.min.apply(Math, dis).toFixed(3)]; + /* bezier path */ + var x1 = p[res[0]].x, + y1 = p[res[0]].y, + x4 = p[res[1]].x, + y4 = p[res[1]].y, + dx = Math.max(Math.abs(x1 - x4) / 2, 10), + dy = Math.max(Math.abs(y1 - y4) / 2, 10), + x2 = [x1, x1, x1 - dx, x1 + dx][res[0]].toFixed(3), + y2 = [y1 - dy, y1 + dy, y1, y1][res[0]].toFixed(3), + x3 = [0, 0, 0, 0, x4, x4, x4 - dx, x4 + dx][res[1]].toFixed(3), + y3 = [0, 0, 0, 0, y1 + dy, y1 - dy, y4, y4][res[1]].toFixed(3); + /* assemble path and arrow */ + var path = ["M", x1.toFixed(3), y1.toFixed(3), "C", x2, y2, x3, y3, x4.toFixed(3), y4.toFixed(3)].join(","); + /* arrow */ + if(style && style.directed) { + /* magnitude, length of the last path vector */ + var mag = Math.sqrt((y4 - y3) * (y4 - y3) + (x4 - x3) * (x4 - x3)); + /* vector normalisation to specified length */ + var norm = function(x,l){return (-x*(l||5)/mag);}; + /* calculate array coordinates (two lines orthogonal to the path vector) */ + var arr = [ + {x:(norm(x4-x3)+norm(y4-y3)+x4).toFixed(3), y:(norm(y4-y3)+norm(x4-x3)+y4).toFixed(3)}, + {x:(norm(x4-x3)-norm(y4-y3)+x4).toFixed(3), y:(norm(y4-y3)-norm(x4-x3)+y4).toFixed(3)} + ]; + path = path + ",M"+arr[0].x+","+arr[0].y+",L"+x4+","+y4+",L"+arr[1].x+","+arr[1].y; + } + /* function to be used for moving existent path(s), e.g. animate() or attr() */ + var move = "attr"; + /* applying path(s) */ + edge.fg && edge.fg[move]({path:path}) + || (edge.fg = selfRef.path(path).attr({stroke: style && style.stroke || "#000", fill: "none"}).toBack()); + edge.bg && edge.bg[move]({path:path}) + || style && style.fill && (edge.bg = style.fill.split && selfRef.path(path).attr({stroke: style.fill.split("|")[0], fill: "none", "stroke-width": style.fill.split("|")[1] || 3}).toBack()); + /* setting label */ + style && style.label + && (edge.label && edge.label.attr({x:(x1+x4)/2, y:(y1+y4)/2}) + || (edge.label = selfRef.text((x1+x4)/2, (y1+y4)/2, style.label).attr({fill: "#000", "font-size": style["font-size"] || "12px"}))); +// && selfRef.text(x4, y4, style.label).attr({stroke: style && style.stroke || "#fff", "font-weight":"bold", "font-size":"20px"}) +// style && style.callback && style.callback(edge); + } + } + edge.draw(); + return edge; +}; +//Raphael.prototype.set.prototype.dodo=function(){console.log("works");}; diff --git a/addons/base_diagram/static/lib/js/dracula_graph.coffee b/addons/base_diagram/static/lib/js/dracula_graph.coffee new file mode 100644 index 00000000000..bb91945098d --- /dev/null +++ b/addons/base_diagram/static/lib/js/dracula_graph.coffee @@ -0,0 +1,524 @@ +### + * Dracula Graph Layout and Drawing Framework 0.0.3alpha + * (c) 2010 Philipp Strathausen , http://strathausen.eu + * + * Contributions by: + * Branched by Jake Stothard . + * + * based on the Graph JavaScript framework, version 0.0.1 + * (c) 2006 Aslak Hellesoy + * (c) 2006 Dave Hoover + * + * Ported from Graph::Layouter::Spring in + * http://search.cpan.org/~pasky/Graph-Layderer-0.02/ + * The algorithm is based on a spring-style layouter of a Java-based social + * network tracker PieSpy written by Paul Mutton Epaul@jibble.orgE. + * + * This code is freely distributable under the terms of an MIT-style license. + * For details, see the Graph web site: http://dev.buildpatternd.com/trac + * + * Links: + * + * Graph Dracula JavaScript Framework: + * http://graphdracula.net + * + * Demo of the original applet: + * http://redsquirrel.com/dave/work/webdep/ + * + * Mirrored original source code at snipplr: + * http://snipplr.com/view/1950/graph-javascript-framework-version-001/ + * + * Original usage example: + * http://ajaxian.com/archives/new-javascriptcanvas-graph-library + * +### + + +### + Edge Factory +### +AbstractEdge = -> + +AbstractEdge.prototype = + hide: -> + @connection.fg.hide() + @connection.bg && @bg.connection.hide() + +EdgeFactory = -> + @template = new AbstractEdge() + @template.style = new Object() + @template.style.directed = false + @template.weight = 1 + +EdgeFactory.prototype = + build: (source, target) -> + e = jQuery.extend true, {}, @template + e.source = source + e.target = target + e + +### + Graph +### +Graph = -> + @nodes = {} + @edges = [] + @snapshots = [] # previous graph states TODO to be implemented + @edgeFactory = new EdgeFactory() + +Graph.prototype = +### + add a node + @id the node's ID (string or number) + @content (optional, dictionary) can contain any information that is + being interpreted by the layout algorithm or the graph + representation +### + addNode: (id, content) -> + # testing if node is already existing in the graph + if @nodes[id] == undefined + @nodes[id] = new Graph.Node id, content + @nodes[id] + + addEdge: (source, target, style) -> + s = @addNode source + t = @addNode target + var edge = @edgeFactory.build s, t + jQuery.extend edge.style, style + s.edges.push edge + @edges.push edge + # NOTE: Even directed edges are added to both nodes. + t.edges.push edge + + # TODO to be implemented + # Preserve a copy of the graph state (nodes, positions, ...) + # @comment a comment describing the state + snapShot: (comment) -> + ###/* FIXME + var graph = new Graph() + graph.nodes = jQuery.extend(true, {}, @nodes) + graph.edges = jQuery.extend(true, {}, @edges) + @snapshots.push({comment: comment, graph: graph}) + */ + ### + + removeNode: (id) -> + delete @nodes[id] + for i = 0; i < @edges.length; i++ + if @edges[i].source.id == id || @edges[i].target.id == id + @edges.splice(i, 1) + i-- + +/* + * Node + */ +Graph.Node = (id, node) -> + node = node || {} + node.id = id + node.edges = [] + node.hide = -> + @hidden = true + @shape && @shape.hide() # FIXME this is representation specific code and should be elsewhere */ + for(i in @edges) + (@edges[i].source.id == id || @edges[i].target == id) && @edges[i].hide && @edges[i].hide() + + node.show = -> + @hidden = false + @shape && @shape.show() + for(i in @edges) + (@edges[i].source.id == id || @edges[i].target == id) && @edges[i].show && @edges[i].show() + + node + +Graph.Node.prototype = { } + +### + Renderer base class +### +Graph.Renderer = { } + +### + Renderer implementation using RaphaelJS +### +Graph.Renderer.Raphael = (element, graph, width, height) -> + @width = width || 400 + @height = height || 400 + var selfRef = this + @r = Raphael element, @width, @height + @radius = 40 # max dimension of a node + @graph = graph + @mouse_in = false + + # TODO default node rendering + if(!@graph.render) { + @graph.render = -> + return + } + } + + /* + * Dragging + */ + @isDrag = false + @dragger = (e) -> + @dx = e.clientX + @dy = e.clientY + selfRef.isDrag = this + @set && @set.animate "fill-opacity": .1, 200 && @set.toFront() + e.preventDefault && e.preventDefault() + + document.onmousemove = (e) { + e = e || window.event + if (selfRef.isDrag) { + var bBox = selfRef.isDrag.set.getBBox() + // TODO round the coordinates here (eg. for proper image representation) + var newX = e.clientX - selfRef.isDrag.dx + (bBox.x + bBox.width / 2) + var newY = e.clientY - selfRef.isDrag.dy + (bBox.y + bBox.height / 2) + /* prevent shapes from being dragged out of the canvas */ + var clientX = e.clientX - (newX < 20 ? newX - 20 : newX > selfRef.width - 20 ? newX - selfRef.width + 20 : 0) + var clientY = e.clientY - (newY < 20 ? newY - 20 : newY > selfRef.height - 20 ? newY - selfRef.height + 20 : 0) + selfRef.isDrag.set.translate(clientX - Math.round(selfRef.isDrag.dx), clientY - Math.round(selfRef.isDrag.dy)) + // console.log(clientX - Math.round(selfRef.isDrag.dx), clientY - Math.round(selfRef.isDrag.dy)) + for (var i in selfRef.graph.edges) { + selfRef.graph.edges[i].connection && selfRef.graph.edges[i].connection.draw() + } + //selfRef.r.safari() + selfRef.isDrag.dx = clientX + selfRef.isDrag.dy = clientY + } + } + document.onmouseup = -> + selfRef.isDrag && selfRef.isDrag.set.animate({"fill-opacity": .6}, 500) + selfRef.isDrag = false + } + @draw() +} +Graph.Renderer.Raphael.prototype = { + translate: (point) { + return [ + (point[0] - @graph.layoutMinX) * @factorX + @radius, + (point[1] - @graph.layoutMinY) * @factorY + @radius + ] + }, + + rotate: (point, length, angle) { + var dx = length * Math.cos(angle) + var dy = length * Math.sin(angle) + return [point[0]+dx, point[1]+dy] + }, + + draw: -> + @factorX = (@width - 2 * @radius) / (@graph.layoutMaxX - @graph.layoutMinX) + @factorY = (@height - 2 * @radius) / (@graph.layoutMaxY - @graph.layoutMinY) + for (i in @graph.nodes) { + @drawNode(@graph.nodes[i]) + } + for (var i = 0; i < @graph.edges.length; i++) { + @drawEdge(@graph.edges[i]) + } + }, + + drawNode: (node) { + var point = @translate([node.layoutPosX, node.layoutPosY]) + node.point = point + + /* if node has already been drawn, move the nodes */ + if(node.shape) { + var oBBox = node.shape.getBBox() + var opoint = { x: oBBox.x + oBBox.width / 2, y: oBBox.y + oBBox.height / 2} + node.shape.translate(Math.round(point[0] - opoint.x), Math.round(point[1] - opoint.y)) + @r.safari() + return node + }/* else, draw new nodes */ + + var shape + + /* if a node renderer is provided by the user, then use it + or the default render instead */ + if(!node.render) { + node.render = (r, node) { + /* the default node drawing */ + var color = Raphael.getColor() + var ellipse = r.ellipse(0, 0, 30, 20).attr({fill: color, stroke: color, "stroke-width": 2}) + /* set DOM node ID */ + ellipse.node.id = node.label || node.id + shape = r.set(). + push(ellipse). + push(r.text(0, 30, node.label || node.id)) + return shape + } + } + /* or check for an ajax representation of the nodes */ + if(node.shapes) { + // TODO ajax representation evaluation + } + + shape = node.render(@r, node).hide() + + shape.attr({"fill-opacity": .6}) + /* re-reference to the node an element belongs to, needed for dragging all elements of a node */ + shape.items.forEach((item){ item.set = shape; item.node.style.cursor = "move"; }) + shape.mousedown(@dragger) + + var box = shape.getBBox() + shape.translate(Math.round(point[0]-(box.x+box.width/2)),Math.round(point[1]-(box.y+box.height/2))) + //console.log(box,point) + node.hidden || shape.show() + node.shape = shape + }, + drawEdge: (edge) { + /* if this edge already exists the other way around and is undirected */ + if(edge.backedge) + return + if(edge.source.hidden || edge.target.hidden) { + edge.connection && edge.connection.fg.hide() | edge.connection.bg && edge.connection.bg.hide() + return + } + /* if edge already has been drawn, only refresh the edge */ + if(!edge.connection) { + edge.style && edge.style.callback && edge.style.callback(edge); // TODO move this somewhere else + edge.connection = @r.connection(edge.source.shape, edge.target.shape, edge.style) + return + } + //FIXME showing doesn't work well + edge.connection.fg.show() + edge.connection.bg && edge.connection.bg.show() + edge.connection.draw() + } +} +Graph.Layout = {} +Graph.Layout.Spring = (graph) { + @graph = graph + @iterations = 500 + @maxRepulsiveForceDistance = 6 + @k = 2 + @c = 0.01 + @maxVertexMovement = 0.5 + @layout() +} +Graph.Layout.Spring.prototype = { + layout: -> + @layoutPrepare() + for (var i = 0; i < @iterations; i++) { + @layoutIteration() + } + @layoutCalcBounds() + }, + + layoutPrepare: -> + for (i in @graph.nodes) { + var node = @graph.nodes[i] + node.layoutPosX = 0 + node.layoutPosY = 0 + node.layoutForceX = 0 + node.layoutForceY = 0 + } + + }, + + layoutCalcBounds: -> + var minx = Infinity, maxx = -Infinity, miny = Infinity, maxy = -Infinity + + for (i in @graph.nodes) { + var x = @graph.nodes[i].layoutPosX + var y = @graph.nodes[i].layoutPosY + + if(x > maxx) maxx = x + if(x < minx) minx = x + if(y > maxy) maxy = y + if(y < miny) miny = y + } + + @graph.layoutMinX = minx + @graph.layoutMaxX = maxx + @graph.layoutMinY = miny + @graph.layoutMaxY = maxy + }, + + layoutIteration: -> + // Forces on nodes due to node-node repulsions + + var prev = new Array() + for(var c in @graph.nodes) { + var node1 = @graph.nodes[c] + for (var d in prev) { + var node2 = @graph.nodes[prev[d]] + @layoutRepulsive(node1, node2) + + } + prev.push(c) + } + + // Forces on nodes due to edge attractions + for (var i = 0; i < @graph.edges.length; i++) { + var edge = @graph.edges[i] + @layoutAttractive(edge); + } + + // Move by the given force + for (i in @graph.nodes) { + var node = @graph.nodes[i] + var xmove = @c * node.layoutForceX + var ymove = @c * node.layoutForceY + + var max = @maxVertexMovement + if(xmove > max) xmove = max + if(xmove < -max) xmove = -max + if(ymove > max) ymove = max + if(ymove < -max) ymove = -max + + node.layoutPosX += xmove + node.layoutPosY += ymove + node.layoutForceX = 0 + node.layoutForceY = 0 + } + }, + + layoutRepulsive: (node1, node2) { + var dx = node2.layoutPosX - node1.layoutPosX + var dy = node2.layoutPosY - node1.layoutPosY + var d2 = dx * dx + dy * dy + if(d2 < 0.01) { + dx = 0.1 * Math.random() + 0.1 + dy = 0.1 * Math.random() + 0.1 + var d2 = dx * dx + dy * dy + } + var d = Math.sqrt(d2) + if(d < @maxRepulsiveForceDistance) { + var repulsiveForce = @k * @k / d + node2.layoutForceX += repulsiveForce * dx / d + node2.layoutForceY += repulsiveForce * dy / d + node1.layoutForceX -= repulsiveForce * dx / d + node1.layoutForceY -= repulsiveForce * dy / d + } + }, + + layoutAttractive: (edge) { + var node1 = edge.source + var node2 = edge.target + + var dx = node2.layoutPosX - node1.layoutPosX + var dy = node2.layoutPosY - node1.layoutPosY + var d2 = dx * dx + dy * dy + if(d2 < 0.01) { + dx = 0.1 * Math.random() + 0.1 + dy = 0.1 * Math.random() + 0.1 + var d2 = dx * dx + dy * dy + } + var d = Math.sqrt(d2) + if(d > @maxRepulsiveForceDistance) { + d = @maxRepulsiveForceDistance + d2 = d * d + } + var attractiveForce = (d2 - @k * @k) / @k + if(edge.attraction == undefined) edge.attraction = 1 + attractiveForce *= Math.log(edge.attraction) * 0.5 + 1 + + node2.layoutForceX -= attractiveForce * dx / d + node2.layoutForceY -= attractiveForce * dy / d + node1.layoutForceX += attractiveForce * dx / d + node1.layoutForceY += attractiveForce * dy / d + } +} + +Graph.Layout.Ordered = (graph, order) { + @graph = graph + @order = order + @layout() +} +Graph.Layout.Ordered.prototype = { + layout: -> + @layoutPrepare() + @layoutCalcBounds() + }, + + layoutPrepare: (order) { + for (i in @graph.nodes) { + var node = @graph.nodes[i] + node.layoutPosX = 0 + node.layoutPosY = 0 + } + var counter = 0 + for (i in @order) { + var node = @order[i] + node.layoutPosX = counter + node.layoutPosY = Math.random() + counter++ + } + }, + + layoutCalcBounds: -> + var minx = Infinity, maxx = -Infinity, miny = Infinity, maxy = -Infinity + + for (i in @graph.nodes) { + var x = @graph.nodes[i].layoutPosX + var y = @graph.nodes[i].layoutPosY + + if(x > maxx) maxx = x + if(x < minx) minx = x + if(y > maxy) maxy = y + if(y < miny) miny = y + } + + @graph.layoutMinX = minx + @graph.layoutMaxX = maxx + + @graph.layoutMinY = miny + @graph.layoutMaxY = maxy + } +} + +/* + * usefull JavaScript extensions, + */ + + log(a) {console.log&&console.log(a);} + +/* + * Raphael Tooltip Plugin + * - attaches an element as a tooltip to another element + * + * Usage example, adding a rectangle as a tooltip to a circle: + * + * paper.circle(100,100,10).tooltip(paper.rect(0,0,20,30)) + * + * If you want to use more shapes, you'll have to put them into a set. + * + */ +Raphael.el.tooltip = (tp) { + @tp = tp + @tp.o = {x: 0, y: 0} + @tp.hide() + @hover( + (event){ + @mousemove((event){ + @tp.translate(event.clientX - + @tp.o.x,event.clientY - @tp.o.y) + @tp.o = {x: event.clientX, y: event.clientY} + }) + @tp.show().toFront() + }, + (event){ + @tp.hide() + @unmousemove() + }) + return this +} + +/* For IE */ +if (!Array.prototype.forEach) +{ + Array.prototype.forEach = (fun /*, thisp*/) + { + var len = @length + if (typeof fun != "") + throw new TypeError() + + var thisp = arguments[1] + for (var i = 0; i < len; i++) + { + if (i in this) + fun.call(thisp, this[i], i, this) + } + } +} diff --git a/addons/base_diagram/static/lib/js/dracula_graph.js b/addons/base_diagram/static/lib/js/dracula_graph.js new file mode 100644 index 00000000000..f7069c5d2e5 --- /dev/null +++ b/addons/base_diagram/static/lib/js/dracula_graph.js @@ -0,0 +1,525 @@ +/* + * Dracula Graph Layout and Drawing Framework 0.0.3alpha + * (c) 2010 Philipp Strathausen , http://strathausen.eu + * Contributions by Jake Stothard . + * + * based on the Graph JavaScript framework, version 0.0.1 + * (c) 2006 Aslak Hellesoy + * (c) 2006 Dave Hoover + * + * Ported from Graph::Layouter::Spring in + * http://search.cpan.org/~pasky/Graph-Layderer-0.02/ + * The algorithm is based on a spring-style layouter of a Java-based social + * network tracker PieSpy written by Paul Mutton . + * + * This code is freely distributable under the MIT license. Commercial use is + * hereby granted without any cost or restriction. + * + * Links: + * + * Graph Dracula JavaScript Framework: + * http://graphdracula.net + * + /*--------------------------------------------------------------------------*/ + +/* + * Edge Factory + */ +var AbstractEdge = function() { +} +AbstractEdge.prototype = { + hide: function() { + this.connection.fg.hide(); + this.connection.bg && this.bg.connection.hide(); + } +}; +var EdgeFactory = function() { + this.template = new AbstractEdge(); + this.template.style = new Object(); + this.template.style.directed = false; + this.template.weight = 1; +}; +EdgeFactory.prototype = { + build: function(source, target) { + var e = jQuery.extend(true, {}, this.template); + e.source = source; + e.target = target; + return e; + } +}; + +/* + * Graph + */ +var Graph = function() { + this.nodes = {}; + this.edges = []; + this.snapshots = []; // previous graph states TODO to be implemented + this.edgeFactory = new EdgeFactory(); +}; +Graph.prototype = { + /* + * add a node + * @id the node's ID (string or number) + * @content (optional, dictionary) can contain any information that is + * being interpreted by the layout algorithm or the graph + * representation + */ + addNode: function(id, content) { + /* testing if node is already existing in the graph */ + if(this.nodes[id] == undefined) { + this.nodes[id] = new Graph.Node(id, content); + } + return this.nodes[id]; + }, + + addEdge: function(source, target, style) { + var s = this.addNode(source); + var t = this.addNode(target); + var edge = this.edgeFactory.build(s, t); + jQuery.extend(edge.style,style); + s.edges.push(edge); + this.edges.push(edge); + // NOTE: Even directed edges are added to both nodes. + t.edges.push(edge); + }, + + /* TODO to be implemented + * Preserve a copy of the graph state (nodes, positions, ...) + * @comment a comment describing the state + */ + snapShot: function(comment) { + /* FIXME + var graph = new Graph(); + graph.nodes = jQuery.extend(true, {}, this.nodes); + graph.edges = jQuery.extend(true, {}, this.edges); + this.snapshots.push({comment: comment, graph: graph}); + */ + }, + removeNode: function(id) { + delete this.nodes[id]; + for(var i = 0; i < this.edges.length; i++) { + if (this.edges[i].source.id == id || this.edges[i].target.id == id) { + this.edges.splice(i, 1); + i--; + } + } + } +}; + +/* + * Node + */ +Graph.Node = function(id, node){ + node = node || {}; + node.id = id; + node.edges = []; + node.hide = function() { + this.hidden = true; + this.shape && this.shape.hide(); /* FIXME this is representation specific code and should be elsewhere */ + for(i in this.edges) + (this.edges[i].source.id == id || this.edges[i].target == id) && this.edges[i].hide && this.edges[i].hide(); + }; + node.show = function() { + this.hidden = false; + this.shape && this.shape.show(); + for(i in this.edges) + (this.edges[i].source.id == id || this.edges[i].target == id) && this.edges[i].show && this.edges[i].show(); + }; + return node; +}; +Graph.Node.prototype = { +}; + +/* + * Renderer base class + */ +Graph.Renderer = {}; + +/* + * Renderer implementation using RaphaelJS + */ +Graph.Renderer.Raphael = function(element, graph, width, height) { + this.width = width || 800; + this.height = height || 800; + var selfRef = this; + this.r = Raphael(element, this.width, this.height); + this.radius = 40; /* max dimension of a node */ + this.graph = graph; + this.mouse_in = false; + + /* TODO default node rendering function */ + if(!this.graph.render) { + this.graph.render = function() { + return; + } + } + + /* + * Dragging + */ + this.isDrag = false; + this.dragger = function (e) { + this.dx = e.clientX; + this.dy = e.clientY; + selfRef.isDrag = this; + this.set && this.set.animate({"fill-opacity": .1}, 200) && this.set.toFront(); + e.preventDefault && e.preventDefault(); + }; + + var d = document.getElementById(element); + d.onmousemove = function (e) { + e = e || window.event; + if (selfRef.isDrag) { + var bBox = selfRef.isDrag.set.getBBox(); + // TODO round the coordinates here (eg. for proper image representation) + var newX = e.clientX - selfRef.isDrag.dx + (bBox.x + bBox.width / 2); + var newY = e.clientY - selfRef.isDrag.dy + (bBox.y + bBox.height / 2); + /* prevent shapes from being dragged out of the canvas */ + var clientX = e.clientX - (newX < 20 ? newX - 20 : newX > selfRef.width - 20 ? newX - selfRef.width + 20 : 0); + var clientY = e.clientY - (newY < 20 ? newY - 20 : newY > selfRef.height - 20 ? newY - selfRef.height + 20 : 0); + selfRef.isDrag.set.translate(clientX - Math.round(selfRef.isDrag.dx), clientY - Math.round(selfRef.isDrag.dy)); + // console.log(clientX - Math.round(selfRef.isDrag.dx), clientY - Math.round(selfRef.isDrag.dy)); + for (var i in selfRef.graph.edges) { + selfRef.graph.edges[i].connection && selfRef.graph.edges[i].connection.draw(); + } + //selfRef.r.safari(); + selfRef.isDrag.dx = clientX; + selfRef.isDrag.dy = clientY; + } + }; + d.onmouseup = function () { + selfRef.isDrag && selfRef.isDrag.set.animate({"fill-opacity": .6}, 500); + selfRef.isDrag = false; + }; + this.draw(); +}; +Graph.Renderer.Raphael.prototype = { + translate: function(point) { + return [ + (point[0] - this.graph.layoutMinX) * this.factorX + this.radius, + (point[1] - this.graph.layoutMinY) * this.factorY + this.radius + ]; + }, + + rotate: function(point, length, angle) { + var dx = length * Math.cos(angle); + var dy = length * Math.sin(angle); + return [point[0]+dx, point[1]+dy]; + }, + + draw: function() { + this.factorX = (this.width - 2 * this.radius) / (this.graph.layoutMaxX - this.graph.layoutMinX); + this.factorY = (this.height - 2 * this.radius) / (this.graph.layoutMaxY - this.graph.layoutMinY); + for (i in this.graph.nodes) { + this.drawNode(this.graph.nodes[i]); + } + for (var i = 0; i < this.graph.edges.length; i++) { + this.drawEdge(this.graph.edges[i]); + } + }, + + drawNode: function(node) { + var point = this.translate([node.layoutPosX, node.layoutPosY]); + node.point = point; + + /* if node has already been drawn, move the nodes */ + if(node.shape) { + var oBBox = node.shape.getBBox(); + var opoint = { x: oBBox.x + oBBox.width / 2, y: oBBox.y + oBBox.height / 2}; + node.shape.translate(Math.round(point[0] - opoint.x), Math.round(point[1] - opoint.y)); + this.r.safari(); + return node; + }/* else, draw new nodes */ + + var shape; + + /* if a node renderer function is provided by the user, then use it + or the default render function instead */ + if(!node.render) { + node.render = function(r, node) { + /* the default node drawing */ + var color = Raphael.getColor(); + var ellipse = r.ellipse(0, 0, 30, 20).attr({fill: color, stroke: color, "stroke-width": 2}); + /* set DOM node ID */ + ellipse.node.id = node.label || node.id; + shape = r.set(). + push(ellipse). + push(r.text(0, 30, node.label || node.id)); + return shape; + } + } + /* or check for an ajax representation of the nodes */ + if(node.shapes) { + // TODO ajax representation evaluation + } + + shape = node.render(this.r, node).hide(); + + shape.attr({"fill-opacity": .6}); + /* re-reference to the node an element belongs to, needed for dragging all elements of a node */ + shape.items.forEach(function(item){ item.set = shape; item.node.style.cursor = "move"; }); + shape.mousedown(this.dragger); + + var box = shape.getBBox(); + shape.translate(Math.round(point[0]-(box.x+box.width/2)),Math.round(point[1]-(box.y+box.height/2))) + //console.log(box,point); + node.hidden || shape.show(); + node.shape = shape; + }, + drawEdge: function(edge) { + /* if this edge already exists the other way around and is undirected */ + if(edge.backedge) + return; + if(edge.source.hidden || edge.target.hidden) { + edge.connection && edge.connection.fg.hide() | edge.connection.bg && edge.connection.bg.hide(); + return; + } + /* if edge already has been drawn, only refresh the edge */ + if(!edge.connection) { + edge.style && edge.style.callback && edge.style.callback(edge); // TODO move this somewhere else + edge.connection = this.r.connection(edge.source.shape, edge.target.shape, edge.style); + return; + } + //FIXME showing doesn't work well + edge.connection.fg.show(); + edge.connection.bg && edge.connection.bg.show(); + edge.connection.draw(); + } +}; +Graph.Layout = {}; +Graph.Layout.Spring = function(graph) { + this.graph = graph; + this.iterations = 500; + this.maxRepulsiveForceDistance = 6; + this.k = 2; + this.c = 0.01; + this.maxVertexMovement = 0.5; + this.layout(); +}; +Graph.Layout.Spring.prototype = { + layout: function() { + this.layoutPrepare(); + for (var i = 0; i < this.iterations; i++) { + this.layoutIteration(); + } + this.layoutCalcBounds(); + }, + + layoutPrepare: function() { + for (i in this.graph.nodes) { + var node = this.graph.nodes[i]; + node.layoutPosX = 0; + node.layoutPosY = 0; + node.layoutForceX = 0; + node.layoutForceY = 0; + } + + }, + + layoutCalcBounds: function() { + var minx = Infinity, maxx = -Infinity, miny = Infinity, maxy = -Infinity; + + for (i in this.graph.nodes) { + var x = this.graph.nodes[i].layoutPosX; + var y = this.graph.nodes[i].layoutPosY; + + if(x > maxx) maxx = x; + if(x < minx) minx = x; + if(y > maxy) maxy = y; + if(y < miny) miny = y; + } + + this.graph.layoutMinX = minx; + this.graph.layoutMaxX = maxx; + this.graph.layoutMinY = miny; + this.graph.layoutMaxY = maxy; + }, + + layoutIteration: function() { + // Forces on nodes due to node-node repulsions + + var prev = new Array(); + for(var c in this.graph.nodes) { + var node1 = this.graph.nodes[c]; + for (var d in prev) { + var node2 = this.graph.nodes[prev[d]]; + this.layoutRepulsive(node1, node2); + + } + prev.push(c); + } + + // Forces on nodes due to edge attractions + for (var i = 0; i < this.graph.edges.length; i++) { + var edge = this.graph.edges[i]; + this.layoutAttractive(edge); + } + + // Move by the given force + for (i in this.graph.nodes) { + var node = this.graph.nodes[i]; + var xmove = this.c * node.layoutForceX; + var ymove = this.c * node.layoutForceY; + + var max = this.maxVertexMovement; + if(xmove > max) xmove = max; + if(xmove < -max) xmove = -max; + if(ymove > max) ymove = max; + if(ymove < -max) ymove = -max; + + node.layoutPosX += xmove; + node.layoutPosY += ymove; + node.layoutForceX = 0; + node.layoutForceY = 0; + } + }, + + layoutRepulsive: function(node1, node2) { + var dx = node2.layoutPosX - node1.layoutPosX; + var dy = node2.layoutPosY - node1.layoutPosY; + var d2 = dx * dx + dy * dy; + if(d2 < 0.01) { + dx = 0.1 * Math.random() + 0.1; + dy = 0.1 * Math.random() + 0.1; + var d2 = dx * dx + dy * dy; + } + var d = Math.sqrt(d2); + if(d < this.maxRepulsiveForceDistance) { + var repulsiveForce = this.k * this.k / d; + node2.layoutForceX += repulsiveForce * dx / d; + node2.layoutForceY += repulsiveForce * dy / d; + node1.layoutForceX -= repulsiveForce * dx / d; + node1.layoutForceY -= repulsiveForce * dy / d; + } + }, + + layoutAttractive: function(edge) { + var node1 = edge.source; + var node2 = edge.target; + + var dx = node2.layoutPosX - node1.layoutPosX; + var dy = node2.layoutPosY - node1.layoutPosY; + var d2 = dx * dx + dy * dy; + if(d2 < 0.01) { + dx = 0.1 * Math.random() + 0.1; + dy = 0.1 * Math.random() + 0.1; + var d2 = dx * dx + dy * dy; + } + var d = Math.sqrt(d2); + if(d > this.maxRepulsiveForceDistance) { + d = this.maxRepulsiveForceDistance; + d2 = d * d; + } + var attractiveForce = (d2 - this.k * this.k) / this.k; + if(edge.attraction == undefined) edge.attraction = 1; + attractiveForce *= Math.log(edge.attraction) * 0.5 + 1; + + node2.layoutForceX -= attractiveForce * dx / d; + node2.layoutForceY -= attractiveForce * dy / d; + node1.layoutForceX += attractiveForce * dx / d; + node1.layoutForceY += attractiveForce * dy / d; + } +}; + +Graph.Layout.Ordered = function(graph, order) { + this.graph = graph; + this.order = order; + this.layout(); +}; +Graph.Layout.Ordered.prototype = { + layout: function() { + this.layoutPrepare(); + this.layoutCalcBounds(); + }, + + layoutPrepare: function(order) { + for (i in this.graph.nodes) { + var node = this.graph.nodes[i]; + node.layoutPosX = 0; + node.layoutPosY = 0; + } + var counter = 0; + for (i in this.order) { + var node = this.order[i]; + node.layoutPosX = counter; + node.layoutPosY = Math.random(); + counter++; + } + }, + + layoutCalcBounds: function() { + var minx = Infinity, maxx = -Infinity, miny = Infinity, maxy = -Infinity; + + for (i in this.graph.nodes) { + var x = this.graph.nodes[i].layoutPosX; + var y = this.graph.nodes[i].layoutPosY; + + if(x > maxx) maxx = x; + if(x < minx) minx = x; + if(y > maxy) maxy = y; + if(y < miny) miny = y; + } + + this.graph.layoutMinX = minx; + this.graph.layoutMaxX = maxx; + + this.graph.layoutMinY = miny; + this.graph.layoutMaxY = maxy; + } +}; + +/* + * usefull JavaScript extensions, + */ + +function log(a) {console.log&&console.log(a);} + +/* + * Raphael Tooltip Plugin + * - attaches an element as a tooltip to another element + * + * Usage example, adding a rectangle as a tooltip to a circle: + * + * paper.circle(100,100,10).tooltip(paper.rect(0,0,20,30)); + * + * If you want to use more shapes, you'll have to put them into a set. + * + */ +Raphael.el.tooltip = function (tp) { + this.tp = tp; + this.tp.o = {x: 0, y: 0}; + this.tp.hide(); + this.hover( + function(event){ + this.mousemove(function(event){ + this.tp.translate(event.clientX - + this.tp.o.x,event.clientY - this.tp.o.y); + this.tp.o = {x: event.clientX, y: event.clientY}; + }); + this.tp.show().toFront(); + }, + function(event){ + this.tp.hide(); + this.unmousemove(); + }); + return this; +}; + +/* For IE */ +if (!Array.prototype.forEach) +{ + Array.prototype.forEach = function(fun /*, thisp*/) + { + var len = this.length; + if (typeof fun != "function") + throw new TypeError(); + + var thisp = arguments[1]; + for (var i = 0; i < len; i++) + { + if (i in this) + fun.call(thisp, this[i], i, this); + } + }; +} diff --git a/addons/base_diagram/static/lib/js/raphael-min.js b/addons/base_diagram/static/lib/js/raphael-min.js new file mode 100644 index 00000000000..8718b5bc749 --- /dev/null +++ b/addons/base_diagram/static/lib/js/raphael-min.js @@ -0,0 +1,7 @@ +/* + * Raphael 1.3.1 - JavaScript Vector Library + * + * Copyright (c) 2008 - 2009 Dmitry Baranovskiy (http://raphaeljs.com) + * Licensed under the MIT (http://www.opensource.org/licenses/mit-license.php) license. + */ +Raphael=(function(){var a=/[, ]+/,aO=/^(circle|rect|path|ellipse|text|image)$/,L=document,au=window,l={was:"Raphael" in au,is:au.Raphael},an=function(){if(an.is(arguments[0],"array")){var d=arguments[0],e=w[aW](an,d.splice(0,3+an.is(d[0],al))),S=e.set();for(var R=0,a0=d[m];R

";if(ag.childNodes[m]!=2){return null;}}an.svg=!(an.vml=an.type=="VML");aT[aY]=an[aY];an._id=0;an._oid=0;an.fn={};an.is=function(e,d){d=aZ.call(d);return((d=="object"||d=="undefined")&&typeof e==d)||(e==null&&d=="null")||aZ.call(aw.call(e).slice(8,-1))==d;};an.setWindow=function(d){au=d;L=au.document;};var aD=function(e){if(an.vml){var d=/^\s+|\s+$/g;aD=aj(function(R){var S;R=(R+at)[aP](d,at);try{var a0=new ActiveXObject("htmlfile");a0.write("");a0.close();S=a0.body;}catch(a2){S=createPopup().document.body;}var i=S.createTextRange();try{S.style.color=R;var a1=i.queryCommandValue("ForeColor");a1=((a1&255)<<16)|(a1&65280)|((a1&16711680)>>>16);return"#"+("000000"+a1[aA](16)).slice(-6);}catch(a2){return"none";}});}else{var E=L.createElement("i");E.title="Rapha\xebl Colour Picker";E.style.display="none";L.body[aL](E);aD=aj(function(i){E.style.color=i;return L.defaultView.getComputedStyle(E,at).getPropertyValue("color");});}return aD(e);};an.hsb2rgb=aj(function(a3,a1,a7){if(an.is(a3,"object")&&"h" in a3&&"s" in a3&&"b" in a3){a7=a3.b;a1=a3.s;a3=a3.h;}var R,S,a8;if(a7==0){return{r:0,g:0,b:0,hex:"#000"};}if(a3>1||a1>1||a7>1){a3/=255;a1/=255;a7/=255;}var a0=~~(a3*6),a4=(a3*6)-a0,E=a7*(1-a1),e=a7*(1-(a1*a4)),a9=a7*(1-(a1*(1-a4)));R=[a7,e,E,E,a9,a7,a7][a0];S=[a9,a7,a7,e,E,E,a9][a0];a8=[E,E,a9,a7,a7,e,E][a0];R*=255;S*=255;a8*=255;var a5={r:R,g:S,b:a8},d=(~~R)[aA](16),a2=(~~S)[aA](16),a6=(~~a8)[aA](16);d=d[aP](aU,"0");a2=a2[aP](aU,"0");a6=a6[aP](aU,"0");a5.hex="#"+d+a2+a6;return a5;},an);an.rgb2hsb=aj(function(d,e,a1){if(an.is(d,"object")&&"r" in d&&"g" in d&&"b" in d){a1=d.b;e=d.g;d=d.r;}if(an.is(d,"string")){var a3=an.getRGB(d);d=a3.r;e=a3.g;a1=a3.b;}if(d>1||e>1||a1>1){d/=255;e/=255;a1/=255;}var a0=g(d,e,a1),i=aI(d,e,a1),R,E,S=a0;if(i==a0){return{h:0,s:0,b:a0};}else{var a2=(a0-i);E=a2/a0;if(d==a0){R=(e-a1)/a2;}else{if(e==a0){R=2+((a1-d)/a2);}else{R=4+((d-e)/a2);}}R/=6;R<0&&R++;R>1&&R--;}return{h:R,s:E,b:S};},an);var aE=/,?([achlmqrstvxz]),?/gi;an._path2string=function(){return this.join(",")[aP](aE,"$1");};function aj(E,e,d){function i(){var R=Array[aY].slice.call(arguments,0),a0=R[az]("\u25ba"),S=i.cache=i.cache||{},a1=i.count=i.count||[];if(S[Q](a0)){return d?d(S[a0]):S[a0];}a1[m]>=1000&&delete S[a1.shift()];a1[f](a0);S[a0]=E[aW](e,R);return d?d(S[a0]):S[a0];}return i;}an.getRGB=aj(function(d){if(!d||!!((d=d+at).indexOf("-")+1)){return{r:-1,g:-1,b:-1,hex:"none",error:1};}if(d=="none"){return{r:-1,g:-1,b:-1,hex:"none"};}!(({hs:1,rg:1})[Q](d.substring(0,2))||d.charAt()=="#")&&(d=aD(d));var S,i,E,a2,a3,a0=d.match(x);if(a0){if(a0[2]){a2=G(a0[2].substring(5),16);E=G(a0[2].substring(3,5),16);i=G(a0[2].substring(1,3),16);}if(a0[3]){a2=G((a3=a0[3].charAt(3))+a3,16);E=G((a3=a0[3].charAt(2))+a3,16);i=G((a3=a0[3].charAt(1))+a3,16);}if(a0[4]){a0=a0[4][z](/\s*,\s*/);i=W(a0[0]);E=W(a0[1]);a2=W(a0[2]);}if(a0[5]){a0=a0[5][z](/\s*,\s*/);i=W(a0[0])*2.55;E=W(a0[1])*2.55;a2=W(a0[2])*2.55;}if(a0[6]){a0=a0[6][z](/\s*,\s*/);i=W(a0[0]);E=W(a0[1]);a2=W(a0[2]);return an.hsb2rgb(i,E,a2);}if(a0[7]){a0=a0[7][z](/\s*,\s*/);i=W(a0[0])*2.55;E=W(a0[1])*2.55;a2=W(a0[2])*2.55;return an.hsb2rgb(i,E,a2);}a0={r:i,g:E,b:a2};var e=(~~i)[aA](16),R=(~~E)[aA](16),a1=(~~a2)[aA](16);e=e[aP](aU,"0");R=R[aP](aU,"0");a1=a1[aP](aU,"0");a0.hex="#"+e+R+a1;return a0;}return{r:-1,g:-1,b:-1,hex:"none",error:1};},an);an.getColor=function(e){var i=this.getColor.start=this.getColor.start||{h:0,s:1,b:e||0.75},d=this.hsb2rgb(i.h,i.s,i.b);i.h+=0.075;if(i.h>1){i.h=0;i.s-=0.2;i.s<=0&&(this.getColor.start={h:0,s:1,b:i.b});}return d.hex;};an.getColor.reset=function(){delete this.start;};an.parsePathString=aj(function(d){if(!d){return null;}var i={a:7,c:6,h:1,l:2,m:2,q:4,s:4,t:2,v:1,z:0},e=[];if(an.is(d,"array")&&an.is(d[0],"array")){e=av(d);}if(!e[m]){(d+at)[aP](/([achlmqstvz])[\s,]*((-?\d*\.?\d*(?:e[-+]?\d+)?\s*,?\s*)+)/ig,function(R,E,a1){var a0=[],S=aZ.call(E);a1[aP](/(-?\d*\.?\d*(?:e[-+]?\d+)?)\s*,?\s*/ig,function(a3,a2){a2&&a0[f](+a2);});while(a0[m]>=i[S]){e[f]([E][aS](a0.splice(0,i[S])));if(!i[S]){break;}}});}e[aA]=an._path2string;return e;});an.findDotsAtSegment=function(e,d,be,bc,a0,R,a2,a1,a8){var a6=1-a8,a5=aM(a6,3)*e+aM(a6,2)*3*a8*be+a6*3*a8*a8*a0+aM(a8,3)*a2,a3=aM(a6,3)*d+aM(a6,2)*3*a8*bc+a6*3*a8*a8*R+aM(a8,3)*a1,ba=e+2*a8*(be-e)+a8*a8*(a0-2*be+e),a9=d+2*a8*(bc-d)+a8*a8*(R-2*bc+d),bd=be+2*a8*(a0-be)+a8*a8*(a2-2*a0+be),bb=bc+2*a8*(R-bc)+a8*a8*(a1-2*R+bc),a7=(1-a8)*e+a8*be,a4=(1-a8)*d+a8*bc,E=(1-a8)*a0+a8*a2,i=(1-a8)*R+a8*a1,S=(90-ab.atan((ba-bd)/(a9-bb))*180/ab.PI);(ba>bd||a91){bi=ab.sqrt(by)*bi;bg=ab.sqrt(by)*bg;}var E=bi*bi,br=bg*bg,bt=(a4==S?-1:1)*ab.sqrt(ab.abs((E*br-E*bn*bn-br*bo*bo)/(E*bn*bn+br*bo*bo))),bd=bt*bi*bn/bg+(a9+a8)/2,bc=bt*-bg*bo/bi+(bE+bD)/2,a3=ab.asin(((bE-bc)/bg).toFixed(7)),a2=ab.asin(((bD-bc)/bg).toFixed(7));a3=a9a2){a3=a3-R*2;}if(!S&&a2>a3){a2=a2-R*2;}}else{a3=bb[0];a2=bb[1];bd=bb[2];bc=bb[3];}var a7=a2-a3;if(ab.abs(a7)>bf){var be=a2,bh=a8,a5=bD;a2=a3+bf*(S&&a2>a3?1:-1);a8=bd+bi*ab.cos(a2);bD=bc+bg*ab.sin(a2);bm=K(a8,bD,bi,bg,ba,0,S,bh,a5,[a2,be,bd,bc]);}a7=a2-a3;var a1=ab.cos(a3),bC=ab.sin(a3),a0=ab.cos(a2),bB=ab.sin(a2),bp=ab.tan(a7/4),bs=4/3*bi*bp,bq=4/3*bg*bp,bz=[a9,bE],bx=[a9+bs*bC,bE-bq*a1],bw=[a8+bs*bB,bD-bq*a0],bu=[a8,bD];bx[0]=2*bz[0]-bx[0];bx[1]=2*bz[1]-bx[1];if(bb){return[bx,bw,bu][aS](bm);}else{bm=[bx,bw,bu][aS](bm)[az]()[z](",");var bk=[];for(var bv=0,bl=bm[m];bv1000000000000&&(a0=0.5);ab.abs(S)>1000000000000&&(S=0.5);if(a0>0&&a0<1){e=M(i,d,R,E,a9,a8,a5,a2,a0);a6[f](e.x);a3[f](e.y);}if(S>0&&S<1){e=M(i,d,R,E,a9,a8,a5,a2,S);a6[f](e.x);a3[f](e.y);}a7=(a8-2*E+d)-(a2-2*a8+E);a4=2*(E-d)-2*(a8-E);a1=d-E;a0=(-a4+ab.sqrt(a4*a4-4*a7*a1))/2/a7;S=(-a4-ab.sqrt(a4*a4-4*a7*a1))/2/a7;ab.abs(a0)>1000000000000&&(a0=0.5);ab.abs(S)>1000000000000&&(S=0.5);if(a0>0&&a0<1){e=M(i,d,R,E,a9,a8,a5,a2,a0);a6[f](e.x);a3[f](e.y);}if(S>0&&S<1){e=M(i,d,R,E,a9,a8,a5,a2,S);a6[f](e.x);a3[f](e.y);}return{min:{x:aI[aW](0,a6),y:aI[aW](0,a3)},max:{x:g[aW](0,a6),y:g[aW](0,a3)}};}),H=aj(function(a9,a4){var R=r(a9),a5=a4&&r(a4),a6={x:0,y:0,bx:0,by:0,X:0,Y:0,qx:null,qy:null},d={x:0,y:0,bx:0,by:0,X:0,Y:0,qx:null,qy:null},a0=function(ba,bb){var i,bc;if(!ba){return["C",bb.x,bb.y,bb.x,bb.y,bb.x,bb.y];}!(ba[0] in {T:1,Q:1})&&(bb.qx=bb.qy=null);switch(ba[0]){case"M":bb.X=ba[1];bb.Y=ba[2];break;case"A":ba=["C"][aS](K[aW](0,[bb.x,bb.y][aS](ba.slice(1))));break;case"S":i=bb.x+(bb.x-(bb.bx||bb.x));bc=bb.y+(bb.y-(bb.by||bb.y));ba=["C",i,bc][aS](ba.slice(1));break;case"T":bb.qx=bb.x+(bb.x-(bb.qx||bb.x));bb.qy=bb.y+(bb.y-(bb.qy||bb.y));ba=["C"][aS](aK(bb.x,bb.y,bb.qx,bb.qy,ba[1],ba[2]));break;case"Q":bb.qx=ba[1];bb.qy=ba[2];ba=["C"][aS](aK(bb.x,bb.y,ba[1],ba[2],ba[3],ba[4]));break;case"L":ba=["C"][aS](aX(bb.x,bb.y,ba[1],ba[2]));break;case"H":ba=["C"][aS](aX(bb.x,bb.y,ba[1],bb.y));break;case"V":ba=["C"][aS](aX(bb.x,bb.y,bb.x,ba[1]));break;case"Z":ba=["C"][aS](aX(bb.x,bb.y,bb.X,bb.Y));break;}return ba;},e=function(ba,bb){if(ba[bb][m]>7){ba[bb].shift();var bc=ba[bb];while(bc[m]){ba.splice(bb++,0,["C"][aS](bc.splice(0,6)));}ba.splice(bb,1);a7=g(R[m],a5&&a5[m]||0);}},E=function(be,bd,bb,ba,bc){if(be&&bd&&be[bc][0]=="M"&&bd[bc][0]!="M"){bd.splice(bc,0,["M",ba.x,ba.y]);bb.bx=0;bb.by=0;bb.x=be[bc][1];bb.y=be[bc][2];a7=g(R[m],a5&&a5[m]||0);}};for(var a2=0,a7=g(R[m],a5&&a5[m]||0);a23){return{container:1,x:arguments[0],y:arguments[1],width:arguments[2],height:arguments[3]};}}},aG=function(d,i){var e=this;for(var E in i){if(i[Q](E)&&!(E in d)){switch(typeof i[E]){case"function":(function(R){d[E]=d===e?R:function(){return R[aW](e,arguments);};})(i[E]);break;case"object":d[E]=d[E]||{};aG.call(this,d[E],i[E]);break;default:d[E]=i[E];break;}}}},ak=function(d,e){d==e.top&&(e.top=d.prev);d==e.bottom&&(e.bottom=d.next);d.next&&(d.next.prev=d.prev);d.prev&&(d.prev.next=d.next);},Y=function(d,e){if(e.top===d){return;}ak(d,e);d.next=null;d.prev=e.top;e.top.next=d;e.top=d;},k=function(d,e){if(e.bottom===d){return;}ak(d,e);d.next=e.bottom;d.prev=null;e.bottom.prev=d;e.bottom=d;},A=function(e,d,i){ak(e,i);d==i.top&&(i.top=e);d.next&&(d.next.prev=e);e.next=d.next;e.prev=d;d.next=e;},aq=function(e,d,i){ak(e,i);d==i.bottom&&(i.bottom=e);d.prev&&(d.prev.next=e);e.prev=d.prev;d.prev=e;e.next=d;},s=function(d){return function(){throw new Error("Rapha\xebl: you are calling to method \u201c"+d+"\u201d of removed object");};},ar=/^r(?:\(([^,]+?)\s*,\s*([^\)]+?)\))?/;if(an.svg){aT[aY].svgns="http://www.w3.org/2000/svg";aT[aY].xlink="http://www.w3.org/1999/xlink";var O=function(d){return +d+(~~d===d)*0.5;},V=function(S){for(var e=0,E=S[m];e0.5)*2-1);aM(a1-0.5,2)+aM(S-0.5,2)>0.25&&(S=ab.sqrt(0.25-aM(a1-0.5,2))*ba+0.5)&&S!=0.5&&(S=S.toFixed(5)-0.00001*ba);}return at;});a7=a7[z](/\s*\-\s*/);if(a4=="linear"){var a0=a7.shift();a0=-W(a0);if(isNaN(a0)){return null;}var R=[0,0,ab.cos(a0*ab.PI/180),ab.sin(a0*ab.PI/180)],a6=1/(g(ab.abs(R[2]),ab.abs(R[3]))||1);R[2]*=a6;R[3]*=a6;if(R[2]<0){R[0]=-R[2];R[2]=0;}if(R[3]<0){R[1]=-R[3];R[3]=0;}}var a3=p(a7);if(!a3){return null;}var e=aJ(a4+"Gradient");e.id="r"+(an._id++)[aA](36);aJ(e,a4=="radial"?{fx:a1,fy:S}:{x1:R[0],y1:R[1],x2:R[2],y2:R[3]});d.defs[aL](e);for(var a2=0,a8=a3[m];a2a1.height)&&(a1.height=a0.y+a0.height-a1.y);(a0.x+a0.width-a1.x>a1.width)&&(a1.width=a0.x+a0.width-a1.x);}}E&&this.hide();return a1;};ax[aY].attr=function(){if(this.removed){return this;}if(arguments[m]==0){var R={};for(var E in this.attrs){if(this.attrs[Q](E)){R[E]=this.attrs[E];}}this._.rt.deg&&(R.rotation=this.rotate());(this._.sx!=1||this._.sy!=1)&&(R.scale=this.scale());R.gradient&&R.fill=="none"&&(R.fill=R.gradient)&&delete R.gradient;return R;}if(arguments[m]==1&&an.is(arguments[0],"string")){if(arguments[0]=="translation"){return t.call(this);}if(arguments[0]=="rotation"){return this.rotate();}if(arguments[0]=="scale"){return this.scale();}if(arguments[0]=="fill"&&this.attrs.fill=="none"&&this.attrs.gradient){return this.attrs.gradient;}return this.attrs[arguments[0]];}if(arguments[m]==1&&an.is(arguments[0],"array")){var d={};for(var e in arguments[0]){if(arguments[0][Q](e)){d[arguments[0][e]]=this.attrs[arguments[0][e]];}}return d;}if(arguments[m]==2){var S={};S[arguments[0]]=arguments[1];aa(this,S);}else{if(arguments[m]==1&&an.is(arguments[0],"object")){aa(this,arguments[0]);}}return this;};ax[aY].toFront=function(){if(this.removed){return this;}this.node.parentNode[aL](this.node);var d=this.paper;d.top!=this&&Y(this,d);return this;};ax[aY].toBack=function(){if(this.removed){return this;}if(this.node.parentNode.firstChild!=this.node){this.node.parentNode.insertBefore(this.node,this.node.parentNode.firstChild);k(this,this.paper);var d=this.paper;}return this;};ax[aY].insertAfter=function(d){if(this.removed){return this;}var e=d.node;if(e.nextSibling){e.parentNode.insertBefore(this.node,e.nextSibling);}else{e.parentNode[aL](this.node);}A(this,d,this.paper);return this;};ax[aY].insertBefore=function(d){if(this.removed){return this;}var e=d.node;e.parentNode.insertBefore(this.node,e);aq(this,d,this.paper);return this;};var P=function(e,d,S,R){d=O(d);S=O(S);var E=aJ("circle");e.canvas&&e.canvas[aL](E);var i=new ax(E,e);i.attrs={cx:d,cy:S,r:R,fill:"none",stroke:"#000"};i.type="circle";aJ(E,i.attrs);return i;};var aF=function(i,d,a1,e,S,a0){d=O(d);a1=O(a1);var R=aJ("rect");i.canvas&&i.canvas[aL](R);var E=new ax(R,i);E.attrs={x:d,y:a1,width:e,height:S,r:a0||0,rx:a0||0,ry:a0||0,fill:"none",stroke:"#000"};E.type="rect";aJ(R,E.attrs);return E;};var ai=function(e,d,a0,S,R){d=O(d);a0=O(a0);var E=aJ("ellipse");e.canvas&&e.canvas[aL](E);var i=new ax(E,e);i.attrs={cx:d,cy:a0,rx:S,ry:R,fill:"none",stroke:"#000"};i.type="ellipse";aJ(E,i.attrs);return i;};var o=function(i,a0,d,a1,e,S){var R=aJ("image");aJ(R,{x:d,y:a1,width:e,height:S,preserveAspectRatio:"none"});R.setAttributeNS(i.xlink,"href",a0);i.canvas&&i.canvas[aL](R);var E=new ax(R,i);E.attrs={x:d,y:a1,width:e,height:S,src:a0};E.type="image";return E;};var X=function(e,d,S,R){var E=aJ("text");aJ(E,{x:d,y:S,"text-anchor":"middle"});e.canvas&&e.canvas[aL](E);var i=new ax(E,e);i.attrs={x:d,y:S,"text-anchor":"middle",text:R,font:j.font,stroke:"none",fill:"#000"};i.type="text";aa(i,i.attrs);return i;};var aV=function(e,d){this.width=e||this.width;this.height=d||this.height;this.canvas[v]("width",this.width);this.canvas[v]("height",this.height);return this;};var w=function(){var E=ao[aW](null,arguments),i=E&&E.container,e=E.x,a0=E.y,R=E.width,d=E.height;if(!i){throw new Error("SVG container not found.");}var S=aJ("svg");R=R||512;d=d||342;aJ(S,{xmlns:"http://www.w3.org/2000/svg",version:1.1,width:R,height:d});if(i==1){S.style.cssText="position:absolute;left:"+e+"px;top:"+a0+"px";L.body[aL](S);}else{if(i.firstChild){i.insertBefore(S,i.firstChild);}else{i[aL](S);}}i=new aT;i.width=R;i.height=d;i.canvas=S;aG.call(i,i,an.fn);i.clear();return i;};aT[aY].clear=function(){var d=this.canvas;while(d.firstChild){d.removeChild(d.firstChild);}this.bottom=this.top=null;(this.desc=aJ("desc"))[aL](L.createTextNode("Created with Rapha\xebl"));d[aL](this.desc);d[aL](this.defs=aJ("defs"));};aT[aY].remove=function(){this.canvas.parentNode&&this.canvas.parentNode.removeChild(this.canvas);for(var d in this){this[d]=s(d);}};}if(an.vml){var aH=function(a8){var a5=/[ahqstv]/ig,a0=r;(a8+at).match(a5)&&(a0=H);a5=/[clmz]/g;if(a0==r&&!(a8+at).match(a5)){var e={M:"m",L:"l",C:"c",Z:"x",m:"t",l:"r",c:"v",z:"x"},R=/([clmz]),?([^clmz]*)/gi,S=/-?[^,\s-]+/g;var a4=(a8+at)[aP](R,function(a9,bb,i){var ba=[];i[aP](S,function(bc){ba[f](O(bc));});return e[bb]+ba;});return a4;}var a6=a0(a8),E,a4=[],d;for(var a2=0,a7=a6[m];a21&&(e=1);a7.opacity=e;}a8.fill&&(a7.on=true);if(a7.on==null||a8.fill=="none"){a7.on=false;}if(a7.on&&a8.fill){var i=a8.fill.match(c);if(i){a7.src=i[1];a7.type="tile";}else{a7.color=an.getRGB(a8.fill).hex;a7.src=at;a7.type="solid";if(an.getRGB(a8.fill).error&&(bd.type in {circle:1,ellipse:1}||(a8.fill+at).charAt()!="r")&&b(bd,a8.fill)){a9.fill="none";a9.gradient=a8.fill;}}}ba&&a6[aL](a7);var R=(a6.getElementsByTagName("stroke")&&a6.getElementsByTagName("stroke")[0]),bb=false;!R&&(bb=R=ah("stroke"));if((a8.stroke&&a8.stroke!="none")||a8["stroke-width"]||a8["stroke-opacity"]!=null||a8["stroke-dasharray"]||a8["stroke-miterlimit"]||a8["stroke-linejoin"]||a8["stroke-linecap"]){R.on=true;}(a8.stroke=="none"||R.on==null||a8.stroke==0||a8["stroke-width"]==0)&&(R.on=false);R.on&&a8.stroke&&(R.color=an.getRGB(a8.stroke).hex);var e=((+a9["stroke-opacity"]+1||2)-1)*((+a9.opacity+1||2)-1),a4=(W(a8["stroke-width"])||1)*0.75;e<0&&(e=0);e>1&&(e=1);a8["stroke-width"]==null&&(a4=a9["stroke-width"]);a8["stroke-width"]&&(R.weight=a4);a4&&a4<1&&(e*=a4)&&(R.weight=1);R.opacity=e;a8["stroke-linejoin"]&&(R.joinstyle=a8["stroke-linejoin"]||"miter");R.miterlimit=a8["stroke-miterlimit"]||8;a8["stroke-linecap"]&&(R.endcap=a8["stroke-linecap"]=="butt"?"flat":a8["stroke-linecap"]=="square"?"square":"round");if(a8["stroke-dasharray"]){var a5={"-":"shortdash",".":"shortdot","-.":"shortdashdot","-..":"shortdashdotdot",". ":"dot","- ":"dash","--":"longdash","- .":"dashdot","--.":"longdashdot","--..":"longdashdotdot"};R.dashstyle=a5[Q](a8["stroke-dasharray"])?a5[a8["stroke-dasharray"]]:at;}bb&&a6[aL](R);}if(bd.type=="text"){var a0=bd.paper.span.style;a9.font&&(a0.font=a9.font);a9["font-family"]&&(a0.fontFamily=a9["font-family"]);a9["font-size"]&&(a0.fontSize=a9["font-size"]);a9["font-weight"]&&(a0.fontWeight=a9["font-weight"]);a9["font-style"]&&(a0.fontStyle=a9["font-style"]);bd.node.string&&(bd.paper.span.innerHTML=(bd.node.string+at)[aP](/"));bd.W=a9.w=bd.paper.span.offsetWidth;bd.H=a9.h=bd.paper.span.offsetHeight;bd.X=a9.x;bd.Y=a9.y+O(bd.H/2);switch(a9["text-anchor"]){case"start":bd.node.style["v-text-align"]="left";bd.bbx=O(bd.W/2);break;case"end":bd.node.style["v-text-align"]="right";bd.bbx=-O(bd.W/2);break;default:bd.node.style["v-text-align"]="center";break;}}};var b=function(d,a1){d.attrs=d.attrs||{};var a2=d.attrs,a4=d.node.getElementsByTagName("fill"),S="linear",a0=".5 .5";d.attrs.gradient=a1;a1=(a1+at)[aP](ar,function(a6,a7,i){S="radial";if(a7&&i){a7=W(a7);i=W(i);aM(a7-0.5,2)+aM(i-0.5,2)>0.25&&(i=ab.sqrt(0.25-aM(a7-0.5,2))*((i>0.5)*2-1)+0.5);a0=a7+am+i;}return at;});a1=a1[z](/\s*\-\s*/);if(S=="linear"){var e=a1.shift();e=-W(e);if(isNaN(e)){return null;}}var R=p(a1);if(!R){return null;}d=d.shape||d.node;a4=a4[0]||ah("fill");if(R[m]){a4.on=true;a4.method="none";a4.type=(S=="radial")?"gradientradial":"gradient";a4.color=R[0].color;a4.color2=R[R[m]-1].color;var a5=[];for(var E=0,a3=R[m];E');};}catch(af){ah=function(d){return L.createElement("<"+d+' xmlns="urn:schemas-microsoft.com:vml" class="rvml">');};}var w=function(){var i=ao[aW](null,arguments),d=i.container,a2=i.height,a3,e=i.width,a1=i.x,a0=i.y;if(!d){throw new Error("VML container not found.");}var R=new aT,S=R.canvas=L.createElement("div"),E=S.style;e=e||512;a2=a2||342;e==+e&&(e+="px");a2==+a2&&(a2+="px");R.width=1000;R.height=1000;R.coordsize="1000 1000";R.coordorigin="0 0";R.span=L.createElement("span");R.span.style.cssText="position:absolute;left:-9999em;top:-9999em;padding:0;margin:0;line-height:1;display:inline;";S[aL](R.span);E.cssText=an.format("width:{0};height:{1};position:absolute;clip:rect(0 {0} {1} 0);overflow:hidden",e,a2);if(d==1){L.body[aL](S);E.left=a1+"px";E.top=a0+"px";}else{d.style.width=e;d.style.height=a2;if(d.firstChild){d.insertBefore(S,d.firstChild);}else{d[aL](S);}}aG.call(R,R,an.fn);return R;};aT[aY].clear=function(){this.canvas.innerHTML=at;this.span=L.createElement("span");this.span.style.cssText="position:absolute;left:-9999em;top:-9999em;padding:0;margin:0;line-height:1;display:inline;";this.canvas[aL](this.span);this.bottom=this.top=null;};aT[aY].remove=function(){this.canvas.parentNode.removeChild(this.canvas);for(var d in this){this[d]=s(d);}};}if((/^Apple|^Google/).test(navigator.vendor)&&!(navigator.userAgent.indexOf("Version/4.0")+1)){aT[aY].safari=function(){var d=this.rect(-99,-99,this.width+99,this.height+99);setTimeout(function(){d.remove();});};}else{aT[aY].safari=function(){};}var ae=(function(){if(L.addEventListener){return function(R,i,e,d){var E=function(S){return e.call(d,S);};R.addEventListener(i,E,false);return function(){R.removeEventListener(i,E,false);return true;};};}else{if(L.attachEvent){return function(S,E,i,e){var R=function(a0){return i.call(e,a0||au.event);};S.attachEvent("on"+E,R);var d=function(){S.detachEvent("on"+E,R);return true;};return d;};}}})();for(var ac=F[m];ac--;){(function(d){ax[aY][d]=function(e){if(an.is(e,"function")){this.events=this.events||[];this.events.push({name:d,f:e,unbind:ae(this.shape||this.node,d,e,this)});}return this;};ax[aY]["un"+d]=function(E){var i=this.events,e=i[m];while(e--){if(i[e].name==d&&i[e].f==E){i[e].unbind();i.splice(e,1);!i.length&&delete this.events;return this;}}return this;};})(F[ac]);}ax[aY].hover=function(e,d){return this.mouseover(e).mouseout(d);};ax[aY].unhover=function(e,d){return this.unmouseover(e).unmouseout(d);};aT[aY].circle=function(d,i,e){return P(this,d||0,i||0,e||0);};aT[aY].rect=function(d,R,e,i,E){return aF(this,d||0,R||0,e||0,i||0,E||0);};aT[aY].ellipse=function(d,E,i,e){return ai(this,d||0,E||0,i||0,e||0);};aT[aY].path=function(d){d&&!an.is(d,"string")&&!an.is(d[0],"array")&&(d+=at);return q(an.format[aW](an,arguments),this);};aT[aY].image=function(E,d,R,e,i){return o(this,E||"about:blank",d||0,R||0,e||0,i||0);};aT[aY].text=function(d,i,e){return X(this,d||0,i||0,e||at);};aT[aY].set=function(d){arguments[m]>1&&(d=Array[aY].splice.call(arguments,0,arguments[m]));return new T(d);};aT[aY].setSize=aV;aT[aY].top=aT[aY].bottom=null;aT[aY].raphael=an;function u(){return this.x+am+this.y;}ax[aY].scale=function(a6,a5,E,e){if(a6==null&&a5==null){return{x:this._.sx,y:this._.sy,toString:u};}a5=a5||a6;!+a5&&(a5=a6);var ba,a8,a9,a7,bm=this.attrs;if(a6!=0){var a4=this.getBBox(),a1=a4.x+a4.width/2,R=a4.y+a4.height/2,bl=a6/this._.sx,bk=a5/this._.sy;E=(+E||E==0)?E:a1;e=(+e||e==0)?e:R;var a3=~~(a6/ab.abs(a6)),a0=~~(a5/ab.abs(a5)),be=this.node.style,bo=E+(a1-E)*bl,bn=e+(R-e)*bk;switch(this.type){case"rect":case"image":var a2=bm.width*a3*bl,bd=bm.height*a0*bk;this.attr({height:bd,r:bm.r*aI(a3*bl,a0*bk),width:a2,x:bo-a2/2,y:bn-bd/2});break;case"circle":case"ellipse":this.attr({rx:bm.rx*a3*bl,ry:bm.ry*a0*bk,r:bm.r*aI(a3*bl,a0*bk),cx:bo,cy:bn});break;case"path":var bg=ad(bm.path),bh=true;for(var bj=0,bc=bg[m];bjS){if(e&&!a8.start){a6=an.findDotsAtSegment(a5,a4,E[1],E[2],E[3],E[4],E[5],E[6],(S-a3)/a1);R+=["C",a6.start.x,a6.start.y,a6.m.x,a6.m.y,a6.x,a6.y];if(a0){return R;}a8.start=R;R=["M",a6.x,a6.y+"C",a6.n.x,a6.n.y,a6.end.x,a6.end.y,E[5],E[6]][az]();a3+=a1;a5=+E[5];a4=+E[6];continue;}if(!d&&!e){a6=an.findDotsAtSegment(a5,a4,E[1],E[2],E[3],E[4],E[5],E[6],(S-a3)/a1);return{x:a6.x,y:a6.y,alpha:a6.alpha};}}a3+=a1;a5=+E[5];a4=+E[6];}R+=E;}a8.end=R;a6=d?a3:e?a8:an.findDotsAtSegment(a5,a4,E[1],E[2],E[3],E[4],E[5],E[6],1);a6.alpha&&(a6={x:a6.x,y:a6.y,alpha:a6.alpha});return a6;};},n=aj(function(E,d,a0,S,a6,a5,a4,a3){var R={x:0,y:0},a2=0;for(var a1=0;a1<1.01;a1+=0.01){var e=M(E,d,a0,S,a6,a5,a4,a3,a1);a1&&(a2+=ab.sqrt(aM(R.x-e.x,2)+aM(R.y-e.y,2)));R=e;}return a2;});var ap=aB(1),C=aB(),J=aB(0,1);ax[aY].getTotalLength=function(){if(this.type!="path"){return;}return ap(this.attrs.path);};ax[aY].getPointAtLength=function(d){if(this.type!="path"){return;}return C(this.attrs.path,d);};ax[aY].getSubpath=function(i,e){if(this.type!="path"){return;}if(ab.abs(this.getTotalLength()-e)<0.000001){return J(this.attrs.path,i).end;}var d=J(this.attrs.path,e,1);return i?J(d,i).end:d;};an.easing_formulas={linear:function(d){return d;},"<":function(d){return aM(d,3);},">":function(d){return aM(d-1,3)+1;},"<>":function(d){d=d*2;if(d<1){return aM(d,3)/2;}d-=2;return(aM(d,3)+2)/2;},backIn:function(e){var d=1.70158;return e*e*((d+1)*e-d);},backOut:function(e){e=e-1;var d=1.70158;return e*e*((d+1)*e+d)+1;},elastic:function(i){if(i==0||i==1){return i;}var e=0.3,d=e/4;return aM(2,-10*i)*ab.sin((i-d)*(2*ab.PI)/e)+1;},bounce:function(E){var e=7.5625,i=2.75,d;if(E<(1/i)){d=e*E*E;}else{if(E<(2/i)){E-=(1.5/i);d=e*E*E+0.75;}else{if(E<(2.5/i)){E-=(2.25/i);d=e*E*E+0.9375;}else{E-=(2.625/i);d=e*E*E+0.984375;}}}return d;}};var I={length:0},aR=function(){var a2=+new Date;for(var be in I){if(be!="length"&&I[Q](be)){var bj=I[be];if(bj.stop){delete I[be];I[m]--;continue;}var a0=a2-bj.start,bb=bj.ms,ba=bj.easing,bf=bj.from,a7=bj.diff,E=bj.to,a6=bj.t,a9=bj.prev||0,a1=bj.el,R=bj.callback,a8={},d;if(a0255?255:(d<0?0:d);},t=function(d,i){if(d==null){return{x:this._.tx,y:this._.ty,toString:u};}this._.tx+=+d;this._.ty+=+i;switch(this.type){case"circle":case"ellipse":this.attr({cx:+d+this.attrs.cx,cy:+i+this.attrs.cy});break;case"rect":case"image":case"text":this.attr({x:+d+this.attrs.x,y:+i+this.attrs.y});break;case"path":var e=ad(this.attrs.path);e[0][1]+=+d;e[0][2]+=+i;this.attr({path:e});break;}return this;};ax[aY].animateWith=function(e,i,d,R,E){I[e.id]&&(i.start=I[e.id].start);return this.animate(i,d,R,E);};ax[aY].animateAlong=ay();ax[aY].animateAlongBack=ay(1);function ay(d){return function(E,i,e,S){var R={back:d};an.is(e,"function")?(S=e):(R.rot=e);E&&E.constructor==ax&&(E=E.attrs.path);E&&(R.along=E);return this.animate(R,i,S);};}ax[aY].onAnimation=function(d){this._run=d||0;return this;};ax[aY].animate=function(be,a5,a4,E){if(an.is(a4,"function")||!a4){E=a4||null;}var a9={},e={},a2={};for(var a6 in be){if(be[Q](a6)){if(Z[Q](a6)){a9[a6]=this.attr(a6);(a9[a6]==null)&&(a9[a6]=j[a6]);e[a6]=be[a6];switch(Z[a6]){case"along":var bc=ap(be[a6]),a7=C(be[a6],bc*!!be.back),R=this.getBBox();a2[a6]=bc/a5;a2.tx=R.x;a2.ty=R.y;a2.sx=a7.x;a2.sy=a7.y;e.rot=be.rot;e.back=be.back;e.len=bc;be.rot&&(a2.r=W(this.rotate())||0);break;case"number":a2[a6]=(e[a6]-a9[a6])/a5;break;case"colour":a9[a6]=an.getRGB(a9[a6]);var a8=an.getRGB(e[a6]);a2[a6]={r:(a8.r-a9[a6].r)/a5,g:(a8.g-a9[a6].g)/a5,b:(a8.b-a9[a6].b)/a5};break;case"path":var S=H(a9[a6],e[a6]);a9[a6]=S[0];var a3=S[1];a2[a6]=[];for(var bb=0,a1=a9[a6][m];bb +// +// Math.seedrandom('yipee'); Sets Math.random to a function that is +// initialized using the given explicit seed. +// +// Math.seedrandom(); Sets Math.random to a function that is +// seeded using the current time, dom state, +// and other accumulated local entropy. +// The generated seed string is returned. +// +// Math.seedrandom('yowza', true); +// Seeds using the given explicit seed mixed +// together with accumulated entropy. +// +// +// Seeds using physical random bits downloaded +// from random.org. +// +// Examples: +// +// Math.seedrandom("hello"); // Use "hello" as the seed. +// document.write(Math.random()); // Always 0.5463663768140734 +// document.write(Math.random()); // Always 0.43973793770592234 +// var rng1 = Math.random; // Remember the current prng. +// +// var autoseed = Math.seedrandom(); // New prng with an automatic seed. +// document.write(Math.random()); // Pretty much unpredictable. +// +// Math.random = rng1; // Continue "hello" prng sequence. +// document.write(Math.random()); // Always 0.554769432473455 +// +// Math.seedrandom(autoseed); // Restart at the previous seed. +// document.write(Math.random()); // Repeat the 'unpredictable' value. +// +// Notes: +// +// Each time seedrandom('arg') is called, entropy from the passed seed +// is accumulated in a pool to help generate future seeds for the +// zero-argument form of Math.seedrandom, so entropy can be injected over +// time by calling seedrandom with explicit data repeatedly. +// +// On speed - This javascript implementation of Math.random() is about +// 3-10x slower than the built-in Math.random() because it is not native +// code, but this is typically fast enough anyway. Seeding is more expensive, +// especially if you use auto-seeding. Some details (timings on Chrome 4): +// +// Our Math.random() - avg less than 0.002 milliseconds per call +// seedrandom('explicit') - avg less than 0.5 milliseconds per call +// seedrandom('explicit', true) - avg less than 2 milliseconds per call +// seedrandom() - avg about 38 milliseconds per call +// +// LICENSE (BSD): +// +// Copyright 2010 David Bau, all rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of this module nor the names of its contributors may +// be used to endorse or promote products derived from this software +// without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +/** + * All code is in an anonymous closure to keep the global namespace clean. + * + * @param {number=} overflow + * @param {number=} startdenom + */ +(function (pool, math, width, chunks, significance, overflow, startdenom) { + + +// +// seedrandom() +// This is the seedrandom function described above. +// +math['seedrandom'] = function seedrandom(seed, use_entropy) { + var key = []; + var arc4; + + // Flatten the seed string or build one from local entropy if needed. + seed = mixkey(flatten( + use_entropy ? [seed, pool] : + arguments.length ? seed : + [new Date().getTime(), pool, window], 3), key); + + // Use the seed to initialize an ARC4 generator. + arc4 = new ARC4(key); + + // Mix the randomness into accumulated entropy. + mixkey(arc4.S, pool); + + // Override Math.random + + // This function returns a random double in [0, 1) that contains + // randomness in every bit of the mantissa of the IEEE 754 value. + + math['random'] = function random() { // Closure to return a random double: + var n = arc4.g(chunks); // Start with a numerator n < 2 ^ 48 + var d = startdenom; // and denominator d = 2 ^ 48. + var x = 0; // and no 'extra last byte'. + while (n < significance) { // Fill up all significant digits by + n = (n + x) * width; // shifting numerator and + d *= width; // denominator and generating a + x = arc4.g(1); // new least-significant-byte. + } + while (n >= overflow) { // To avoid rounding up, before adding + n /= 2; // last byte, shift everything + d /= 2; // right using integer math until + x >>>= 1; // we have exactly the desired bits. + } + return (n + x) / d; // Form the number within [0, 1). + }; + + // Return the seed that was used + return seed; +}; + +// +// ARC4 +// +// An ARC4 implementation. The constructor takes a key in the form of +// an array of at most (width) integers that should be 0 <= x < (width). +// +// The g(count) method returns a pseudorandom integer that concatenates +// the next (count) outputs from ARC4. Its return value is a number x +// that is in the range 0 <= x < (width ^ count). +// +/** @constructor */ +function ARC4(key) { + var t, u, me = this, keylen = key.length; + var i = 0, j = me.i = me.j = me.m = 0; + me.S = []; + me.c = []; + + // The empty key [] is treated as [0]. + if (!keylen) { key = [keylen++]; } + + // Set up S using the standard key scheduling algorithm. + while (i < width) { me.S[i] = i++; } + for (i = 0; i < width; i++) { + t = me.S[i]; + j = lowbits(j + t + key[i % keylen]); + u = me.S[j]; + me.S[i] = u; + me.S[j] = t; + } + + // The "g" method returns the next (count) outputs as one number. + me.g = function getnext(count) { + var s = me.S; + var i = lowbits(me.i + 1); var t = s[i]; + var j = lowbits(me.j + t); var u = s[j]; + s[i] = u; + s[j] = t; + var r = s[lowbits(t + u)]; + while (--count) { + i = lowbits(i + 1); t = s[i]; + j = lowbits(j + t); u = s[j]; + s[i] = u; + s[j] = t; + r = r * width + s[lowbits(t + u)]; + } + me.i = i; + me.j = j; + return r; + }; + // For robust unpredictability discard an initial batch of values. + // See http://www.rsa.com/rsalabs/node.asp?id=2009 + me.g(width); +} + +// +// flatten() +// Converts an object tree to nested arrays of strings. +// +/** @param {Object=} result + * @param {string=} prop */ +function flatten(obj, depth, result, prop) { + result = []; + if (depth && typeof(obj) == 'object') { + for (prop in obj) { + if (prop.indexOf('S') < 5) { // Avoid FF3 bug (local/sessionStorage) + try { result.push(flatten(obj[prop], depth - 1)); } catch (e) {} + } + } + } + return result.length ? result : '' + obj; +} + +// +// mixkey() +// Mixes a string seed into a key that is an array of integers, and +// returns a shortened string seed that is equivalent to the result key. +// +/** @param {number=} smear + * @param {number=} j */ +function mixkey(seed, key, smear, j) { + seed += ''; // Ensure the seed is a string + smear = 0; + for (j = 0; j < seed.length; j++) { + key[lowbits(j)] = + lowbits((smear ^= key[lowbits(j)] * 19) + seed.charCodeAt(j)); + } + seed = ''; + for (j in key) { seed += String.fromCharCode(key[j]); } + return seed; +} + +// +// lowbits() +// A quick "n mod width" for width a power of 2. +// +function lowbits(n) { return n & (width - 1); } + +// +// The following constants are related to IEEE 754 limits. +// +startdenom = math.pow(width, chunks); +significance = math.pow(2, significance); +overflow = significance * 2; + +// +// When seedrandom.js is loaded, we immediately mix a few bits +// from the built-in RNG into the entropy pool. Because we do +// not want to intefere with determinstic PRNG state later, +// seedrandom will not call math.random on its own again after +// initialization. +// +mixkey(math.random(), pool); + +// End anonymous scope, and pass initial values. +})( + [], // pool: entropy pool starts empty + Math, // math: package containing random, pow, and seedrandom + 256, // width: each RC4 output is 0 <= x < 256 + 6, // chunks: at least six RC4 outputs for each double + 52 // significance: there are 52 significant digits in a double +); diff --git a/addons/base_diagram/static/src/js/diagram.js b/addons/base_diagram/static/src/js/diagram.js new file mode 100644 index 00000000000..cc0f69b9eb5 --- /dev/null +++ b/addons/base_diagram/static/src/js/diagram.js @@ -0,0 +1,175 @@ +/*--------------------------------------------------------- + * OpenERP base library + *---------------------------------------------------------*/ + +openerp.base.diagram = function (openerp) { + +openerp.base.views.add('diagram', 'openerp.base.DiagramView'); +openerp.base.DiagramView = openerp.base.Controller.extend({ + init: function(view_manager, session, element_id, dataset, view_id){ + this._super(session, element_id); + this.view_manager = view_manager; + this.dataset = dataset; + this.model = dataset.model; + this.view_id = view_id; + this.name = ""; + this.domain = this.dataset._domain ? this.dataset._domain: []; + this.context = {}; + this.ids = this.dataset.ids; + + console.log('data set>>',this.dataset) + }, + start: function() { + this.rpc("/base_diagram/diagram/load", {"model": this.model, "view_id": this.view_id}, this.on_loaded); + }, + + toTitleCase: function(str) { + return str.replace(/\w\S*/g, function(txt){return txt.charAt(0).toUpperCase() + txt.substr(1).toLowerCase();}); + }, + + on_loaded: function(result) { + + var self = this; + if(this.ids && this.ids.length) { + this.id = this.ids[0]; + } + + this.fields_view = result.fields_view; + this.view_id = this.fields_view.view_id; + this.name = this.fields_view.name; + + this.fields = this.fields_view.fields; + + var children = this.fields_view.arch.children; + /* + * For Nodes (Fields) + */ + this.node = ''; + this.bgcolor = ''; + this.shape = ''; + this.visible_fields_nodes = []; + this.invisible_fields_nodes = []; + this.fields_nodes_string = []; + + /* + * For Arraows(Connector) + */ + this.connector = ''; + this.src_node = ''; + this.des_node = ''; + this.connector_fields = []; + this.fields_connector_string = []; + + for(ch in children) { + if(children[ch]['tag'] == 'node') { + this.node = children[ch]['attrs']['object']; + this.bgcolor = children[ch]['attrs']['bgcolor'] || ''; + this.shape = children[ch]['attrs']['shape'] || ''; + for(node_chld in children[ch]['children']) { + if (children[ch]['children'][node_chld]['tag'] = 'field') { + var ch_name = children[ch]['children'][node_chld]['attrs']['name']; + + if (children[ch]['children'][node_chld]['attrs']['invisible']) { + if (children[ch]['children'][node_chld]['attrs']['invisible'] == 1 && children[ch]['children'][node_chld]['attrs']['invisible'] == '1') { + this.invisible_fields_nodes.push(ch_name) + } + } + else { + this.visible_fields_nodes.push(ch_name); + var ch_node_string = this.fields[ch_name]['string'] || this.toTitleCase(ch_name); + this.fields_nodes_string.push(ch_node_string) + } + } + } + } else if(children[ch]['tag'] == 'arrow') { + this.connector = children[ch]['attrs']['object']; + this.src_node = children[ch]['attrs']['source']; + this.des_node = children[ch]['attrs']['destination']; + for (arrow_chld in children[ch]['children']) { + if (children[ch]['children'][arrow_chld]['tag'] = 'field') { + var arr_ch_name = children[ch]['children'][arrow_chld]['attrs']['name']; + var ch_node_string = this.fields[arr_ch_name]['string'] || this.toTitleCase(arr_ch_name); + this.fields_connector_string.push(ch_node_string); + this.connector_fields.push(arr_ch_name); + } + } + } + } + this.$element.html(QWeb.render("DiagramView", {"fields_view": this.fields_view})); + + +// g.addEdge("strawberry", "cherry"); +// g.addEdge("strawberry", "apple"); +// g.addEdge("strawberry", "tomato"); +// +// g.addEdge("tomato", "apple"); +// g.addEdge("tomato", "kiwi"); +// +// g.addEdge("cherry", "apple"); +// g.addEdge("cherry", "kiwi"); + + + + if(this.id) { + this.rpc( + '/base_diagram/diagram/get_diagram_info', + { + 'id': this.id, + 'model': this.model, + 'bgcolor': this.bgcolor, + 'shape': this.shape, + 'node': this.node, + 'connector': this.connector, + 'src_node': this.src_node, + 'des_node': this.des_node, + 'visible_node_fields': this.visible_fields_nodes, + 'invisible_node_fields': this.invisible_fields_nodes, + 'node_fields_string': this.fields_nodes_string, + 'connector_fields': this.connector_fields, + 'connector_fields_string': this.fields_connector_string + }, + function(result) { + self.draw_diagram(result); + } + ) + } + }, + + draw_diagram: function(result) { + console.log('this>>>',this) + var g = new Graph(); + + this.in_transition_field = result['in_transition_field']; + this.out_transition_field = result['out_transition_field']; + var res_nodes = result['nodes']; + var res_connectors = result['conn']; +// for(nd in res_nodes) { +// var res_node = res_nodes[nd]; +// console.log('nodes',res_node, res_node['shape']) +// var state; +// } + + for(cr in res_connectors) { + var res_connector = res_connectors[cr]; + g.addEdge(res_connector['source'], res_connector['destination']); + + } + + var layouter = new Graph.Layout.Spring(g); + layouter.layout(); + + var renderer = new Graph.Renderer.Raphael('dia-canvas', g, 800, 500); + renderer.draw(); + }, + + do_show: function () { + this.$element.show(); + }, + + do_hide: function () { + this.$element.hide(); + } +}); +}; + +// vim:et fdc=0 fdl=0 foldnestmax=3 fdm=syntax: diff --git a/addons/base_diagram/static/src/js/views.js b/addons/base_diagram/static/src/js/views.js deleted file mode 100644 index 606e1e5c78c..00000000000 --- a/addons/base_diagram/static/src/js/views.js +++ /dev/null @@ -1,12 +0,0 @@ -/*--------------------------------------------------------- - * OpenERP base library - *---------------------------------------------------------*/ - -openerp.base_diagram = function(openerp) { - -openerp.base_diagram.DiagramView = openerp.base.Controller.extend({ -}); - -}; - -// vim:et fdc=0 fdl=0 foldnestmax=3 fdm=syntax: From 6844f1a4ce472070d09423a65aebc05fc08fc8f3 Mon Sep 17 00:00:00 2001 From: "Quentin (OpenERP)" Date: Thu, 7 Apr 2011 13:22:35 +0200 Subject: [PATCH 080/259] [REVERT] reverted revision 4590, for fix 724820 which should have never landed on trunk bzr revid: qdp-launchpad@openerp.com-20110407112235-kfqsiby1an1zvcn2 --- addons/stock/stock.py | 2 -- addons/stock/stock_view.xml | 2 -- 2 files changed, 4 deletions(-) diff --git a/addons/stock/stock.py b/addons/stock/stock.py index 96f5855166e..94d8e3b1cfb 100644 --- a/addons/stock/stock.py +++ b/addons/stock/stock.py @@ -1553,7 +1553,6 @@ class stock_move(osv.osv): # used for colors in tree views: 'scrapped': fields.related('location_dest_id','scrap_location',type='boolean',relation='stock.location',string='Scrapped', readonly=True), - 'tracking': fields.boolean('Track Lots'), } _constraints = [ (_check_tracking, @@ -1744,7 +1743,6 @@ class stock_move(osv.osv): 'product_uom': product.uom_id.id, 'product_uos': uos_id, 'product_qty': 1.00, - 'tracking': product.track_production, 'product_uos_qty' : self.pool.get('stock.move').onchange_quantity(cr, uid, ids, prod_id, 1.00, product.uom_id.id, uos_id)['value']['product_uos_qty'] } if not ids: diff --git a/addons/stock/stock_view.xml b/addons/stock/stock_view.xml index 60cd813e5fc..488cc801f63 100644 --- a/addons/stock/stock_view.xml +++ b/addons/stock/stock_view.xml @@ -1463,13 +1463,11 @@
- +
- - - - - - - + + + + + + + + + + + + + diff --git a/addons/base/static/test/list.js b/addons/base/static/test/list.js new file mode 100644 index 00000000000..ed055d0bb8a --- /dev/null +++ b/addons/base/static/test/list.js @@ -0,0 +1,48 @@ +$(document).ready(function () { + /** + * Tests a jQuery collection against a selector ("ands" the .is() of each + * member of the collection, instead of "or"-ing them) + * + * @param {jQuery} $c a jQuery collection object + * @param {String} selector the selector to test the collection against + */ + var are = function ($c, selector) { + return ($c.filter(function () { return $(this).is(selector); }).length + === $c.length); + }; + + var fvg = {fields_view: { + 'fields': [], + 'arch': { + 'attrs': {string: ''} + } + }}; + + var openerp; + module("ListView", { + setup: function () { + openerp = window.openerp.init(true); + window.openerp.base.chrome(openerp); + // views loader stuff + window.openerp.base.views(openerp); + window.openerp.base.list(openerp); + } + }); + + asyncTest('render selection checkboxes', 2, function () { + var listview = new openerp.base.ListView( + {}, null, + 'qunit-fixture', {model: null}); + + listview.on_loaded(fvg); + + listview.do_fill_table([{}, {}, {}]).then(function () { + ok(are(listview.$element.find('tbody th'), + '.oe-record-selector')); + ok(are(listview.$element.find('tbody th input'), + ':checkbox:not([name])')); + start(); + }); + }); + +}); diff --git a/addons/base/static/test/qunit-doc.js b/addons/base/static/test/qunit-doc.js new file mode 100644 index 00000000000..3667cc3eb40 --- /dev/null +++ b/addons/base/static/test/qunit-doc.js @@ -0,0 +1,143 @@ +/** + * Defines a module scope (which lasts until the next call to module). + * + * This module scopes implies setup and teardown callbacks running for each test. + * + * @function + * @param {String} name the name of the module + * @param {Object} [lifecycle] callbacks to run before and after each test of the module + * @param {Function} lifecycle.setup function running before each test of this module + * @param {Function} lifecycle.teardown function running after each test of this module + */ +var module; +/** + * Defines a given test to run. Runs all the assertions present in the test + * + * @function + * @param {String} name the name of the test + * @param {Number} [expected] number of assertions expected to run in this test (useful for asynchronous tests) + * @param {Function} test the testing code to run, holding a sequence of assertions (at least one) + */ +var test; +/** + * Defines an asynchronous test: equivalent to calling stop() at the start of + * a normal test(). + * + * The test code needs to restart the test runner via start() + * + * @function + * @param {String} name the name of the test + * @param {Number} [expected] number of assertions expected to run in this test (useful for asynchronous tests) + * @param {Function} test the testing code to run, holding a sequence of assertions (at least one) + */ +var asyncTest; +/** + * The most basic boolean assertion (~assertTrue or assert). + * + * Passes if its argument is truthy + * + * @function + * @param {Boolean} state an arbitrary expression, evaluated in a boolean context + * @param {String} [message] the message to output with the assertion result + */ +var ok; +/** + * Equality assertion (~assertEqual) + * + * Passes if both arguments are equal (via ==) + * + * @function + * @param {Object} actual the object to check for correctness (processing result) + * @param {Object} expected the object to check against + * @param {String} [message] message output with the assertion result + */ +var equal; +/** + * Inequality assertion (~assertNotEqual) + * + * Passes if the arguments are different (via !=) + * + * @function + * @param {Object} actual the object to check for correctness (processing result) + * @param {Object} expected the object to check against + * @param {String} [message] message output with the assertion result + */ +var notEqual; +/** + * Recursive equality assertion. + * + * Works on primitive types using === and traversing through + * Objects and Arrays as well checking their components + * + * @function + * @param {Object} actual the object to check for correctness (processing result) + * @param {Object} expected the object to check against + * @param {String} [message] message output with the assertion result + */ +var deepEqual; +/** + * Recursive inequality assertion. + * + * Works on primitive types using !== and traversing through + * Objects and Arrays as well checking their components + * + * @function + * @param {Object} actual the object to check for correctness (processing result) + * @param {Object} expected the object to check against + * @param {String} [message] message output with the assertion result + */ +var notDeepEqual; +/** + * Strict equality assertion (~assertEqual) + * + * Passes if both arguments are identical (via ===) + * + * @function + * @param {Object} actual the object to check for correctness (processing result) + * @param {Object} expected the object to check against + * @param {String} [message] message output with the assertion result + */ +var strictEqual; +/** + * Strict inequality assertion (~assertNotEqual) + * + * Passes if both arguments are identical (via !==) + * + * @function + * @param {Object} actual the object to check for correctness (processing result) + * @param {Object} expected the object to check against + * @param {String} [message] message output with the assertion result + */ +var notStrictEqual; +/** + * Passes if the provided block raised an exception. + * + * The expect argument can be provided to perform further assertion checks on the exception itself: + * * If it's a RegExp test the exception against the regexp (message?) + * * If it's a constructor, check if the exception is an instance of it + * * If it's an other type of function, call it with the exception as first parameter + * - If the function returns true, the assertion validates + * - Otherwise it fails + * + * @function + * @param {Function} block function which should raise an exception when called + * @param {Object} [expect] a RegExp, a constructor or a Function + * @param {String} [message] message output with the assertion result + */ +var raises; +/** + * Starts running the test runner again from the point where it was + * stopped. + * + * Used to resume testing after a callback. + * + * @function + */ +var start; +/** + * Stops the test runner in order to wait for an asynchronous test to run + * + * @function + * @param {Number} [timeout] fails the test after the timeout triggers, only for debugging tests + */ +var stop; diff --git a/addons/base/static/test/test.html b/addons/base/static/test/test.html index 9681be8e389..776b03146ff 100644 --- a/addons/base/static/test/test.html +++ b/addons/base/static/test/test.html @@ -21,6 +21,7 @@ + @@ -35,4 +36,5 @@ + From 51d8fdd6463fa546ba61319f1f73be8871c3e185 Mon Sep 17 00:00:00 2001 From: Antony Lesuisse Date: Thu, 7 Apr 2011 14:13:31 +0200 Subject: [PATCH 088/259] [MERGE] gantt viw from trunk-proto61-dhtmlx-gantt-cpa bzr revid: al@openerp.com-20110407121331-wx5uwrhtmsnrlsj9 --- addons/base/controllers/main.py | 2 +- addons/base/static/src/base.html | 4 + addons/base/static/src/js/base.js | 1 + addons/base/static/src/xml/base.xml | 13 + addons/base_gantt/__init__.py | 2 + addons/base_gantt/__openerp__.py | 7 + addons/base_gantt/controllers/__init__.py | 1 + addons/base_gantt/controllers/main.py | 184 + .../static/lib/dhtmlxGantt/License_GPL.html | 73 + .../lib/dhtmlxGantt/codebase/dhtmlxcommon.js | 933 +++ .../lib/dhtmlxGantt/codebase/dhtmlxgantt.css | 15 + .../lib/dhtmlxGantt/codebase/dhtmlxgantt.js | 384 ++ .../lib/dhtmlxGantt/codebase/imgs/arr.gif | Bin 0 -> 162 bytes .../lib/dhtmlxGantt/codebase/imgs/bg.png | Bin 0 -> 151 bytes .../lib/dhtmlxGantt/codebase/imgs/bg_week.png | Bin 0 -> 275 bytes .../codebase/imgs/menu/menu_bg.png | Bin 0 -> 159 bytes .../codebase/imgs/menu/menu_selection.png | Bin 0 -> 600 bytes .../codebase/imgs/menu/window_tr.png | Bin 0 -> 2247 bytes .../lib/dhtmlxGantt/codebase/imgs/minus.gif | Bin 0 -> 121 bytes .../codebase/imgs/parentnode_filled.png | Bin 0 -> 186 bytes .../lib/dhtmlxGantt/codebase/imgs/plus.gif | Bin 0 -> 124 bytes .../dhtmlxGantt/codebase/imgs/progress_bg.png | Bin 0 -> 186 bytes .../codebase/imgs/progress_filled.png | Bin 0 -> 186 bytes .../static/lib/dhtmlxGantt/index.html | 107 + .../static/lib/dhtmlxGantt/readme.txt | 7 + .../lib/dhtmlxGantt/sources/dhtmlxcommon.js | 938 +++ .../lib/dhtmlxGantt/sources/dhtmlxgantt.js | 6122 +++++++++++++++++ addons/base_gantt/static/src/gantt.js | 227 + 28 files changed, 9019 insertions(+), 1 deletion(-) create mode 100644 addons/base_gantt/__init__.py create mode 100644 addons/base_gantt/__openerp__.py create mode 100644 addons/base_gantt/controllers/__init__.py create mode 100644 addons/base_gantt/controllers/main.py create mode 100644 addons/base_gantt/static/lib/dhtmlxGantt/License_GPL.html create mode 100644 addons/base_gantt/static/lib/dhtmlxGantt/codebase/dhtmlxcommon.js create mode 100644 addons/base_gantt/static/lib/dhtmlxGantt/codebase/dhtmlxgantt.css create mode 100644 addons/base_gantt/static/lib/dhtmlxGantt/codebase/dhtmlxgantt.js create mode 100644 addons/base_gantt/static/lib/dhtmlxGantt/codebase/imgs/arr.gif create mode 100644 addons/base_gantt/static/lib/dhtmlxGantt/codebase/imgs/bg.png create mode 100644 addons/base_gantt/static/lib/dhtmlxGantt/codebase/imgs/bg_week.png create mode 100644 addons/base_gantt/static/lib/dhtmlxGantt/codebase/imgs/menu/menu_bg.png create mode 100644 addons/base_gantt/static/lib/dhtmlxGantt/codebase/imgs/menu/menu_selection.png create mode 100644 addons/base_gantt/static/lib/dhtmlxGantt/codebase/imgs/menu/window_tr.png create mode 100644 addons/base_gantt/static/lib/dhtmlxGantt/codebase/imgs/minus.gif create mode 100644 addons/base_gantt/static/lib/dhtmlxGantt/codebase/imgs/parentnode_filled.png create mode 100644 addons/base_gantt/static/lib/dhtmlxGantt/codebase/imgs/plus.gif create mode 100644 addons/base_gantt/static/lib/dhtmlxGantt/codebase/imgs/progress_bg.png create mode 100644 addons/base_gantt/static/lib/dhtmlxGantt/codebase/imgs/progress_filled.png create mode 100644 addons/base_gantt/static/lib/dhtmlxGantt/index.html create mode 100644 addons/base_gantt/static/lib/dhtmlxGantt/readme.txt create mode 100644 addons/base_gantt/static/lib/dhtmlxGantt/sources/dhtmlxcommon.js create mode 100644 addons/base_gantt/static/lib/dhtmlxGantt/sources/dhtmlxgantt.js create mode 100644 addons/base_gantt/static/src/gantt.js diff --git a/addons/base/controllers/main.py b/addons/base/controllers/main.py index 870f3494320..9db66638b22 100644 --- a/addons/base/controllers/main.py +++ b/addons/base/controllers/main.py @@ -93,7 +93,7 @@ class Session(openerpweb.Controller): @openerpweb.jsonrequest def modules(self, req): - return {"modules": ["base", "base_hello", "base_calendar"]} + return {"modules": ["base", "base_hello", "base_calendar", "base_gantt"]} @openerpweb.jsonrequest def csslist(self, req, mods='base,base_hello'): diff --git a/addons/base/static/src/base.html b/addons/base/static/src/base.html index 8bb4793d42c..3bfadba0782 100644 --- a/addons/base/static/src/base.html +++ b/addons/base/static/src/base.html @@ -23,7 +23,11 @@ + + + + diff --git a/addons/base/static/src/js/base.js b/addons/base/static/src/js/base.js index 4833551c24e..5975bce8023 100644 --- a/addons/base/static/src/js/base.js +++ b/addons/base/static/src/js/base.js @@ -122,6 +122,7 @@ openerp.base = function(instance) { openerp.base.search(instance); openerp.base.list(instance); openerp.base.form(instance); + openerp.base.gantt(instance); }; // vim:et fdc=0 fdl=0 foldnestmax=3 fdm=syntax: diff --git a/addons/base/static/src/xml/base.xml b/addons/base/static/src/xml/base.xml index 9a41ba630f3..7a982e631fe 100644 --- a/addons/base/static/src/xml/base.xml +++ b/addons/base/static/src/xml/base.xml @@ -167,6 +167,19 @@
+ +

+ + + + + +
+
+
+
+
+

diff --git a/addons/base_gantt/__init__.py b/addons/base_gantt/__init__.py new file mode 100644 index 00000000000..53e20f29429 --- /dev/null +++ b/addons/base_gantt/__init__.py @@ -0,0 +1,2 @@ +#!/usr/bin/python +import controllers \ No newline at end of file diff --git a/addons/base_gantt/__openerp__.py b/addons/base_gantt/__openerp__.py new file mode 100644 index 00000000000..d3b4dbd3885 --- /dev/null +++ b/addons/base_gantt/__openerp__.py @@ -0,0 +1,7 @@ +{ + "name": "Base Gantt", + "version": "2.0", + "depends": [], + "js": ["static/*/js/*.js"], + "css": [], +} diff --git a/addons/base_gantt/controllers/__init__.py b/addons/base_gantt/controllers/__init__.py new file mode 100644 index 00000000000..039d9715fab --- /dev/null +++ b/addons/base_gantt/controllers/__init__.py @@ -0,0 +1 @@ +import main \ No newline at end of file diff --git a/addons/base_gantt/controllers/main.py b/addons/base_gantt/controllers/main.py new file mode 100644 index 00000000000..7edb4d28763 --- /dev/null +++ b/addons/base_gantt/controllers/main.py @@ -0,0 +1,184 @@ +import glob, os +from xml.etree import ElementTree +import math +import simplejson +import openerpweb +import time +import datetime +from base.controllers.main import Xml2Json + + +COLOR_PALETTE = ['#f57900', '#cc0000', '#d400a8', '#75507b', '#3465a4', '#73d216', '#c17d11', '#edd400', + '#fcaf3e', '#ef2929', '#ff00c9', '#ad7fa8', '#729fcf', '#8ae234', '#e9b96e', '#fce94f', + '#ff8e00', '#ff0000', '#b0008c', '#9000ff', '#0078ff', '#00ff00', '#e6ff00', '#ffff00', + '#905000', '#9b0000', '#840067', '#510090', '#0000c9', '#009b00', '#9abe00', '#ffc900', ] + +_colorline = ['#%02x%02x%02x' % (25 + ((r + 10) % 11) * 23, 5 + ((g + 1) % 11) * 20, 25 + ((b + 4) % 11) * 23) for r in range(11) for g in range(11) for b in range(11) ] + +def choice_colors(n): + if n > len(COLOR_PALETTE): + return _colorline[0:-1:len(_colorline) / (n + 1)] + elif n: + return COLOR_PALETTE[:n] + return [] + +class GanttView(openerpweb.Controller): + _cp_path = "/base_gantt/ganttview" + + date_start = None + date_delay = None + date_stop = None + color_field = None + + day_length = 8 + fields = {} + events = [] + calendar_fields = {} + ids = [] + model = '' + domain = [] + context = {} + event_res = [] + colors = {} + color_values = [] + + @openerpweb.jsonrequest + def load(self, req, model, view_id): + m = req.session.model(model) + r = m.fields_view_get(view_id, 'gantt') + r["arch"] = Xml2Json.convert_to_structure(r["arch"]) + return {'fields_view':r} + + @openerpweb.jsonrequest + def get_events(self, req, **kw): + + self.model = kw['model'] + self.fields = kw['fields'] + self.day_length = kw['day_length'] + self.calendar_fields = kw['calendar_fields'] + self.color_field = kw.get('color_field') or self.color_field or None + self.fields[self.color_field] = "" + self.colors = kw.get('colors') or {} + self.text = self.calendar_fields['text']['name'] + + self.date_start = self.calendar_fields['date_start']['name'] + self.fields[self.date_start] = "" + + if self.calendar_fields.get('date_stop'): + self.date_stop = self.calendar_fields['date_stop']['name'] + self.fields[self.date_stop] = "" + if self.calendar_fields.get('date_delay'): + self.date_delay = self.calendar_fields['date_delay']['name'] + self.fields[self.date_delay] = "" + if self.calendar_fields.get('parent'): + self.parent = self.calendar_fields['parent']['name'] + self.fields[self.parent] = "" + + model = req.session.model(self.model) + event_ids = model.search([]) + + return self.create_event(event_ids, model) + + def create_event(self, event_ids, model): + + self.events = model.read(event_ids, self.fields.keys()) + result = [] + for evt in self.events: + + event_res = {} + key = evt[self.color_field] + name = key + value = key + if isinstance(key, list): # M2O, XMLRPC returns List instead of Tuple + name = key[0] + value = key[-1] + evt[self.color_field] = key = key[-1] + if isinstance(key, tuple): # M2O + value, name = key + + self.colors[key] = (name, value, None) + + st_date = evt.get(self.date_start) + if st_date: + self.set_format(st_date) + if self.date_delay: + duration = evt.get(self.date_delay) + else: + en_date = evt.get(self.date_stop) + + duration = (time.mktime(time.strptime(en_date, self.format))-\ + time.mktime(time.strptime(st_date, self.format)))/ (60 * 60) + + if duration > self.day_length : + d = math.floor(duration / 24) + h = duration % 24 + duration = d * self.day_length + h + + event_res = {} + event_res['start_date'] = st_date + event_res['duration'] = duration + event_res['text'] = evt.get(self.text) + event_res['id'] = evt['id'] + event_res['parent'] = evt.get(self.parent) + result.append(event_res) + + colors = choice_colors(len(self.colors)) + for i, (key, value) in enumerate(self.colors.items()): + self.colors[key] = [value[0], value[1], colors[i]] + + return {'result': result,'sidebar': self.colors} + + def set_format(self, st_date): + if len(st_date) == 10 : + self.format = "%Y-%m-%d" + else : + self.format = "%Y-%m-%d %H:%M:%S" + return + + def check_format(self, date): + if self.format == "%Y-%m-%d %H:%M:%S": + date = date + " 00:00:00" + return date + + @openerpweb.jsonrequest + def on_event_resize(self, req, **kw): + if self.date_delay: + key = self.date_delay + value = kw['duration'] + else: + key = self.date_stop + value = self.check_format(kw['end_date']) + try: + model = req.session.model(self.model) + res = model.write(kw['id'], {key : value}) + except Exception, e: + print "eeeeeeeeeeeeeeeeeeeeeeeeeee",e + return True + + @openerpweb.jsonrequest + def on_event_drag(self, req, **kw): + start_date = self.check_format(kw['start_date']) + if self.date_delay: + key = self.date_delay + value = kw['duration'] + else: + key = self.date_stop + value = self.check_format(kw['end_date']) + try: + model = req.session.model(self.model) + res = model.write(kw['id'], {self.date_start : start_date, key : value}) + except Exception, e: + print "eeeeeeeeeeeeeeeeeeeeeeeeeee",e + return True + + @openerpweb.jsonrequest + def reload_gantt(self, req, **kw): + + model = req.session.model(kw['model']) + if (kw['domain']): + domain = (kw['color_field'],'in', kw['domain']) + event_ids = model.search([domain]) + else: + event_ids = model.search([]) + return self.create_event(event_ids, model) + \ No newline at end of file diff --git a/addons/base_gantt/static/lib/dhtmlxGantt/License_GPL.html b/addons/base_gantt/static/lib/dhtmlxGantt/License_GPL.html new file mode 100644 index 00000000000..afe2ef33f0b --- /dev/null +++ b/addons/base_gantt/static/lib/dhtmlxGantt/License_GPL.html @@ -0,0 +1,73 @@ +

GNU GENERAL PUBLIC LICENSE

+Version 2, June 1991

+

+

Copyright (C) 1989, 1991 Free Software Foundation, Inc.

+

59 Temple Place - Suite 330, Boston, MA 02111-1307, USA

+

+

Everyone is permitted to copy and distribute verbatim copies

+

of this license document, but changing it is not allowed.

+

+

+

TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION

+

0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you".

+

+

Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does.

+

+

1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program.

+

+

You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee.

+

+

2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions:

+

+

+

a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change.

+

+

b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License.

+

+

c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.)

+

These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it.

+

+

Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program.

+

+

In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License.

+

+

3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following:

+

+

a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or,

+

+

b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or,

+

+

c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.)

+

The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable.

+

+

If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code.

+

+

4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance.

+

+

5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it.

+

+

6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License.

+

+

7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program.

+

+

If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances.

+

+

It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice.

+

+

This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License.

+

+

8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License.

+

+

9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns.

+

+

Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation.

+

+

10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally.

+

+

NO WARRANTY

+

+

11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.

+

+

12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.

+

+

\ No newline at end of file diff --git a/addons/base_gantt/static/lib/dhtmlxGantt/codebase/dhtmlxcommon.js b/addons/base_gantt/static/lib/dhtmlxGantt/codebase/dhtmlxcommon.js new file mode 100644 index 00000000000..208124b8c74 --- /dev/null +++ b/addons/base_gantt/static/lib/dhtmlxGantt/codebase/dhtmlxcommon.js @@ -0,0 +1,933 @@ +dhtmlx=function(obj){ + for (var a in obj) dhtmlx[a]=obj[a]; + return dhtmlx; //simple singleton +}; +dhtmlx.extend_api=function(name,map,ext){ + var t = window[name]; + if (!t) return; //component not defined + window[name]=function(obj){ + if (obj && typeof obj == "object" && !obj.tagName){ + var that = t.apply(this,(map._init?map._init(obj):arguments)); + //global settings + for (var a in dhtmlx) + if (map[a]) this[map[a]](dhtmlx[a]); + //local settings + for (var a in obj){ + if (map[a]) this[map[a]](obj[a]); + else if (a.indexOf("on")==0){ + this.attachEvent(a,obj[a]); + } + } + } else + var that = t.apply(this,arguments); + if (map._patch) map._patch(this); + return that||this; + }; + window[name].prototype=t.prototype; + if (ext) + dhtmlXHeir(window[name].prototype,ext); +}; + +dhtmlxAjax={ + get:function(url,callback){ + var t=new dtmlXMLLoaderObject(true); + t.async=(arguments.length<3); + t.waitCall=callback; + t.loadXML(url) + return t; + }, + post:function(url,post,callback){ + var t=new dtmlXMLLoaderObject(true); + t.async=(arguments.length<4); + t.waitCall=callback; + t.loadXML(url,true,post) + return t; + }, + getSync:function(url){ + return this.get(url,null,true) + }, + postSync:function(url,post){ + return this.post(url,post,null,true); + } +} + +/** + * @desc: xmlLoader object + * @type: private + * @param: funcObject - xml parser function + * @param: object - jsControl object + * @param: async - sync/async mode (async by default) + * @param: rSeed - enable/disable random seed ( prevent IE caching) + * @topic: 0 + */ +function dtmlXMLLoaderObject(funcObject, dhtmlObject, async, rSeed){ + this.xmlDoc=""; + + if (typeof (async) != "undefined") + this.async=async; + else + this.async=true; + + this.onloadAction=funcObject||null; + this.mainObject=dhtmlObject||null; + this.waitCall=null; + this.rSeed=rSeed||false; + return this; +}; +/** + * @desc: xml loading handler + * @type: private + * @param: dtmlObject - xmlLoader object + * @topic: 0 + */ +dtmlXMLLoaderObject.prototype.waitLoadFunction=function(dhtmlObject){ + var once = true; + this.check=function (){ + if ((dhtmlObject)&&(dhtmlObject.onloadAction != null)){ + if ((!dhtmlObject.xmlDoc.readyState)||(dhtmlObject.xmlDoc.readyState == 4)){ + if (!once) + return; + + once=false; //IE 5 fix + if (typeof dhtmlObject.onloadAction == "function") + dhtmlObject.onloadAction(dhtmlObject.mainObject, null, null, null, dhtmlObject); + + if (dhtmlObject.waitCall){ + dhtmlObject.waitCall.call(this,dhtmlObject); + dhtmlObject.waitCall=null; + } + } + } + }; + return this.check; +}; + +/** + * @desc: return XML top node + * @param: tagName - top XML node tag name (not used in IE, required for Safari and Mozilla) + * @type: private + * @returns: top XML node + * @topic: 0 + */ +dtmlXMLLoaderObject.prototype.getXMLTopNode=function(tagName, oldObj){ + if (this.xmlDoc.responseXML){ + var temp = this.xmlDoc.responseXML.getElementsByTagName(tagName); + if(temp.length==0 && tagName.indexOf(":")!=-1) + var temp = this.xmlDoc.responseXML.getElementsByTagName((tagName.split(":"))[1]); + var z = temp[0]; + } else + var z = this.xmlDoc.documentElement; + + if (z){ + this._retry=false; + return z; + } + + if ((_isIE)&&(!this._retry)){ + //fall back to MS.XMLDOM + var xmlString = this.xmlDoc.responseText; + var oldObj = this.xmlDoc; + this._retry=true; + this.xmlDoc=new ActiveXObject("Microsoft.XMLDOM"); + this.xmlDoc.async=false; + this.xmlDoc["loadXM"+"L"](xmlString); + + return this.getXMLTopNode(tagName, oldObj); + } + dhtmlxError.throwError("LoadXML", "Incorrect XML", [ + (oldObj||this.xmlDoc), + this.mainObject + ]); + + return document.createElement("DIV"); +}; + +/** + * @desc: load XML from string + * @type: private + * @param: xmlString - xml string + * @topic: 0 + */ +dtmlXMLLoaderObject.prototype.loadXMLString=function(xmlString){ + { + try{ + var parser = new DOMParser(); + this.xmlDoc=parser.parseFromString(xmlString, "text/xml"); + } + catch (e){ + this.xmlDoc=new ActiveXObject("Microsoft.XMLDOM"); + this.xmlDoc.async=this.async; + this.xmlDoc["loadXM"+"L"](xmlString); + } + } + + this.onloadAction(this.mainObject, null, null, null, this); + + if (this.waitCall){ + this.waitCall(); + this.waitCall=null; + } +} +/** + * @desc: load XML + * @type: private + * @param: filePath - xml file path + * @param: postMode - send POST request + * @param: postVars - list of vars for post request + * @topic: 0 + */ +dtmlXMLLoaderObject.prototype.loadXML=function(filePath, postMode, postVars, rpc){ + if (this.rSeed) + filePath+=((filePath.indexOf("?") != -1) ? "&" : "?")+"a_dhx_rSeed="+(new Date()).valueOf(); + this.filePath=filePath; + + if ((!_isIE)&&(window.XMLHttpRequest)) + this.xmlDoc=new XMLHttpRequest(); + else { + if (document.implementation&&document.implementation.createDocument){ + this.xmlDoc=document.implementation.createDocument("", "", null); + this.xmlDoc.onload=new this.waitLoadFunction(this); + this.xmlDoc.load(filePath); + return; + } else + this.xmlDoc=new ActiveXObject("Microsoft.XMLHTTP"); + } + + if (this.async) + this.xmlDoc.onreadystatechange=new this.waitLoadFunction(this); + this.xmlDoc.open(postMode ? "POST" : "GET", filePath, this.async); + + if (rpc){ + this.xmlDoc.setRequestHeader("User-Agent", "dhtmlxRPC v0.1 ("+navigator.userAgent+")"); + this.xmlDoc.setRequestHeader("Content-type", "text/xml"); + } + + else if (postMode) + this.xmlDoc.setRequestHeader('Content-type', 'application/x-www-form-urlencoded'); + + this.xmlDoc.setRequestHeader("X-Requested-With","XMLHttpRequest"); + this.xmlDoc.send(null||postVars); + + if (!this.async) + (new this.waitLoadFunction(this))(); +}; +/** + * @desc: destructor, cleans used memory + * @type: private + * @topic: 0 + */ +dtmlXMLLoaderObject.prototype.destructor=function(){ + this._filterXPath = null; + this._getAllNamedChilds = null; + this._retry = null; + this.async = null; + this.rSeed = null; + this.filePath = null; + this.onloadAction = null; + this.mainObject = null; + this.xmlDoc = null; + this.doXPath = null; + this.doXPathOpera = null; + this.doXSLTransToObject = null; + this.doXSLTransToString = null; + this.loadXML = null; + this.loadXMLString = null; + // this.waitLoadFunction = null; + this.doSerialization = null; + this.xmlNodeToJSON = null; + this.getXMLTopNode = null; + this.setXSLParamValue = null; + return null; +} + +dtmlXMLLoaderObject.prototype.xmlNodeToJSON = function(node){ + var t={}; + for (var i=0; i-1) + _isChrome=true; + +if ((navigator.userAgent.indexOf('Safari') != -1)||(navigator.userAgent.indexOf('Konqueror') != -1)){ + var _KHTMLrv = parseFloat(navigator.userAgent.substr(navigator.userAgent.indexOf('Safari')+7, 5)); + + if (_KHTMLrv > 525){ //mimic FF behavior for Safari 3.1+ + _isFF=true; + var _FFrv = 1.9; + } else + _isKHTML=true; +} else if (navigator.userAgent.indexOf('Opera') != -1){ + _isOpera=true; + _OperaRv=parseFloat(navigator.userAgent.substr(navigator.userAgent.indexOf('Opera')+6, 3)); +} + + +else if (navigator.appName.indexOf("Microsoft") != -1){ + _isIE=true; + if (navigator.appVersion.indexOf("MSIE 8.0")!= -1 && document.compatMode != "BackCompat") _isIE=8; +} else { + _isFF=true; + var _FFrv = parseFloat(navigator.userAgent.split("rv:")[1]) +} + + +//multibrowser Xpath processor +dtmlXMLLoaderObject.prototype.doXPath=function(xpathExp, docObj, namespace, result_type){ + if (_isKHTML || (!_isIE && !window.XPathResult)) + return this.doXPathOpera(xpathExp, docObj); + + if (_isIE){ //IE + if (!docObj) + if (!this.xmlDoc.nodeName) + docObj=this.xmlDoc.responseXML + else + docObj=this.xmlDoc; + + if (!docObj) + dhtmlxError.throwError("LoadXML", "Incorrect XML", [ + (docObj||this.xmlDoc), + this.mainObject + ]); + + if (namespace != null) + docObj.setProperty("SelectionNamespaces", "xmlns:xsl='"+namespace+"'"); // + + if (result_type == 'single'){ + return docObj.selectSingleNode(xpathExp); + } + else { + return docObj.selectNodes(xpathExp)||new Array(0); + } + } else { //Mozilla + var nodeObj = docObj; + + if (!docObj){ + if (!this.xmlDoc.nodeName){ + docObj=this.xmlDoc.responseXML + } + else { + docObj=this.xmlDoc; + } + } + + if (!docObj) + dhtmlxError.throwError("LoadXML", "Incorrect XML", [ + (docObj||this.xmlDoc), + this.mainObject + ]); + + if (docObj.nodeName.indexOf("document") != -1){ + nodeObj=docObj; + } + else { + nodeObj=docObj; + docObj=docObj.ownerDocument; + } + var retType = XPathResult.ANY_TYPE; + + if (result_type == 'single') + retType=XPathResult.FIRST_ORDERED_NODE_TYPE + var rowsCol = new Array(); + var col = docObj.evaluate(xpathExp, nodeObj, function(pref){ + return namespace + }, retType, null); + + if (retType == XPathResult.FIRST_ORDERED_NODE_TYPE){ + return col.singleNodeValue; + } + var thisColMemb = col.iterateNext(); + + while (thisColMemb){ + rowsCol[rowsCol.length]=thisColMemb; + thisColMemb=col.iterateNext(); + } + return rowsCol; + } +} + +function _dhtmlxError(type, name, params){ + if (!this.catches) + this.catches=new Array(); + + return this; +} + +_dhtmlxError.prototype.catchError=function(type, func_name){ + this.catches[type]=func_name; +} +_dhtmlxError.prototype.throwError=function(type, name, params){ + if (this.catches[type]) + return this.catches[type](type, name, params); + + if (this.catches["ALL"]) + return this.catches["ALL"](type, name, params); + + alert("Error type: "+arguments[0]+"\nDescription: "+arguments[1]); + return null; +} + +window.dhtmlxError=new _dhtmlxError(); + + +//opera fake, while 9.0 not released +//multibrowser Xpath processor +dtmlXMLLoaderObject.prototype.doXPathOpera=function(xpathExp, docObj){ + //this is fake for Opera + var z = xpathExp.replace(/[\/]+/gi, "/").split('/'); + var obj = null; + var i = 1; + + if (!z.length) + return []; + + if (z[0] == ".") + obj=[docObj]; else if (z[0] == ""){ + obj=(this.xmlDoc.responseXML||this.xmlDoc).getElementsByTagName(z[i].replace(/\[[^\]]*\]/g, "")); + i++; + } else + return []; + + for (i; i < z.length; i++)obj=this._getAllNamedChilds(obj, z[i]); + + if (z[i-1].indexOf("[") != -1) + obj=this._filterXPath(obj, z[i-1]); + return obj; +} + +dtmlXMLLoaderObject.prototype._filterXPath=function(a, b){ + var c = new Array(); + var b = b.replace(/[^\[]*\[\@/g, "").replace(/[\[\]\@]*/g, ""); + + for (var i = 0; i < a.length; i++) + if (a[i].getAttribute(b)) + c[c.length]=a[i]; + + return c; +} +dtmlXMLLoaderObject.prototype._getAllNamedChilds=function(a, b){ + var c = new Array(); + + if (_isKHTML) + b=b.toUpperCase(); + + for (var i = 0; i < a.length; i++)for (var j = 0; j < a[i].childNodes.length; j++){ + if (_isKHTML){ + if (a[i].childNodes[j].tagName&&a[i].childNodes[j].tagName.toUpperCase() == b) + c[c.length]=a[i].childNodes[j]; + } + + else if (a[i].childNodes[j].tagName == b) + c[c.length]=a[i].childNodes[j]; + } + + return c; +} + +function dhtmlXHeir(a, b){ + for (var c in b) + if (typeof (b[c]) == "function") + a[c]=b[c]; + return a; +} + +function dhtmlxEvent(el, event, handler){ + if (el.addEventListener) + el.addEventListener(event, handler, false); + + else if (el.attachEvent) + el.attachEvent("on"+event, handler); +} + +//============= XSL Extension =================================== + +dtmlXMLLoaderObject.prototype.xslDoc=null; +dtmlXMLLoaderObject.prototype.setXSLParamValue=function(paramName, paramValue, xslDoc){ + if (!xslDoc) + xslDoc=this.xslDoc + + if (xslDoc.responseXML) + xslDoc=xslDoc.responseXML; + var item = + this.doXPath("/xsl:stylesheet/xsl:variable[@name='"+paramName+"']", xslDoc, + "http:/\/www.w3.org/1999/XSL/Transform", "single"); + + if (item != null) + item.firstChild.nodeValue=paramValue +} +dtmlXMLLoaderObject.prototype.doXSLTransToObject=function(xslDoc, xmlDoc){ + if (!xslDoc) + xslDoc=this.xslDoc; + + if (xslDoc.responseXML) + xslDoc=xslDoc.responseXML + + if (!xmlDoc) + xmlDoc=this.xmlDoc; + + if (xmlDoc.responseXML) + xmlDoc=xmlDoc.responseXML + + //MOzilla + if (!_isIE){ + if (!this.XSLProcessor){ + this.XSLProcessor=new XSLTProcessor(); + this.XSLProcessor.importStylesheet(xslDoc); + } + var result = this.XSLProcessor.transformToDocument(xmlDoc); + } else { + var result = new ActiveXObject("Msxml2.DOMDocument.3.0"); + try{ + xmlDoc.transformNodeToObject(xslDoc, result); + }catch(e){ + result = xmlDoc.transformNode(xslDoc); + } + } + return result; +} + +dtmlXMLLoaderObject.prototype.doXSLTransToString=function(xslDoc, xmlDoc){ + var res = this.doXSLTransToObject(xslDoc, xmlDoc); + if(typeof(res)=="string") + return res; + return this.doSerialization(res); +} + +dtmlXMLLoaderObject.prototype.doSerialization=function(xmlDoc){ + if (!xmlDoc) + xmlDoc=this.xmlDoc; + if (xmlDoc.responseXML) + xmlDoc=xmlDoc.responseXML + if (!_isIE){ + var xmlSerializer = new XMLSerializer(); + return xmlSerializer.serializeToString(xmlDoc); + } else + return xmlDoc.xml; +} + +/** +* @desc: +* @type: private +*/ +dhtmlxEventable=function(obj){ + obj.attachEvent=function(name, catcher, callObj){ + name='ev_'+name.toLowerCase(); + if (!this[name]) + this[name]=new this.eventCatcher(callObj||this); + + return(name+':'+this[name].addEvent(catcher)); //return ID (event name & event ID) + } + obj.callEvent=function(name, arg0){ + name='ev_'+name.toLowerCase(); + if (this[name]) + return this[name].apply(this, arg0); + return true; + } + obj.checkEvent=function(name){ + return (!!this['ev_'+name.toLowerCase()]) + } + obj.eventCatcher=function(obj){ + var dhx_catch = []; + var z = function(){ + var res = true; + for (var i = 0; i < dhx_catch.length; i++){ + if (dhx_catch[i] != null){ + var zr = dhx_catch[i].apply(obj, arguments); + res=res&&zr; + } + } + return res; + } + z.addEvent=function(ev){ + if (typeof (ev) != "function") + ev=eval(ev); + if (ev) + return dhx_catch.push(ev)-1; + return false; + } + z.removeEvent=function(id){ + dhx_catch[id]=null; + } + return z; + } + obj.detachEvent=function(id){ + if (id != false){ + var list = id.split(':'); //get EventName and ID + this[list[0]].removeEvent(list[1]); //remove event + } + } + obj.detachAllEvents = function(){ + for (var name in this){ + if (name.indexOf("ev_")==0) + delete this[name]; + } + } +} diff --git a/addons/base_gantt/static/lib/dhtmlxGantt/codebase/dhtmlxgantt.css b/addons/base_gantt/static/lib/dhtmlxGantt/codebase/dhtmlxgantt.css new file mode 100644 index 00000000000..2923173eebc --- /dev/null +++ b/addons/base_gantt/static/lib/dhtmlxGantt/codebase/dhtmlxgantt.css @@ -0,0 +1,15 @@ +.taskPanelBorder{border-width: 2px 2px 2px 2px;border-style:solid;border-color: #737373;} +.taskName{font-family: Tahoma, Arial; font-weight: bold;font-size: 11px;color: #FFFFFF;cursor: pointer;white-space: nowrap;} +.moveInfo{font-family: Tahoma, Arial;font-size: 10px;color:#006600;white-space: nowrap;} +.descTask{font-family: Tahoma, Arial;font-size: 10px;color:#276F9E;cursor: default;white-space: nowrap;} +.descProject{font-family: Tahoma, Arial;font-size: 10px;color:#006600;cursor: default;white-space: nowrap;} +.dayNumber, .monthName{font-family:Tahoma,Arial;font-weight:bold;font-size:9px;color:#858585;text-align:center;vertical-align:middle;} +.monthName {border-top:1px solid #f1f3f1; border-bottom:1px solid #f1f3f1; border-left:1px solid #f1f3f1;text-align:left;padding-left:5px;} +.poPupInfo{background: #FFFFFF;width : 170px;border: 1px dotted #279e00;padding: 4px 6px 4px 6px;float: left;} +.poPupTime{background: #FFFFFF;border: 1px dotted #279e00;height : 25px;width : 70px;position: absolute;z-index:2;} +.contextMenu{z-index:10;width:150px;cursor:pointer;font-family: Tahoma, Arial;font-size:12px;color:#7D7D7D;border: 1px solid #808080;} +.taskNameItem{font-family: Tahoma, Arial;font-size: 11px;font-weight: normal;color: #7D7D7D;} +.panelErrors{;padding: 4px 6px 4px 6px;font-family: Tahoma, Arial;font-size: 12px;color: red;white-space: nowrap;} +.st {font-family: Arial, Helvetica, Sans-serif; font-size: 10px; font-weight: normal; color: #688060;} +.ut {font-family: Arial, Helvetica, Sans-serif; font-size: 11px; font-weight: normal; color: #323232;} +.lt {font-family: Arial, Helvetica, Sans-serif; font-size: 11px; font-weight: normal; color: #323232; padding: 0px 0px 0px 14px; margin: 0px; display: block;} diff --git a/addons/base_gantt/static/lib/dhtmlxGantt/codebase/dhtmlxgantt.js b/addons/base_gantt/static/lib/dhtmlxGantt/codebase/dhtmlxgantt.js new file mode 100644 index 00000000000..454e20e7838 --- /dev/null +++ b/addons/base_gantt/static/lib/dhtmlxGantt/codebase/dhtmlxgantt.js @@ -0,0 +1,384 @@ +//v.1.3 build 100805 + +/* +Copyright DHTMLX LTD. http://www.dhtmlx.com +To use this component please contact sales@dhtmlx.com to obtain license +*/ + +function GanttProjectInfo(id, name, startDate) +{this.Id = id;this.Name = name;this.StartDate = startDate;this.ParentTasks = []};GanttProjectInfo.prototype.deleteTask = function(id) +{var task = this.getTaskById(id);if (task){if (!task.ParentTask){for (var i = 0;i < this.ParentTasks.length;i++){if (this.ParentTasks[i].Id == id){if (this.ParentTasks[i].nextParentTask){if (this.ParentTasks[i].previousParentTask){this.ParentTasks[i].previousParentTask.nextParentTask = this.ParentTasks[i].nextParentTask;this.ParentTasks[i].nextParentTask.previousParentTask = this.ParentTasks[i].previousParentTask}else {this.ParentTasks[i].nextParentTask.previousParentTask = null}}else {if (this.ParentTasks[i].previousParentTask){this.ParentTasks[i].previousParentTask.nextParentTask = null}};this.ParentTasks[i] = null;this.ParentTasks.splice(i, 1);break}}}else + {var parentTask = task.ParentTask;for (var i = 0;i < parentTask.ChildTasks.length;i++){if (parentTask.ChildTasks[i].Id == id){if (parentTask.ChildTasks[i].nextChildTask){if (parentTask.ChildTasks[i].previousChildTask){parentTask.ChildTasks[i].previousChildTask.nextChildTask = parentTask.ChildTasks[i].nextChildTask;parentTask.ChildTasks[i].nextChildTask.previousChildTask = parentTask.ChildTasks[i].previousChildTask}else {parentTask.ChildTasks[i].nextChildTask.previousChildTask = null}}else {if (parentTask.ChildTasks[i].previousChildTask){parentTask.ChildTasks[i].previousChildTask.nextChildTask = null}};parentTask.ChildTasks[i] = null;parentTask.ChildTasks.splice(i, 1);break}}}}};GanttProjectInfo.prototype.addTask = function(task) +{this.ParentTasks.push(task);task.setProject(this)};GanttProjectInfo.prototype.getTaskById = function(id) +{for (var j = 0;j < this.ParentTasks.length;j++){var task = this.getTaskByIdInTree(this.ParentTasks[j], id);if (task)return task};return null};GanttProjectInfo.prototype.getTaskByIdInTree = function(parentTask, id) +{if (parentTask.Id == id){return parentTask}else + {for (var i = 0;i < parentTask.ChildTasks.length;i++){if (parentTask.ChildTasks[i].Id == id){return parentTask.ChildTasks[i]};if (parentTask.ChildTasks[i].ChildTasks.length > 0){if (parentTask.ChildTasks[i].ChildTasks.length > 0){var cTask = this.getTaskByIdInTree(parentTask.ChildTasks[i], id);if (cTask)return cTask}}}};return null};function GanttTaskInfo(id, name, est, duration, percentCompleted, predecessorTaskId) +{this.Id = id;this.Name = name;this.EST = est;this.Duration = duration;this.PercentCompleted = percentCompleted;this.PredecessorTaskId = predecessorTaskId;this.ChildTasks = [];this.ChildPredTasks = [];this.ParentTask = null;this.PredecessorTask = null;this.Project = null;this.nextChildTask = null;this.previousChildTask = null;this.nextParentTask = null;this.previousParentTask = null};GanttTaskInfo.prototype.addChildTask = function(task) +{this.ChildTasks.push(task);task.ParentTask = this};GanttTaskInfo.prototype.setProject = function(project) +{this.Project = project;for (var j = 0;j < this.ChildTasks.length;j++){this.ChildTasks[j].setProject(project)}};function GanttTask(taskInfo, project, chart) +{this.isTask = true;this.Chart = chart;this.Project = project;this.TaskInfo = taskInfo;this.checkMove = false;this.checkResize = false;this.moveChild = false;this.maxPosXMove = -1;this.minPosXMove = -1;this.maxWidthResize = -1;this.minWidthResize = -1;this.posX = 0;this.posY = 0;this.MouseX = 0;this.taskItemWidth = 0;this.isHide = false;this._heightHideTasks = 0;this._isOpen = true;this.descrTask = null;this.cTaskItem = null;this.cTaskNameItem = null;this.parentTask = null;this.predTask = null;this.childTask = [];this.childPredTask = [];this.nextChildTask = null;this.previousChildTask = null;this.nextParentTask = null;this.previousParentTask = null};function GanttProject(Chart, projectInfo) +{this.isProject = true;this.nextProject = null;this.previousProject = null;this.arrTasks = [];this.Project = projectInfo;this.Chart = Chart;this.percentCompleted = 0;this.Duration = 0;this.descrProject = null;this.projectItem = null;this.projectNameItem = null;this.posY = 0;this.posX = 0};GanttProject.prototype.checkWidthProjectNameItem = function() +{if (this.projectNameItem.offsetWidth + this.projectNameItem.offsetLeft > this.Chart.maxWidthPanelNames){var width = this.projectNameItem.offsetWidth + this.projectNameItem.offsetLeft - this.Chart.maxWidthPanelNames;var countChar = Math.round(width / (this.projectNameItem.offsetWidth / this.projectNameItem.firstChild.length));var pName = this.Project.Name.substring(0, this.projectNameItem.firstChild.length - countChar - 3);pName += "...";this.projectNameItem.innerHTML = pName}};GanttProject.prototype.create = function() +{var containerTasks = this.Chart.oData.firstChild;this.posX = (this.Project.StartDate - this.Chart.startDate) / (60 * 60 * 1000) * this.Chart.hourInPixels;if (this.previousProject){if (this.previousProject.arrTasks.length > 0){var lastChildTask = this.Chart.getLastChildTask(this.previousProject.arrTasks[this.previousProject.arrTasks.length - 1]);this.posY = parseInt(lastChildTask.cTaskItem[0].style.top) + this.Chart.heightTaskItem + 11}else {this.posY = parseInt(this.previousProject.projectItem[0].style.top) + this.Chart.heightTaskItem + 11}}else {this.posY = 6};if (this.Chart._showTreePanel){var containerNames = this.Chart.panelNames.firstChild;this.projectNameItem = this.createProjectNameItem();containerNames.appendChild(this.projectNameItem);this.checkWidthProjectNameItem()};this.projectItem = [this.createProjectItem(),[]];containerTasks.appendChild(this.projectItem[0]);if (this.Chart.isShowDescProject){containerTasks.appendChild(this.createDescrProject())};this.addDayInPanelTime()};function GanttChart() +{this.Error = new GanttError();this.dhtmlXMLSenderObject = new dhtmlXMLSenderObject(this);this.heightTaskItem = 12;this.dayInPixels = 24;this.hoursInDay = 8;this._showTreePanel = true;this._showTooltip = true;this.isShowDescTask = false;this.isShowDescProject = false;this.isShowNewProject = true;this.isEditable = false;this.isShowConMenu = false;this.correctError = false;this.maxWidthPanelNames = 150;this.minWorkLength = 8;this.paramShowTask = [];this.paramShowProject = [];this.savePath = null;this.loadPath = null;this.divTimeInfo = null;this.divInfo = null;this.panelNames = null;this.panelTime = null;this.oData = null;this.content = null;this.panelErrors = null;this.contextMenu = null;this.hourInPixelsWork = this.dayInPixels / this.hoursInDay;this.hourInPixels = this.dayInPixels / 24;this.countDays = 0;this.startDate = null;this.initialPos = 0;this.contentHeight = 0;this.contentWidth = 0;this._oDataHeight = 0;this.Project = [];this.arrProjects = [];this.xmlLoader = null;this._isIE = false;this._isFF = false;this._isOpera = false;this._isMove = false;this._isResize = false;this._isError = false;this.imgs = "codebase/imgs/";this.stylePath = "codebase/dhtmlxgantt.css";this.shortMonthNames = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];this.monthNames = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"];this._useShortMonthNames = true;dhtmlxEventable(this)};GanttChart.prototype.setImagePath = function(newPath) +{this.imgs = newPath};GanttChart.prototype.setStylePath = function(newPath) +{this.stylePath = newPath};GanttChart.prototype.setSavePath = function(newPath) +{this.savePath = newPath};GanttChart.prototype.setLoadPath = function(newPath) +{this.loadPath = newPath};GanttChart.prototype.setCorrectError = function(isCorrectError) +{this.correctError = isCorrectError};GanttChart.prototype.showDescTask = function(isShowDescTask, param) +{this.isShowDescTask = isShowDescTask;var arrValues = new Array(5);if (this.isShowDescTask){if (param){var arrParam = param.split(",");for (var i = 0;i < arrParam.length;i++){var k = this.getParamShowTask(arrParam[i]);arrValues[k] = 1}}else {arrValues[this.getParamShowTask('')] = 1};this.paramShowTask = this.getValueShowTask(arrValues)}};GanttChart.prototype.showDescProject = function(isShowDescProject, param) +{this.isShowDescProject = isShowDescProject;var arrValues = new Array(4);if (this.isShowDescProject){if (param){var arrParam = param.split(",");for (var i = 0;i < arrParam.length;i++){var k = this.getParamShowProject(arrParam[i]);arrValues[k] = 1}}else {arrValues[this.getParamShowProject('')] = 1};this.paramShowProject = this.getValueShowProject(arrValues)}};GanttChart.prototype.showContextMenu = function(show) +{this.isShowConMenu = show};GanttChart.prototype.setContextMenu = function(menu) +{this.showContextMenu(true);this.contextMenu = menu};GanttChart.prototype.showNewProject = function(show) +{this.isShowNewProject = show};GanttChart.prototype.getParamShowTask = function(param) +{switch (param) {case 'n': + + return 0;break;case 'd': + + return 1;break;case 'e': + + return 2;break;case 'p': + + return 3;break;case 's-f': + + return 4;break;default: + return 0;break}};GanttChart.prototype.getParamShowProject = function(param) +{switch (param) {case 'n': + + return 0;break;case 'd': + + return 1;break;case 's': + + return 2;break;case 'p': + + return 3;break;default: + return 0;break}};GanttChart.prototype.getValueShowTask = function(param) +{var arrValues = [];for (var i = 0;i < param.length;i++){if (param[i]){switch (i) {case 0: + arrValues.push('Name');break;case 1: + arrValues.push('Duration');break;case 2: + arrValues.push('EST');break;case 3: + arrValues.push('PercentComplete');break;case 4: + arrValues.push('S-F');break;default: + break}}};return arrValues};GanttChart.prototype.getValueShowProject = function(param) +{var arrValues = [];for (var i = 0;i < param.length;i++){if (param[i]){switch (i) {case 0: + arrValues.push('Name');break;case 1: + arrValues.push('Duration');break;case 2: + arrValues.push('StartDate');break;case 3: + arrValues.push('PercentComplete');break;default: + break}}};return arrValues};GanttChart.prototype.setEditable = function(isEditable) +{this.isEditable = isEditable};GanttChart.prototype.showTreePanel = function(show) +{this._showTreePanel = show};GanttChart.prototype.showTooltip = function(show) +{this._showTooltip = show};GanttChart.prototype.getProjectById = function(id) +{for (var i = 0;i < this.arrProjects.length;i++){if (this.arrProjects[i].Project.Id == id){return this.arrProjects[i]}};return null};GanttChart.prototype.getBrowserType = function() +{if (navigator.appName.indexOf('Explorer')!= -1) + {this._isIE = true}else if (navigator.userAgent.indexOf('Mozilla')!= -1) + {this._isFF = true}else if (navigator.userAgent.indexOf('Opera')!= -1) + {this._isOpera = true}};GanttChart.prototype.addProject = function(projectInfo) +{this.Project.push(projectInfo)};GanttProject.prototype.deleteTask = function(id) +{var task = this.getTaskById(id);if (task){this.deleteChildTask(task)}else {this.Chart.Error.throwError("DATA_INSERT_ERROR", 30, [id])}};GanttChart.prototype.deleteProject = function(id) +{var project = this.getProjectById(id);if (project){if (project.arrTasks.length > 0){while (project.arrTasks.length > 0){project.deleteChildTask(project.arrTasks[0])}};if (project.nextProject)project.shiftNextProject(project, -23);for (var i = 0;i < this.Project.length;i++){if (this.Project[i].Id == project.Project.Id){this.Project.splice(i, 1)}};if ((project.previousProject)&& + (project.nextProject)) + {var previousProject = project.previousProject;previousProject.nextProject = project.nextProject};if ((project.previousProject)&& + !(project.nextProject)) + {var previousProject = project.previousProject;previousProject.nextProject = null};if (!(project.previousProject)&& + (project.nextProject)) + {var nextProject = project.nextProject;nextProject.previousProject = null};for (var i = 0;i < this.arrProjects.length;i++){if (this.arrProjects[i].Project.Id == id){this.arrProjects.splice(i, 1)}};project.projectItem[0].parentNode.removeChild(project.projectItem[0]);if (this.isShowDescProject){project.descrProject.parentNode.removeChild(project.descrProject)};if (this._showTreePanel){project.projectNameItem.parentNode.removeChild(project.projectNameItem)};this._oDataHeight -= 11 + this.heightTaskItem;if (this.Project.length == 0){if (this.isShowNewProject){var d = new Date(this.startDate);var t = new Date(d.setDate(d.getDate() + 1));var pi = new GanttProjectInfo(1, "New project", t);this.Project.push(pi);var project = new GanttProject(this, pi);project.create();this.arrProjects.push(project);this._oDataHeight += 11 + this.heightTaskItem}}}else {this.Error.throwError("DATA_INSERT_ERROR", 31, [id])}};GanttProject.prototype.setName = function(name) +{if ((name != "")&& (name != null)) {this.Project.Name = name;if (this.Chart._showTreePanel){this.projectNameItem.innerHTML = name;this.projectNameItem.title = name;this.checkWidthProjectNameItem()};if (this.Chart.isShowDescProject)this.descrProject.innerHTML = this.getDescStr();this.addDayInPanelTime()}};GanttProject.prototype.setPercentCompleted = function(percentCompleted) +{percentCompleted = parseInt(percentCompleted);if (isNaN(percentCompleted)) + {this.Chart.Error.throwError("DATA_INSERT_ERROR", 6, null);return false};if (percentCompleted > 100){this.Chart.Error.throwError("DATA_INSERT_ERROR", 7, null);return false}else if (percentCompleted < 0){this.Chart.Error.throwError("DATA_INSERT_ERROR", 8, null);return false};if ((percentCompleted > 0)&& (percentCompleted < 100) && (this.percentCompleted > 0) && (this.percentCompleted < 100)) + {this.projectItem[0].firstChild.rows[0].cells[0].width = parseInt(percentCompleted) + "%";this.projectItem[0].firstChild.rows[0].cells[0].firstChild.style.width = (percentCompleted * this.Duration * this.Chart.hourInPixelsWork) / 100 + "px";this.projectItem[0].firstChild.rows[0].cells[1].width = (100 - parseInt(percentCompleted)) + "%";this.projectItem[0].firstChild.rows[0].cells[1].firstChild.style.width = ((100 - percentCompleted) * this.Duration * this.Chart.hourInPixelsWork) / 100 + "px"}else if (((percentCompleted == 0)|| (percentCompleted == 100)) && (this.percentCompleted > 0) && (this.percentCompleted < 100)) + {if (percentCompleted == 0){this.projectItem[0].firstChild.rows[0].cells[0].parentNode.removeChild(this.projectItem[0].firstChild.rows[0].cells[0]);this.projectItem[0].firstChild.rows[0].cells[0].width = 100 + "%";this.projectItem[0].firstChild.rows[0].cells[0].firstChild.style.width = this.Duration * this.Chart.hourInPixelsWork + "px"}else if (percentCompleted == 100){this.projectItem[0].firstChild.rows[0].cells[1].parentNode.removeChild(this.projectItem[0].firstChild.rows[0].cells[1]);this.projectItem[0].firstChild.rows[0].cells[0].width = 100 + "%";this.projectItem[0].firstChild.rows[0].cells[0].firstChild.style.width = this.Duration * this.Chart.hourInPixelsWork + "px"}}else if (((percentCompleted == 0)|| (percentCompleted == 100)) && ((this.percentCompleted == 0) || (this.percentCompleted == 100))) + {if ((percentCompleted == 0)&& (this.percentCompleted == 100)) + {this.projectItem[0].firstChild.rows[0].cells[0].firstChild.src = this.Chart.imgs + "progress_bg.png"}else if ((percentCompleted == 100)&& (this.percentCompleted == 0)) + {this.projectItem[0].firstChild.rows[0].cells[0].firstChild.src = this.Chart.imgs + "parentnode_filled.png"}}else if (((percentCompleted > 0)|| (percentCompleted < 100)) && ((this.percentCompleted == 0) || (this.percentCompleted == 100))) + {this.projectItem[0].firstChild.rows[0].cells[0].parentNode.removeChild(this.projectItem[0].firstChild.rows[0].cells[0]);var cellprojectItem = document.createElement("TD");this.projectItem[0].firstChild.rows[0].appendChild(cellprojectItem);cellprojectItem.width = percentCompleted + "%";var imgPr = document.createElement("img");imgPr.style.width = (percentCompleted * this.Duration * this.Chart.hourInPixelsWork) / 100 + "px";imgPr.style.height = this.Chart.heightTaskItem + "px";cellprojectItem.appendChild(imgPr);imgPr.src = this.Chart.imgs + "parentnode_filled.png";cellprojectItem = document.createElement("TD");this.projectItem[0].firstChild.rows[0].appendChild(cellprojectItem);cellprojectItem.width = (100 - percentCompleted) + "%";imgPr = document.createElement("img");imgPr.style.width = ((100 - percentCompleted) * this.Duration * this.Chart.hourInPixelsWork) / 100 + "px";imgPr.style.height = this.Chart.heightTaskItem + "px";cellprojectItem.appendChild(imgPr);imgPr.src = this.Chart.imgs + "progress_bg.png"}else if (this.percentCompleted == -1){if (percentCompleted == 100){this.projectItem[0].firstChild.rows[0].cells[0].firstChild.src = this.Chart.imgs + "parentnode_filled.png"}else if (percentCompleted < 100 && percentCompleted > 0){this.projectItem[0].firstChild.rows[0].cells[0].parentNode.removeChild(this.projectItem[0].firstChild.rows[0].cells[0]);var cellprojectItem = document.createElement("TD");this.projectItem[0].firstChild.rows[0].appendChild(cellprojectItem);cellprojectItem.width = percentCompleted + "%";var imgPr = document.createElement("img");imgPr.style.width = (percentCompleted * this.Duration * this.Chart.hourInPixelsWork) / 100 + "px";imgPr.style.height = this.Chart.heightTaskItem + "px";cellprojectItem.appendChild(imgPr);imgPr.src = this.Chart.imgs + "parentnode_filled.png";cellprojectItem = document.createElement("TD");this.projectItem[0].firstChild.rows[0].appendChild(cellprojectItem);cellprojectItem.width = (100 - percentCompleted) + "%";imgPr = document.createElement("img");imgPr.style.width = ((100 - percentCompleted) * this.Duration * this.Chart.hourInPixelsWork) / 100 + "px";imgPr.style.height = this.Chart.heightTaskItem + "px";cellprojectItem.appendChild(imgPr);imgPr.src = this.Chart.imgs + "progress_bg.png"}};this.percentCompleted = percentCompleted;if (this.Chart.isShowDescProject)this.descrProject.innerHTML = this.getDescStr();return true};GanttProject.prototype.deleteChildTask = function(task) +{if (task){if (task.cTaskItem[0].style.display == "none"){this.Chart.openTree(task.parentTask)};if (task.childPredTask.length > 0){for (var i = 0;i < task.childPredTask.length;i++){for (var t = 0;t < task.childPredTask[i].cTaskItem[1].length;t++){task.childPredTask[i].cTaskItem[1][t].parentNode.removeChild(task.childPredTask[i].cTaskItem[1][t])};task.childPredTask[i].cTaskItem[1] = [];task.childPredTask[i].predTask = null}};if (task.childTask.length > 0){while (task.childTask.length > 0){this.deleteChildTask(task.childTask[0])}};if (task.cTaskItem[0].style.display != "none")task.shiftCurrentTasks(task, -23);this.Project.deleteTask(task.TaskInfo.Id);if (task.cTaskItem[0]){task.cTaskItem[0].parentNode.removeChild(task.cTaskItem[0])};if (this.Chart.isShowDescTask){task.descrTask.parentNode.removeChild(task.descrTask)};if (task.cTaskItem[1].length > 0){for (var j = 0;j < task.cTaskItem[1].length;j++){task.cTaskItem[1][j].parentNode.removeChild(task.cTaskItem[1][j])}};if (task.cTaskNameItem[0]){task.cTaskNameItem[0].parentNode.removeChild(task.cTaskNameItem[0])};if (task.cTaskNameItem[1]){for (var j = 0;j < task.cTaskNameItem[1].length;j++){task.cTaskNameItem[1][j].parentNode.removeChild(task.cTaskNameItem[1][j])}};if (task.cTaskNameItem[2]){task.cTaskNameItem[2].parentNode.removeChild(task.cTaskNameItem[2])};if (task.parentTask){if (task.previousChildTask){if (task.nextChildTask){task.previousChildTask.nextChildTask = task.nextChildTask}else {task.previousChildTask.nextChildTask = null}};var parentTask = task.parentTask;for (var i = 0;i < parentTask.childTask.length;i++){if (parentTask.childTask[i].TaskInfo.Id == task.TaskInfo.Id){parentTask.childTask[i] = null;parentTask.childTask.splice(i, 1);break}};if (parentTask.childTask.length == 0){if (parentTask.cTaskNameItem[2]){parentTask.cTaskNameItem[2].parentNode.removeChild(parentTask.cTaskNameItem[2]);parentTask.cTaskNameItem[2] = null}}}else + {if (task.previousParentTask){if (task.nextParentTask){task.previousParentTask.nextParentTask = task.nextParentTask}else {task.previousParentTask.nextParentTask = null}};var project = task.Project;for (var i = 0;i < project.arrTasks.length;i++){if (project.arrTasks[i].TaskInfo.Id == task.TaskInfo.Id){project.arrTasks.splice(i, 1)}}};if (task.predTask){var predTask = task.predTask;for (var i = 0;i < predTask.childPredTask.length;i++){if (predTask.childPredTask[i].TaskInfo.Id == task.TaskInfo.Id){predTask.childPredTask[i] = null;predTask.childPredTask.splice(i, 1)}}};if (task.Project.arrTasks.length != 0){task.Project.shiftProjectItem()}else {task.Project.projectItem[0].style.display = "none";if (this.Chart.isShowDescProject)this.hideDescrProject()};this.Chart._oDataHeight -= 11 + this.Chart.heightTaskItem}};GanttProject.prototype.insertTask = function(id, name, EST, Duration, PercentCompleted, predecessorTaskId, parentTaskId) +{var task = null;var _task = null;if (this.Project.getTaskById(id)) {this.Chart.Error.throwError("DATA_INSERT_ERROR", 22, [id]);return false};if ((!Duration)|| (Duration < this.Chart.minWorkLength)) {Duration = this.Chart.minWorkLength};if ((!name)|| (name == "")) {name = id};if ((!PercentCompleted)|| (PercentCompleted == "")) {PercentCompleted = 0}else {PercentCompleted = parseInt(PercentCompleted);if (PercentCompleted < 0 || PercentCompleted > 100){this.Chart.Error.throwError("DATA_INSERT_ERROR", 35, null);return false}};var sortRequired = false;if ((parentTaskId)&& (parentTaskId != "")) {var parentTask = this.Project.getTaskById(parentTaskId);if (!parentTask){this.Chart.Error.throwError("DATA_INSERT_ERROR", 21, [parentTaskId]);return false};EST = EST || parentTask.EST;if (EST < parentTask.EST){this.Chart.Error.throwError("DATA_INSERT_ERROR", 20, [id,parentTaskId]);return false};task = new GanttTaskInfo(id, name, EST, Duration, PercentCompleted, predecessorTaskId);if (!this.Chart.checkPosParentTask(parentTask, task)) {this.Chart.Error.throwError("DATA_INSERT_ERROR", 19, [parentTaskId,id]);return false};task.ParentTask = parentTask;var _parentTask = this.getTaskById(parentTask.Id);var isHide = false;if (_parentTask.cTaskItem[0].style.display == "none"){isHide = true}else if (_parentTask.cTaskNameItem[2]){if (!_parentTask._isOpen){isHide = true}};if (isHide){if (_parentTask.childTask.length == 0){this.Chart.openTree(_parentTask.parentTask)}else {this.Chart.openTree(_parentTask)}};if (predecessorTaskId != ""){var predTask = this.Project.getTaskById(predecessorTaskId);if (!predTask){this.Chart.Error.throwError("DATA_INSERT_ERROR", 27, [predecessorTaskId]);return false};if (predTask.ParentTask){if (predTask.ParentTask.Id != task.ParentTask.Id){this.Chart.Error.throwError("DATA_INSERT_ERROR", 32, [predTask.Id,task.Id]);return false}}else {this.Chart.Error.throwError("DATA_INSERT_ERROR", 32, [predTask.Id,task.Id]);return false};if (!this.Chart.checkPosPredecessorTask(predTask, task)) {this.Chart.correctPosPredecessorTask(predTask, task)};task.PredecessorTask = predTask};var isAdd = false;if (sortRequired)for (var i = 0;i < parentTask.ChildTasks.length;i++){if (task.EST < parentTask.ChildTasks[i].EST){parentTask.ChildTasks.splice(i, 0, task);if (i > 0){parentTask.ChildTasks[i - 1].nextChildTask = parentTask.ChildTasks[i];parentTask.ChildTasks[i].previousChildTask = parentTask.ChildTasks[i - 1]};if (parentTask.ChildTasks[i + 1]){parentTask.ChildTasks[i + 1].previousChildTask = parentTask.ChildTasks[i];parentTask.ChildTasks[i].nextChildTask = parentTask.ChildTasks[i + 1]};isAdd = true;break}};if (!isAdd){if (parentTask.ChildTasks.length > 0){parentTask.ChildTasks[parentTask.ChildTasks.length - 1].nextChildTask = task;task.previousChildTask = parentTask.ChildTasks[parentTask.ChildTasks.length - 1]};parentTask.ChildTasks.push(task)};if (parentTask.ChildTasks.length == 1){_parentTask.cTaskNameItem[2] = _parentTask.createTreeImg()};_task = new GanttTask(task, this, this.Chart);_task.create();if (task.nextChildTask)_task.nextChildTask = _task.Project.getTaskById(task.nextChildTask.Id);_task.addDayInPanelTime();_task.shiftCurrentTasks(_task, 23)}else + {EST = EST || this.Project.StartDate;task = new GanttTaskInfo(id, name, EST, Duration, PercentCompleted, predecessorTaskId);if (task.EST <= this.Chart.startDate){this.Chart.Error.throwError("DATA_INSERT_ERROR", 18, [task.Id]);return false};if (predecessorTaskId != ""){var predTask = this.Project.getTaskById(predecessorTaskId);if (!predTask){this.Chart.Error.throwError("DATA_INSERT_ERROR", 27, [predecessorTaskId]);return false};if (!this.Chart.checkPosPredecessorTask(predTask, task)) {this.Chart.correctPosPredecessorTask(predTask, task)};if (predTask.ParentTask){this.Chart.Error.throwError("DATA_INSERT_ERROR", 15, [task.Id,predTask.Id]);return false};task.PredecessorTask = predTask};var isAdd = false;if (sortRequired)for (var i = 0;i < this.Project.ParentTasks.length;i++){if (EST < this.Project.ParentTasks[i].EST){this.Project.ParentTasks.splice(i, 0, task);if (i > 0){this.Project.ParentTasks[i - 1].nextParentTask = task;task.previousParentTask = this.Project.ParentTasks[i - 1]};if (this.Project.ParentTasks[i + 1]){this.Project.ParentTasks[i + 1].previousParentTask = task;task.nextParentTask = this.Project.ParentTasks[i + 1]};isAdd = true;break}};if (!isAdd){if (this.Project.ParentTasks.length > 0){this.Project.ParentTasks[this.Project.ParentTasks.length - 1].nextParentTask = task;task.previousParentTask = this.Project.ParentTasks[this.Project.ParentTasks.length - 1]};this.Project.ParentTasks.push(task)};_task = new GanttTask(task, this, this.Chart);_task.create();if (task.nextParentTask)_task.nextParentTask = _task.Project.getTaskById(task.nextParentTask.Id);_task.addDayInPanelTime();this.arrTasks.push(_task);_task.shiftCurrentTasks(_task, 23);this.projectItem[0].style.display = "inline";this.setPercentCompleted(this.getPercentCompleted());this.shiftProjectItem();if (this.Chart.isShowDescProject){this.showDescrProject()}};this.Chart.checkHeighPanelTasks();return _task};GanttChart.prototype.checkPosPredecessorTask = function(predTask, task) +{var widthPred = this.getWidthOnDuration(predTask.Duration);var posPred = this.getPosOnDate(predTask.EST);var posChild = this.getPosOnDate(task.EST);return (widthPred + posPred) <= posChild};GanttChart.prototype.correctPosPredecessorTask = function(predTask, ctask, ctaskObj) +{var newDate = new Date(predTask.EST);newDate.setHours(newDate.getHours() + (predTask.Duration / this.hoursInDay * 24));if (newDate.getHours()> 0) {newDate.setHours(0);newDate.setDate(newDate.getDate() + 1)};if (ctaskObj)ctaskObj.setEST(newDate, true);else ctask.EST = newDate;if (ctask.ParentTask){if (!this.checkPosParentTask(ctask.ParentTask, ctask)) + {var newDate2 = new Date(ctask.ParentTask.EST);newDate2.setHours(newDate2.getHours() + (ctask.ParentTask.Duration / this.hoursInDay * 24));ctask.Duration = parseInt((parseInt((newDate2 - ctask.EST) / (1000 * 60 * 60))) * this.hoursInDay / 24)}}};GanttChart.prototype.correctPosParentTask = function(parentTask, ctask) +{if (!ctask.PredecessorTask){if (parentTask.EST > ctask.EST){ctask.EST = new Date(parentTask.EST)};if (!this.checkPosParentTask(parentTask, ctask)) {ctask.Duration = parentTask.Duration}}else + {this.correctPosPredecessorTask(ctask.PredecessorTask, ctask)}};GanttChart.prototype.checkPosParentTaskInTree = function(parentTask) +{var isError = false;for (var t = 0;t < parentTask.ChildTasks.length;t++){if (!this.checkPosParentTask(parentTask, parentTask.ChildTasks[t])) + {if (!this.correctError){this.Error.throwError("DATA_ERROR", 28, [parentTask.Id,parentTask.ChildTasks[t].Id]);return true}else {this.correctPosParentTask(parentTask, parentTask.ChildTasks[t])}};if (parentTask.EST > parentTask.ChildTasks[t].EST){if (!this.correctError){this.Error.throwError("DATA_ERROR", 33, [parentTask.Id,parentTask.ChildTasks[t].Id]);return true}else {this.correctPosParentTask(parentTask, parentTask.ChildTasks[t])}};if (parentTask.ChildTasks[t].ChildTasks.length > 0){isError = this.checkPosParentTaskInTree(parentTask.ChildTasks[t])}};return isError};GanttChart.prototype.setPredTask = function(project) +{var isError = false;for (var k = 0;k < project.ParentTasks.length;k++){if (!this.isEmpty(project.ParentTasks[k].PredecessorTaskId)) + {project.ParentTasks[k].PredecessorTask = project.getTaskById(project.ParentTasks[k].PredecessorTaskId);if (!project.ParentTasks[k].PredecessorTask){if (!this.correctError){this.Error.throwError("DATA_ERROR", 27, [project.ParentTasks[k].PredecessorTaskId]);return true}};project.ParentTasks[k].PredecessorTask.ChildPredTasks.push(project.ParentTasks[k])};if (project.ParentTasks[k].PredecessorTask){if (!this.checkPosPredecessorTask(project.ParentTasks[k].PredecessorTask, project.ParentTasks[k])) {if (!this.correctError){this.Error.throwError("DATA_ERROR", 26, [project.ParentTasks[k].PredecessorTask.Id,project.ParentTasks[k].Id]);return true}else {this.correctPosPredecessorTask(project.ParentTasks[k].PredecessorTask, project.ParentTasks[k])}}};isError = this.setPredTaskInTree(project.ParentTasks[k]);if (isError)return isError};return isError};GanttChart.prototype.setPredTaskInTree = function(parentTask) +{var isError = false;for (var t = 0;t < parentTask.ChildTasks.length;t++){if (!this.isEmpty(parentTask.ChildTasks[t].PredecessorTaskId)) + {parentTask.ChildTasks[t].PredecessorTask = parentTask.Project.getTaskById(parentTask.ChildTasks[t].PredecessorTaskId);if (!parentTask.ChildTasks[t].PredecessorTask){if (!this.correctError){this.Error.throwError("DATA_ERROR", 27, [parentTask.ChildTasks[t].PredecessorTaskId]);return true}};if (!this.checkPosPredecessorTask(parentTask.ChildTasks[t].PredecessorTask, parentTask.ChildTasks[t])) + {if (!this.correctError){this.Error.throwError("DATA_ERROR", 26, [parentTask.ChildTasks[t].PredecessorTask.Id,parentTask.ChildTasks[t].Id]);return true}else {this.correctPosPredecessorTask(parentTask.ChildTasks[t].PredecessorTask, parentTask.ChildTasks[t])}};parentTask.ChildTasks[t].PredecessorTask.ChildPredTasks.push(parentTask.ChildTasks[t])};if (parentTask.ChildTasks[t].ChildTasks.length > 0){isError = this.setPredTaskInTree(parentTask.ChildTasks[t])}};return isError};GanttChart.prototype.checkPosParentTask = function(parentTask, task) +{var widthParent = this.getWidthOnDuration(parentTask.Duration);var posParent = this.getPosOnDate(parentTask.EST);var posChild = this.getPosOnDate(task.EST);var widthChild = this.getWidthOnDuration(task.Duration);return (widthParent + posParent) >= (posChild + widthChild)};GanttChart.prototype.insertProject = function(id, name, startDate) +{if (this._isError){this.clearData();this.clearItems();this.hidePanelErrors();this._isError = false};if (this.startDate >= startDate){this.Error.throwError("DATA_INSERT_ERROR", 14, null);return false};if (this.getProjectById(id)) {this.Error.throwError("DATA_INSERT_ERROR", 23, [id]);return false};this.checkHeighPanelTasks();var project = new GanttProjectInfo(id, name, startDate);this.Project.push(project);var _project = new GanttProject(this, project);for (var i = 0;i < this.arrProjects.length;i++){if (startDate < this.arrProjects[i].Project.StartDate){this.arrProjects.splice(i, 0, _project);if (i > 0){_project.previousProject = this.arrProjects[i - 1];this.arrProjects[i - 1].nextProject = _project};if (i + 1 <= this.arrProjects.length){_project.nextProject = this.arrProjects[i + 1];this.arrProjects[i + 1].previousProject = _project;_project.shiftNextProject(_project, 23)};_project.create();if (this.isShowDescProject){_project.hideDescrProject()};return _project}};if (this.arrProjects.length > 0){this.arrProjects[this.arrProjects.length - 1].nextProject = _project;_project.previousProject = this.arrProjects[this.arrProjects.length - 1]};this.arrProjects.push(_project);_project.create();if (this.isShowDescProject){_project.hideDescrProject()};return _project};GanttChart.prototype._showContextMenu = function(event, obj) +{if (this.contextMenu.isDhtmlxMenuObject){var res = this.callEvent("onBeforeContextMenu", [this.contextMenu, obj]);if (res === false)return;var x, y;if (_isIE){var dEl0 = window.document.documentElement, dEl1 = window.document.body, corrector = new Array((dEl0.scrollLeft||dEl1.scrollLeft),(dEl0.scrollTop||dEl1.scrollTop));x = event.clientX + corrector[0];y = event.clientY + corrector[1]}else {x = event.pageX;y = event.pageY};this.contextMenu.showContextMenu(x-1, y-1)}else {var elem = event.srcElement || event.target;this.contextMenu.showContextMenu(elem.style.left, elem.style.top, obj)}};GanttChart.prototype.openTree = function(parentTask) +{var lastParentTask = this.getLastCloseParent(parentTask);if (parentTask.TaskInfo.Id != lastParentTask.TaskInfo.Id){this.openNode(lastParentTask);this.openTree(parentTask)}else {this.openNode(lastParentTask)}};GanttChart.prototype.openNode = function(parentTask) +{if (!parentTask._isOpen){parentTask.cTaskNameItem[2].src = this.imgs + "minus.gif";parentTask._isOpen = true;parentTask.shiftCurrentTasks(parentTask, parentTask._heightHideTasks);parentTask.showChildTasks(parentTask, parentTask._isOpen);parentTask._heightHideTasks = 0}};GanttChart.prototype.getLastCloseParent = function(task) +{if (task.parentTask){if ((!task.parentTask._isOpen)|| + (task.parentTask.cTaskNameItem[2].style.display == "none")) {return this.getLastCloseParent(task.parentTask)}else {return task}}else {return task}};GanttTask.prototype.setPredecessor = function(predecessorTaskId) +{if (predecessorTaskId == "")this.clearPredTask();else + {var task = this.TaskInfo;if (task.Id == predecessorTaskId){this.Chart.Error.throwError("DATA_INSERT_ERROR", 36);return false};var predTaskObj = this.Project.getTaskById(predecessorTaskId);if (!predTaskObj){this.Chart.Error.throwError("DATA_INSERT_ERROR", 27, [predecessorTaskId]);return false};var predTask = predTaskObj.TaskInfo;var a1 = predTask.ParentTask == null, a2 = task.ParentTask == null;if (a1 && !a2 || !a1 && a2 || !a1 && !a2 && (predTask.ParentTask.Id != task.ParentTask.Id)) {this.Chart.Error.throwError("DATA_INSERT_ERROR", 32, [predTask.Id,task.Id]);return false};this.clearPredTask();if (!this.Chart.checkPosPredecessorTask(predTask, task)) {this.Chart.correctPosPredecessorTask(predTask, task, this)};task.PredecessorTaskId = predecessorTaskId;task.PredecessorTask = predTask;this.predTask = predTaskObj;predTaskObj.childPredTask.push(this);this.cTaskItem[1] = this.createConnectingLinesDS()};return true};GanttTask.prototype.clearPredTask = function() {if (this.predTask){var ch = this.predTask.childPredTask;for (var i = 0;i < ch.length;i++){if (ch[i] == this){ch.splice(i, 1);break}};for (var i = 0;i < this.cTaskItem[1].length;i++){this.cTaskItem[1][i].parentNode.removeChild(this.cTaskItem[1][i])};this.cTaskItem[1] = [];this.TaskInfo.PredecessorTaskId = null;this.TaskInfo.PredecessorTask = null;this.predTask = null}};GanttTask.prototype.setEST = function(est, shiftChild) +{this.moveChild = shiftChild;this.getMoveInfo();var pos = this.Chart.getPosOnDate(est);if ((parseInt(this.cTaskItem[0].firstChild.firstChild.width)+ pos > this.maxPosXMove) && (this.maxPosXMove != -1)) + {this.Chart.Error.throwError("DATA_INSERT_ERROR", 12, [this.TaskInfo.Id]);this.maxPosXMove = -1;this.minPosXMove = -1;return false};if (pos < this.minPosXMove){this.Chart.Error.throwError("DATA_INSERT_ERROR", 11, [this.TaskInfo.Id]);this.maxPosXMove = -1;this.minPosXMove = -1;return false};this.cTaskItem[0].style.left = pos;var width = pos - this.posX;this.moveCurrentTaskItem(width, shiftChild);this.Project.shiftProjectItem();if (this.Chart.isShowDescTask)this.descrTask.innerHTML = this.getDescStr();this.addDayInPanelTime();this.posX = 0;this.maxPosXMove = -1;this.minPosXMove = -1;return true};GanttTask.prototype.setDuration = function(duration) +{this.getResizeInfo();var width = this.Chart.getWidthOnDuration(duration);if ((width > this.maxWidthResize)&& (this.maxWidthResize != -1)) + {this.Chart.Error.throwError("DATA_INSERT_ERROR", 10, [this.TaskInfo.Id]);return false}else if (width < this.minWidthResize){this.Chart.Error.throwError("DATA_INSERT_ERROR", 9, [this.TaskInfo.Id]);return false}else {this.taskItemWidth = parseInt(this.cTaskItem[0].firstChild.firstChild.width);this.resizeTaskItem(width);this.endResizeItem();if (this.Chart.isShowDescTask)this.descrTask.innerHTML = this.getDescStr();return true}};GanttTask.prototype.setPercentCompleted = function(percentCompleted) +{percentCompleted = parseInt(percentCompleted);if (isNaN(percentCompleted)) + {this.Chart.Error.throwError("DATA_INSERT_ERROR", 6, null);return false};if (percentCompleted > 100){this.Chart.Error.throwError("DATA_INSERT_ERROR", 7, null);return false};if (percentCompleted < 0){this.Chart.Error.throwError("DATA_INSERT_ERROR", 8, null);return false};if ((percentCompleted != 0)&& (percentCompleted != 100)) + {if ((this.TaskInfo.PercentCompleted != 0)&& (this.TaskInfo.PercentCompleted != 100)) + {this.cTaskItem[0].childNodes[0].firstChild.rows[0].cells[0].width = percentCompleted + "%";this.cTaskItem[0].childNodes[0].firstChild.rows[0].cells[1].width = 100 - percentCompleted + "%"}else if ((this.TaskInfo.PercentCompleted == 0)|| (this.TaskInfo.PercentCompleted == 100)) + {this.cTaskItem[0].childNodes[0].firstChild.rows[0].cells[0].parentNode.removeChild(this.cTaskItem[0].childNodes[0].firstChild.rows[0].cells[0]);var cellTblTask = document.createElement("td");this.cTaskItem[0].childNodes[0].firstChild.rows[0].appendChild(cellTblTask);cellTblTask.height = this.Chart.heightTaskItem + "px";cellTblTask.width = percentCompleted + "%";var imgPrF = document.createElement("img");imgPrF.style.width = (percentCompleted * this.TaskInfo.Duration * this.Chart.hourInPixelsWork) / 100 + "px";imgPrF.style.height = this.Chart.heightTaskItem + "px";cellTblTask.appendChild(imgPrF);imgPrF.src = this.Chart.imgs + "progress_filled.png";cellTblTask = document.createElement("td");this.cTaskItem[0].childNodes[0].firstChild.rows[0].appendChild(cellTblTask);cellTblTask.height = this.Chart.heightTaskItem + "px";cellTblTask.width = (100 - percentCompleted) + "%";imgPrF = document.createElement("img");imgPrF.style.width = ((100 - percentCompleted) * this.TaskInfo.Duration * this.Chart.hourInPixelsWork) / 100 + "px";imgPrF.style.height = this.Chart.heightTaskItem + "px";cellTblTask.appendChild(imgPrF);imgPrF.src = this.Chart.imgs + "progress_bg.png"}}else if (percentCompleted == 0){if ((this.TaskInfo.PercentCompleted != 0)&& (this.TaskInfo.PercentCompleted != 100)) + {this.cTaskItem[0].childNodes[0].firstChild.rows[0].cells[0].parentNode.removeChild(this.cTaskItem[0].childNodes[0].firstChild.rows[0].cells[0]);this.cTaskItem[0].childNodes[0].firstChild.rows[0].cells[0].width = 100 + "%"}else + {this.cTaskItem[0].childNodes[0].firstChild.rows[0].cells[0].firstChild.src = this.Chart.imgs + "progress_bg.png"}}else if (percentCompleted == 100){if ((this.TaskInfo.PercentCompleted != 0)&& (this.TaskInfo.PercentCompleted != 100)) + {this.cTaskItem[0].childNodes[0].firstChild.rows[0].cells[1].parentNode.removeChild(this.cTaskItem[0].childNodes[0].firstChild.rows[0].cells[1]);this.cTaskItem[0].childNodes[0].firstChild.rows[0].cells[0].width = 100 + "%"}else + {this.cTaskItem[0].childNodes[0].firstChild.rows[0].cells[0].firstChild.src = this.Chart.imgs + "progress_filled.png"}};this.TaskInfo.PercentCompleted = percentCompleted;this.taskItemWidth = parseInt(this.cTaskItem[0].firstChild.firstChild.width);this.resizeTaskItem(this.taskItemWidth);this.endResizeItem();if (this.Chart.isShowDescTask)this.descrTask.innerHTML = this.getDescStr();return true};GanttTask.prototype.setName = function(name) +{if ((name != "")&& (name != null)) {this.TaskInfo.Name = name;if (this.Chart._showTreePanel){this.cTaskNameItem[0].innerHTML = name;this.cTaskNameItem[0].title = name;this.checkWidthTaskNameItem()};if (this.Chart.isShowDescTask)this.descrTask.innerHTML = this.getDescStr();this.addDayInPanelTime()}};GanttChart.prototype.getProjectInfoById = function(id) +{for (var i = 0;i < this.Project.length;i++){if (this.Project[i].Id == id){return this.Project[i]}};return null};GanttChart.prototype.loadData = function(content, isFile, isLocal) +{this.clearData();if ((isFile == null)|| (isFile == 'undefined')) + {isFile = false};if ((isLocal == null)|| (isLocal == 'undefined')) + {isLocal = false};this.loadXML(content, isFile, isLocal);this.Project.sort(this.sort_byStartDate);this.startDate = this.getStartDate();this.clearItems();for (var i = 0;i < this.Project.length;i++){for (var k = 0;k < this.Project[i].ParentTasks.length;k++){if ((this.Project[i].ParentTasks[k].EST != null)&& (this.Project[i].ParentTasks[k].EST != '')) {this.setESTChild(this.Project[i].ParentTasks[k])}else {this.Error.throwError("DATA_ERROR", 25, [this.Project[i].ParentTasks[k].Id]);return};if (this.setPredTask(this.Project[i])) return};for (var k = 0;k < this.Project[i].ParentTasks.length;k++){if (this.Project[i].ParentTasks[k].EST < this.Project[i].StartDate){this.Error.throwError("DATA_ERROR", 24, [this.Project[i].ParentTasks[k].Id,this.Project[i].Id]);return};if (this.checkPosParentTaskInTree(this.Project[i].ParentTasks[k])) return};this.sortTasksByEST(this.Project[i])};for (var i = 0;i < this.Project.length;i++){var project = new GanttProject(this, this.Project[i]);if (this.arrProjects.length > 0){var previousProject = this.arrProjects[this.arrProjects.length - 1];project.previousProject = previousProject;previousProject.nextProject = project};project.create();this.checkHeighPanelTasks();this.arrProjects.push(project);this.createTasks(project)}};GanttChart.prototype.clearAll = function() +{this._oDataHeight = 0;this.startDate = null;this._isError = false;this.hidePanelErrors();this.clearData();this.clearItems()};GanttChart.prototype.clearData = function() +{this._oDataHeight = 0;this.startDate = null;this._isError = false;this.hidePanelErrors();this.Project = [];this.arrProjects = []};GanttChart.prototype.clearItems = function() +{this.oData.removeChild(this.oData.firstChild);this.oData.appendChild(this.createPanelTasks());this.oData.firstChild.appendChild(this.divInfo);this.oData.firstChild.appendChild(this.panelErrors);if (this._showTreePanel){this.panelNames.removeChild(this.panelNames.firstChild);this.panelNames.appendChild(this.createPanelNamesTasks())};this.panelTime.removeChild(this.panelTime.firstChild);this.panelTime.appendChild(this.createPanelTime())};GanttChart.prototype.loadXML = function(content, isFile, isLocal) +{if (isFile && (content == null || content == "")) + {this.Error.throwError("DATA_SEND_ERROR", 4, null);return};this.xmlLoader = new dtmlXMLLoaderObject(null, this, false);try + {if (!isFile)try {this.xmlLoader.loadXMLString(content)}catch(e) {this.Error.throwError("DATA_LOAD_ERROR", 37, [content])}else + if (!isLocal){this.xmlLoader.loadXML(this.loadPath + "?path=" + content + "&rnd=" + (new Date() - 0), false)}else + {this.xmlLoader.loadXML(content + "?rnd=" + (new Date() - 0), false)};this.doLoadDetails(isLocal)}catch(e) + {this.Error.throwError("DATA_LOAD_ERROR", 5, [content])}};GanttChart.prototype.doLoadDetails = function(isLocal) +{switch (this.xmlLoader.xmlDoc.status) {case 0: + if (!isLocal){this.Error.throwError("DATA_LOAD_ERROR", 1, null);return};break;case 404: + if (!isLocal){this.Error.throwError("DATA_LOAD_ERROR", 5, [this.loadPath])}else + {this.Error.throwError("DATA_LOAD_ERROR", 5, [this.xmlLoader.filePath]) + };return;break;case 500: + this.Error.throwError("DATA_LOAD_ERROR", 2, null);return;break;default: + break};var name = null;var id = null;var est = null;var duration = null;var percentCompleted = null;var predecessorTaskId = null;var projectArr = this.xmlLoader.doXPath("//project");for (var j = 0;j < projectArr.length;j++){var startDateTemp = projectArr[j].getAttribute("startdate");var startDate = startDateTemp.split(",");var project = new GanttProjectInfo(projectArr[j].getAttribute("id"), projectArr[j].getAttribute("name"), new Date(startDate[0], (parseInt(startDate[1]) - 1), startDate[2]));var taskArr = this.xmlLoader.doXPath("./task", projectArr[j]);for (var i = 0;i < taskArr.length;i++){id = taskArr[i].getAttribute("id");name = (this.xmlLoader.doXPath("./name", taskArr[i])[0].firstChild == null) ? "" : this.xmlLoader.doXPath("./name", taskArr[i])[0].firstChild.nodeValue;var estTemp = (this.xmlLoader.doXPath("./est", taskArr[i])[0].firstChild == null) ? "" : this.xmlLoader.doXPath("./est", taskArr[i])[0].firstChild.nodeValue;est = estTemp.split(",");duration = (this.xmlLoader.doXPath("./duration", taskArr[i])[0].firstChild == null) ? "" : this.xmlLoader.doXPath("./duration", taskArr[i])[0].firstChild.nodeValue;percentCompleted = (this.xmlLoader.doXPath("./percentcompleted", taskArr[i])[0].firstChild == null) ? "" : this.xmlLoader.doXPath("./percentcompleted", taskArr[i])[0].firstChild.nodeValue;predecessorTaskId = (this.xmlLoader.doXPath("./predecessortasks", taskArr[i])[0].firstChild == null) ? "" : this.xmlLoader.doXPath("./predecessortasks", taskArr[i])[0].firstChild.nodeValue;var task = new GanttTaskInfo(id, name, new Date(est[0], (parseInt(est[1]) - 1), est[2]), duration, percentCompleted, predecessorTaskId);var childTasksNode = this.xmlLoader.doXPath("./childtasks", taskArr[i]);var childTasksArr = this.xmlLoader.doXPath("./task", childTasksNode[0]);if (childTasksArr.length != 0)this.readChildTasksXML(task, childTasksArr);project.addTask(task)};this.addProject(project)}};GanttChart.prototype.readChildTasksXML = function(parentTask, childTasksArrXML) +{var name = null;var id = null;var est = null;var duration = null;var percentCompleted = null;var predecessorTaskId = null;for (var i = 0;i < childTasksArrXML.length;i ++){id = childTasksArrXML[i].getAttribute("id");name = (this.xmlLoader.doXPath("./name", childTasksArrXML[i])[0].firstChild == null) ? "" : this.xmlLoader.doXPath("./name", childTasksArrXML[i])[0].firstChild.nodeValue;var estTemp = (this.xmlLoader.doXPath("./est", childTasksArrXML[i])[0].firstChild == null) ? "" : this.xmlLoader.doXPath("./est", childTasksArrXML[i])[0].firstChild.nodeValue;est = estTemp.split(",");duration = (this.xmlLoader.doXPath("./duration", childTasksArrXML[i])[0].firstChild == null) ? "" : this.xmlLoader.doXPath("./duration", childTasksArrXML[i])[0].firstChild.nodeValue;percentCompleted = (this.xmlLoader.doXPath("./percentcompleted", childTasksArrXML[i])[0].firstChild == null) ? "" : this.xmlLoader.doXPath("./percentcompleted", childTasksArrXML[i])[0].firstChild.nodeValue;predecessorTaskId = (this.xmlLoader.doXPath("./predecessortasks", childTasksArrXML[i])[0].firstChild == null) ? "" : this.xmlLoader.doXPath("./predecessortasks", childTasksArrXML[i])[0].firstChild.nodeValue;var task = new GanttTaskInfo(id, name, new Date(est[0], (parseInt(est[1]) - 1), est[2]), duration, percentCompleted, predecessorTaskId);task.ParentTask = parentTask;parentTask.addChildTask(task);var childTasksNode = this.xmlLoader.doXPath("./childtasks", childTasksArrXML[i]);var childTasksArr = this.xmlLoader.doXPath("./task", childTasksNode[0]);if (childTasksArr.length != 0){this.readChildTasksXML(task, childTasksArr)}}};GanttChart.prototype.getXML = function() +{var strXML = "";for (var i = 0;i < this.Project.length;i++){strXML += "";for (var j = 0;j < this.Project[i].ParentTasks.length;j++){strXML += "";strXML += "" + this.Project[i].ParentTasks[j].Name + "";strXML += "" + this.Project[i].ParentTasks[j].EST.getFullYear() + "," + (this.Project[i].ParentTasks[j].EST.getMonth() + 1) + "," + this.Project[i].ParentTasks[j].EST.getDate() + "";strXML += "" + this.Project[i].ParentTasks[j].Duration + "";strXML += "" + this.Project[i].ParentTasks[j].PercentCompleted + "";strXML += "" + this.Project[i].ParentTasks[j].PredecessorTaskId + "";strXML += "";strXML += this.createChildTasksXML(this.Project[i].ParentTasks[j].ChildTasks);strXML += "";strXML += ""};strXML += ""};strXML += "";return strXML};GanttChart.prototype.createChildTasksXML = function(childTasks) +{var strXML = "";for (var n = 0;n < childTasks.length;n++){strXML += "";strXML += "" + childTasks[n].Name + "";strXML += "" + childTasks[n].EST.getFullYear() + "," + (childTasks[n].EST.getMonth() + 1) + "," + childTasks[n].EST.getDate() + "";strXML += "" + childTasks[n].Duration + "";strXML += "" + childTasks[n].PercentCompleted + "";strXML += "" + childTasks[n].PredecessorTaskId + "";if (childTasks[n].ChildTasks){strXML += "";strXML += this.createChildTasksXML(childTasks[n].ChildTasks);strXML += ""};strXML += ""};return strXML};GanttChart.prototype.sort_byEST = function(a, b) +{if (a.EST < b.EST)return -1;if (a.EST > b.EST)return 1;return 0};GanttChart.prototype.sort_byStartDate = function(a, b) +{if (a["StartDate"] < b["StartDate"])return -1;if (a["StartDate"] > b["StartDate"])return 1;return 0};GanttChart.prototype.setESTChild = function(parentTask) +{for (var t = 0;t < parentTask.ChildTasks.length;t++){if ((parentTask.ChildTasks[t].EST == null )|| (parentTask.ChildTasks[t].EST == "")) + {parentTask.ChildTasks[t].EST = parentTask.EST};if (parentTask.ChildTasks[t].ChildTasks.length != 0)this.setESTChild(parentTask.ChildTasks[t])}};GanttChart.prototype.createPanelTasks = function() +{var divTasks = document.createElement("div");divTasks.className = "taskPanel";divTasks.style.cssText = "position:relative;";divTasks.style.height = this.contentHeight - 63 + "px";var w = this.startDate ? (this.startDate.getDay()-1) : ((new Date(0)).getDay()-1);if (w==-1)w=6;divTasks.style.background = "url(" + this.imgs + "bg_week.png) -"+(w*24)+"px 0px";this.panelTasks = divTasks;return divTasks};GanttChart.prototype.createPanelNamesTasks = function() +{var divListNames = document.createElement("div");divListNames.innerHTML = " ";divListNames.style.cssText = "position:relative;background:url(" + this.imgs + "bg.png)";divListNames.style.height = this.contentHeight - 63 + "px";divListNames.style.width = this.maxWidthPanelNames + "px";return divListNames};GanttChart.prototype.createPopUpInfo = function() +{var divTaskInfo = document.createElement("div");divTaskInfo.style.cssText = 'display: none;';var tblTaskInfo = document.createElement("table");tblTaskInfo.style.cssText = "position:absolute;top:0px;left:0px";tblTaskInfo.className = "poPupInfo";divTaskInfo.appendChild(tblTaskInfo);var rowTaskInfo = tblTaskInfo.insertRow(tblTaskInfo.rows.length);var cellTaskInfo = document.createElement("td");rowTaskInfo.appendChild(cellTaskInfo);this.divInfo = divTaskInfo;return divTaskInfo};GanttChart.prototype.createPopUpTimeInfo = function() +{var divTimeInfo = document.createElement("div");divTimeInfo.style.display = "none";var tblTimeInfo = document.createElement("table");tblTimeInfo.className = "poPupTime";divTimeInfo.appendChild(tblTimeInfo);var rowTimeInfo = tblTimeInfo.insertRow(tblTimeInfo.rows.length);var cellTimeInfo = document.createElement("td");cellTimeInfo.align = "center";rowTimeInfo.appendChild(cellTimeInfo);return divTimeInfo};GanttChart.prototype.createPanelTime = function() +{var panelTime = document.createElement("div");panelTime.style.position = "relative";var tblTime = document.createElement("table");panelTime.appendChild(tblTime);tblTime.cellPadding = "0px";tblTime.border = "0px";tblTime.cellSpacing = "0px";tblTime.bgColor = "#FFFFFF";tblTime.style.marginTop = "0px";var monthRow = tblTime.insertRow(tblTime.rows.length);var newRow = tblTime.insertRow(tblTime.rows.length);for (var i = 0;i < this.countDays;i++){this.addPointInTimePanel(newRow, panelTime);this.addDayInPanelTime(newRow)};return panelTime};GanttChart.prototype.addPointInTimePanel = function(row, panelTime) +{var leftLine = document.createElement("div");leftLine.style.cssText = "position:absolute;left:" + ( row.cells.length * this.dayInPixels ) + "px;top:20px;height:20px;width:1px;font-size:1px;margin-left:0px;margin-right:0px;margin-top:0px;margin-bottom:0px;background:#f1f3f1;";panelTime.appendChild(leftLine)};GanttChart.prototype._calculateMonthColSpan = function(date, maxLen) {var m1 = date.getMonth();for(var i=1;i<=maxLen;i++){date.setDate(date.getDate() + 1);var m2 = date.getMonth();if (m2 != m1)return i};return maxLen};GanttChart.prototype.getMonthScaleLabel = function(date) {return (this._useShortMonthNames ? this.shortMonthNames : this.monthNames)[date.getMonth()] + " '" + (""+date.getFullYear()).substring(2)};GanttChart.prototype.useShortMonthNames = function(flag) {this._useShortMonthNames = flag};GanttChart.prototype.setShortMonthNames = function(names) {this.shortMonthNames = names};GanttChart.prototype.setMonthNames = function(names) {this.monthNames = names};GanttChart.prototype.addDayInPanelTime = function(row) +{var self = this, idx = row.cells.length, date = new Date(this.startDate);var newCell = row.insertCell(idx);newCell.style.height = "20px";newCell.style.width = this.dayInPixels + "px";newCell.className = "dayNumber";date.setDate(date.getDate() + parseInt(idx));var day = date.getDate() + newCell.innerHTML = day;newCell.setAttribute("idx", idx);var monthRow = row.parentNode.parentNode.rows[0];if (idx==0 || day==1){var newCell2 = monthRow.insertCell(monthRow.cells.length);newCell2.className = "monthName";newCell2.style.height = "20px";if (monthRow.cells.length%2 == 0)newCell2.style.backgroundColor = "#f7f8f7";newCell2.colSpan = this._calculateMonthColSpan(new Date(date), Math.max(1,this.countDays-idx));newCell2.innerHTML = this.getMonthScaleLabel(date)}else {var n = monthRow.cells.length, cs=0;for(var i=0;i=cs)monthRow.cells[n-1].colSpan += 1};var w = date.getDay();if (w==0 || w==6)newCell.style.backgroundColor = "#f7f8f7"};GanttChart.prototype.incHeightPanelTasks = function(height) +{var containerTasks = this.oData.firstChild;containerTasks.style.height = parseInt(containerTasks.style.height) + height + "px"};GanttChart.prototype.incHeightPanelNames = function(height) +{var containerNames = this.panelNames.firstChild;containerNames.style.height = parseInt(containerNames.style.height) + height + "px"};GanttChart.prototype.checkHeighPanelTasks = function() +{this._oDataHeight += 11 + this.heightTaskItem;if ((parseInt(this.oData.firstChild.style.height)<= this._oDataHeight)) {this.incHeightPanelTasks(this.heightTaskItem + 11);if (this._showTreePanel)this.incHeightPanelNames(this.heightTaskItem + 11)}};GanttChart.prototype.sortTasksByEST = function(project) +{project.ParentTasks.sort(this.sort_byEST);for (var i = 0;i < project.ParentTasks.length;i++){project.ParentTasks[i] = this.sortChildTasks(project.ParentTasks[i])}};GanttChart.prototype.sortChildTasks = function(parenttask) +{parenttask.ChildTasks.sort(this.sort_byEST);for (var i = 0;i < parenttask.ChildTasks.length;i++){if (parenttask.ChildTasks[i].ChildTasks.length > 0)this.sortChildTasks(parenttask.ChildTasks[i])};return parenttask};GanttChart.prototype.errorDataHandler = function(type, descr, params) +{if (!this._isError){this.clearData();this.showPanelErrors();this._isError = true};this.addErrorInPanelErrors(type, descr)};GanttChart.prototype.createPanelErrors = function() +{var tbl = document.createElement("table");tbl.width = "100%";tbl.style.display = "none";tbl.className = "panelErrors";this.panelErrors = tbl;return tbl};GanttChart.prototype.showPanelErrors = function() +{this.panelErrors.style.display = "inline"};GanttChart.prototype.hidePanelErrors = function() +{for (var i = 0;i < this.panelErrors.rows.length;i++){this.panelErrors.rows[i].parentNode.removeChild(this.panelErrors.rows[i])};this.panelErrors.style.display = "none"};GanttChart.prototype.addErrorInPanelErrors = function(type, descr) +{var row = this.panelErrors.insertRow(this.panelErrors.rows.length);var cell = document.createElement("td");cell.style.height = "20px";cell.style.width = "100px";cell.innerHTML = type;row.appendChild(cell);cell = document.createElement("td");row.appendChild(cell);cell.innerHTML = descr};GanttChart.prototype.errorSendDataHandler = function(type, descr, params) +{alert(descr)};GanttChart.prototype.errorLoadDataHandler = function(type, descr, params) +{alert(descr)};GanttChart.prototype.errorAPIHandler = function(type, descr, params) +{alert(descr)};GanttChart.prototype.saveData = function(fileName) +{try {if (!this.dhtmlXMLSenderObject.isProcessed){this.dhtmlXMLSenderObject.sendData(fileName, this.savePath, this.getXML())}}catch(e) {this.Error.throwError("DATA_SEND_ERROR", e, null)}};GanttChart.prototype.create = function(divId) +{var self = this;var content = document.getElementById(divId);this.content = content;this.getBrowserType();if (this._isIE){document.body.attachEvent('onselectstart', function() {window.event.returnValue = false});document.body.attachEvent('onkeydown', function() {if (event.keyCode == 65 && event.ctrlKey)window.event.returnValue = false})}else {content.addEventListener('mousedown', function(e) {e.preventDefault()}, true);document.addEventListener('keydown', function(e) {if (e.keyCode == 65 && e.ctrlKey)e.preventDefault()}, true)};this.Error.catchError("DATA_ERROR", function(type, descr, params) {self.errorDataHandler(type, descr, params) + });this.Error.catchError("DATA_SEND_ERROR", function(type, descr, params) {self.errorSendDataHandler(type, descr, params) + });this.Error.catchError("DATA_INSERT_ERROR", function(type, descr, params) {self.errorAPIHandler(type, descr, params) + });this.Error.catchError("DATA_LOAD_ERROR", function(type, descr, params) {self.errorLoadDataHandler(type, descr, params) + });var tableControl = document.createElement("table");tableControl.cellPadding = "0";tableControl.cellSpacing = "0";tableControl.style.cssText = "width: 100%;position: relative;";var newRowTblControl = tableControl.insertRow(tableControl.rows.length);var newCellTblControl;this.contentHeight = content.offsetHeight;this.contentWidth = content.offsetWidth;content.appendChild(tableControl);this.countDays = this.getCountDays();this.Project.sort(this.sort_byStartDate);this.startDate = this.getStartDate();this.panelTime = document.createElement("div");this.panelTime.appendChild(this.createPanelTime());this.panelTime.style.cssText = "position:relative;overflow:hidden;height:40px;top:0px;left:1px";this.oData = document.createElement("div");this.oData.appendChild(this.createPanelTasks());this.oData.style.cssText = "position:relative;overflow:scroll;height:" + (this.contentHeight - 40) + "px;border-left:#f1f3f1 1px solid";this.oData.firstChild.appendChild(this.createPanelErrors());if (this._showTreePanel){this.panelNames = document.createElement("div");newCellTblControl = document.createElement("td");newCellTblControl.vAlign = "top";this.panelNames.appendChild(this.createPanelNamesTasks());this.panelNames.style.cssText = "position:relative;top:40px;overflow:hidden;border-left:#f1f3f1 1px solid;border-bottom:#f1f3f1 1px solid";newCellTblControl.appendChild(this.panelNames);newRowTblControl.appendChild(newCellTblControl)};newCellTblControl = document.createElement("td");var divCell = document.createElement("div");divCell.style.cssText = "position: relative;";divCell.appendChild(this.panelTime);divCell.appendChild(this.oData);newCellTblControl.appendChild(divCell);newRowTblControl.appendChild(newCellTblControl);if (this._showTreePanel){this.panelNames.style.height = (this.contentHeight - 56) + "px";this.panelNames.style.width = this.maxWidthPanelNames + "px";this.oData.style.width = (this.contentWidth - this.maxWidthPanelNames) + "px";this.panelTasks.style.width = this.dayInPixels * this.countDays + "px";this.panelTime.style.width = (this.contentWidth - this.maxWidthPanelNames - 0*18) + "px";this.panelTime.firstChild.style.width = this.dayInPixels * this.countDays + "px";if (this.isShowConMenu && this.contextMenu == null)this.contextMenu = new contextMenu(this)}else {this.oData.style.width = this.contentWidth + "px";this.panelTime.style.width = (this.contentWidth - 16) + "px"};if (this._isOpera){this.oData.onmousewheel = function() {return false}};this.oData.onscroll = function() {self.panelTime.scrollLeft = this.scrollLeft;if (self.panelNames){self.panelNames.scrollTop = this.scrollTop;if (self.isShowConMenu)self.contextMenu.hideContextMenu()}};this.divTimeInfo = this.createPopUpTimeInfo();divCell.appendChild(this.divTimeInfo);this.oData.firstChild.appendChild(this.createPopUpInfo());for (var i = 0;i < this.Project.length;i++){for (var k = 0;k < this.Project[i].ParentTasks.length;k++){if (this.isEmpty(this.Project[i].ParentTasks[k].EST)) {this.Project[i].ParentTasks[k].EST = this.Project[i].StartDate};this.setESTChild(this.Project[i].ParentTasks[k]);if (this.setPredTask(this.Project[i])) return};for (var k = 0;k < this.Project[i].ParentTasks.length;k++){if (this.Project[i].ParentTasks[k].EST < this.Project[i].StartDate){if (!this.correctError){this.Error.throwError("DATA_ERROR", 24, [this.Project[i].ParentTasks[k].Id,this.Project[i].Id]);return}else {this.Project[i].ParentTasks[k].EST = this.Project[i].StartDate}};if (this.checkPosParentTaskInTree(this.Project[i].ParentTasks[k])) return};this.sortTasksByEST(this.Project[i])};for (var i = 0;i < this.Project.length;i++){var project = new GanttProject(this, this.Project[i]);if (this.arrProjects.length > 0){var previousProject = this.arrProjects[this.arrProjects.length - 1];project.previousProject = previousProject;previousProject.nextProject = project};project.create();this.checkHeighPanelTasks();this.arrProjects.push(project);this.createTasks(project)};return this};GanttChart.prototype.isEmpty = function(value) +{return (value == null || value == '')};GanttChart.prototype.getPrintableHTML = function() +{var w = parseInt(this.oData.firstChild.style.width) - parseInt(this.oData.style.width);var h = parseInt(this.panelTasks.style.height) - parseInt(this.panelTasks.parentNode.style.height);this.oData.setAttribute("id","ganttPrint02");this.panelNames.setAttribute("id","ganttPrint03");var res = 'onload=function(){var w=' + w + ',h=' + h + + ',c1=document.getElementById("ganttPrint01"),c2=document.getElementById("ganttPrint02"),c3=document.getElementById("ganttPrint03");' + + 'c2.style.width=parseInt(c2.style.width)+w+"px";c2.previousSibling.style.width=c2.style.width;c1.style.width=parseInt(c1.style.width)+w+"px";c2.style.height=parseInt(c2.style.height)+h+"px";' + + 'c2.style.overflow="hidden";c3.style.height=c3.firstChild.style.height;c1.style.height=parseInt(c1.style.height)+h+"px"}' + + '

' + this.content.innerHTML + '
';this.oData.setAttribute("id",null);this.panelNames.setAttribute("id",null);return res};GanttChart.prototype.printToWindow = function(message) +{var o = window.open();o.document.write(this.getPrintableHTML());o.document.close();if (message!==null){o.alert(message ? message : "Use browser's menu \"File->Print preview\" to setup page layout." )}};GanttChart.prototype.getStartDate = function() +{for (var i = 0;i < this.Project.length;i++){if (this.startDate){if (this.Project[i].StartDate < this.startDate){this.startDate = new Date(this.Project[i].StartDate)}}else {this.startDate = new Date(this.Project[i].StartDate)}};this.initialPos = 24 * this.hourInPixels;if (this.startDate){return new Date(this.startDate.setHours(this.startDate.getHours() - 24))}else {return new Date()}};GanttChart.prototype.getCountDays = function() +{if (this._showTreePanel){return parseInt((this.contentWidth - this.maxWidthPanelNames) / (this.hourInPixels * 24))}else {return parseInt((this.contentWidth) / (this.hourInPixels * 24))}};GanttChart.prototype.createTasks = function(project) +{for (var j = 0;j < project.Project.ParentTasks.length;j++){if (j > 0){project.Project.ParentTasks[j - 1].nextParentTask = project.Project.ParentTasks[j];project.Project.ParentTasks[j].previousParentTask = project.Project.ParentTasks[j - 1]};var task = new GanttTask(project.Project.ParentTasks[j], project, this);project.arrTasks.push(task);task.create();this.checkHeighPanelTasks();if (project.Project.ParentTasks[j].ChildTasks.length > 0){this.createChildItemControls(project.Project.ParentTasks[j].ChildTasks, project)}}};GanttChart.prototype.createChildItemControls = function(arrChildTasks, project) +{for (var i = 0;i < arrChildTasks.length;i++){if (i > 0){arrChildTasks[i].previousChildTask = arrChildTasks[i - 1];arrChildTasks[i - 1].nextChildTask = arrChildTasks[i]};var task = new GanttTask(arrChildTasks[i], project, this);task.create();this.checkHeighPanelTasks();if (arrChildTasks[i].ChildTasks.length > 0){this.createChildItemControls(arrChildTasks[i].ChildTasks, project)}}};GanttTask.prototype.getPopUpInfo = function(object, event) +{var posY = object.offsetTop + this.Chart.heightTaskItem + 6;var posX = object.offsetLeft + ((event.layerX == null) ? event.offsetX : event.layerX);var tblInfo = this.Chart.divInfo.lastChild;tblInfo.rows[0].cells[0].innerHTML = "
" + this.TaskInfo.Name + "
";tblInfo.rows[0].cells[0].innerHTML += "EST: " + this.TaskInfo.EST.getDate() + "." + (this.TaskInfo.EST.getMonth() + 1) + "." + this.TaskInfo.EST.getFullYear() + "
";tblInfo.rows[0].cells[0].innerHTML += "Duration: " + this.TaskInfo.Duration + " hours
";tblInfo.rows[0].cells[0].innerHTML += "Percent Complete: " + this.TaskInfo.PercentCompleted + "%
";if (this.predTask){tblInfo.rows[0].cells[0].innerHTML += "Predecessor Task: ";tblInfo.rows[0].cells[0].innerHTML += "*" + this.TaskInfo.PredecessorTask.Name + ""};if (this.TaskInfo.ChildTasks.length != 0){tblInfo.rows[0].cells[0].innerHTML += "Child Tasks: ";for (var i = 0;i < this.TaskInfo.ChildTasks.length;i++){tblInfo.rows[0].cells[0].innerHTML += (i == this.TaskInfo.ChildTasks.length - 1) ? ("*" + this.TaskInfo.ChildTasks[i].Name + "") : ("*" + this.TaskInfo.ChildTasks[i].Name + "")}};if (this.TaskInfo.ParentTask){tblInfo.rows[0].cells[0].innerHTML += "Parent Task: ";tblInfo.rows[0].cells[0].innerHTML += "*" + this.TaskInfo.ParentTask.Name + ""};this.Chart.divInfo.style.cssText = "z-index:2;position: absolute;display: inline;";if (posY + this.Chart.divInfo.lastChild.offsetHeight + 10 > this.Chart.oData.offsetHeight + this.Chart.oData.scrollTop){this.Chart.divInfo.style.top = (posY - this.Chart.divInfo.lastChild.offsetHeight - 10 - this.Chart.heightTaskItem) + "px"}else {this.Chart.divInfo.style.top = posY + "px"};if (this.Chart.divInfo.lastChild.offsetWidth + posX + 10 > this.Chart.oData.offsetWidth + this.Chart.oData.scrollLeft){this.Chart.divInfo.style.left = posX - (this.Chart.divInfo.lastChild.offsetWidth + posX + 20 - (this.Chart.oData.offsetWidth + this.Chart.oData.scrollLeft)) + "px"}else {this.Chart.divInfo.style.left = posX + "px"}};GanttTask.prototype.closePopUpInfo = function() +{this.Chart.divInfo.style.display = "none"};GanttTask.prototype.createConnectingLinesPN = function() +{var arrConnectingLinesNames = [];return arrConnectingLinesNames};GanttTask.prototype.createConnectingLinesDS = function() +{var oData = this.Chart.oData.firstChild;var arrLines = [];var arrowImg = new Image();arrowImg.src = this.Chart.imgs + "arr.gif";var lineVerticalRight = document.createElement("div");var lineHorizontal = document.createElement("div");var posXPredecessorTask = parseInt(this.predTask.cTaskItem[0].style.left);var posYPredecessorTask = parseInt(this.predTask.cTaskItem[0].style.top);var posXChildTask = parseInt(this.cTaskItem[0].style.left);var posYChildTask = this.posY + 2;var widthChildTask = parseInt(this.predTask.cTaskItem[0].firstChild.firstChild.width);var widthPredecessorTask = parseInt(this.predTask.cTaskItem[0].firstChild.firstChild.width);if (posYPredecessorTask < posYChildTask){lineVerticalRight.style.cssText = "border-width: 0px 0px 0px 1px;border-style: solid;border-color: #4A8F43;margin: 0px;padding: 0px;z-index:0;font-size: 1px;position: absolute;" + + "height:" + (posYChildTask - this.Chart.heightTaskItem / 2 - posYPredecessorTask - 3) + "px;width:" + 1 + "px;left:" + (posXPredecessorTask + widthPredecessorTask - 20 ) + "px;top:" + (posYPredecessorTask + this.Chart.heightTaskItem) + "px;";lineHorizontal.style.cssText = "height:1px;border-color: #4A8F43;border-style: solid;border-width: 1px 0px 0px 0px;margin: 0px;padding: 0px;z-index:0;position: absolute;" + + "width:" + (15 + (posXChildTask - (widthPredecessorTask + posXPredecessorTask))) + "px;left:" + (posXPredecessorTask + widthPredecessorTask - 20 ) + "px;top:" + (posYChildTask + 2) + "px;";arrowImg.style.cssText = "margin: 0px;padding: 0px;width:7px;height:14px;position: absolute;left:" + (posXChildTask - 7) + "px;top:" + (posYChildTask - 1) + "px;"}else {lineVerticalRight.style.cssText = "border-width: 0px 0px 0px 1px;border-style: solid;border-color: #4A8F43;margin: 0px;padding: 0px;z-index:0;font-size: 1px;position: absolute;" + + "height:" + (posYPredecessorTask + 2 - posYChildTask) + "px;width:" + 1 + "px;left:" + (posXPredecessorTask + widthPredecessorTask - 20 ) + "px;top:" + (posYChildTask + 2) + "px;";lineHorizontal.style.cssText = "height:1px;border-color: #4A8F43;border-style: solid;border-width: 1px 0px 0px 0px;margin: 0px;padding: 0px;z-index:0;position: absolute;" + + "width:" + (15 + (posXChildTask - (widthPredecessorTask + posXPredecessorTask))) + "px;left:" + (posXPredecessorTask + widthPredecessorTask - 20 ) + "px;top:" + (posYChildTask + 2) + "px;";arrowImg.style.cssText = "margin: 0px;padding: 0px;width:7px;height:14px;position: absolute;left:" + (posXChildTask - 7) + "px;top:" + (posYChildTask - 1) + "px;"};oData.appendChild(lineVerticalRight);oData.appendChild(lineHorizontal);oData.appendChild(arrowImg);arrLines.push(lineVerticalRight);arrLines.push(arrowImg);arrLines.push(lineHorizontal);return arrLines};GanttTask.prototype.showChildTasks = function(task, isOpen) +{if (isOpen){for (var i = 0;i < task.childTask.length;i++){if (task.childTask[i].cTaskItem[0].style.display == "none"){task.childTask[i].cTaskItem[0].style.display = "inline";task.childTask[i].cTaskNameItem[0].style.display = "inline";if (this.Chart.isShowDescTask){task.childTask[i].showDescTask()};task.isHide = false;if (task.childTask[i].cTaskNameItem[2]){task.childTask[i].cTaskNameItem[2].style.display = "inline";isOpen = task.childTask[i]._isOpen};for (var k = 0;k < task.childTask[i].cTaskItem[1].length;k++){task.childTask[i].cTaskItem[1][k].style.display = "inline"};for (var k = 0;k < task.childTask[i].cTaskNameItem[1].length;k++){task.childTask[i].cTaskNameItem[1][k].style.display = "inline"};this._heightHideTasks += this.Chart.heightTaskItem + 11;if (task.childTask[i].childTask.length > 0){this.showChildTasks(task.childTask[i], isOpen)}}}}};GanttTask.prototype.hideChildTasks = function(task) +{for (var i = 0;i < task.childTask.length;i++){if (task.childTask[i].cTaskItem[0].style.display != "none"){task.childTask[i].cTaskItem[0].style.display = "none";task.childTask[i].cTaskNameItem[0].style.display = "none";if (this.Chart.isShowDescTask){task.childTask[i].hideDescTask()};task.isHide = true;if (task.childTask[i].cTaskNameItem[2]){task.childTask[i].cTaskNameItem[2].style.display = "none"};for (var k = 0;k < task.childTask[i].cTaskItem[1].length;k++){task.childTask[i].cTaskItem[1][k].style.display = "none"};for (var k = 0;k < task.childTask[i].cTaskNameItem[1].length;k++){task.childTask[i].cTaskNameItem[1][k].style.display = "none"};this._heightHideTasks += this.Chart.heightTaskItem + 11;if (task.childTask[i].childTask.length > 0){this.hideChildTasks(task.childTask[i])}}}};GanttTask.prototype.shiftCurrentTasks = function(task, height) +{this.shiftNextTask(this, height);task.Project.shiftNextProject(task.Project, height)};GanttProject.prototype.shiftNextProject = function(project, height) +{if (project.nextProject){project.nextProject.shiftProject(height);this.shiftNextProject(project.nextProject, height)}};GanttProject.prototype.shiftProject = function(height) +{this.projectItem[0].style.top = parseInt(this.projectItem[0].style.top) + height + "px";if (this.Chart.isShowDescProject){this.descrProject.style.top = parseInt(this.descrProject.style.top) + height + "px"};if (this.Chart._showTreePanel){this.projectNameItem.style.top = parseInt(this.projectNameItem.style.top) + height + "px"};if (this.arrTasks.length > 0)this.shiftNextParentTask(this.arrTasks[0], height)};GanttProject.prototype.shiftTask = function(task, height) +{if (this.Chart._showTreePanel){task.cTaskNameItem[0].style.top = parseInt(task.cTaskNameItem[0].style.top) + height + "px";if (task.cTaskNameItem[2]){task.cTaskNameItem[2].style.top = parseInt(task.cTaskNameItem[2].style.top) + height + "px"};if (task.parentTask && task.cTaskNameItem[1][0]){task.cTaskNameItem[1][0].style.top = parseInt(task.cTaskNameItem[1][0].style.top) + height + "px";task.cTaskNameItem[1][1].style.top = parseInt(task.cTaskNameItem[1][1].style.top) + height + "px"}};task.cTaskItem[0].style.top = parseInt(task.cTaskItem[0].style.top) + height + "px";if (this.Chart.isShowDescTask){task.descrTask.style.top = parseInt(task.descrTask.style.top) + height + "px"};if (task.cTaskItem[1][0]){task.cTaskItem[1][0].style.top = parseInt(task.cTaskItem[1][0].style.top) + height + "px";task.cTaskItem[1][1].style.top = parseInt(task.cTaskItem[1][1].style.top) + height + "px";task.cTaskItem[1][2].style.top = parseInt(task.cTaskItem[1][2].style.top) + height + "px"}};GanttProject.prototype.shiftNextParentTask = function(task, height) +{this.shiftTask(task, height);this.shiftChildTasks(task, height);if (task.nextParentTask){this.shiftNextParentTask(task.nextParentTask, height)}};GanttProject.prototype.shiftChildTasks = function(task, height) +{for (var i = 0;i < task.childTask.length;i++){this.shiftTask(task.childTask[i], height);if (task.childTask[i].childTask.length > 0){this.shiftChildTasks(task.childTask[i], height)}}};GanttTask.prototype.shiftTask = function(task, height) +{if (this.Chart._showTreePanel){task.cTaskNameItem[0].style.top = parseInt(task.cTaskNameItem[0].style.top) + height + "px";if (task.cTaskNameItem[2]){task.cTaskNameItem[2].style.top = parseInt(task.cTaskNameItem[2].style.top) + height + "px"};if (task.parentTask){if (task.cTaskNameItem[1].length > 0)if ((parseInt(this.cTaskNameItem[0].style.top)> parseInt(task.parentTask.cTaskNameItem[0].style.top)) + && (task.cTaskNameItem[1][0].style.display != "none")) {task.cTaskNameItem[1][0].style.height = parseInt(task.cTaskNameItem[1][0].style.height) + height + "px"}else {task.cTaskNameItem[1][0].style.top = parseInt(task.cTaskNameItem[1][0].style.top) + height + "px"};if (task.cTaskNameItem[1].length > 1)task.cTaskNameItem[1][1].style.top = parseInt(task.cTaskNameItem[1][1].style.top) + height + "px"}};task.cTaskItem[0].style.top = parseInt(task.cTaskItem[0].style.top) + height + "px";if (this.Chart.isShowDescTask){task.descrTask.style.top = parseInt(task.descrTask.style.top) + height + "px"};if (task.predTask){if (task.cTaskItem[1].length > 0)if (((parseInt(this.cTaskItem[0].style.top)> parseInt(task.predTask.cTaskItem[0].style.top)) || + (this.cTaskItem[0].id == task.predTask.TaskInfo.Id)) && + task.cTaskItem[1][0].style.display != "none") {task.cTaskItem[1][0].style.height = parseInt(task.cTaskItem[1][0].style.height) + height + "px"}else {task.cTaskItem[1][0].style.top = parseInt(task.cTaskItem[1][0].style.top) + height + "px"};if (task.cTaskItem[1].length > 2){task.cTaskItem[1][1].style.top = parseInt(task.cTaskItem[1][1].style.top) + height + "px";task.cTaskItem[1][2].style.top = parseInt(task.cTaskItem[1][2].style.top) + height + "px"}}};GanttTask.prototype.shiftNextTask = function(task, height) +{if (task.nextChildTask){this.shiftTask(task.nextChildTask, height);this.shiftChildTask(task.nextChildTask, height);this.shiftNextTask(task.nextChildTask, height)}else if (task.parentTask){this.shiftNextTask(task.parentTask, height)}else if (task.nextParentTask){this.shiftTask(task.nextParentTask, height);this.shiftChildTask(task.nextParentTask, height);this.shiftNextTask(task.nextParentTask, height)}};GanttTask.prototype.shiftChildTask = function(task, height) +{for (var i = 0;i < task.childTask.length;i++){this.shiftTask(task.childTask[i], height);if (task.childTask[i].childTask.length > 0){this.shiftChildTask(task.childTask[i], height)}}};GanttChart.prototype.getPosOnDate = function(est) +{return (est - this.startDate) / (60 * 60 * 1000) * this.hourInPixels};GanttChart.prototype.getWidthOnDuration = function(duration) +{return Math.round(this.hourInPixelsWork * duration)};GanttTask.prototype.endMove = function() +{var width = parseInt(this.cTaskItem[0].style.left) - this.posX;var est = this.getDateOnPosition(parseInt(this.cTaskItem[0].style.left));est = this.checkPos(est);this.wasMoved = this.TaskInfo.EST.valueOf() != est.valueOf();if (this.checkMove){width = this.Chart.getPosOnDate(est) - this.posX;this.moveCurrentTaskItem(width, this.moveChild);this.Project.shiftProjectItem()};this.checkMove = false;this.posX = 0;this.maxPosXMove = -1;this.minPosXMove = -1;this.cTaskItem[0].childNodes[1].firstChild.rows[0].cells[0].innerHTML = "";if (this.Chart._isFF)document.body.style.cursor = "";if (this.Chart._isIE)this.cTaskItem[0].childNodes[2].childNodes[0].style.cursor = ""};GanttTask.prototype.checkPos = function(est) +{var h = est.getHours();if (h >= 12){est.setDate(est.getDate() + 1);est.setHours(0);if ((parseInt(this.cTaskItem[0].firstChild.firstChild.width)+ this.Chart.getPosOnDate(est) > this.maxPosXMove) && (this.maxPosXMove != -1)) + {est.setDate(est.getDate() - 1);est.setHours(0)}}else if ((h < 12)&& (h != 0)) + {est.setHours(0);if ((this.Chart.getPosOnDate(est)< this.minPosXMove)) + {est.setDate(est.getDate() + 1)}};this.cTaskItem[0].style.left = this.Chart.getPosOnDate(est) + "px";return est};GanttTask.prototype.getMaxPosPredChildTaskItem = function() +{var posPredChildTaskItem = 0;var nextPosPredChildTaskItem = 0;for (var i = 0;i < this.childPredTask.length;i++){nextPosPredChildTaskItem = this.getMaxPosPredChildTaskItemInTree(this.childPredTask[i]);if (nextPosPredChildTaskItem > posPredChildTaskItem){posPredChildTaskItem = nextPosPredChildTaskItem}};return posPredChildTaskItem};GanttTask.prototype.getMaxPosPredChildTaskItemInTree = function(task) +{var currentPos = parseInt(task.cTaskItem[0].firstChild.firstChild.width) + parseInt(task.cTaskItem[0].style.left);var posPredChildTaskItem = 0;var nextPosPredChildTaskItem = 0;for (var i = 0;i < task.childPredTask.length;i++){nextPosPredChildTaskItem = this.getMaxPosPredChildTaskItemInTree(task.childPredTask[i]);if (nextPosPredChildTaskItem > posPredChildTaskItem){posPredChildTaskItem = nextPosPredChildTaskItem}};if (posPredChildTaskItem > currentPos){return posPredChildTaskItem}else + {return currentPos}};GanttProject.prototype.getTaskById = function(id) +{for (var i = 0;i < this.arrTasks.length;i++){var task = this.searchTaskInTree(this.arrTasks[i], id);if (task)return task};return null};GanttProject.prototype.searchTaskInTree = function(task, id) +{if (task.TaskInfo.Id == id){return task}else + {for (var i = 0;i < task.childTask.length;i++){if (task.childTask[i].TaskInfo.Id == id){return task.childTask[i]}else + {if (task.childTask[i].childTask.length > 0){var cTask = this.searchTaskInTree(task.childTask[i], id);if (cTask)return cTask}}}};return null};GanttProject.prototype.shiftProjectItem = function() +{var posItemL = null;var posItemR = null;var posProjectItemL = parseInt(this.projectItem[0].style.left);var posProjectItemR = parseInt(this.projectItem[0].firstChild.style.width) + parseInt(this.projectItem[0].style.left);var widthProjectItem = parseInt(this.projectItem[0].firstChild.style.width);for (var t = 0;t < this.arrTasks.length;t++){var tmpPosItemL = parseInt(this.arrTasks[t].cTaskItem[0].style.left);var tmpPosItemR = parseInt(this.arrTasks[t].cTaskItem[0].style.left) + parseInt(this.arrTasks[t].cTaskItem[0].firstChild.firstChild.width);if (!posItemL){posItemL = tmpPosItemL};if (!posItemR){posItemR = tmpPosItemR};if (posItemL > tmpPosItemL){posItemL = tmpPosItemL};if (posItemR < tmpPosItemR){posItemR = tmpPosItemR}};if (posItemL != posProjectItemL){this.Project.StartDate = new Date(this.Chart.startDate);this.Project.StartDate.setHours(this.Project.StartDate.getHours() + (posItemL / this.Chart.hourInPixels))};this.projectItem[0].style.left = posItemL + "px";this.resizeProjectItem(posItemR - posItemL);this.Duration = Math.round(parseInt(this.projectItem[0].firstChild.width) / (this.Chart.hourInPixelsWork));if (this.Chart.isShowDescProject){this.moveDescrProject()};this.addDayInPanelTime()};GanttProject.prototype.addDayInPanelTime = function() +{var width = parseInt(this.projectItem[0].style.left) + parseInt(this.projectItem[0].firstChild.style.width) + 20;if (this.Chart.isShowDescProject){width += this.descrProject.offsetWidth};var table = this.Chart.panelTime.firstChild, tbody = table.firstChild;if (parseInt(tbody.offsetWidth)< width) + {var countDays = Math.round((width - parseInt(tbody.offsetWidth)) / this.Chart.dayInPixels);var row = tbody.rows[1];for (var n = 0;n < countDays;n++){this.Chart.addPointInTimePanel(row, table);this.Chart.addDayInPanelTime(row)};var w = this.Chart.dayInPixels * (row.cells.length);tbody.style.width = w + "px";this.Chart.panelTasks.style.width = (w-18) + "px"}};GanttProject.prototype.addEvent = function (elm, evType, fn, useCapture) +{if (elm.addEventListener){elm.addEventListener(evType, fn, useCapture);return true}else if (elm.attachEvent){return elm.attachEvent('on' + evType, fn)}else {elm['on' + evType] = fn}};GanttProject.prototype.getPopUpInfo = function(object, event) +{var posX = object.offsetLeft + ((event.layerX == null) ? event.offsetX : event.layerX);var posY = object.offsetTop + this.Chart.heightTaskItem + 6;var tblInfo = this.Chart.divInfo.lastChild;tblInfo.rows[0].cells[0].innerHTML = "
" + this.Project.Name + "
";tblInfo.rows[0].cells[0].innerHTML += "Start Date: " + this.Project.StartDate.getDate() + "." + (this.Project.StartDate.getMonth() + 1) + "." + this.Project.StartDate.getFullYear() + "
";tblInfo.rows[0].cells[0].innerHTML += "Duration: " + this.Duration + " hours
";tblInfo.rows[0].cells[0].innerHTML += "Percent Complete: " + this.percentCompleted + "%
";this.Chart.divInfo.style.cssText = "z-index:2;position: absolute;display: inline;";if (posY + this.Chart.divInfo.lastChild.offsetHeight + 6 > this.Chart.oData.offsetHeight + this.Chart.oData.scrollTop){this.Chart.divInfo.style.top = (posY - this.Chart.divInfo.lastChild.offsetHeight - 10 - this.Chart.heightTaskItem) + "px"}else {this.Chart.divInfo.style.top = posY + "px"};if (this.Chart.divInfo.lastChild.offsetWidth + posX + 10 > this.Chart.oData.offsetWidth + this.Chart.oData.scrollLeft){this.Chart.divInfo.style.left = posX - (this.Chart.divInfo.lastChild.offsetWidth + posX + 20 - (this.Chart.oData.offsetWidth + this.Chart.oData.scrollLeft)) + "px"}else {this.Chart.divInfo.style.left = posX + "px"}};GanttProject.prototype.closePopUpInfo = function() +{this.Chart.divInfo.style.display = "none"};GanttProject.prototype.resizeProjectItem = function(width) +{var percentCompleted = this.percentCompleted;if (percentCompleted > 0 && percentCompleted < 100){this.projectItem[0].firstChild.style.width = width + "px";this.projectItem[0].firstChild.width = width + "px";this.projectItem[0].style.width = width + "px";this.projectItem[0].firstChild.rows[0].cells[0].firstChild.style.width = Math.round(width * percentCompleted / 100) + "px";this.projectItem[0].firstChild.rows[0].cells[1].firstChild.style.width = Math.round(width * (100 - percentCompleted) / 100) + "px";this.projectItem[0].lastChild.firstChild.width = width + "px"}else if (percentCompleted == 0 || percentCompleted == 100){this.projectItem[0].firstChild.style.width = width + "px";this.projectItem[0].firstChild.width = width + "px";this.projectItem[0].style.width = width + "px";this.projectItem[0].firstChild.rows[0].cells[0].firstChild.style.width = width + "px";this.projectItem[0].lastChild.firstChild.width = width + "px"}};GanttTask.prototype.moveCurrentTaskItem = function(width, moveChild) +{var taskItem = this.cTaskItem[0];this.TaskInfo.EST = new Date(this.Chart.startDate);this.TaskInfo.EST.setHours(this.TaskInfo.EST.getHours() + (parseInt(taskItem.style.left) / this.Chart.hourInPixels));if (this.Chart.isShowDescTask){this.showDescTask()};if (this.cTaskItem[1].length > 0){this.cTaskItem[1][2].style.width = parseInt(this.cTaskItem[1][2].style.width) + width + "px";this.cTaskItem[1][1].style.left = parseInt(this.cTaskItem[1][1].style.left) + width + "px"};for (var i = 0;i < this.childTask.length;i++){if (!this.childTask[i].predTask){this.moveChildTaskItems(this.childTask[i], width, moveChild)}};for (var i = 0;i < this.childPredTask.length;i++){this.moveChildTaskItems(this.childPredTask[i], width, moveChild)}};GanttTask.prototype.moveChildTaskItems = function(task, width, moveChild) +{var taskItem = task.cTaskItem[0];if (moveChild){taskItem.style.left = parseInt(taskItem.style.left) + width + "px";task.addDayInPanelTime();task.TaskInfo.EST = new Date(this.Chart.startDate);task.TaskInfo.EST.setHours(task.TaskInfo.EST.getHours() + (parseInt(taskItem.style.left) / this.Chart.hourInPixels));for (var n = 0;n < task.cTaskItem[1].length;n++){task.cTaskItem[1][n].style.left = parseInt(task.cTaskItem[1][n].style.left) + width + "px"};for (var i = 0;i < task.childTask.length;i++){if (!task.childTask[i].predTask){this.moveChildTaskItems(task.childTask[i], width, moveChild)}};for (var i = 0;i < task.childPredTask.length;i++){this.moveChildTaskItems(task.childPredTask[i], width, moveChild)}}else + {if (task.cTaskItem[1].length > 0){task.cTaskItem[1][2].style.left = parseInt(task.cTaskItem[1][2].style.left) + width + "px";task.cTaskItem[1][2].style.width = parseInt(task.cTaskItem[1][2].style.width) - width + "px";task.cTaskItem[1][0].style.left = parseInt(task.cTaskItem[1][0].style.left) + width + "px"}};if (this.Chart.isShowDescTask){task.moveDescTask()}};GanttTask.prototype.addDayInPanelTime = function() +{var taskItem = this.cTaskItem[0];var width = parseInt(taskItem.style.left) + parseInt(taskItem.firstChild.firstChild.width) + 20;if (this.Chart.isShowDescTask){width += this.descrTask.offsetWidth};var table = this.Chart.panelTime.firstChild, tbody = table.firstChild;if (parseInt(tbody.offsetWidth)< width) + {var row = tbody.rows[1];var countDays = Math.round((width + 20 - parseInt(tbody.offsetWidth)) / this.Chart.dayInPixels);for (var n = 0;n < countDays;n++){this.Chart.addPointInTimePanel(row, table);this.Chart.addDayInPanelTime(row)};var w = this.Chart.dayInPixels * (row.cells.length);tbody.style.width = w + "px";this.Chart.panelTasks.style.width = (w-18) + "px"}};GanttTask.prototype.getDateOnPosition = function(position) +{var date = new Date(this.Chart.startDate);date.setHours(date.getHours() + (position / this.Chart.hourInPixels));return date};GanttTask.prototype.moveItem = function(event) +{var pageX = event.screenX;var posTaskItem = (this.posX + (pageX - this.MouseX));var widthTaskItem = parseInt(this.cTaskItem[0].childNodes[0].firstChild.width);var posTaskItemR = posTaskItem + widthTaskItem;if (this.checkMove){var date = this.getDateOnPosition(posTaskItem);var res = this.Chart.callEvent("onTaskDragging", [this,date])!==false;if (res && ((this.minPosXMove <= posTaskItem)) + && ((posTaskItemR <= this.maxPosXMove) || (this.maxPosXMove == -1))) + {this.moveTaskItem(posTaskItem)}}};GanttTask.prototype.moveTaskItem = function(posX) +{this.addDayInPanelTime();this.cTaskItem[0].style.left = posX + "px";var date = this.getDateOnPosition(posX);this.cTaskItem[0].childNodes[1].firstChild.rows[0].cells[0].innerHTML = date.getDate() + '.' + (date.getMonth() + 1) + '.' + date.getUTCFullYear()};GanttTask.prototype.resizeItem = function(event) +{if (this.checkResize){var MouseX = event.screenX;var widthTaskItem = this.taskItemWidth + (MouseX - this.MouseX);var countHours = Math.round(widthTaskItem / this.Chart.hourInPixelsWork);if (this.Chart.callEvent("onTaskResizing", [this,countHours])===false) return;if (widthTaskItem >= this.taskItemWidth){if ((widthTaskItem <= this.maxWidthResize)|| (this.maxWidthResize == -1)) + {this.resizeTaskItem(widthTaskItem);this.addDayInPanelTime()}else if ((this.maxWidthResize != -1)&& (widthTaskItem > this.maxWidthResize)) + {this.resizeTaskItem(this.maxWidthResize)}}else if (widthTaskItem <= this.taskItemWidth){if (widthTaskItem >= this.minWidthResize){this.resizeTaskItem(widthTaskItem)}else if (widthTaskItem < this.minWidthResize){this.resizeTaskItem(this.minWidthResize)}}}};GanttTask.prototype.resizeTaskItem = function(width) +{var taskItem = this.cTaskItem[0];var countHours = Math.round(width / this.Chart.hourInPixelsWork);var c = taskItem.childNodes[0].firstChild.rows[0].cells[0];if (c){c.firstChild.style.width = parseInt(c.width) * width / 100 + "px"};c = taskItem.childNodes[0].firstChild.rows[0].cells[1];if (c){c.firstChild.style.width = parseInt(c.width) * width / 100 + "px"};taskItem.childNodes[0].firstChild.width = width + "px";taskItem.childNodes[1].firstChild.width = width + "px";this.cTaskItem[0].childNodes[1].firstChild.rows[0].cells[0].innerHTML = countHours;taskItem.childNodes[2].childNodes[0].style.width = width + "px";taskItem.childNodes[2].childNodes[1].style.left = width - 10 + "px"};GanttTask.prototype.endResizeItem = function() +{var taskItem = this.cTaskItem[0];this.wasResized = this.taskItemWidth != parseInt(taskItem.childNodes[0].firstChild.width);if (this.wasResized){var posXL = taskItem.offsetLeft;var posXR = taskItem.offsetLeft + parseInt(taskItem.childNodes[0].firstChild.width);this.TaskInfo.Duration = Math.round((posXR - posXL) / this.Chart.hourInPixelsWork);if (this.childPredTask.length > 0){for (var j = 0;j < this.childPredTask.length;j++){this.childPredTask[j].cTaskItem[1][2].style.width = parseInt(this.childPredTask[j].cTaskItem[1][2].style.width) - (parseInt(taskItem.childNodes[0].firstChild.width) - this.taskItemWidth) + "px";this.childPredTask[j].cTaskItem[1][2].style.left = parseInt(this.childPredTask[j].cTaskItem[1][2].style.left) + (parseInt(taskItem.childNodes[0].firstChild.width) - this.taskItemWidth) + "px";this.childPredTask[j].cTaskItem[1][0].style.left = parseInt(this.childPredTask[j].cTaskItem[1][0].style.left) + (parseInt(taskItem.childNodes[0].firstChild.width) - this.taskItemWidth) + "px"}}};this.cTaskItem[0].childNodes[1].firstChild.rows[0].cells[0].innerHTML = "";this.checkResize = false;this.taskItemWidth = 0;this.MouseX = 0;if (this.Chart.isShowDescTask){this.showDescTask()};this.Project.shiftProjectItem();if (this.Chart._isFF)document.body.style.cursor = ""};GanttProject.prototype.moveDescrProject = function() +{this.descrProject.style.left = (parseInt(this.projectItem[0].style.left) + this.Duration * this.Chart.hourInPixelsWork + 10);this.descrProject.innerHTML = this.getDescStr()};GanttProject.prototype.showDescrProject = function() +{var posX = (parseInt(this.projectItem[0].style.left) + this.Duration * this.Chart.hourInPixelsWork + 10);this.descrProject.style.left = posX + "px";this.descrProject.style.visibility = 'visible';this.descrProject.innerHTML = this.getDescStr()};GanttProject.prototype.hideDescrProject = function() +{this.descrProject.style.visibility = 'hidden'};GanttProject.prototype.getDescStr = function() +{var str = '', delim = ", ";for (var i = 0;i < this.Chart.paramShowProject.length;i++){switch (this.Chart.paramShowProject[i]) {case "Name": + if (str != "")str += delim;str += this.Project[this.Chart.paramShowProject[i]];break;case "StartDate": + if (str != "")str += delim;var d = this.Project[this.Chart.paramShowProject[i]];str += d.getDate() + "." + (d.getMonth() + 1) + "." + d.getFullYear();break;case "Duration": + if (str != "")str += delim;str += this[this.Chart.paramShowProject[i]] + "h";break;case "percentCompleted": + if (str != "")str += delim;str += this[this.Chart.paramShowProject[i]] + "%";break;default: + break}};return str};GanttProject.prototype.createDescrProject = function() +{var posX = (this.posX + this.Duration * this.Chart.hourInPixelsWork + 10);var divDesc = document.createElement("div");divDesc.style.cssText += ";z-index:1;position:absolute;left:" + posX + "px;top:" + this.posY + "px;";divDesc.innerHTML = this.getDescStr();divDesc.className = "descProject";this.descrProject = divDesc;if (this.Project.ParentTasks.length == 0){this.descrProject.style.visibility = 'hidden'};if (this.Chart._showTooltip){var self = this;var getPopUpInfo = function(e) {if ((!self.Chart._isMove)&& (!self.Chart._isResize)) self.getPopUpInfo(self.descrProject, e)};var closePopUpInfo = function() {self.closePopUpInfo()};this.addEvent(divDesc, 'mouseover', getPopUpInfo, false);this.addEvent(divDesc, 'mouseout', closePopUpInfo, false)};return divDesc};GanttProject.prototype.createProjectItem = function() +{var self = this;this.percentCompleted = this.getPercentCompleted();this.Duration = this.getDuration();var projectItem = document.createElement("div");projectItem.id = this.Project.Id;projectItem.style.cssText = ";z-index:1;position: absolute;left:" + this.posX + "px;top:" + this.posY + "px;";projectItem.style.width = this.Duration * this.Chart.hourInPixelsWork + "px";var tblProjectItem = document.createElement("table");projectItem.appendChild(tblProjectItem);tblProjectItem.cellPadding = "0";tblProjectItem.cellSpacing = "0";tblProjectItem.style.cssText = "border: solid 1px #BC810D;";var width = this.Duration * this.Chart.hourInPixelsWork;tblProjectItem.width = ((width == 0) ? 1 : width) + "px";tblProjectItem.style.width = ((width == 0) ? 1 : width) + "px";var rowprojectItem = tblProjectItem.insertRow(tblProjectItem.rows.length);if (this.percentCompleted != -1){if (this.percentCompleted != 0){var cellprojectItem = document.createElement("TD");rowprojectItem.appendChild(cellprojectItem);cellprojectItem.width = this.percentCompleted + "%";cellprojectItem.style.lineHeight = "1px";var imgPr = document.createElement("img");imgPr.style.width = (this.percentCompleted * this.Duration * this.Chart.hourInPixelsWork) / 100 + "px";imgPr.style.height = this.Chart.heightTaskItem + "px";cellprojectItem.appendChild(imgPr);imgPr.src = this.Chart.imgs + "parentnode_filled.png"};if (this.percentCompleted != 100){var cellprojectItem = document.createElement("TD");rowprojectItem.appendChild(cellprojectItem);cellprojectItem.width = (100 - this.percentCompleted) + "%";cellprojectItem.style.lineHeight = "1px";var imgPr = document.createElement("img");imgPr.style.width = ((100 - this.percentCompleted) * this.Duration * this.Chart.hourInPixelsWork) / 100 + "px";imgPr.style.height = this.Chart.heightTaskItem + "px";cellprojectItem.appendChild(imgPr);imgPr.src = this.Chart.imgs + "progress_bg.png"}}else + {var cellprojectItem = document.createElement("TD");rowprojectItem.appendChild(cellprojectItem);cellprojectItem.width = "1px";cellprojectItem.style.lineHeight = "1px";var imgPr = document.createElement("img");imgPr.style.width = "1px";imgPr.style.height = this.Chart.heightTaskItem;cellprojectItem.appendChild(imgPr);imgPr.src = this.Chart.imgs + "progress_bg.png"};var divTaskInfo = document.createElement("div");divTaskInfo.style.cssText = "text-align:center;z-index:2;position:absolute;left:0px;top:0px;";var tblTaskInfo = document.createElement("table");divTaskInfo.appendChild(tblTaskInfo);tblTaskInfo.cellPadding = "0";tblTaskInfo.cellSpacing = "0";tblTaskInfo.height = this.Chart.heightTaskItem + "px";tblTaskInfo.width = ((this.Duration * this.Chart.hourInPixelsWork == 0) ? 1 : this.Duration * this.Chart.hourInPixelsWork) + "px";var rowTaskInfo = tblTaskInfo.insertRow(0);var cellTaskInfo = document.createElement("td");cellTaskInfo.align = "center";cellTaskInfo.vAlign = "top";cellTaskInfo.height = this.Chart.heightTaskItem + "px";cellTaskInfo.className = "moveInfo";cellTaskInfo.style.cssText = ";white-space:nowrap;";rowTaskInfo.appendChild(cellTaskInfo);projectItem.appendChild(divTaskInfo);if (this.Project.ParentTasks.length == 0){projectItem.style.display = "none"};if (this.Chart._showTooltip){var getPopUpInfo = function(e) {if ((!self.Chart._isMove)&& (!self.Chart._isResize)) self.getPopUpInfo(self.projectItem[0], e)};var closePopUpInfo = function() {self.closePopUpInfo()};this.addEvent(divTaskInfo, 'mouseover', getPopUpInfo, false);this.addEvent(divTaskInfo, 'mouseout', closePopUpInfo, false)};return projectItem};GanttProject.prototype.createProjectNameItem = function() +{var self = this;var divName = document.createElement("div");divName.style.cssText = "cursor:pointer;color:#003366;font-weight:bold;font-size:12px;font-family:Tahoma,Arial;white-space:nowrap;height:15px;z-index:1;position:absolute;left:" + 5 + "px;top:" + this.posY + "px;";divName.innerHTML = this.Project.Name;divName.title = this.Project.Name;if (this.Chart.isShowConMenu){var showContMenu = function(event) {if (self.Chart.contextMenu.clear)self.Chart.contextMenu.clear();var hideContMenu = null;if (!self.Chart._isIE){hideContMenu = function() {self.Chart.contextMenu.hideContextMenu();self.Chart.content.removeEventListener("mousedown", hideContMenu, false)}}else + {hideContMenu = function() {self.Chart.contextMenu.hideContextMenu();self.Chart.content.detachEvent("mousedown", hideContMenu)}};self.Chart.content.onmousedown = hideContMenu;if (!self.Chart._isIE){event.stopPropagation()}else + {event.cancelBubble = true};self.Chart._showContextMenu(event, self)};if (this.Chart._isIE){this.addEvent(divName, "contextmenu", function(e) {showContMenu(e);return false}, false)}else + {this.addEvent(divName, "contextmenu", function(e) {e.preventDefault();showContMenu(e)}, false)}};return divName};GanttProject.prototype.getPercentCompleted = function() +{var sum = 0;var percentCompleted = 0;for (var i = 0;i < this.Project.ParentTasks.length;i++){sum += parseInt(this.Project.ParentTasks[i].PercentCompleted)};if (this.Project.ParentTasks.length != 0){return percentCompleted = Math.round(sum / this.Project.ParentTasks.length)}else {return percentCompleted = -1}};GanttProject.prototype.getDuration = function() +{var duration = 0;var tmpDuration = 0;if (this.Project.ParentTasks.length > 0){for (var i = 0;i < this.Project.ParentTasks.length;i++){tmpDuration = this.Project.ParentTasks[i].Duration * 24 / this.Chart.hoursInDay + (this.Project.ParentTasks[i].EST - this.Chart.startDate) / (60 * 60 * 1000);if (tmpDuration > duration){duration = tmpDuration}};return ((duration - this.posX) / 24) * this.Chart.hoursInDay}else + {return 0}};GanttProject.prototype.getId = function() +{return this.Project.Id};GanttProject.prototype.getName = function() +{return this.Project.Name};GanttProject.prototype.getStartDate = function() +{return this.Project.StartDate};GanttTask.prototype.addEvent = function (elm, evType, fn, useCapture) +{if (elm.addEventListener){elm.addEventListener(evType, fn, useCapture);return true}else if (elm.attachEvent){return elm.attachEvent('on' + evType, fn)}else {elm['on' + evType] = fn}};GanttTask.prototype.startMove = function (event) +{this.moveChild = event.ctrlKey;this.MouseX = event.screenX;this.getMoveInfo();this.checkMove = true;if (this.Chart.isShowDescTask){this.hideDescTask()};if (this.Chart._isFF)document.body.style.cursor = "move";if (this.Chart._isIE)event.srcElement.style.cursor = "move"};GanttTask.prototype.showDescTask = function() +{var posX = (parseInt(this.cTaskItem[0].style.left) + this.TaskInfo.Duration * this.Chart.hourInPixelsWork + 10);this.descrTask.style.left = posX + "px";this.descrTask.innerHTML = this.getDescStr();this.descrTask.style.visibility = 'visible'};GanttTask.prototype.hideDescTask = function() +{this.descrTask.style.visibility = 'hidden'};GanttTask.prototype.getDescStr = function() +{var str = '', delim = ", ";for (var i = 0;i < this.Chart.paramShowTask.length;i++){var prop = this.Chart.paramShowTask[i], propValue = this.TaskInfo[prop];switch (prop) {case "Name": + if (str != "")str += delim;str += propValue;break;case "EST": + if (str != "")str += delim;str += propValue.getDate() + "." + (propValue.getMonth() + 1) + "." + propValue.getFullYear();break;case "S-F": + if (str != "")str += delim;propValue = this.TaskInfo["EST"];str += propValue.getDate() + "." + (propValue.getMonth() + 1) + "." + propValue.getFullYear() + " - ";propValue = this.getFinishDate();str += propValue.getDate() + "." + (propValue.getMonth() + 1) + "." + propValue.getFullYear();break;case "Duration": + if (str != "")str += delim;str += propValue + "h";break;case "PercentCompleted": + if (str != "")str += delim;str += propValue + "%";break;default: + break}};return str};GanttTask.prototype.getId = function() +{return this.TaskInfo.Id};GanttTask.prototype.getName = function() +{return this.TaskInfo.Name};GanttTask.prototype.getDuration = function() +{return this.TaskInfo.Duration};GanttTask.prototype.getEST = function() +{return this.TaskInfo.EST};GanttTask.prototype.getFinishDate = function() +{var date = new Date(this.TaskInfo.EST);date.setDate(date.getDate() + parseInt((this.TaskInfo["Duration"]-1)/this.Chart.hoursInDay+1)-1);return date};GanttTask.prototype.getPercentCompleted = function() +{return this.TaskInfo.PercentCompleted};GanttTask.prototype.getPredecessorTaskId = function() +{return this.TaskInfo.PredecessorTaskId ? this.TaskInfo.PredecessorTaskId : null};GanttTask.prototype.getParentTaskId = function() +{return this.parentTask ? this.parentTask.getId() : null};GanttTask.prototype.moveDescTask = function() +{var posX = (parseInt(this.cTaskItem[0].style.left) + this.TaskInfo.Duration * this.Chart.hourInPixelsWork + 10);this.descrTask.style.left = posX + "px"};GanttTask.prototype.getMoveInfo = function() +{this.posX = parseInt(this.cTaskItem[0].style.left);var widthTaskItem = parseInt(this.cTaskItem[0].childNodes[0].firstChild.width);var posParentTaskItem = (this.parentTask == null) ? 0 : parseInt(this.parentTask.cTaskItem[0].style.left);var posPredTaskItem = (this.predTask == null) ? 0 : parseInt(this.predTask.cTaskItem[0].style.left) + parseInt(this.predTask.cTaskItem[0].childNodes[0].firstChild.width);var widthParentTaskItem = (this.parentTask == null) ? 0 : parseInt(this.parentTask.cTaskItem[0].childNodes[0].firstChild.width);var childPredPosX = 0;var childParentPosX = 0;var childParentPosXR = 0;if (this.childPredTask.length > 0){var posChildTaskItem = null;for (var n = 0;n < this.childPredTask.length;n++){if ((!posChildTaskItem)|| ((posChildTaskItem) && (posChildTaskItem > parseInt(this.childPredTask[n].cTaskItem[0].style.left)))) + {posChildTaskItem = parseInt(this.childPredTask[n].cTaskItem[0].style.left)}};childPredPosX = posChildTaskItem};if (this.childTask.length > 0){var posChildTaskItemR = null;for (var n = 0;n < this.childTask.length;n++){if ((!posChildTaskItemR)|| ((posChildTaskItemR) && (posChildTaskItemR > (parseInt(this.childTask[n].cTaskItem[0].style.left))))) + {posChildTaskItemR = parseInt(this.childTask[n].cTaskItem[0].style.left)}};childParentPosXR = posChildTaskItemR;var posChildTaskItem = null;for (var n = 0;n < this.childTask.length;n++){if ((!posChildTaskItem)|| ((posChildTaskItem) && (posChildTaskItem < (parseInt(this.childTask[n].cTaskItem[0].style.left) + parseInt(this.childTask[n].cTaskItem[0].firstChild.firstChild.width))))) + {posChildTaskItem = parseInt(this.childTask[n].cTaskItem[0].style.left) + parseInt(this.childTask[n].cTaskItem[0].firstChild.firstChild.width)}};childParentPosX = posChildTaskItem};if (!this.moveChild){if (this.childPredTask.length > 0){if (this.maxPosXMove < childPredPosX)this.maxPosXMove = childPredPosX};if (this.childTask.length > 0){if ((this.childPredTask.length > 0)&& (this.maxPosXMove - widthTaskItem) > childParentPosXR) this.maxPosXMove = this.maxPosXMove - ((this.maxPosXMove - widthTaskItem) - childParentPosXR);if (!(this.childPredTask.length > 0)) this.maxPosXMove = childParentPosXR + widthTaskItem;this.minPosXMove = (childParentPosX - widthTaskItem)};if (posParentTaskItem > 0){if ((!(this.childPredTask.length > 0)) && (this.childTask.length > 0)) {if (this.maxPosXMove > posParentTaskItem + widthParentTaskItem){this.maxPosXMove = posParentTaskItem + widthParentTaskItem}};if (this.minPosXMove <= posParentTaskItem){this.minPosXMove = posParentTaskItem};if ((!(this.childTask.length > 0)) && (!(this.childPredTask.length > 0))) {this.maxPosXMove = posParentTaskItem + widthParentTaskItem}else if ((!(this.childTask.length > 0)) && (this.childPredTask.length > 0)) {if ((posParentTaskItem + widthParentTaskItem)> posPredTaskItem) {this.maxPosXMove = childPredPosX}}};if (posPredTaskItem > 0){if (this.minPosXMove <= posPredTaskItem){this.minPosXMove = posPredTaskItem}};if ((posPredTaskItem == 0)&& (posParentTaskItem == 0)) {if (this.minPosXMove <= this.Chart.initialPos){this.minPosXMove = this.Chart.initialPos}}}else + {if ((posParentTaskItem > 0)&& (posPredTaskItem == 0)) + {this.minPosXMove = posParentTaskItem;this.maxPosXMove = posParentTaskItem + widthParentTaskItem}else if ((posParentTaskItem == 0)&& (posPredTaskItem == 0)) + {this.minPosXMove = this.Chart.initialPos;this.maxPosXMove = -1}else if ((posParentTaskItem > 0)&& (posPredTaskItem > 0)) + {this.minPosXMove = posPredTaskItem;this.maxPosXMove = posParentTaskItem + widthParentTaskItem}else if ((posParentTaskItem == 0)&& (posPredTaskItem > 0)) + {this.minPosXMove = posPredTaskItem;this.maxPosXMove = -1};if ((this.parentTask)&& (this.childPredTask.length > 0)) + {var posChildTaskItem = this.getMaxPosPredChildTaskItem(this);var posParentTaskItem = parseInt(this.parentTask.cTaskItem[0].style.left) + parseInt(this.parentTask.cTaskItem[0].firstChild.firstChild.width);this.maxPosXMove = this.posX + widthTaskItem + posParentTaskItem - posChildTaskItem}}};GanttTask.prototype.startResize = function(event) +{this.MouseX = event.screenX;this.getResizeInfo();if (this.Chart.isShowDescTask){this.hideDescTask()};this.checkResize = true;this.taskItemWidth = parseInt(this.cTaskItem[0].firstChild.firstChild.width);if (this.Chart._isFF)document.body.style.cursor = "e-resize"};GanttTask.prototype.getResizeInfo = function() +{var taskItem = this.cTaskItem[0];var posParentTaskItem = (this.parentTask == null) ? 0 : parseInt(this.parentTask.cTaskItem[0].style.left);var widthParentTaskItem = (this.parentTask == null) ? 0 : parseInt(this.parentTask.cTaskItem[0].childNodes[0].firstChild.width);var posTaskItem = parseInt(this.cTaskItem[0].style.left);var childPredPosX = 0;var childParentPosX = 0;if (this.childPredTask.length > 0){var posChildTaskItem = null;for (var n = 0;n < this.childPredTask.length;n++){if ((!posChildTaskItem)|| ((posChildTaskItem) && (posChildTaskItem > parseInt(this.childPredTask[n].cTaskItem[0].style.left)))) + {posChildTaskItem = parseInt(this.childPredTask[n].cTaskItem[0].style.left)}};childPredPosX = posChildTaskItem};if (this.childTask.length > 0){var posChildTaskItem = null;for (var n = 0;n < this.childTask.length;n++){if ((!posChildTaskItem)|| ((posChildTaskItem) && (posChildTaskItem < (parseInt(this.childTask[n].cTaskItem[0].style.left) + parseInt(this.childTask[n].cTaskItem[0].firstChild.firstChild.width))))) + {posChildTaskItem = parseInt(this.childTask[n].cTaskItem[0].style.left) + parseInt(this.childTask[n].cTaskItem[0].firstChild.firstChild.width)}};childParentPosX = posChildTaskItem};this.minWidthResize = this.Chart.dayInPixels;if (this.childTask.length > 0){this.minWidthResize = childParentPosX - posTaskItem};if ((this.childPredTask.length > 0)&& (!this.parentTask)) + {this.maxWidthResize = childPredPosX - posTaskItem}else if ((this.childPredTask.length > 0)&& (this.parentTask)) + {var w1 = posParentTaskItem + widthParentTaskItem - posTaskItem;var w2 = childPredPosX - posTaskItem;this.maxWidthResize = Math.min(w1, w2)}else if ((this.childPredTask.length == 0)&& (this.parentTask)) + {this.maxWidthResize = posParentTaskItem + widthParentTaskItem - posTaskItem}};GanttTask.prototype.createTaskItem = function() +{var self = this;this.posX = this.Chart.getPosOnDate(this.TaskInfo.EST);var itemControl = document.createElement("div");itemControl.id = this.TaskInfo.Id;itemControl.style.cssText = ";z-index:1;position:absolute;left:" + this.posX + "px;top:" + this.posY + "px;";var divTaskItem = document.createElement("div");itemControl.appendChild(divTaskItem);divTaskItem.style.cssText = "z-index:1;position: absolute;left:0px;top:0px;";var tblTaskItem = document.createElement("table");divTaskItem.appendChild(tblTaskItem);tblTaskItem.cellPadding = "0";tblTaskItem.cellSpacing = "0";tblTaskItem.width = this.TaskInfo.Duration * this.Chart.hourInPixelsWork + "px";tblTaskItem.style.cssText = "border: solid 1px #6589A9;";var rowTblTask = tblTaskItem.insertRow(tblTaskItem.rows.length);if (this.TaskInfo.PercentCompleted != 0){var cellTblTask = document.createElement("td");rowTblTask.appendChild(cellTblTask);cellTblTask.height = this.Chart.heightTaskItem + "px";cellTblTask.width = this.TaskInfo.PercentCompleted + "%";cellTblTask.style.lineHeight = "1px";var imgPr = document.createElement("img");imgPr.style.width = (this.TaskInfo.PercentCompleted * this.TaskInfo.Duration * this.Chart.hourInPixelsWork) / 100 + "px";imgPr.style.height = this.Chart.heightTaskItem + "px";cellTblTask.appendChild(imgPr);imgPr.src = this.Chart.imgs + "progress_filled.png"};if (this.TaskInfo.PercentCompleted != 100){var cellTblTask = document.createElement("td");rowTblTask.appendChild(cellTblTask);cellTblTask.height = this.Chart.heightTaskItem + "px";cellTblTask.width = (100 - this.TaskInfo.PercentCompleted) + "%";cellTblTask.style.lineHeight = "1px";var imgPrF = document.createElement("img");imgPrF.style.width = ((100 - this.TaskInfo.PercentCompleted) * this.TaskInfo.Duration * this.Chart.hourInPixelsWork) / 100 + "px";imgPrF.style.height = this.Chart.heightTaskItem + "px";cellTblTask.appendChild(imgPrF);imgPrF.src = this.Chart.imgs + "progress_bg.png"};if (this.Chart.isEditable){var divTaskInfo = document.createElement("div");divTaskInfo.style.cssText = "text-align:center;font-size:9px;z-index:2;position: absolute;left:0px;top:0px;";var tblTaskInfo = document.createElement("table");divTaskInfo.appendChild(tblTaskInfo);tblTaskInfo.cellPadding = "0";tblTaskInfo.cellSpacing = "0";tblTaskInfo.height = this.Chart.heightTaskItem + "px";tblTaskInfo.width = this.TaskInfo.Duration * this.Chart.hourInPixelsWork + "px";var rowTaskInfo = tblTaskInfo.insertRow(0);var cellTaskInfo = document.createElement("TD");cellTaskInfo.align = "center";cellTaskInfo.vAlign = "top";cellTaskInfo.height = this.Chart.heightTaskItem + "px";cellTaskInfo.className = "moveInfo";cellTaskInfo.style.cssText = ";white-space:nowrap;font-size:9px";rowTaskInfo.appendChild(cellTaskInfo);itemControl.appendChild(divTaskInfo)};var divTaskName = document.createElement("div");itemControl.appendChild(divTaskName);divTaskName.style.cssText = ";z-index:2;position: absolute;left:0px;top:0px;";var divMove = document.createElement("div");divMove.innerHTML = "";if (this.Chart._isIE){divMove.style.background = "#000000";divMove.style.filter = "alpha(opacity=0)"};divMove.style.height = this.Chart.heightTaskItem + "px";divMove.style.width = this.TaskInfo.Duration * this.Chart.hourInPixelsWork + "px";divTaskName.appendChild(divMove);if (this.Chart._showTooltip){var getPopUpInfo = function(e) {if ((!self.Chart._isMove)&& (!self.Chart._isResize)) self.getPopUpInfo(self.cTaskItem[0], e)};var closePopUpInfo = function() {self.closePopUpInfo()};this.addEvent(divMove, 'mouseover', getPopUpInfo, false);this.addEvent(divMove, 'mouseout', closePopUpInfo, false)};var taskClick = function() {self.Chart.callEvent("onTaskClick", [self])};this.addEvent(divMove, 'click', taskClick, false);if (this.Chart.isEditable){var divResize = document.createElement("div");divResize.style.cssText = ";z-index:10;position: absolute;left:" + (this.TaskInfo.Duration * this.Chart.hourInPixelsWork - 10) + "px;top:0px;";divResize.style.height = this.Chart.heightTaskItem + "px";divResize.style.width = "10px";divResize.innerHTML = "";divTaskName.appendChild(divResize);var startMove = function(e) {if (self.Chart.callEvent("onTaskStartDrag", [self])===false) return;var moveItem = function(e1) {if (self.checkMove)self.moveItem(e1)};var endMove = function() {if (self.checkMove){self.endMove();self.Chart._isMove = false;if (self.Chart._isIE){document.body.releaseCapture();document.detachEvent("onmousemove", moveItem);document.detachEvent("onmouseup", endMove)}else {document.removeEventListener("mousemove", moveItem, true);document.removeEventListener("mouseup", endMove, true)};if (self.wasMoved)self.Chart.callEvent("onTaskEndDrag", [self])}};self.addEvent(document, 'mousemove', moveItem, true);self.addEvent(document, 'mouseup', endMove, true);if (self.Chart._showTooltip)self.closePopUpInfo();self.startMove(e);self.Chart._isMove = true;if (self.Chart._isIE)document.body.setCapture(false)};var startResize = function(e) {if (self.Chart.callEvent("onTaskStartResize", [self])===false) return;var resizeItem = function(e1) {if (self.checkResize)self.resizeItem(e1)};var endResizeItem = function() {if (self.checkResize){self.endResizeItem();self.Chart._isResize = false;if (self.Chart._isIE){document.body.releaseCapture();document.detachEvent("onmousemove", resizeItem);document.detachEvent("onmouseup", endResizeItem)}else {document.removeEventListener("mousemove", resizeItem, true);document.removeEventListener("mouseup", endResizeItem, true)};if (self.wasResized)self.Chart.callEvent("onTaskEndResize", [self])}};self.addEvent(document, 'mousemove', resizeItem, false);self.addEvent(document, 'mouseup', endResizeItem, false);self.startResize(e);if (self.Chart._isIE)document.body.setCapture(false);self.Chart._isResize = true};this.addEvent(divMove, 'mousedown', startMove, false);this.addEvent(divResize, 'mousedown', startResize, false);var setCursorResize = function(e2) {if (!self.Chart._isMove)(e2.srcElement?e2.srcElement:e2.target).style.cursor = "e-resize"};var setCursorStandart = function(e3) {if (!self.checkResize)(e3.srcElement?e3.srcElement:e3.target).style.cursor = ""};this.addEvent(divResize, 'mouseover', setCursorResize, false);this.addEvent(divResize, 'mouseout', setCursorStandart, false)};return itemControl};GanttTask.prototype.createTaskNameItem = function(hasChildren) +{var self = this;var divName = document.createElement("div");divName.id = this.TaskInfo.Id;divName.style.cssText = "cursor:pointer;white-space:nowrap;height:15px;z-index:1;position:absolute;left:20px;top: " + this.posY + "px;";if (hasChildren)divName.style.fontWeight = "bold";divName.className = "taskNameItem";divName.title = this.TaskInfo.Name;divName.innerHTML = this.TaskInfo.Name;if (this.Chart.isShowConMenu){var showContMenu = function(event) {if (self.Chart.contextMenu.clear)self.Chart.contextMenu.clear();var hideContMenu = function() {self.Chart.contextMenu.hideContextMenu();if (self.Chart._isIE)self.Chart.content.detachEvent("mousedown", hideContMenu);else + self.Chart.content.removeEventListener("mousedown", hideContMenu, false)};self.Chart.content.onmousedown = hideContMenu;if (!self.Chart._isIE){event.stopPropagation()}else + {event.cancelBubble = true};self.Chart._showContextMenu(event, self)};if (this.Chart._isIE){this.addEvent(divName, "contextmenu", function(e) {showContMenu(e);return false}, false)}else + {this.addEvent(divName, "contextmenu", function(e) {e.preventDefault();showContMenu(e)}, false)}};return divName};GanttTask.prototype.createTaskDescItem = function() +{var posX = (this.posX + this.TaskInfo.Duration * this.Chart.hourInPixelsWork + 10);var divDesc = document.createElement("div");divDesc.style.cssText += ";z-index:1;position:absolute;left:" + posX + "px;top:" + this.posY + "px;";divDesc.innerHTML = this.getDescStr();divDesc.className = "descTask";this.descrTask = divDesc;if (this.Chart._showTooltip){var self = this;var getPopUpInfo = function(e) {if ((!self.Chart._isMove)&& (!self.Chart._isResize)) self.getPopUpInfo(self.descrTask, e)};var closePopUpInfo = function() {self.closePopUpInfo()};this.addEvent(divDesc, 'mouseover', getPopUpInfo, false);this.addEvent(divDesc, 'mouseout', closePopUpInfo, false)};return divDesc};GanttTask.prototype.checkWidthTaskNameItem = function() +{if (this.cTaskNameItem[0].offsetWidth + this.cTaskNameItem[0].offsetLeft > this.Chart.maxWidthPanelNames){var width = this.cTaskNameItem[0].offsetWidth + this.cTaskNameItem[0].offsetLeft - this.Chart.maxWidthPanelNames;var countChar = Math.round(width / (this.cTaskNameItem[0].offsetWidth / this.cTaskNameItem[0].firstChild.length));var tName = this.TaskInfo.Name.substring(0, this.cTaskNameItem[0].firstChild.length - countChar - 3);tName += "...";this.cTaskNameItem[0].innerHTML = tName}};GanttTask.prototype.create = function() +{var containerTasks = this.Chart.oData.firstChild;var containerNames = null;if (this.Chart._showTreePanel)containerNames = this.Chart.panelNames.firstChild;var predecessorTask = this.TaskInfo.PredecessorTask;var parentTask = this.TaskInfo.ParentTask;var isCParentTask = (this.TaskInfo.ChildTasks.length > 0);var self = this;this.cTaskItem = [];this.cTaskNameItem = [];if (!parentTask){if (this.TaskInfo.previousParentTask){this.previousParentTask = this.Project.getTaskById(this.TaskInfo.previousParentTask.Id);var lastChildTask = this.Chart.getLastChildTask(this.previousParentTask);this.posY = parseInt(lastChildTask.cTaskItem[0].style.top) + this.Chart.heightTaskItem + 11;this.previousParentTask.nextParentTask = this}else {this.posY = parseInt(this.Project.projectItem[0].style.top) + this.Chart.heightTaskItem + 11}};if (parentTask){var task = this.Project.getTaskById(this.TaskInfo.ParentTask.Id);this.parentTask = task;if (this.TaskInfo.previousChildTask){this.previousChildTask = this.Project.getTaskById(this.TaskInfo.previousChildTask.Id);var lastChildTask = this.Chart.getLastChildTask(this.previousChildTask);this.posY = parseInt(lastChildTask.cTaskItem[0].style.top) + this.Chart.heightTaskItem + 11;this.previousChildTask.nextChildTask = this}else {this.posY = parseInt(task.cTaskItem[0].style.top) + this.Chart.heightTaskItem + 11};task.childTask.push(this)};if (predecessorTask){var task = this.Project.getTaskById(predecessorTask.Id);this.predTask = task;task.childPredTask.push(this)};this.cTaskItem.push(this.createTaskItem());containerTasks.appendChild(this.cTaskItem[0]);if (this.Chart.panelNames){this.cTaskNameItem.push(this.createTaskNameItem(isCParentTask));this.Chart.panelNames.firstChild.appendChild(this.cTaskNameItem[0])};if (this.Chart.isShowDescTask){containerTasks.appendChild(this.createTaskDescItem())};var arrConnectingLines = [];if (predecessorTask)arrConnectingLines = this.createConnectingLinesDS();this.cTaskItem.push(arrConnectingLines);if (this.Chart.panelNames){var arrConnectingLinesNames = [];if (parentTask){this.cTaskNameItem[0].style.left = parseInt(this.parentTask.cTaskNameItem[0].style.left) + 15 + "px";arrConnectingLinesNames = this.createConnectingLinesPN()};this.checkWidthTaskNameItem();var treeImg = null;if (isCParentTask)treeImg = this.createTreeImg();this.cTaskNameItem.push(arrConnectingLinesNames);this.cTaskNameItem.push(treeImg)};this.addDayInPanelTime();return this};GanttTask.prototype.createTreeImg = function() +{var self = this;var treeImg = new Image();treeImg.src = this.Chart.imgs + "minus.gif";treeImg.id = this.TaskInfo.Id;treeImg.onclick = function() + {if (self._isOpen){this.src = self.Chart.imgs + "plus.gif";self._isOpen = false;self.hideChildTasks(self);self.shiftCurrentTasks(self, -self._heightHideTasks)}else + {this.src = self.Chart.imgs + "minus.gif";self._isOpen = true;self.shiftCurrentTasks(self, self._heightHideTasks);self.showChildTasks(self, true);self._heightHideTasks = 0}};this.Chart.panelNames.firstChild.appendChild(treeImg);treeImg.style.cssText = "cursor:pointer;left:" + (parseInt(this.cTaskNameItem[0].style.left) - 12) + "px;top:" + (parseInt(this.cTaskNameItem[0].style.top) + 3) + "px;z-index:12;position:absolute;";return treeImg};GanttChart.prototype.getLastChildTask = function(task) +{if (task.childTask.length > 0){return this.getLastChildTask(task.childTask[task.childTask.length - 1])}else + {return task}};dhtmlXMLSenderObject = function(ganttChart) +{this.xmlHttp = this.createXMLHttpRequest();this.isProcessed = false;this.path = null;this.filename = null;this.Chart = ganttChart};dhtmlXMLSenderObject.prototype.createXMLHttpRequest = function() +{if (window.XMLHttpRequest){return new XMLHttpRequest()}else if (window.ActiveXObject){return new ActiveXObject("Microsoft.XMLHTTP")}};dhtmlXMLSenderObject.prototype.sendData = function(filename, path, xmlData) +{var self = this;this.path = path;this.filename = filename;if ((this.path == null)|| (this.path == "")) + {this.Chart.Error.throwError("DATA_SEND_ERROR", 3, null);return};if ((this.filename == null)|| (this.filename == "")) + {this.Chart.Error.throwError("DATA_SEND_ERROR", 4, null);return};this.isProcessed = true;this.xmlHttp.open("POST", this.path, true);if (this.Chart._isFF){this.xmlHttp.onerror = function() {self.xmlHttp.onreadystatechange = null;self.xmlHttp.abort();self.isProcessed = false}};this.xmlHttp.onreadystatechange = function() {self.getStatus()};this.xmlHttp.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");this.xmlHttp.send("data=" + encodeURI(xmlData) + "&filename=" + filename)};dhtmlXMLSenderObject.prototype.getStatus = function() +{if (this.xmlHttp.readyState == 4){var _status = "";try {_status = this.xmlHttp.status}catch(e) {this.Chart.Error.throwError("DATA_SEND_ERROR", 1, null);return 0};switch (_status) {case 0: + this.Chart.Error.throwError("DATA_SEND_ERROR", 1, null);break;case 404: + this.Chart.Error.throwError("DATA_SEND_ERROR", 5, [this.path]);break;case 500: + this.Chart.Error.throwError("DATA_SEND_ERROR", 2, null);break;case 12029: + this.Chart.Error.throwError("DATA_SEND_ERROR", 1, null);break;default: + if (!(_status >= 200 && _status < 300 || _status == 304)) + {this.Chart.Error.throwError("DATA_SEND_ERROR", 0, null)};break};this.isProcessed = false}};function GanttError() {this.catches = [];this._errors = [];this._init();return this};GanttError.prototype._init = function() +{this._errors[0] = "Connection error";this._errors[1] = "Cannot connect";this._errors[2] = "Server error";this._errors[3] = "Path is null or empty";this._errors[4] = "Filename is null or empty";this._errors[5] = "File (%0) is not found";this._errors[6] = "Percent Complete should be a number";this._errors[7] = "Percent Complete should be <= 100";this._errors[8] = "Percent Complete should be >= 0";this._errors[9] = "Increase duration of task(%0)";this._errors[10] = "Reduce duration of task(%0)";this._errors[11] = "Increase EST of child task (%0)";this._errors[12] = "Reduce EST of task (%0)";this._errors[13] = "The project (%0) is added";this._errors[14] = "Start Date of the project < start Date of the control";this._errors[15] = "Task (%0) cannot be the child of predecessor task(%1)";this._errors[16] = "Time of the termination of predecessor task(%0) > EST of child task(%1)";this._errors[17] = "The Predecessor (%0) task does not exist";this._errors[18] = "The EST of task (%0) < start date of the control";this._errors[19] = "Time of the termination of parent task (%0) < time of the termination of child task(%1)";this._errors[20] = "The EST of task (%0) < EST of parent task(%1)";this._errors[21] = "The parent task (%0) does not exist";this._errors[22] = "The task (%0) is added";this._errors[23] = "The project (%0) is added";this._errors[24] = "Task (%0) EST < project (%1) startDate";this._errors[25] = "Parent task (%0) EST cannot be null";this._errors[26] = "Predecessor task (%0) position error. Reduce duration of predecessor task (%0) or increase EST of child task (%1)";this._errors[27] = "Predecessor task (%0) does not exist";this._errors[28] = "Increase duration of parent task (%0) or reduce EST of child task (%1) or reduce duration of child task(%1)";this._errors[29] = "Reduce EST of parent task (%0) or increase EST of child task (%1)";this._errors[30] = "The task(%0) does not exist";this._errors[31] = "The project(%0) does not exist";this._errors[32] = "Predecessor task(%0) and child task(%1) should have the same parent";this._errors[33] = "Reduce EST of parent task (%0) or increase EST of child task (%1)";this._errors[34] = "EST of task(%0) < start date of the project(%1)";this._errors[35] = "Percent Complete should be <= 100 and >= 0";this._errors[36] = "You may not connect a task to itself.";this._errors[37] = "Cannot parse this XML string."};GanttError.prototype.catchError = function(type, handler) {this.catches[type] = handler};GanttError.prototype.getErrorString = function(str, params) +{if (!params){return str}else {for (var i = 0;i < params.length;i++){var re = new RegExp("%" + i, "gi");str = str.replace(re, params[i])};return str}};GanttError.prototype.throwError = function(type, description, params) {if (this.catches[type]){var index = parseInt(description);var errorStr = this.getErrorString(this._errors[index], params);return this.catches[type](type, errorStr, params)};return null};function contextMenu(chart) +{this.Chart = chart;this.TabContainer = null;this.MenuPanel = null;this.tabPanel = null;this.arrTabs = [];this.isShow = false;this.hideDiv = null;this._init()};contextMenu.prototype._init = function() +{this.createMenuPanel();this.createHideDiv();this.createTabContainer();this.createTabPanel();var self = this;var arrItems = [];var tab1 = this.createTab(1, "Rename task", "t", true, this);tab1.addItem(1, "New name", document.createElement("input"), "text", function() {tab1.arrItems[0].control.focus()});tab1.addItem(2, "Rename", document.createElement("input"), "button", + function() {var name = tab1.arrItems[0].control.value;try {tab1.object.setName(name);tab1.hide()}catch(e) {}});var tab2 = this.createTab(2, "Delete task", "t", true, this);tab2.addItem(1, "Delete", document.createElement("input"), "button", + function() + {try {tab2.object.Project.deleteTask(tab2.object.TaskInfo.Id);tab2.hide()}catch(e) {}});var tab3 = this.createTab(3, "Set EST", "t", true, this);tab3.addItem(1, "EST", document.createElement("input"), "text", function() {tab3.arrItems[0].control.focus()});tab3.addItem(2, "Move children", document.createElement("input"), "checkbox", function() {tab3.arrItems[1].control.focus()});tab3.addItem(3, "Update", document.createElement("input"), "button", + function() {var isMoveChild = tab3.arrItems[1].control.checked;var arr = tab3.arrItems[0].control.value.split(".");var est = (arr.length < 3) ? null : (new Date(arr[2], parseInt(arr[1]) - 1, arr[0]));try {if (tab3.object.setEST(est, isMoveChild)) tab3.hide()}catch(e) {}});var tab4 = this.createTab(4, "Set duration", "t", true, this);tab4.addItem(1, "Duration", document.createElement("input"), "text", function() {tab4.arrItems[0].control.focus()});tab4.addItem(2, "Update", document.createElement("input"), "button", + function() {var d = tab4.arrItems[0].control.value;try {if (tab4.object.setDuration(d)) tab4.hide()}catch(e) {}});var tab5 = this.createTab(5, "Set % complete", "t", true, this);tab5.addItem(1, "Percent Complete", document.createElement("input"), "text", function() {tab5.arrItems[0].control.focus()});tab5.addItem(2, "Update", document.createElement("input"), "button", + function() {var p = tab5.arrItems[0].control.value;try {if (tab5.object.setPercentCompleted(p)) tab5.hide()}catch(e) {}});var tab13 = this.createTab(13, "Set predecessor", "t", true, this);tab13.addItem(1, "Predecessor", document.createElement("input"), "text", function() {tab13.arrItems[0].control.focus()});tab13.addItem(2, "Update", document.createElement("input"), "button", + function() {var p = tab13.arrItems[0].control.value;try {if (tab13.object.setPredecessor(p)) tab13.hide()}catch(e) {}});var tab6 = this.createTab(6, "Rename project", "p", true, this);tab6.addItem(1, "New name", document.createElement("input"), "text", function() {tab6.arrItems[0].control.focus()});tab6.addItem(2, "Rename", document.createElement("input"), "button", + function() {var name = tab6.arrItems[0].control.value;try {tab6.object.setName(name);tab6.hide()}catch(e) {}});var tab7 = this.createTab(7, "Delete project", "p", true, this);tab7.addItem(1, "Delete", document.createElement("input"), "button", + function() {try {tab7.object.Chart.deleteProject(tab7.object.Project.Id);tab7.hide()}catch(e) {}});var tab8 = this.createTab(8, "Set % complete", "p", true, this);tab8.addItem(1, "Percent Complete", document.createElement("input"), "text", function() {tab8.arrItems[0].control.focus()});tab8.addItem(2, "Update", document.createElement("input"), "button", + function() {var p = tab8.arrItems[0].control.value;try {if (tab8.object.setPercentCompleted(p)) tab8.hide()}catch(e) {}});var tab9 = this.createTab(9, "Add new task", "p", true, this);tab9.addItem(1, "Id", document.createElement("input"), "text", function() {tab9.arrItems[0].control.focus()});tab9.addItem(2, "Name", document.createElement("input"), "text", function() {tab9.arrItems[1].control.focus()});tab9.addItem(3, "EST", document.createElement("input"), "text", function() {tab9.arrItems[2].control.focus()});tab9.addItem(4, "Duration", document.createElement("input"), "text", function() {tab9.arrItems[3].control.focus()});tab9.addItem(5, "Percent complete", document.createElement("input"), "text", function() {tab9.arrItems[4].control.focus()});tab9.addItem(6, "Parent task id", document.createElement("input"), "text", function() {tab9.arrItems[5].control.focus()});tab9.addItem(7, "Pred task id", document.createElement("input"), "text", function() {tab9.arrItems[6].control.focus()});tab9.addItem(9, "Insert", document.createElement("input"), "button", + function() {try {var id = tab9.arrItems[0].control.value;var name = tab9.arrItems[1].control.value;var arr = tab9.arrItems[2].control.value.split(".");var est = (arr.length < 3) ? null : (new Date(arr[2], parseInt(arr[1]) - 1, arr[0]));var duration = tab9.arrItems[3].control.value;var pc = tab9.arrItems[4].control.value;var parentTaskId = tab9.arrItems[5].control.value;var predTaskId = tab9.arrItems[6].control.value;if (tab9.object.insertTask(id, name, est, duration, pc, predTaskId, parentTaskId)) tab9.hide()}catch(e) {}});var tab11 = this.createTab(11, "Add successor task", "t", true, this);tab11.addItem(1, "Id", document.createElement("input"), "text", function() {tab11.arrItems[0].control.focus()});tab11.addItem(2, "Name", document.createElement("input"), "text", function() {tab11.arrItems[1].control.focus()});tab11.addItem(3, "EST", document.createElement("input"), "text", function() {tab11.arrItems[2].control.focus()});tab11.addItem(4, "Duration", document.createElement("input"), "text", function() {tab11.arrItems[3].control.focus()});tab11.addItem(5, "Percent complete", document.createElement("input"), "text", function() {tab11.arrItems[4].control.focus()});tab11.addItem(6, "Insert", document.createElement("input"), "button", + function() {try {var pr = tab11.object.Project;var id = tab11.arrItems[0].control.value;var name = tab11.arrItems[1].control.value;var arr = tab11.arrItems[2].control.value.split(".");var est = (arr.length < 3) ? null : (new Date(arr[2], parseInt(arr[1]) - 1, arr[0]));var duration = tab11.arrItems[3].control.value;var pc = tab11.arrItems[4].control.value;var parentTaskId = (tab11.object.parentTask == null) ? "" : tab11.object.parentTask.TaskInfo.Id;var predTaskId = tab11.object.TaskInfo.Id;if (pr.insertTask(id, name, est, duration, pc, predTaskId, parentTaskId)) tab11.hide()}catch(e) {}});var tab10 = this.createTab(10, "Add child task", "t", true, this);tab10.addItem(1, "Id", document.createElement("input"), "text", function() {tab10.arrItems[0].control.focus()});tab10.addItem(2, "Name", document.createElement("input"), "text", function() {tab10.arrItems[1].control.focus()});tab10.addItem(3, "EST", document.createElement("input"), "text", function() {tab10.arrItems[2].control.focus()});tab10.addItem(4, "Duration", document.createElement("input"), "text", function() {tab10.arrItems[3].control.focus()});tab10.addItem(5, "Percent complete", document.createElement("input"), "text", function() {tab10.arrItems[4].control.focus()});tab10.addItem(6, "Insert", document.createElement("input"), "button", + function() {try {var pr = tab10.object.Project;var id = tab10.arrItems[0].control.value;var name = tab10.arrItems[1].control.value;var arr = tab10.arrItems[2].control.value.split(".");var est = (arr.length < 3) ? null : (new Date(arr[2], parseInt(arr[1]) - 1, arr[0]));var duration = tab10.arrItems[3].control.value;var pc = tab10.arrItems[4].control.value;var parentTaskId = tab10.object.TaskInfo.Id;var predTaskId = "";if (pr.insertTask(id, name, est, duration, pc, predTaskId, parentTaskId)) tab10.hide()}catch(e) {}});var tab12 = this.createTab(12, "-Insert new project-", "p", false, this);tab12.addItem(1, "Id", document.createElement("input"), "text", function() {tab12.arrItems[0].control.focus()});tab12.addItem(2, "Name", document.createElement("input"), "text", function() {tab12.arrItems[1].control.focus()});tab12.addItem(3, "Start date", document.createElement("input"), "text", function() {tab12.arrItems[2].control.focus()});tab12.addItem(4, "Insert", document.createElement("input"), "button", + function() {try {var id = tab12.arrItems[0].control.value;var namePr = tab12.arrItems[1].control.value;var arr = tab12.arrItems[2].control.value.split(".");var startDatePr = (arr.length < 3) ? null : (new Date(arr[2], parseInt(arr[1]) - 1, arr[0]));if (self.Chart.insertProject(id, namePr, startDatePr)) tab12.hide()}catch(e) {}})};contextMenu.prototype.createHideDiv = function() +{this.hideDiv = document.createElement("div");this.hideDiv.style.position = "absolute";this.hideDiv.style.left = "0px";this.hideDiv.style.top = "0px";this.Chart.content.appendChild(this.hideDiv);this.hideDiv.style.zIndex = 12;this.hideDiv.style.display = "none";this.hideDiv.style.background = "#7D7E7D";this.hideDiv.style.cssText += ";-moz-opacity: 0.5;filter: alpha(opacity=50);opacity:.50;";this.hideDiv.style.width = this.Chart.content.offsetWidth + 2 + "px";this.hideDiv.style.height = this.Chart.content.offsetHeight + 2 + "px"};contextMenu.prototype.createMenuPanel = function() +{this.MenuPanel = document.createElement("div");this.MenuPanel.style.visibility = "hidden";this.MenuPanel.style.cssText += ";z-index:10;";this.MenuPanel.style.position = "absolute";this.Chart.content.appendChild(this.MenuPanel);this.MenuPanel.innerHTML = "
";this.MenuPanel.firstChild.className = "contextMenu";this.MenuPanel.firstChild.cellPadding = 0;this.MenuPanel.firstChild.cellSpacing = 0;this.MenuPanel.firstChild.style.cssText += ";background:url(" + this.Chart.imgs + "menu/menu_bg.png);"};contextMenu.prototype.createTabPanel = function() +{this.tabPanel = document.createElement("div");this.tabPanel.style.visibility = "hidden";this.tabPanel.style.zIndex = "30";this.TabContainer.firstChild.rows[0].cells[0].appendChild(this.tabPanel);this.tabPanel.style.width = "385px";this.tabPanel.style.height = "290px";this.tabPanel.innerHTML = "
";this.tabPanel.firstChild.cellPadding = 0;this.tabPanel.firstChild.cellSpacing = 0;this.tabPanel.firstChild.style.cssText = "width:385px;border: 1px solid #808080;";this.tabPanel.firstChild.rows[0].cells[0].style.cssText = ";height:26px;background:url(" + this.Chart.imgs + "/menu/window_tr.png);background-repeat: no-repeat;color:#fff;font-size:14px;font-weight: bold;font-family: Tahoma, Arial";this.tabPanel.firstChild.rows[0].cells[0].align = "center";this.tabPanel.firstChild.rows[1].cells[0].style.cssText = ";height:270px;background:#F7F7F7;";this.tabPanel.firstChild.rows[1].cells[0].innerHTML = "
";this.tabPanel.firstChild.rows[1].cells[0].firstChild.style.cssText = "width:250px;font-size:11px;font-family:Tahoma,Arial;";this.tabPanel.firstChild.rows[1].cells[0].align = "center"};contextMenu.prototype.addItemMenuPanel = function(tab) +{var self = this;var row = this.MenuPanel.firstChild.insertRow(this.MenuPanel.firstChild.rows.length);var cell = document.createElement('td');cell.innerHTML = tab.Description;cell.style.cssText = "padding-left:10px;height:18px;";this.addEvent(cell, "mousedown", function() {tab.show()}, false);cell.onmouseover = function() {this.style.background = "url(" + self.Chart.imgs + "menu/menu_selection.png)"};cell.onmouseout = function() {this.style.background = ""};row.appendChild(cell)};contextMenu.prototype.showContextMenu = function(x, y, object) +{if (object.constructor == GanttTask){for (var i = 0;i < this.arrTabs.length;i++){if (this.arrTabs[i].type == "t"){this.arrTabs[i].object = object;this.addItemMenuPanel(this.arrTabs[i])}}}else if (object.constructor == GanttProject){for (var i = 0;i < this.arrTabs.length;i++){if (this.arrTabs[i].type == "p"){this.arrTabs[i].object = object;this.addItemMenuPanel(this.arrTabs[i])}}};this.isShow = true;this.MenuPanel.style.cssText += ";z-index:15;";this.MenuPanel.style.visibility = "visible";this.MenuPanel.style.top = parseInt(y) + this.Chart.heightTaskItem - this.Chart.oData.scrollTop + 5 + "px";this.MenuPanel.style.left = x};contextMenu.prototype.hideContextMenu = function() +{this.isShow = false;this.MenuPanel.style.visibility = "hidden"};contextMenu.prototype.clear = function() +{this.MenuPanel.removeChild(this.MenuPanel.firstChild);this.MenuPanel.innerHTML = "
";this.MenuPanel.firstChild.className = "contextMenu";this.MenuPanel.firstChild.cellPadding = 0;this.MenuPanel.firstChild.cellSpacing = 0;this.MenuPanel.firstChild.style.cssText += ";background:url(" + this.Chart.imgs + "menu/menu_bg.png);"};contextMenu.prototype.createTab = function(id, desc, type, showOInfo, menu) +{var tab = new contextMenuTab(id, desc, type, showOInfo, menu);this.arrTabs.push(tab);return tab};contextMenu.prototype.createTabContainer = function() +{this.TabContainer = document.createElement("div");this.TabContainer.style.position = "absolute";this.TabContainer.style.top = "0px";this.TabContainer.style.left = "0px";this.TabContainer.style.visibility = "hidden";this.TabContainer.style.zIndex = "50";this.Chart.content.appendChild(this.TabContainer);this.TabContainer.innerHTML = "
";this.TabContainer.firstChild.style.cssText = ";width:100%;height:100%;";this.TabContainer.firstChild.rows[0].cells[0].align = "center";this.TabContainer.style.width = this.Chart.content.offsetWidth + 2 + "px";this.TabContainer.style.height = this.Chart.content.offsetHeight + 2 + "px"};contextMenu.prototype.getTabById = function(id) +{for (var i = 0;i < this.arrTabs.length;i++){if (this.arrTabs[i].Id == id){return this.arrTabs[i]}};return null};function contextMenuTab(id, description, type, showOInfo, contextMenu) +{this.Id = id;this.arrItems = [];this.TabItemContainer = null;this.Description = description;this.contextMenu = contextMenu;this.type = type;this.object = null;this.showObjectInfo = showOInfo};contextMenu.prototype.addEvent = function (elm, evType, fn, useCapture) +{if (elm.addEventListener){elm.addEventListener(evType, fn, useCapture);return true}else if (elm.attachEvent){return elm.attachEvent('on' + evType, fn)}else {elm['on' + evType] = fn}};contextMenuTab.prototype.addItem = function(id, name, control, type, handler) +{if (handler){control.onclick = handler};control.type = type;if (type == "button"){control.value = name};var tabItem = new contextMenuTabItem(id, name, control, this);this.arrItems.push(tabItem)};contextMenuTab.prototype.show = function() +{this.contextMenu.hideDiv.style.display = "inline";this.contextMenu.TabContainer.style.visibility = "visible";var self = this;this.contextMenu.tabPanel.firstChild.rows[0].cells[0].innerHTML = this.Description;this.contextMenu.tabPanel.style.visibility = "visible";var t = this.contextMenu.tabPanel.firstChild.rows[1].cells[0].firstChild;var c,c2,r = null;if (this.showObjectInfo){if (this.object){if (this.object.constructor == GanttTask){this.insertData(t, "Id", this.object.TaskInfo.Id);this.insertData(t, "Name", this.object.TaskInfo.Name);this.insertData(t, "Duration", this.object.TaskInfo.Duration + " hrs");this.insertData(t, "Percent complete", this.object.TaskInfo.PercentCompleted + "%");this.insertData(t, "EST", this.object.TaskInfo.EST.getDate() + "." + (this.object.TaskInfo.EST.getMonth() + 1) + "." + this.object.TaskInfo.EST.getFullYear());this.insertData(t, "Predecessor", this.object.TaskInfo.PredecessorTaskId)}else + {this.insertData(t, "Id", this.object.Project.Id);this.insertData(t, "Name", this.object.Project.Name);this.insertData(t, "Start date", this.object.Project.StartDate.getDate() + "." + (this.object.Project.StartDate.getMonth() + 1) + "." + this.object.Project.StartDate.getFullYear())}}};var btnCell = null;for (var i = 0;i < this.arrItems.length;i++){if (this.arrItems[i].control.type == "button"){r = t.insertRow(t.rows.length);c = r.insertCell(r.cells.length);btnCell = r.insertCell(r.cells.length);btnCell.appendChild(this.arrItems[i].control)}else + {r = t.insertRow(t.rows.length);c = r.insertCell(r.cells.length);c2 = r.insertCell(r.cells.length);c.innerHTML = this.arrItems[i].Name;c2.appendChild(this.arrItems[i].control)}};var b = document.createElement("input");b.type = "button";b.value = "Cancel";b.onclick = function() + {self.hide()};if (!btnCell){r = t.insertRow(t.rows.length);c = r.insertCell(r.cells.length);btnCell = r.insertCell(r.cells.length)}else {b.style.marginLeft = "10px"};btnCell.appendChild(b)};contextMenuTab.prototype.hide = function() +{this.contextMenu.tabPanel.style.visibility = "hidden";var t = this.contextMenu.tabPanel.firstChild.rows[1].cells[0].firstChild;t.parentNode.removeChild(t);this.contextMenu.tabPanel.firstChild.rows[1].cells[0].innerHTML = "
";this.contextMenu.tabPanel.firstChild.rows[1].cells[0].firstChild.style.cssText = "width:250px;font-size:11px;font-family:Tahoma,Arial;";this.contextMenu.hideDiv.style.display = "none";this.contextMenu.TabContainer.style.visibility = "hidden"};contextMenuTab.prototype.insertData = function(t, name, value) +{var c,c2,r = null;r = t.insertRow(t.rows.length);c = r.insertCell(r.cells.length);c.style.cssText = "width:100px";c.innerHTML = name;c2 = r.insertCell(r.cells.length);c2.innerHTML = value};contextMenuTab.prototype.insertControl = function(t, name, value) +{var c,c2,r = null;r = t.insertRow(t.rows.length);c = r.insertCell(r.cells.length);c.innerHTML = name;c2 = r.insertCell(r.cells.length);c2.appendChild(value)};function contextMenuTabItem(id, name, control, tab) +{this.Id = id;this.Name = name;this.control = control;this.tab = tab}; +//v.1.3 build 9733 + +/* +Copyright DHTMLX LTD. http://www.dhtmlx.com +*/ \ No newline at end of file diff --git a/addons/base_gantt/static/lib/dhtmlxGantt/codebase/imgs/arr.gif b/addons/base_gantt/static/lib/dhtmlxGantt/codebase/imgs/arr.gif new file mode 100644 index 0000000000000000000000000000000000000000..3bd086371b23ad0c66f4083e3a6f760f95c4a826 GIT binary patch literal 162 zcmZ?wbhEHbYg>zAEawExE5-B))+ z&k8MCk()R-`v3p`7apHKcym9H!9X-n{K>+|z#zz=1JVJqlYvz}L8b38<3wcvlM~KN a=K@xAatL%MOz3I)cVIz*hfbFhgEaufL^X*3 literal 0 HcmV?d00001 diff --git a/addons/base_gantt/static/lib/dhtmlxGantt/codebase/imgs/bg.png b/addons/base_gantt/static/lib/dhtmlxGantt/codebase/imgs/bg.png new file mode 100644 index 0000000000000000000000000000000000000000..9d495780d13358403878ceef3eaad657cfe743ca GIT binary patch literal 151 zcmeAS@N?(olHy`uVBq!ia0vp^j6kf%!3-qt88$}%DVB6cUq=Rp^(V|(yIunMk|nMY zCBgY=CFO}lsSJ)O`AMk?p1FzXsX?iUDV2pMQ*D5XI0Jk_T>t<7|NGDH&tE>|6H_V+Po~-c6>ar&aSW-r_2$+_z9s{S)*vDvHJ2`#^2qx7XW2GIyD8gqmhZd#y|yO({&zKN z-hHY6CVn`iY=aBQd*|J(%YFVl@21~(O}i~N;?`g1el$B)er=E0&5x_gkKxt{GV${} b)dLJt(!sxr*7f)SJ;31U>gTe~DWM4fI`MHx literal 0 HcmV?d00001 diff --git a/addons/base_gantt/static/lib/dhtmlxGantt/codebase/imgs/menu/menu_bg.png b/addons/base_gantt/static/lib/dhtmlxGantt/codebase/imgs/menu/menu_bg.png new file mode 100644 index 0000000000000000000000000000000000000000..02f41eaf5d8d6cf4f0050eb850f19298d39a9553 GIT binary patch literal 159 zcmeAS@N?(olHy`uVBq!ia0vp^Q-GL}g9%7(|0+-nq*&4&eH|GX)}JtE?Rp91OP07s zlmzFem6RtIr7}3CUboFyt=akR{ E0D%%QLjV8( literal 0 HcmV?d00001 diff --git a/addons/base_gantt/static/lib/dhtmlxGantt/codebase/imgs/menu/menu_selection.png b/addons/base_gantt/static/lib/dhtmlxGantt/codebase/imgs/menu/menu_selection.png new file mode 100644 index 0000000000000000000000000000000000000000..aa35f7dcf5fd7ecbcd60a57f1972d5ae3e495c15 GIT binary patch literal 600 zcmV-e0;m0nP)PbXFRCwC# znbAtaFcgM+nzY-r%Fuy6f;R&P!Vn)o??lkI^u|lyz`;;AMCu!es0d}yt~STw)=g_S zk|nK~_S`jXn)LtrpPaN55k1c{48!+>-rd9F(@Wf9l%Zb$!1h*Sx4BcRR^mg~b?M~X zP2aU`>+Iynw(Q)-FA*#hpKcn4!>i8ib?^S5-5NDd;XS{;ogN<&Lc%aC&8MO5D53l9 z*7?Qdq;U!_iXzLReh?(&^s)*31@lNn#8|ar$CxtUjjwoTiCU-`JXmsg>h+|lw}T-| z*nw8|QT^~xh+FctEln%L#up-&^TcRqWM-bJ=*KQqilowJ%ntKgV`S6-&}J%&4Vc4- zbk<|#F_;VhRGP+rBWa=v@HiJ93S~sW3CRFZnsc#ue5k(j_ksn{8w~iXI}o*!3_DQk zJm3&a>FXks%95_@YtB695z`b9OHfc5`4z+CxSQH96*70j84{-80U;(o7}33#3;@Li zOW|o#%6OB`FgtC=0+}Y^7Yl@)CzUq~E}ayYY*Nn4-U6i7JcCj);tX8QD-OW_Uh}ev zOyP|_Njs}6zV9=J<(j9}nio&FR;>)f_ZU+Kyv9bo)9ttSnvUZrmZ}UD5d_0dx7XOL mf7v~iKVz39e*TR85MTgp)6Q}?=*PVP0000LKOlKmU5n;qBYE)9dkiydJN|XF3kQeEIYD-~QmADD4mA#&s0Q*UtQ2UZ4Br z!1+7+-EtC%!s)0miOTqmA$TS`Iu@s$WWS_t1YOU%z7V^E@t+~HayD~S%JS!%FW&t4 z-A{)P|2lK}?ayCR;VF_2Z;6I}3OTZyUt@Xsx!`f*(g@XqWWDL)6M3T0_={xUq6Ct9 z`s~NB#WozMMbJZ8VXN6RDN$X7Q+G7%QlN5u)z@Er^Q42G7&M~RG5EnWGWJR$CAu@Dotg1Le*% z07jd$pipt1&sPS`$N6}PED434NKbGkupsfvWwiEb+~DPvuql4Tqlbnx|Qzb!QDW}MOXx$Yj z_cY46pLtF4??zOTU{N1s{H{?j8}hD*Wpf1don`;xv;yCmYCaKKRmZsnG=NKysjb^} zo=*#dj)fV?AZ|0LvS}4n6SA8Tawinr zU;jLsYEt8r#QEAObd;L~jg?O^MO~GIINXvN(-rbuCc>1y$Nua6=SW{(HO9ye%{Mv^nNlu*nPZ&cvJwg{Cx@X*NYZxE% zCuex!Q5ywx#5mSSuWA*7bt_^ynO4wDOD<_ohRx7_$*rqe-QRzGVi1(K=Zc5o zep0nyO{R~RFBgc}$Co>c+6gUYv0P1JYL`B!*L=~XKcXtG5eVoPcEFA)No3f!%lV0p zvbmr!BnUPmT!dkkK|twXi5-hvt@%EN&Cd33ym^d^hkaqtGyOJLS#v|LyNjx=jxvDd zF>6X-OM#b<26D<}Eq0<2_`e%RYj^uRHgP0XTLLVISX39lA#bzu7{Hi21#e%4bOqLCQukXgklX%D8-dJs3HY+dR3rG z&#l_DY68n;mV>Q=Tn@bK7kbI9>OSyaY`Ga@Fp|L`@qc@6(TkcLxn5+bJk&O`4v=G+ z8|eC_+>kiM?<&o*|%{^5LZieoe9Z zY8erp;uBHs2b9|o2nIlmtCQE z7yF=tHdvtdRFIr#47}!4p|=hL0N_*-m2jS#Ya6C#g(u za+Ir>>i#qKgV0RGw<3SE7zKHrIK^X|+`` zc*#`p1>18ZVFQWrBt??x2ddafOaqk1Gj7Jiiks*dfUGu{neZ z+)T#!WGRrGWoj%F640PCRZGg&e$dodsJ0O-n<#Zq)og7LST%r}*qT&wO)bHtXI7|Z ziu>}|k|!2O+YWhg1NYV=fZbT@n64P#zb!cB2xqQAe03c5&Ps{>NeD@>sUCXAH}6pD zsjlE{OdBs4#Jt+;Of+3VV+5<2TPbdi1+0d=@|aZ?lp>eOubc;@XH?i%$ ziuoZzXlKsVwYEQpFS?fY)17t2M9m)7Os##%)alpj%4l^$Z?qA8Y~~*wJ_#f=%Vr&- zw1Kil)zlhqH-WWnpqo#%@ev?bS*W&_HTQapL|$-l!POttG7b!POvo5e-yxRIDA7b@ z0WFcOheBekGqnqdEVsG%iQI)a7)x5Nx!8Jae$hQ*aA5-!X?BdLu^k0gBcHN#mg5AO z@M=0aQ!L>!7vr;^1|p9El$&vB=-3{;A9dCU&sRwzW=ia2Ntk6tRbx-!vLBnd^8u}m zF)=v3c+%DWuTRSka5d|KkqoVDU`-A8x?q;`qiT_>^-f9F1CqF`&p^#nH%33-CxII) zx5!?Qrfomd$W)vjq9pf((?+CXrhahO?D$e%XrHNALYThNdXD01Av=+G{TVJF(=_rl|6mXi`OYuoh8XCOfjFhz6PameS^&d+eI;#|#?U-B=l-$dW zPRfKp)A%1jbSJ#>gK!n0avZcI(`U*sS~a9lQ(>t^=u#^nYQ?aD%4tOs4w|&9Ej=M5 zLrxi<{oK(b;)dmoxOaTZ4FAFCcW`$Oi0({c$}?Lojd*zudtROKwCZD)E44g$O*X%# z_ylX!{m~{D$v!a`SW}C?tS|7 z>CKxr7cN}*|NlP&7%2W^VPs(7WzYffKxQzosBK_%$ei#xWAC#c4;%zjJOjEGuHp*a XQ{c#1qRZge^rpJVP}EzQiNP8G!52A$ literal 0 HcmV?d00001 diff --git a/addons/base_gantt/static/lib/dhtmlxGantt/codebase/imgs/parentnode_filled.png b/addons/base_gantt/static/lib/dhtmlxGantt/codebase/imgs/parentnode_filled.png new file mode 100644 index 0000000000000000000000000000000000000000..1d08f670c44afe996a7eb82b9fc0f67ca585aad5 GIT binary patch literal 186 zcmeAS@N?(olHy`uVBq!ia0vp^j6lrI!3-oj1H|tFDVB6cUq=Rp^(V|(yIunMk|nMY zCBgY=CFO}lsSJ)O`AMk?p1FzXsX?iUDV2pMQ*D5X6a#!hTz_ph`@Pro*Xf);ml}Rw zs{gT8{NMNIKR2oWxjFgIgXO=D#`>KS>jx^9_jGX#skp^*u#u5LfP-PfN{;{Xcb-+O h6WX_S;}Z@82B!B67VrMI-v=sX@O1TaS?83{1ORMpMEw8& literal 0 HcmV?d00001 diff --git a/addons/base_gantt/static/lib/dhtmlxGantt/codebase/imgs/plus.gif b/addons/base_gantt/static/lib/dhtmlxGantt/codebase/imgs/plus.gif new file mode 100644 index 0000000000000000000000000000000000000000..ff22238004d22581ed7955381871bc1f44a0e21f GIT binary patch literal 124 zcmZ?wbhEHbJm%c=6r4cduW+{`vFgw{PG6{{8#>`SVYoKD~MK z=H9(~7cN}*|NlP&7%2W^VPs(7WzYffKxQzoXl~$iSUKTU#@e)>2g3v0B&V=VWzm@( b;4E{5+4asrUxq_XfA$}34cus=#9$2oX9hfW literal 0 HcmV?d00001 diff --git a/addons/base_gantt/static/lib/dhtmlxGantt/codebase/imgs/progress_bg.png b/addons/base_gantt/static/lib/dhtmlxGantt/codebase/imgs/progress_bg.png new file mode 100644 index 0000000000000000000000000000000000000000..69205da45a8db6954269fe3733fcc9948f45d98b GIT binary patch literal 186 zcmeAS@N?(olHy`uVBq!ia0vp^j6lrI!3-oj1H|tFDVB6cUq=Rp^(V|(yIunMk|nMY zCBgY=CFO}lsSJ)O`AMk?p1FzXsX?iUDV2pMQ*D5X6a#!hT;G5C{QJ+JA3uM+{rKtg z*Kd!Wzr6e8*|XPgzJCAl`u&FwpTEp-mfZkUEbr;!7*cVI4WrJ!Meez6PjR-qXb~q~aFK!A3>~0S<-@D>?ql-+7i1 he`}q(&QT5n2Bx1376B74Xakipc)I$ztaD0e0ssPKLD>KR literal 0 HcmV?d00001 diff --git a/addons/base_gantt/static/lib/dhtmlxGantt/index.html b/addons/base_gantt/static/lib/dhtmlxGantt/index.html new file mode 100644 index 00000000000..5196d426ca6 --- /dev/null +++ b/addons/base_gantt/static/lib/dhtmlxGantt/index.html @@ -0,0 +1,107 @@ + + + Gantt Chart + + + + + + + + + + + +
DHTML Gantt sample
+ +

Initialize object on page

+

You can place this JavaScript Gantt Chart anywhere on your web page, attaching it + to any div object.
+

+ + + +<div style="width:950px;height:620px;position:absolute" id="GanttDiv"></div> +<script> + var gantt = new GanttChart(); + gantt.setImagePath("codebase/imgs/"); + gantt.setEditable(true); + ... + gantt.addProject(project_1); + ... + gantt.create("GanttDiv"); +</script> + + +
+
+ + + + diff --git a/addons/base_gantt/static/lib/dhtmlxGantt/readme.txt b/addons/base_gantt/static/lib/dhtmlxGantt/readme.txt new file mode 100644 index 00000000000..fc2627d9fb7 --- /dev/null +++ b/addons/base_gantt/static/lib/dhtmlxGantt/readme.txt @@ -0,0 +1,7 @@ +dhtmlxGantt v.1.3 Standard edition build 100805 + +This component is allowed to be used under GPL, othervise you need to obtain Commercial or Enterise License +to use it in non-GPL project. Please contact sales@dhtmlx.com for details. + + +(c) DHTMLX Ltd. \ No newline at end of file diff --git a/addons/base_gantt/static/lib/dhtmlxGantt/sources/dhtmlxcommon.js b/addons/base_gantt/static/lib/dhtmlxGantt/sources/dhtmlxcommon.js new file mode 100644 index 00000000000..7f68a0a702c --- /dev/null +++ b/addons/base_gantt/static/lib/dhtmlxGantt/sources/dhtmlxcommon.js @@ -0,0 +1,938 @@ +/* +Copyright DHTMLX LTD. http://www.dhtmlx.com +To use this component please contact sales@dhtmlx.com to obtain license +*/ + +dhtmlx=function(obj){ + for (var a in obj) dhtmlx[a]=obj[a]; + return dhtmlx; //simple singleton +}; +dhtmlx.extend_api=function(name,map,ext){ + var t = window[name]; + if (!t) return; //component not defined + window[name]=function(obj){ + if (obj && typeof obj == "object" && !obj.tagName){ + var that = t.apply(this,(map._init?map._init(obj):arguments)); + //global settings + for (var a in dhtmlx) + if (map[a]) this[map[a]](dhtmlx[a]); + //local settings + for (var a in obj){ + if (map[a]) this[map[a]](obj[a]); + else if (a.indexOf("on")==0){ + this.attachEvent(a,obj[a]); + } + } + } else + var that = t.apply(this,arguments); + if (map._patch) map._patch(this); + return that||this; + }; + window[name].prototype=t.prototype; + if (ext) + dhtmlXHeir(window[name].prototype,ext); +}; + +dhtmlxAjax={ + get:function(url,callback){ + var t=new dtmlXMLLoaderObject(true); + t.async=(arguments.length<3); + t.waitCall=callback; + t.loadXML(url) + return t; + }, + post:function(url,post,callback){ + var t=new dtmlXMLLoaderObject(true); + t.async=(arguments.length<4); + t.waitCall=callback; + t.loadXML(url,true,post) + return t; + }, + getSync:function(url){ + return this.get(url,null,true) + }, + postSync:function(url,post){ + return this.post(url,post,null,true); + } +} + +/** + * @desc: xmlLoader object + * @type: private + * @param: funcObject - xml parser function + * @param: object - jsControl object + * @param: async - sync/async mode (async by default) + * @param: rSeed - enable/disable random seed ( prevent IE caching) + * @topic: 0 + */ +function dtmlXMLLoaderObject(funcObject, dhtmlObject, async, rSeed){ + this.xmlDoc=""; + + if (typeof (async) != "undefined") + this.async=async; + else + this.async=true; + + this.onloadAction=funcObject||null; + this.mainObject=dhtmlObject||null; + this.waitCall=null; + this.rSeed=rSeed||false; + return this; +}; +/** + * @desc: xml loading handler + * @type: private + * @param: dtmlObject - xmlLoader object + * @topic: 0 + */ +dtmlXMLLoaderObject.prototype.waitLoadFunction=function(dhtmlObject){ + var once = true; + this.check=function (){ + if ((dhtmlObject)&&(dhtmlObject.onloadAction != null)){ + if ((!dhtmlObject.xmlDoc.readyState)||(dhtmlObject.xmlDoc.readyState == 4)){ + if (!once) + return; + + once=false; //IE 5 fix + if (typeof dhtmlObject.onloadAction == "function") + dhtmlObject.onloadAction(dhtmlObject.mainObject, null, null, null, dhtmlObject); + + if (dhtmlObject.waitCall){ + dhtmlObject.waitCall.call(this,dhtmlObject); + dhtmlObject.waitCall=null; + } + } + } + }; + return this.check; +}; + +/** + * @desc: return XML top node + * @param: tagName - top XML node tag name (not used in IE, required for Safari and Mozilla) + * @type: private + * @returns: top XML node + * @topic: 0 + */ +dtmlXMLLoaderObject.prototype.getXMLTopNode=function(tagName, oldObj){ + if (this.xmlDoc.responseXML){ + var temp = this.xmlDoc.responseXML.getElementsByTagName(tagName); + if(temp.length==0 && tagName.indexOf(":")!=-1) + var temp = this.xmlDoc.responseXML.getElementsByTagName((tagName.split(":"))[1]); + var z = temp[0]; + } else + var z = this.xmlDoc.documentElement; + + if (z){ + this._retry=false; + return z; + } + + if ((_isIE)&&(!this._retry)){ + //fall back to MS.XMLDOM + var xmlString = this.xmlDoc.responseText; + var oldObj = this.xmlDoc; + this._retry=true; + this.xmlDoc=new ActiveXObject("Microsoft.XMLDOM"); + this.xmlDoc.async=false; + this.xmlDoc["loadXM"+"L"](xmlString); + + return this.getXMLTopNode(tagName, oldObj); + } + dhtmlxError.throwError("LoadXML", "Incorrect XML", [ + (oldObj||this.xmlDoc), + this.mainObject + ]); + + return document.createElement("DIV"); +}; + +/** + * @desc: load XML from string + * @type: private + * @param: xmlString - xml string + * @topic: 0 + */ +dtmlXMLLoaderObject.prototype.loadXMLString=function(xmlString){ + { + try{ + var parser = new DOMParser(); + this.xmlDoc=parser.parseFromString(xmlString, "text/xml"); + } + catch (e){ + this.xmlDoc=new ActiveXObject("Microsoft.XMLDOM"); + this.xmlDoc.async=this.async; + this.xmlDoc["loadXM"+"L"](xmlString); + } + } + + this.onloadAction(this.mainObject, null, null, null, this); + + if (this.waitCall){ + this.waitCall(); + this.waitCall=null; + } +} +/** + * @desc: load XML + * @type: private + * @param: filePath - xml file path + * @param: postMode - send POST request + * @param: postVars - list of vars for post request + * @topic: 0 + */ +dtmlXMLLoaderObject.prototype.loadXML=function(filePath, postMode, postVars, rpc){ + if (this.rSeed) + filePath+=((filePath.indexOf("?") != -1) ? "&" : "?")+"a_dhx_rSeed="+(new Date()).valueOf(); + this.filePath=filePath; + + if ((!_isIE)&&(window.XMLHttpRequest)) + this.xmlDoc=new XMLHttpRequest(); + else { + if (document.implementation&&document.implementation.createDocument){ + this.xmlDoc=document.implementation.createDocument("", "", null); + this.xmlDoc.onload=new this.waitLoadFunction(this); + this.xmlDoc.load(filePath); + return; + } else + this.xmlDoc=new ActiveXObject("Microsoft.XMLHTTP"); + } + + if (this.async) + this.xmlDoc.onreadystatechange=new this.waitLoadFunction(this); + this.xmlDoc.open(postMode ? "POST" : "GET", filePath, this.async); + + if (rpc){ + this.xmlDoc.setRequestHeader("User-Agent", "dhtmlxRPC v0.1 ("+navigator.userAgent+")"); + this.xmlDoc.setRequestHeader("Content-type", "text/xml"); + } + + else if (postMode) + this.xmlDoc.setRequestHeader('Content-type', 'application/x-www-form-urlencoded'); + + this.xmlDoc.setRequestHeader("X-Requested-With","XMLHttpRequest"); + this.xmlDoc.send(null||postVars); + + if (!this.async) + (new this.waitLoadFunction(this))(); +}; +/** + * @desc: destructor, cleans used memory + * @type: private + * @topic: 0 + */ +dtmlXMLLoaderObject.prototype.destructor=function(){ + this._filterXPath = null; + this._getAllNamedChilds = null; + this._retry = null; + this.async = null; + this.rSeed = null; + this.filePath = null; + this.onloadAction = null; + this.mainObject = null; + this.xmlDoc = null; + this.doXPath = null; + this.doXPathOpera = null; + this.doXSLTransToObject = null; + this.doXSLTransToString = null; + this.loadXML = null; + this.loadXMLString = null; + // this.waitLoadFunction = null; + this.doSerialization = null; + this.xmlNodeToJSON = null; + this.getXMLTopNode = null; + this.setXSLParamValue = null; + return null; +} + +dtmlXMLLoaderObject.prototype.xmlNodeToJSON = function(node){ + var t={}; + for (var i=0; i-1) + _isChrome=true; + +if ((navigator.userAgent.indexOf('Safari') != -1)||(navigator.userAgent.indexOf('Konqueror') != -1)){ + var _KHTMLrv = parseFloat(navigator.userAgent.substr(navigator.userAgent.indexOf('Safari')+7, 5)); + + if (_KHTMLrv > 525){ //mimic FF behavior for Safari 3.1+ + _isFF=true; + var _FFrv = 1.9; + } else + _isKHTML=true; +} else if (navigator.userAgent.indexOf('Opera') != -1){ + _isOpera=true; + _OperaRv=parseFloat(navigator.userAgent.substr(navigator.userAgent.indexOf('Opera')+6, 3)); +} + + +else if (navigator.appName.indexOf("Microsoft") != -1){ + _isIE=true; + if (navigator.appVersion.indexOf("MSIE 8.0")!= -1 && document.compatMode != "BackCompat") _isIE=8; +} else { + _isFF=true; + var _FFrv = parseFloat(navigator.userAgent.split("rv:")[1]) +} + + +//multibrowser Xpath processor +dtmlXMLLoaderObject.prototype.doXPath=function(xpathExp, docObj, namespace, result_type){ + if (_isKHTML || (!_isIE && !window.XPathResult)) + return this.doXPathOpera(xpathExp, docObj); + + if (_isIE){ //IE + if (!docObj) + if (!this.xmlDoc.nodeName) + docObj=this.xmlDoc.responseXML + else + docObj=this.xmlDoc; + + if (!docObj) + dhtmlxError.throwError("LoadXML", "Incorrect XML", [ + (docObj||this.xmlDoc), + this.mainObject + ]); + + if (namespace != null) + docObj.setProperty("SelectionNamespaces", "xmlns:xsl='"+namespace+"'"); // + + if (result_type == 'single'){ + return docObj.selectSingleNode(xpathExp); + } + else { + return docObj.selectNodes(xpathExp)||new Array(0); + } + } else { //Mozilla + var nodeObj = docObj; + + if (!docObj){ + if (!this.xmlDoc.nodeName){ + docObj=this.xmlDoc.responseXML + } + else { + docObj=this.xmlDoc; + } + } + + if (!docObj) + dhtmlxError.throwError("LoadXML", "Incorrect XML", [ + (docObj||this.xmlDoc), + this.mainObject + ]); + + if (docObj.nodeName.indexOf("document") != -1){ + nodeObj=docObj; + } + else { + nodeObj=docObj; + docObj=docObj.ownerDocument; + } + var retType = XPathResult.ANY_TYPE; + + if (result_type == 'single') + retType=XPathResult.FIRST_ORDERED_NODE_TYPE + var rowsCol = new Array(); + var col = docObj.evaluate(xpathExp, nodeObj, function(pref){ + return namespace + }, retType, null); + + if (retType == XPathResult.FIRST_ORDERED_NODE_TYPE){ + return col.singleNodeValue; + } + var thisColMemb = col.iterateNext(); + + while (thisColMemb){ + rowsCol[rowsCol.length]=thisColMemb; + thisColMemb=col.iterateNext(); + } + return rowsCol; + } +} + +function _dhtmlxError(type, name, params){ + if (!this.catches) + this.catches=new Array(); + + return this; +} + +_dhtmlxError.prototype.catchError=function(type, func_name){ + this.catches[type]=func_name; +} +_dhtmlxError.prototype.throwError=function(type, name, params){ + if (this.catches[type]) + return this.catches[type](type, name, params); + + if (this.catches["ALL"]) + return this.catches["ALL"](type, name, params); + + alert("Error type: "+arguments[0]+"\nDescription: "+arguments[1]); + return null; +} + +window.dhtmlxError=new _dhtmlxError(); + + +//opera fake, while 9.0 not released +//multibrowser Xpath processor +dtmlXMLLoaderObject.prototype.doXPathOpera=function(xpathExp, docObj){ + //this is fake for Opera + var z = xpathExp.replace(/[\/]+/gi, "/").split('/'); + var obj = null; + var i = 1; + + if (!z.length) + return []; + + if (z[0] == ".") + obj=[docObj]; else if (z[0] == ""){ + obj=(this.xmlDoc.responseXML||this.xmlDoc).getElementsByTagName(z[i].replace(/\[[^\]]*\]/g, "")); + i++; + } else + return []; + + for (i; i < z.length; i++)obj=this._getAllNamedChilds(obj, z[i]); + + if (z[i-1].indexOf("[") != -1) + obj=this._filterXPath(obj, z[i-1]); + return obj; +} + +dtmlXMLLoaderObject.prototype._filterXPath=function(a, b){ + var c = new Array(); + var b = b.replace(/[^\[]*\[\@/g, "").replace(/[\[\]\@]*/g, ""); + + for (var i = 0; i < a.length; i++) + if (a[i].getAttribute(b)) + c[c.length]=a[i]; + + return c; +} +dtmlXMLLoaderObject.prototype._getAllNamedChilds=function(a, b){ + var c = new Array(); + + if (_isKHTML) + b=b.toUpperCase(); + + for (var i = 0; i < a.length; i++)for (var j = 0; j < a[i].childNodes.length; j++){ + if (_isKHTML){ + if (a[i].childNodes[j].tagName&&a[i].childNodes[j].tagName.toUpperCase() == b) + c[c.length]=a[i].childNodes[j]; + } + + else if (a[i].childNodes[j].tagName == b) + c[c.length]=a[i].childNodes[j]; + } + + return c; +} + +function dhtmlXHeir(a, b){ + for (var c in b) + if (typeof (b[c]) == "function") + a[c]=b[c]; + return a; +} + +function dhtmlxEvent(el, event, handler){ + if (el.addEventListener) + el.addEventListener(event, handler, false); + + else if (el.attachEvent) + el.attachEvent("on"+event, handler); +} + +//============= XSL Extension =================================== + +dtmlXMLLoaderObject.prototype.xslDoc=null; +dtmlXMLLoaderObject.prototype.setXSLParamValue=function(paramName, paramValue, xslDoc){ + if (!xslDoc) + xslDoc=this.xslDoc + + if (xslDoc.responseXML) + xslDoc=xslDoc.responseXML; + var item = + this.doXPath("/xsl:stylesheet/xsl:variable[@name='"+paramName+"']", xslDoc, + "http:/\/www.w3.org/1999/XSL/Transform", "single"); + + if (item != null) + item.firstChild.nodeValue=paramValue +} +dtmlXMLLoaderObject.prototype.doXSLTransToObject=function(xslDoc, xmlDoc){ + if (!xslDoc) + xslDoc=this.xslDoc; + + if (xslDoc.responseXML) + xslDoc=xslDoc.responseXML + + if (!xmlDoc) + xmlDoc=this.xmlDoc; + + if (xmlDoc.responseXML) + xmlDoc=xmlDoc.responseXML + + //MOzilla + if (!_isIE){ + if (!this.XSLProcessor){ + this.XSLProcessor=new XSLTProcessor(); + this.XSLProcessor.importStylesheet(xslDoc); + } + var result = this.XSLProcessor.transformToDocument(xmlDoc); + } else { + var result = new ActiveXObject("Msxml2.DOMDocument.3.0"); + try{ + xmlDoc.transformNodeToObject(xslDoc, result); + }catch(e){ + result = xmlDoc.transformNode(xslDoc); + } + } + return result; +} + +dtmlXMLLoaderObject.prototype.doXSLTransToString=function(xslDoc, xmlDoc){ + var res = this.doXSLTransToObject(xslDoc, xmlDoc); + if(typeof(res)=="string") + return res; + return this.doSerialization(res); +} + +dtmlXMLLoaderObject.prototype.doSerialization=function(xmlDoc){ + if (!xmlDoc) + xmlDoc=this.xmlDoc; + if (xmlDoc.responseXML) + xmlDoc=xmlDoc.responseXML + if (!_isIE){ + var xmlSerializer = new XMLSerializer(); + return xmlSerializer.serializeToString(xmlDoc); + } else + return xmlDoc.xml; +} + +/** +* @desc: +* @type: private +*/ +dhtmlxEventable=function(obj){ + obj.attachEvent=function(name, catcher, callObj){ + name='ev_'+name.toLowerCase(); + if (!this[name]) + this[name]=new this.eventCatcher(callObj||this); + + return(name+':'+this[name].addEvent(catcher)); //return ID (event name & event ID) + } + obj.callEvent=function(name, arg0){ + name='ev_'+name.toLowerCase(); + if (this[name]) + return this[name].apply(this, arg0); + return true; + } + obj.checkEvent=function(name){ + return (!!this['ev_'+name.toLowerCase()]) + } + obj.eventCatcher=function(obj){ + var dhx_catch = []; + var z = function(){ + var res = true; + for (var i = 0; i < dhx_catch.length; i++){ + if (dhx_catch[i] != null){ + var zr = dhx_catch[i].apply(obj, arguments); + res=res&&zr; + } + } + return res; + } + z.addEvent=function(ev){ + if (typeof (ev) != "function") + ev=eval(ev); + if (ev) + return dhx_catch.push(ev)-1; + return false; + } + z.removeEvent=function(id){ + dhx_catch[id]=null; + } + return z; + } + obj.detachEvent=function(id){ + if (id != false){ + var list = id.split(':'); //get EventName and ID + this[list[0]].removeEvent(list[1]); //remove event + } + } + obj.detachAllEvents = function(){ + for (var name in this){ + if (name.indexOf("ev_")==0) + delete this[name]; + } + } +} diff --git a/addons/base_gantt/static/lib/dhtmlxGantt/sources/dhtmlxgantt.js b/addons/base_gantt/static/lib/dhtmlxGantt/sources/dhtmlxgantt.js new file mode 100644 index 00000000000..52b9b562e96 --- /dev/null +++ b/addons/base_gantt/static/lib/dhtmlxGantt/sources/dhtmlxgantt.js @@ -0,0 +1,6122 @@ +//v.1.3 build 100805 + +/* +Copyright DHTMLX LTD. http://www.dhtmlx.com +To use this component please contact sales@dhtmlx.com to obtain license +*/ + +/*_TOPICS_ + * @0:Initialization + * @1:Add/delete + * @2:Lookup + * @3:Appearance + * @4:Private + * @5:Handlers + * @6:Load/Save data + * @7:Printing + */ + +/** + * @desc: GanttProjectInfo constructor + * @param: id - id of the project + * @param: name - name of the project + * @param: startDate - start date of the project (JavaScript Date object) + * @type: public + * @topic: 0 + */ +function GanttProjectInfo(id, name, startDate) +{ + this.Id = id; + this.Name = name; + this.StartDate = startDate; + this.ParentTasks = []; +} +/** + * @desc: Delete specified task + * @param: id - id of the task to be deleted + * @type: public + * @topic: 1 + * @edition: Professional + */ +GanttProjectInfo.prototype.deleteTask = function(id) +{ + var task = this.getTaskById(id); + if (task) { + if (!task.ParentTask) { + + for (var i = 0; i < this.ParentTasks.length; i++) { + + if (this.ParentTasks[i].Id == id) { + + if (this.ParentTasks[i].nextParentTask) { + + if (this.ParentTasks[i].previousParentTask) { + this.ParentTasks[i].previousParentTask.nextParentTask = this.ParentTasks[i].nextParentTask; + this.ParentTasks[i].nextParentTask.previousParentTask = this.ParentTasks[i].previousParentTask; + } else { + this.ParentTasks[i].nextParentTask.previousParentTask = null; + } + + } else { + if (this.ParentTasks[i].previousParentTask) { + this.ParentTasks[i].previousParentTask.nextParentTask = null; + } + } + + this.ParentTasks[i] = null; + this.ParentTasks.splice(i, 1); + break; + } + } + + } else + { + var parentTask = task.ParentTask; + for (var i = 0; i < parentTask.ChildTasks.length; i++) { + + if (parentTask.ChildTasks[i].Id == id) { + + if (parentTask.ChildTasks[i].nextChildTask) { + + if (parentTask.ChildTasks[i].previousChildTask) { + + parentTask.ChildTasks[i].previousChildTask.nextChildTask = parentTask.ChildTasks[i].nextChildTask; + parentTask.ChildTasks[i].nextChildTask.previousChildTask = parentTask.ChildTasks[i].previousChildTask; + + } else { + parentTask.ChildTasks[i].nextChildTask.previousChildTask = null; + } + + } else { + if (parentTask.ChildTasks[i].previousChildTask) { + parentTask.ChildTasks[i].previousChildTask.nextChildTask = null; + } + } + + parentTask.ChildTasks[i] = null; + parentTask.ChildTasks.splice(i, 1); + break; + } + + } + } + } +}; +/** + * @desc: Addition of the task in project + * @param: task - TaskInfo object + * @type: public + * @topic: 1 + */ +GanttProjectInfo.prototype.addTask = function(task) +{ + this.ParentTasks.push(task); + task.setProject(this); +}; +/** + * @desc: get object task by id + * @param: id - id of task + * @type: public + * @topic: 2 + */ +GanttProjectInfo.prototype.getTaskById = function(id) +{ + for (var j = 0; j < this.ParentTasks.length; j++) + { + var task = this.getTaskByIdInTree(this.ParentTasks[j], id); + if (task) return task; + } + return null; +}; +/** + * @desc: get object task by id + * @param: parentTask -(object) parent task + * @param: id - id of current task + * @type: private + * @topic: 2 + */ +GanttProjectInfo.prototype.getTaskByIdInTree = function(parentTask, id) +{ + if (parentTask.Id == id) + { + return parentTask; + + } else + { + for (var i = 0; i < parentTask.ChildTasks.length; i++) { + + if (parentTask.ChildTasks[i].Id == id) + { + return parentTask.ChildTasks[i]; + } + if (parentTask.ChildTasks[i].ChildTasks.length > 0) + { + if (parentTask.ChildTasks[i].ChildTasks.length > 0) + { + var cTask = this.getTaskByIdInTree(parentTask.ChildTasks[i], id); + if (cTask) return cTask; + } + } + } + + } + return null; +}; +/** + * @desc: GanttTaskInfo constructor + * @param: id - specifies id of task + * @param: name - specifies name of task + * @param: est - specifies Estimated Start Date of task + * @param: duration - specifies duration of task in hours + * @param: percentCompleted - specifies percentCompleted of task + * @param: predecessorTaskId - specifies predecessorTask Id of task + * @type: public + * @topic: 0 + */ +function GanttTaskInfo(id, name, est, duration, percentCompleted, predecessorTaskId) +{ + this.Id = id; + this.Name = name; + this.EST = est; + this.Duration = duration; + this.PercentCompleted = percentCompleted; + this.PredecessorTaskId = predecessorTaskId; + this.ChildTasks = []; + this.ChildPredTasks = []; + this.ParentTask = null; + this.PredecessorTask = null; + this.Project = null; + this.nextChildTask = null; + this.previousChildTask = null; + this.nextParentTask = null; + this.previousParentTask = null; +} +/** + * @desc: Addition of child task to the parent task + * @param: task - (object) task + * @type: public + * @topic: 1 + */ +GanttTaskInfo.prototype.addChildTask = function(task) +{ + this.ChildTasks.push(task); + task.ParentTask = this; +}; +/** + * @desc: set project to this task and its children + * @param: project - (object) project + * @type: private + * @topic: 0 + */ +GanttTaskInfo.prototype.setProject = function(project) +{ + this.Project = project; + for (var j = 0; j < this.ChildTasks.length; j++) + { + this.ChildTasks[j].setProject(project); + } +}; +/** + * @desc: private GanttTask constructor + * @param: taskInfo - (object)GanttTaskInfo + * @param: project - (object) GanttProject + * @param: chart - (object)GanttChart + * @type: public + * @topic: 0 + */ +function GanttTask(taskInfo, project, chart) +{ + this.isTask = true; + + this.Chart = chart; + this.Project = project; + this.TaskInfo = taskInfo; + + //control variables + this.checkMove = false; + this.checkResize = false; + this.moveChild = false; + + this.maxPosXMove = -1; + this.minPosXMove = -1; + this.maxWidthResize = -1; + this.minWidthResize = -1; + this.posX = 0; + this.posY = 0; + this.MouseX = 0; + this.taskItemWidth = 0; + this.isHide = false; + this._heightHideTasks = 0; + this._isOpen = true; + + this.descrTask = null; + this.cTaskItem = null; + this.cTaskNameItem = null; + + this.parentTask = null; + this.predTask = null; + this.childTask = []; + this.childPredTask = []; + this.nextChildTask = null; + this.previousChildTask = null; + this.nextParentTask = null; + this.previousParentTask = null; + +} +/** + * @desc: private GanttProject constructor + * @type: public + * @topic: 0 + */ +function GanttProject(Chart, projectInfo) +{ + this.isProject = true; + + this.nextProject = null; + this.previousProject = null; + this.arrTasks = []; + this.Project = projectInfo; + this.Chart = Chart; + this.percentCompleted = 0; + this.Duration = 0; + + this.descrProject = null; + this.projectItem = null; + this.projectNameItem = null; + + this.posY = 0; + this.posX = 0; +} +/** + * @desc: check width of projectNameItem + * @type: private + * @topic: 4 + */ +GanttProject.prototype.checkWidthProjectNameItem = function() +{ + if (this.projectNameItem.offsetWidth + this.projectNameItem.offsetLeft > this.Chart.maxWidthPanelNames) + { + var width = this.projectNameItem.offsetWidth + this.projectNameItem.offsetLeft - this.Chart.maxWidthPanelNames; + var countChar = Math.round(width / (this.projectNameItem.offsetWidth / this.projectNameItem.firstChild.length)); + var pName = this.Project.Name.substring(0, this.projectNameItem.firstChild.length - countChar - 3); + pName += "..."; + this.projectNameItem.innerHTML = pName; + } +}; +/** + * @desc: create GanttProject. + * @type: private + * @topic: 0 + */ +GanttProject.prototype.create = function() +{ + var containerTasks = this.Chart.oData.firstChild; + + this.posX = (this.Project.StartDate - this.Chart.startDate) / (60 * 60 * 1000) * this.Chart.hourInPixels; + + if (this.previousProject) + { + if (this.previousProject.arrTasks.length > 0) { + var lastChildTask = this.Chart.getLastChildTask(this.previousProject.arrTasks[this.previousProject.arrTasks.length - 1]); + this.posY = parseInt(lastChildTask.cTaskItem[0].style.top) + this.Chart.heightTaskItem + 11; + } else { + this.posY = parseInt(this.previousProject.projectItem[0].style.top) + this.Chart.heightTaskItem + 11; + } + } else { + this.posY = 6; + } + + if (this.Chart._showTreePanel) { + + var containerNames = this.Chart.panelNames.firstChild; + this.projectNameItem = this.createProjectNameItem(); + containerNames.appendChild(this.projectNameItem); + this.checkWidthProjectNameItem(); + + } + this.projectItem = [this.createProjectItem(),[]]; + containerTasks.appendChild(this.projectItem[0]); + + if (this.Chart.isShowDescProject) { + containerTasks.appendChild(this.createDescrProject()); + } + + this.addDayInPanelTime(); +}; +/** + * @desc: GanttChart constructor + * @type: public + * @topic: 0 + */ +function GanttChart() +{ + this.Error = new GanttError(); + this.dhtmlXMLSenderObject = new dhtmlXMLSenderObject(this); + + //settings + this.heightTaskItem = 12; + this.dayInPixels = 24; + this.hoursInDay = 8; + this._showTreePanel = true; + this._showTooltip = true; + this.isShowDescTask = false; + this.isShowDescProject = false; + this.isShowNewProject = true; + this.isEditable = false; + this.isShowConMenu = false; + this.correctError = false; + this.maxWidthPanelNames = 150; + this.minWorkLength = 8; + this.paramShowTask = []; + this.paramShowProject = []; + + this.savePath = null; + this.loadPath = null; + + //control variables + this.divTimeInfo = null; + this.divInfo = null; + + this.panelNames = null; + this.panelTime = null; + this.oData = null; + this.content = null; + this.panelErrors = null; + this.contextMenu = null; + + this.hourInPixelsWork = this.dayInPixels / this.hoursInDay; + this.hourInPixels = this.dayInPixels / 24; + this.countDays = 0; + this.startDate = null; + this.initialPos = 0; + + this.contentHeight = 0; + this.contentWidth = 0; + this._oDataHeight = 0; + + this.Project = []; + + this.arrProjects = []; + + this.xmlLoader = null; + + + this._isIE = false; + this._isFF = false; + this._isOpera = false; + + this._isMove = false; + this._isResize = false; + this._isError = false; + + this.imgs = "codebase/imgs/"; + this.stylePath = "codebase/dhtmlxgantt.css"; // used in simple printing method getPrintableHTML() + + this.shortMonthNames = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]; + this.monthNames = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"]; + this._useShortMonthNames = true; + + dhtmlxEventable(this); +} +/** + * @desc: set path to image directory + * @param: newPath - path to image directory, end with slash / + * @type: public + * @topic: 0 + * @before_init: 1 + */ +GanttChart.prototype.setImagePath = function(newPath) +{ + this.imgs = newPath; +}; +/** + * @desc: set path to styles file, default is "codebase/dhtmlxgantt.css"; used in simple printing method printToWindow() + * @param: newPath - path to styles file + * @type: public + * @topic: 0 + * @before_init: 1 + */ +GanttChart.prototype.setStylePath = function(newPath) +{ + this.stylePath = newPath; +}; +/** + * @desc: set url which is used to save chart data with saveData() method + * @param: newPath - url to server script. + * @type: public + * @topic: 6 + * @before_init: 1 + */ +GanttChart.prototype.setSavePath = function(newPath) +{ + this.savePath = newPath; +}; +/** + * @desc: set url which is used to load chart data with loadData() method + * @param: newPath - url to server script. + * @type: public + * @topic: 6 + * @before_init: 1 + */ +GanttChart.prototype.setLoadPath = function(newPath) +{ + this.loadPath = newPath; +}; +GanttChart.prototype.setCorrectError = function(isCorrectError) +{ + this.correctError = isCorrectError; +}; + +/** + * @desc: enable or disable inline task description (displayed right after the task bar), and configure the shown values + * @param: isShowDescTask - true/false show or hide + * @param: param - comma separated list of letters: n - Name, d - Duration, e - EST, p -Percent complete. For example value "n,e" will show task name and EST date. + * @type: public + * @topic: 3 + * @before_init: 1 + */ +GanttChart.prototype.showDescTask = function(isShowDescTask, param) +{ + this.isShowDescTask = isShowDescTask; + var arrValues = new Array(5); + + if (this.isShowDescTask) + { + if (param) { + var arrParam = param.split(","); + for (var i = 0; i < arrParam.length; i++) { + var k = this.getParamShowTask(arrParam[i]); + arrValues[k] = 1; + } + } else { + arrValues[this.getParamShowTask('')] = 1; + } + this.paramShowTask = this.getValueShowTask(arrValues); + } + +}; + +/** + * @desc: enable or disable inline project description (displayed right after the project bar), and configure the shown values + * @param: isShowDescProject - true/false show or hide + * @param: param - comma separated list of letters: n - Name, d - Duration, s - Start date, p -Percent complete. For example value "n,s" will show project name and start date. + * @type: public + * @topic: 3 + * @before_init: 1 + */ +GanttChart.prototype.showDescProject = function(isShowDescProject, param) +{ + this.isShowDescProject = isShowDescProject; + var arrValues = new Array(4); + + if (this.isShowDescProject) + { + if (param) { + var arrParam = param.split(","); + for (var i = 0; i < arrParam.length; i++) { + var k = this.getParamShowProject(arrParam[i]); + arrValues[k] = 1; + } + } else { + arrValues[this.getParamShowProject('')] = 1; + } + this.paramShowProject = this.getValueShowProject(arrValues); + } + +}; + +/** + * @desc: enable or disable context menu in tree. it can be used for a simple task manipulations. + * @param: show - true/false show or hide + * @type: public + * @topic: 3 + * @before_init: 1 + */ +GanttChart.prototype.showContextMenu = function(show) +{ + this.isShowConMenu = show; +}; + +/** + * @desc: set custom context menu for the tree. + * @param: menu - an instance of dhtmlxMenu. + * @type: public + * @topic: 3 + * @before_init: 1 + */ +GanttChart.prototype.setContextMenu = function(menu) +{ + this.showContextMenu(true); + this.contextMenu = menu; +}; + +/** + * @desc: show new project at startup. it is usefull if you have no project at all, and you need some start point. also menu is attached to this project item. + * @param: show - true/false show or hide + * @type: public + * @topic: 3 + * @before_init: 1 + */ +GanttChart.prototype.showNewProject = function(show) +{ + this.isShowNewProject = show; +}; + +GanttChart.prototype.getParamShowTask = function(param) +{ + switch (param) { + case 'n': + //name + return 0; + break; + case 'd': + //duration + return 1; + break; + case 'e': + //est + return 2; + break; + case 'p': + //percent complete + return 3; + break; + case 's-f': + //start-finish + return 4; + break; + default: + return 0; + break; + } +}; + +GanttChart.prototype.getParamShowProject = function(param) +{ + switch (param) { + case 'n': + //name + return 0; + break; + case 'd': + //duration + return 1; + break; + case 's': + //start date + return 2; + break; + case 'p': + //percent complete + return 3; + break; + default: + return 0; + break; + } +}; + +GanttChart.prototype.getValueShowTask = function(param) +{ + var arrValues = []; + for (var i = 0; i < param.length; i++) { + if (param[i]) + { + switch (i) { + case 0: + arrValues.push('Name'); + break; + case 1: + arrValues.push('Duration'); + break; + case 2: + arrValues.push('EST'); + break; + case 3: + arrValues.push('PercentComplete'); + break; + case 4: + arrValues.push('S-F'); + break; + default: + break; + } + } + } + return arrValues; +}; + +GanttChart.prototype.getValueShowProject = function(param) +{ + var arrValues = []; + for (var i = 0; i < param.length; i++) { + + if (param[i]) + { + switch (i) { + case 0: + arrValues.push('Name'); + break; + case 1: + arrValues.push('Duration'); + break; + case 2: + arrValues.push('StartDate'); + break; + case 3: + arrValues.push('PercentComplete'); + break; + + default: + break; + } + } + } + return arrValues; +}; + +/** + * @desc: make Gantt Chart editable by user + * @param: isEditable - (true/false) + * @type: public + * @topic: 0 + * @before_init: 1 + */ +GanttChart.prototype.setEditable = function(isEditable) +{ + this.isEditable = isEditable; +}; +//#__pro_feature:01102007{ +/** + * @desc: show left side tree panel + * @param: show - (true/false) + * @type: public + * @topic: 0 + * @before_init: 1 + * @edition: Professional + */ +GanttChart.prototype.showTreePanel = function(show) +{ + this._showTreePanel = show; +}; +/** + * @desc: show task & project tooltip + * @param: show - (true/false) + * @type: public + * @topic: 0 + * @before_init: 1 + */ +GanttChart.prototype.showTooltip = function(show) +{ + this._showTooltip = show; +}; +//#} +/** + * @desc: Get current project by id + * @param: id - id of current project + * @type: public + * @topic: 2 + */ +GanttChart.prototype.getProjectById = function(id) +{ + + for (var i = 0; i < this.arrProjects.length; i++) { + + if (this.arrProjects[i].Project.Id == id) + { + return this.arrProjects[i]; + } + } + return null; +}; +/** + * @desc: Get browser type + * @type: private + * @topic: 4 + */ +GanttChart.prototype.getBrowserType = function() +{ + + if (navigator.appName.indexOf('Explorer') != -1) + { + this._isIE = true; + + } else if (navigator.userAgent.indexOf('Mozilla') != -1) + { + this._isFF = true; + + } else if (navigator.userAgent.indexOf('Opera') != -1) + { + this._isOpera = true; + } +}; +/** + * @desc: Add new project + * @param: project - (object) GanttProjectInfo + * @type: public + * @topic: 0 + * @before_init: 1 + */ +GanttChart.prototype.addProject = function(projectInfo) +{ + this.Project.push(projectInfo); +}; +/** + * @desc: Removal of GanttTask + * @param: id - id of GanttTask + * @type: public + * @topic: 1 + */ +GanttProject.prototype.deleteTask = function(id) +{ + var task = this.getTaskById(id); + if (task) { + this.deleteChildTask(task); + } else { + this.Chart.Error.throwError("DATA_INSERT_ERROR", 30, [id]); + } +}; +/** + * @desc: Removal of GanttProject + * @param: id - id of project + * @type: public + * @topic: 1 + */ +GanttChart.prototype.deleteProject = function(id) +{ + var project = this.getProjectById(id); + + if (project) + { + if (project.arrTasks.length > 0) + { + while (project.arrTasks.length > 0) { + project.deleteChildTask(project.arrTasks[0]); + } + } + + if (project.nextProject)project.shiftNextProject(project, -23); + + for (var i = 0; i < this.Project.length; i++) { + + if (this.Project[i].Id == project.Project.Id) { + this.Project.splice(i, 1); + } + } + + + if ((project.previousProject) && + (project.nextProject)) + { + var previousProject = project.previousProject; + previousProject.nextProject = project.nextProject; + } + + if ((project.previousProject) && + !(project.nextProject)) + { + var previousProject = project.previousProject; + previousProject.nextProject = null; + + } + if (!(project.previousProject) && + (project.nextProject)) + { + var nextProject = project.nextProject; + nextProject.previousProject = null; + + } + + for (var i = 0; i < this.arrProjects.length; i++) { + + if (this.arrProjects[i].Project.Id == id) + { + this.arrProjects.splice(i, 1); + } + } + + project.projectItem[0].parentNode.removeChild(project.projectItem[0]); + + if (this.isShowDescProject) { + project.descrProject.parentNode.removeChild(project.descrProject); + } + + if (this._showTreePanel) { + project.projectNameItem.parentNode.removeChild(project.projectNameItem); + } + + this._oDataHeight -= 11 + this.heightTaskItem; + + if (this.Project.length == 0) + { + if (this.isShowNewProject) + { + var d = new Date(this.startDate); + var t = new Date(d.setDate(d.getDate() + 1)); + + var pi = new GanttProjectInfo(1, "New project", t); + this.Project.push(pi); + var project = new GanttProject(this, pi); + project.create(); + this.arrProjects.push(project); + this._oDataHeight += 11 + this.heightTaskItem; + } + } + + + } else { + this.Error.throwError("DATA_INSERT_ERROR", 31, [id]); + } +}; +/** + * @desc: Set name of project. + * @param: name - new name of Project. + * @type: public + * @topic: 0 + */ +GanttProject.prototype.setName = function(name) +{ + if ((name != "") && (name != null)) { + this.Project.Name = name; + if (this.Chart._showTreePanel) + { + this.projectNameItem.innerHTML = name; + this.projectNameItem.title = name; + this.checkWidthProjectNameItem(); + } + + if (this.Chart.isShowDescProject)this.descrProject.innerHTML = this.getDescStr(); + this.addDayInPanelTime(); + } +}; +/** + * @desc: Set Percent Completed of project + * @param: percentCompleted - percent completed of Project + * @type: public + * @topic: 0 + */ +GanttProject.prototype.setPercentCompleted = function(percentCompleted) +{ + percentCompleted = parseInt(percentCompleted); + if (isNaN(percentCompleted)) + { + this.Chart.Error.throwError("DATA_INSERT_ERROR", 6, null); + return false; + } + + if (percentCompleted > 100) + { + this.Chart.Error.throwError("DATA_INSERT_ERROR", 7, null); + return false; + + } else if (percentCompleted < 0) + { + this.Chart.Error.throwError("DATA_INSERT_ERROR", 8, null); + return false; + } + + if ((percentCompleted > 0) && (percentCompleted < 100) && (this.percentCompleted > 0) && (this.percentCompleted < 100)) + { + this.projectItem[0].firstChild.rows[0].cells[0].width = parseInt(percentCompleted) + "%"; + this.projectItem[0].firstChild.rows[0].cells[0].firstChild.style.width = (percentCompleted * this.Duration * this.Chart.hourInPixelsWork) / 100 + "px"; + this.projectItem[0].firstChild.rows[0].cells[1].width = (100 - parseInt(percentCompleted)) + "%"; + this.projectItem[0].firstChild.rows[0].cells[1].firstChild.style.width = ((100 - percentCompleted) * this.Duration * this.Chart.hourInPixelsWork) / 100 + "px"; + + } else if (((percentCompleted == 0) || (percentCompleted == 100)) && (this.percentCompleted > 0) && (this.percentCompleted < 100)) + { + if (percentCompleted == 0) + { + this.projectItem[0].firstChild.rows[0].cells[0].parentNode.removeChild(this.projectItem[0].firstChild.rows[0].cells[0]); + this.projectItem[0].firstChild.rows[0].cells[0].width = 100 + "%"; + this.projectItem[0].firstChild.rows[0].cells[0].firstChild.style.width = this.Duration * this.Chart.hourInPixelsWork + "px"; + + } else if (percentCompleted == 100) + { + this.projectItem[0].firstChild.rows[0].cells[1].parentNode.removeChild(this.projectItem[0].firstChild.rows[0].cells[1]); + this.projectItem[0].firstChild.rows[0].cells[0].width = 100 + "%"; + this.projectItem[0].firstChild.rows[0].cells[0].firstChild.style.width = this.Duration * this.Chart.hourInPixelsWork + "px"; + } + + } else if (((percentCompleted == 0) || (percentCompleted == 100)) && ((this.percentCompleted == 0) || (this.percentCompleted == 100))) + { + if ((percentCompleted == 0) && (this.percentCompleted == 100)) + { + this.projectItem[0].firstChild.rows[0].cells[0].firstChild.src = this.Chart.imgs + "progress_bg.png"; + + } else if ((percentCompleted == 100) && (this.percentCompleted == 0)) + { + this.projectItem[0].firstChild.rows[0].cells[0].firstChild.src = this.Chart.imgs + "parentnode_filled.png"; + } + + } else if (((percentCompleted > 0) || (percentCompleted < 100)) && ((this.percentCompleted == 0) || (this.percentCompleted == 100))) + { + this.projectItem[0].firstChild.rows[0].cells[0].parentNode.removeChild(this.projectItem[0].firstChild.rows[0].cells[0]); + + var cellprojectItem = document.createElement("TD"); + this.projectItem[0].firstChild.rows[0].appendChild(cellprojectItem); + cellprojectItem.width = percentCompleted + "%"; + + var imgPr = document.createElement("img"); + imgPr.style.width = (percentCompleted * this.Duration * this.Chart.hourInPixelsWork) / 100 + "px"; + imgPr.style.height = this.Chart.heightTaskItem + "px"; + cellprojectItem.appendChild(imgPr); + imgPr.src = this.Chart.imgs + "parentnode_filled.png"; + + + cellprojectItem = document.createElement("TD"); + this.projectItem[0].firstChild.rows[0].appendChild(cellprojectItem); + cellprojectItem.width = (100 - percentCompleted) + "%"; + imgPr = document.createElement("img"); + + imgPr.style.width = ((100 - percentCompleted) * this.Duration * this.Chart.hourInPixelsWork) / 100 + "px"; + imgPr.style.height = this.Chart.heightTaskItem + "px"; + cellprojectItem.appendChild(imgPr); + imgPr.src = this.Chart.imgs + "progress_bg.png"; + + } else if (this.percentCompleted == -1) + { + if (percentCompleted == 100) + { + this.projectItem[0].firstChild.rows[0].cells[0].firstChild.src = this.Chart.imgs + "parentnode_filled.png"; + + } else if (percentCompleted < 100 && percentCompleted > 0) + { + + this.projectItem[0].firstChild.rows[0].cells[0].parentNode.removeChild(this.projectItem[0].firstChild.rows[0].cells[0]); + + var cellprojectItem = document.createElement("TD"); + this.projectItem[0].firstChild.rows[0].appendChild(cellprojectItem); + cellprojectItem.width = percentCompleted + "%"; + + var imgPr = document.createElement("img"); + imgPr.style.width = (percentCompleted * this.Duration * this.Chart.hourInPixelsWork) / 100 + "px"; + imgPr.style.height = this.Chart.heightTaskItem + "px"; + cellprojectItem.appendChild(imgPr); + imgPr.src = this.Chart.imgs + "parentnode_filled.png"; + + cellprojectItem = document.createElement("TD"); + this.projectItem[0].firstChild.rows[0].appendChild(cellprojectItem); + cellprojectItem.width = (100 - percentCompleted) + "%"; + imgPr = document.createElement("img"); + + imgPr.style.width = ((100 - percentCompleted) * this.Duration * this.Chart.hourInPixelsWork) / 100 + "px"; + imgPr.style.height = this.Chart.heightTaskItem + "px"; + cellprojectItem.appendChild(imgPr); + imgPr.src = this.Chart.imgs + "progress_bg.png"; + } + + } + + this.percentCompleted = percentCompleted; + if (this.Chart.isShowDescProject)this.descrProject.innerHTML = this.getDescStr(); + return true; +}; +/** + * @desc: Removal of child GanttTask + * @param: task - (object)parent GanttTask + * @type: private + * @topic: 1 + */ +GanttProject.prototype.deleteChildTask = function(task) +{ + if (task) + { + if (task.cTaskItem[0].style.display == "none") { + this.Chart.openTree(task.parentTask); + } + //delete of connecting lines + if (task.childPredTask.length > 0) { + for (var i = 0; i < task.childPredTask.length; i++) + { + for (var t = 0; t < task.childPredTask[i].cTaskItem[1].length; t++) { + task.childPredTask[i].cTaskItem[1][t].parentNode.removeChild(task.childPredTask[i].cTaskItem[1][t]); + } + task.childPredTask[i].cTaskItem[1] = []; + task.childPredTask[i].predTask = null; + } + } + + //delete child task + if (task.childTask.length > 0) { + while (task.childTask.length > 0) { + this.deleteChildTask(task.childTask[0]); + } + } + + //shift tasks + if (task.cTaskItem[0].style.display != "none") task.shiftCurrentTasks(task, -23); + + //delete object task + this.Project.deleteTask(task.TaskInfo.Id); + + //delete div and connecting lines from oData + if (task.cTaskItem[0]) { + task.cTaskItem[0].parentNode.removeChild(task.cTaskItem[0]); + } + + if (this.Chart.isShowDescTask) { + task.descrTask.parentNode.removeChild(task.descrTask); + } + + if (task.cTaskItem[1].length > 0) { + for (var j = 0; j < task.cTaskItem[1].length; j++) { + task.cTaskItem[1][j].parentNode.removeChild(task.cTaskItem[1][j]); + } + } + + //delete div and connecting lines from panelName + if (task.cTaskNameItem[0]) { + task.cTaskNameItem[0].parentNode.removeChild(task.cTaskNameItem[0]); + } + + if (task.cTaskNameItem[1]) { + for (var j = 0; j < task.cTaskNameItem[1].length; j++) { + task.cTaskNameItem[1][j].parentNode.removeChild(task.cTaskNameItem[1][j]); + } + } + + if (task.cTaskNameItem[2]) { + task.cTaskNameItem[2].parentNode.removeChild(task.cTaskNameItem[2]); + } + + //delete object task + if (task.parentTask) + { + if (task.previousChildTask) { + if (task.nextChildTask) { + task.previousChildTask.nextChildTask = task.nextChildTask; + } else { + task.previousChildTask.nextChildTask = null; + } + + } + + var parentTask = task.parentTask; + for (var i = 0; i < parentTask.childTask.length; i++) + { + if (parentTask.childTask[i].TaskInfo.Id == task.TaskInfo.Id) { + parentTask.childTask[i] = null; + parentTask.childTask.splice(i, 1); + break; + } + } + if (parentTask.childTask.length == 0) { + if (parentTask.cTaskNameItem[2]) { + parentTask.cTaskNameItem[2].parentNode.removeChild(parentTask.cTaskNameItem[2]); + parentTask.cTaskNameItem[2] = null; + } + } + } else + { + if (task.previousParentTask) + { + if (task.nextParentTask) { + task.previousParentTask.nextParentTask = task.nextParentTask; + } else { + task.previousParentTask.nextParentTask = null; + } + + } + + var project = task.Project; + for (var i = 0; i < project.arrTasks.length; i++) { + if (project.arrTasks[i].TaskInfo.Id == task.TaskInfo.Id) { + project.arrTasks.splice(i, 1); + } + } + + } + + if (task.predTask) { + var predTask = task.predTask; + for (var i = 0; i < predTask.childPredTask.length; i++) { + + if (predTask.childPredTask[i].TaskInfo.Id == task.TaskInfo.Id) { + predTask.childPredTask[i] = null; + predTask.childPredTask.splice(i, 1); + } + + } + + } + if (task.Project.arrTasks.length != 0) { + task.Project.shiftProjectItem(); + } + else { + task.Project.projectItem[0].style.display = "none"; + if (this.Chart.isShowDescProject) this.hideDescrProject(); + } + this.Chart._oDataHeight -= 11 + this.Chart.heightTaskItem; + } + +}; +/** + * @desc: Insert the task in the project and returns it + * @param: id - Specifies id of task + * @param: name - Specifies name of task + * @param: EST - Specifies est of task + * @param: Duration - Specifies duration of task + * @param: PercentCompleted - Specifies percentCompleted of task + * @param: predecessorTaskId - Specifies predecessorTask Id of task + * @type: public + * @topic: 1 + */ +GanttProject.prototype.insertTask = function(id, name, EST, Duration, PercentCompleted, predecessorTaskId, parentTaskId) +{ + var task = null; + var _task = null; + + if (this.Project.getTaskById(id)) { + this.Chart.Error.throwError("DATA_INSERT_ERROR", 22, [id]); + return false; + } + + if ((!Duration) || (Duration < this.Chart.minWorkLength)) { + Duration = this.Chart.minWorkLength; + } + if ((!name) || (name == "")) { + name = id; + } + if ((!PercentCompleted) || (PercentCompleted == "")) { + PercentCompleted = 0; + + } else { + PercentCompleted = parseInt(PercentCompleted); + + if (PercentCompleted < 0 || PercentCompleted > 100) { + this.Chart.Error.throwError("DATA_INSERT_ERROR", 35, null); + return false; + } + } + + var sortRequired = false; + + if ((parentTaskId) && (parentTaskId != "")) { + var parentTask = this.Project.getTaskById(parentTaskId); + if (!parentTask) { + this.Chart.Error.throwError("DATA_INSERT_ERROR", 21, [parentTaskId]); + return false; + } + + EST = EST || parentTask.EST; + if (EST < parentTask.EST) { + this.Chart.Error.throwError("DATA_INSERT_ERROR", 20, [id,parentTaskId]); + return false; + } + + task = new GanttTaskInfo(id, name, EST, Duration, PercentCompleted, predecessorTaskId); + + if (!this.Chart.checkPosParentTask(parentTask, task)) { + this.Chart.Error.throwError("DATA_INSERT_ERROR", 19, [parentTaskId,id]); + return false; + } + task.ParentTask = parentTask; + + var _parentTask = this.getTaskById(parentTask.Id); + + var isHide = false; + if (_parentTask.cTaskItem[0].style.display == "none") { + isHide = true; + } else if (_parentTask.cTaskNameItem[2]) { + if (!_parentTask._isOpen) { + isHide = true; + } + } + + if (isHide) { + if (_parentTask.childTask.length == 0) { + this.Chart.openTree(_parentTask.parentTask); + } else { + this.Chart.openTree(_parentTask); + } + } + + if (predecessorTaskId != "") + { + var predTask = this.Project.getTaskById(predecessorTaskId); + if (!predTask) { + this.Chart.Error.throwError("DATA_INSERT_ERROR", 27, [predecessorTaskId]); + return false; + } + + if (predTask.ParentTask) { + if (predTask.ParentTask.Id != task.ParentTask.Id) { + this.Chart.Error.throwError("DATA_INSERT_ERROR", 32, [predTask.Id,task.Id]); + return false; + } + } else { + this.Chart.Error.throwError("DATA_INSERT_ERROR", 32, [predTask.Id,task.Id]); + return false; + } + + if (!this.Chart.checkPosPredecessorTask(predTask, task)) { + this.Chart.correctPosPredecessorTask(predTask, task); + } + + task.PredecessorTask = predTask; + } + + var isAdd = false; + + if (sortRequired) for (var i = 0; i < parentTask.ChildTasks.length; i++) { + if (task.EST < parentTask.ChildTasks[i].EST) + { + parentTask.ChildTasks.splice(i, 0, task); + if (i > 0) { + parentTask.ChildTasks[i - 1].nextChildTask = parentTask.ChildTasks[i]; + parentTask.ChildTasks[i].previousChildTask = parentTask.ChildTasks[i - 1]; + } + if (parentTask.ChildTasks[i + 1]) { + parentTask.ChildTasks[i + 1].previousChildTask = parentTask.ChildTasks[i]; + parentTask.ChildTasks[i].nextChildTask = parentTask.ChildTasks[i + 1]; + } + isAdd = true; + break; + } + } + + if (!isAdd) { + if (parentTask.ChildTasks.length > 0) { + parentTask.ChildTasks[parentTask.ChildTasks.length - 1].nextChildTask = task; + task.previousChildTask = parentTask.ChildTasks[parentTask.ChildTasks.length - 1]; + } + parentTask.ChildTasks.push(task); + } + + if (parentTask.ChildTasks.length == 1) { + _parentTask.cTaskNameItem[2] = _parentTask.createTreeImg(); + } + + _task = new GanttTask(task, this, this.Chart); + _task.create(); + + if (task.nextChildTask) _task.nextChildTask = _task.Project.getTaskById(task.nextChildTask.Id); + _task.addDayInPanelTime(); + _task.shiftCurrentTasks(_task, 23); + + } else + { + + EST = EST || this.Project.StartDate; + + task = new GanttTaskInfo(id, name, EST, Duration, PercentCompleted, predecessorTaskId); + + if (task.EST <= this.Chart.startDate) { + this.Chart.Error.throwError("DATA_INSERT_ERROR", 18, [task.Id]); + return false; + } + + if (predecessorTaskId != "") { + var predTask = this.Project.getTaskById(predecessorTaskId); + if (!predTask) { + this.Chart.Error.throwError("DATA_INSERT_ERROR", 27, [predecessorTaskId]); + return false; + } + + if (!this.Chart.checkPosPredecessorTask(predTask, task)) { + this.Chart.correctPosPredecessorTask(predTask, task); + } + + if (predTask.ParentTask) { + this.Chart.Error.throwError("DATA_INSERT_ERROR", 15, [task.Id,predTask.Id]); + return false; + } + task.PredecessorTask = predTask; + } + var isAdd = false; + + if (sortRequired) for (var i = 0; i < this.Project.ParentTasks.length; i++) { + + if (EST < this.Project.ParentTasks[i].EST) + { + this.Project.ParentTasks.splice(i, 0, task); + if (i > 0) { + this.Project.ParentTasks[i - 1].nextParentTask = task; + task.previousParentTask = this.Project.ParentTasks[i - 1]; + } + if (this.Project.ParentTasks[i + 1]) { + this.Project.ParentTasks[i + 1].previousParentTask = task; + task.nextParentTask = this.Project.ParentTasks[i + 1]; + } + isAdd = true; + break; + } + } + + if (!isAdd) { + if (this.Project.ParentTasks.length > 0) { + this.Project.ParentTasks[this.Project.ParentTasks.length - 1].nextParentTask = task; + task.previousParentTask = this.Project.ParentTasks[this.Project.ParentTasks.length - 1]; + } + this.Project.ParentTasks.push(task); + } + + _task = new GanttTask(task, this, this.Chart); + _task.create(); + if (task.nextParentTask) _task.nextParentTask = _task.Project.getTaskById(task.nextParentTask.Id); + _task.addDayInPanelTime(); + + this.arrTasks.push(_task); + _task.shiftCurrentTasks(_task, 23); + this.projectItem[0].style.display = "inline"; + this.setPercentCompleted(this.getPercentCompleted()); + this.shiftProjectItem(); + + if (this.Chart.isShowDescProject) { + this.showDescrProject(); + } + + } + + this.Chart.checkHeighPanelTasks(); + + return _task; +}; +/** + * @desc: Check Position of predecessor task + * @param: predTask - (object) predecessor task + * @param: task - (object) current task + * @type: private + * @topic: 4 + */ +GanttChart.prototype.checkPosPredecessorTask = function(predTask, task) +{ + var widthPred = this.getWidthOnDuration(predTask.Duration); + var posPred = this.getPosOnDate(predTask.EST); + var posChild = this.getPosOnDate(task.EST); + return (widthPred + posPred) <= posChild; + +}; +GanttChart.prototype.correctPosPredecessorTask = function(predTask, ctask, ctaskObj) +{ + var newDate = new Date(predTask.EST); + newDate.setHours(newDate.getHours() + (predTask.Duration / this.hoursInDay * 24)); + if (newDate.getHours() > 0) { + newDate.setHours(0); + newDate.setDate(newDate.getDate() + 1); + } + + if (ctaskObj) ctaskObj.setEST(newDate, true); + else ctask.EST = newDate; + + if (ctask.ParentTask) + { + if (!this.checkPosParentTask(ctask.ParentTask, ctask)) + { + var newDate2 = new Date(ctask.ParentTask.EST); + newDate2.setHours(newDate2.getHours() + (ctask.ParentTask.Duration / this.hoursInDay * 24)); + ctask.Duration = parseInt((parseInt((newDate2 - ctask.EST) / (1000 * 60 * 60))) * this.hoursInDay / 24); + } + } +}; +GanttChart.prototype.correctPosParentTask = function(parentTask, ctask) +{ + if (!ctask.PredecessorTask) + { + if (parentTask.EST > ctask.EST) { + ctask.EST = new Date(parentTask.EST); + } + if (!this.checkPosParentTask(parentTask, ctask)) { + ctask.Duration = parentTask.Duration; + } + } else + { + this.correctPosPredecessorTask(ctask.PredecessorTask, ctask); + } +}; + +/** + * @desc: Check position of parent task + * @param: parentTask - (object) parent task + * @type: private + * @topic: 4 + */ +GanttChart.prototype.checkPosParentTaskInTree = function(parentTask) +{ + var isError = false; + for (var t = 0; t < parentTask.ChildTasks.length; t++) + { + + if (!this.checkPosParentTask(parentTask, parentTask.ChildTasks[t])) + { + if (!this.correctError) { + this.Error.throwError("DATA_ERROR", 28, [parentTask.Id,parentTask.ChildTasks[t].Id]); + return true; + } else { + this.correctPosParentTask(parentTask, parentTask.ChildTasks[t]); + } + } + if (parentTask.EST > parentTask.ChildTasks[t].EST) + { + if (!this.correctError) { + this.Error.throwError("DATA_ERROR", 33, [parentTask.Id,parentTask.ChildTasks[t].Id]); + return true; + } else { + this.correctPosParentTask(parentTask, parentTask.ChildTasks[t]); + } + } + + if (parentTask.ChildTasks[t].ChildTasks.length > 0) + { + isError = this.checkPosParentTaskInTree(parentTask.ChildTasks[t]); + } + + } + return isError; +}; +/** + * @desc: Set Predecessor Task to child + * @param: project - (object) current Project + * @type: private + * @topic: 0 + */ +GanttChart.prototype.setPredTask = function(project) +{ + var isError = false; + for (var k = 0; k < project.ParentTasks.length; k++) { + + if (!this.isEmpty(project.ParentTasks[k].PredecessorTaskId)) + { + project.ParentTasks[k].PredecessorTask = project.getTaskById(project.ParentTasks[k].PredecessorTaskId); + if (!project.ParentTasks[k].PredecessorTask) { + if (!this.correctError) { + this.Error.throwError("DATA_ERROR", 27, [project.ParentTasks[k].PredecessorTaskId]); + return true; + } + } + + project.ParentTasks[k].PredecessorTask.ChildPredTasks.push(project.ParentTasks[k]); + } + + if (project.ParentTasks[k].PredecessorTask) + { + if (!this.checkPosPredecessorTask(project.ParentTasks[k].PredecessorTask, project.ParentTasks[k])) { + if (!this.correctError) { + this.Error.throwError("DATA_ERROR", 26, [project.ParentTasks[k].PredecessorTask.Id,project.ParentTasks[k].Id]); + return true; + } else { + this.correctPosPredecessorTask(project.ParentTasks[k].PredecessorTask, project.ParentTasks[k]); + } + + } + } + isError = this.setPredTaskInTree(project.ParentTasks[k]); + if (isError) return isError; + } + return isError; + +}; +/** + * @desc: Set Predecessor Task to child + * @param: project - (object) current parent task + * @type: private + * @topic: 0 + */ +GanttChart.prototype.setPredTaskInTree = function(parentTask) +{ + var isError = false; + for (var t = 0; t < parentTask.ChildTasks.length; t++) + { + if (!this.isEmpty(parentTask.ChildTasks[t].PredecessorTaskId)) + { + parentTask.ChildTasks[t].PredecessorTask = parentTask.Project.getTaskById(parentTask.ChildTasks[t].PredecessorTaskId); + if (!parentTask.ChildTasks[t].PredecessorTask) + { + if (!this.correctError) { + this.Error.throwError("DATA_ERROR", 27, [parentTask.ChildTasks[t].PredecessorTaskId]); + return true; + } + + } + + if (!this.checkPosPredecessorTask(parentTask.ChildTasks[t].PredecessorTask, parentTask.ChildTasks[t])) + { + if (!this.correctError) { + this.Error.throwError("DATA_ERROR", 26, [parentTask.ChildTasks[t].PredecessorTask.Id,parentTask.ChildTasks[t].Id]); + return true; + } else { + this.correctPosPredecessorTask(parentTask.ChildTasks[t].PredecessorTask, parentTask.ChildTasks[t]); + } + } + parentTask.ChildTasks[t].PredecessorTask.ChildPredTasks.push(parentTask.ChildTasks[t]); + } + + if (parentTask.ChildTasks[t].ChildTasks.length > 0) + { + isError = this.setPredTaskInTree(parentTask.ChildTasks[t]); + } + + } + return isError; +}; +/** + * @desc: Check Position of Parent Task + * @param: parentTask - (object) Parent Task + * @param: task - (object) current Task + * @type: private + * @topic: 4 + */ +GanttChart.prototype.checkPosParentTask = function(parentTask, task) +{ + var widthParent = this.getWidthOnDuration(parentTask.Duration); + var posParent = this.getPosOnDate(parentTask.EST); + var posChild = this.getPosOnDate(task.EST); + var widthChild = this.getWidthOnDuration(task.Duration); + return (widthParent + posParent) >= (posChild + widthChild); +}; +/** + * @desc: Insert new GanttProject and returns it + * @param: id - id of project + * @param: name - name of project + * @param: startDate - Start Date of project + * @type: public + * @topic: 1 + */ +GanttChart.prototype.insertProject = function(id, name, startDate) +{ + if (this._isError) + { + this.clearData(); + this.clearItems(); + this.hidePanelErrors(); + this._isError = false; + } + + if (this.startDate >= startDate) { + this.Error.throwError("DATA_INSERT_ERROR", 14, null); + return false; + } + + if (this.getProjectById(id)) { + this.Error.throwError("DATA_INSERT_ERROR", 23, [id]); + return false; + } + + this.checkHeighPanelTasks(); + + var project = new GanttProjectInfo(id, name, startDate); + + this.Project.push(project); + + var _project = new GanttProject(this, project); + + for (var i = 0; i < this.arrProjects.length; i++) { + + if (startDate < this.arrProjects[i].Project.StartDate) { + this.arrProjects.splice(i, 0, _project); + if (i > 0) { + _project.previousProject = this.arrProjects[i - 1]; + this.arrProjects[i - 1].nextProject = _project; + } + if (i + 1 <= this.arrProjects.length) { + _project.nextProject = this.arrProjects[i + 1]; + this.arrProjects[i + 1].previousProject = _project; + _project.shiftNextProject(_project, 23); + } + _project.create(); + + if (this.isShowDescProject) { + _project.hideDescrProject(); + } + return _project; + } + } + + if (this.arrProjects.length > 0) { + this.arrProjects[this.arrProjects.length - 1].nextProject = _project; + _project.previousProject = this.arrProjects[this.arrProjects.length - 1]; + } + + this.arrProjects.push(_project); + _project.create(); + + if (this.isShowDescProject) { + _project.hideDescrProject(); + } + + return _project; +}; +/** + * @desc: show context menu in tree in current position + * @type: private + * @topic: 4 + */ +GanttChart.prototype._showContextMenu = function(event, obj) +{ + if (this.contextMenu.isDhtmlxMenuObject) { + var res = this.callEvent("onBeforeContextMenu", [this.contextMenu, obj]); + if (res === false) return; + + var x, y; + if (_isIE){ + var dEl0 = window.document.documentElement, dEl1 = window.document.body, corrector = new Array((dEl0.scrollLeft||dEl1.scrollLeft),(dEl0.scrollTop||dEl1.scrollTop)); + x = event.clientX + corrector[0]; + y = event.clientY + corrector[1]; + } else { + x = event.pageX; + y = event.pageY; + } + this.contextMenu.showContextMenu(x-1, y-1); + } else { + var elem = event.srcElement || event.target; + this.contextMenu.showContextMenu(elem.style.left, elem.style.top, obj); + } + +}; +/** + * @desc: Opens a tree + * @param: parentTask - (object) parent task + * @type: private + * @topic: 3 + */ +GanttChart.prototype.openTree = function(parentTask) +{ + var lastParentTask = this.getLastCloseParent(parentTask); + if (parentTask.TaskInfo.Id != lastParentTask.TaskInfo.Id) { + + this.openNode(lastParentTask); + this.openTree(parentTask); + + } else { + this.openNode(lastParentTask); + } +}; +/** + * @desc: Opens current node + * @param: parentTask - (object) parent task + * @type: private + * @topic: 3 + */ +GanttChart.prototype.openNode = function(parentTask) +{ + if (!parentTask._isOpen) + { + parentTask.cTaskNameItem[2].src = this.imgs + "minus.gif"; + parentTask._isOpen = true; + parentTask.shiftCurrentTasks(parentTask, parentTask._heightHideTasks); + parentTask.showChildTasks(parentTask, parentTask._isOpen); + parentTask._heightHideTasks = 0; + } +}; +/** + * @desc: get last close parent + * @param: task - (object) task + * @type: private + * @topic: 2 + */ +GanttChart.prototype.getLastCloseParent = function(task) +{ + if (task.parentTask) + { + if ((!task.parentTask._isOpen) || + (task.parentTask.cTaskNameItem[2].style.display == "none")) { + return this.getLastCloseParent(task.parentTask); + + } else { + return task; + } + + } else { + return task; + } +}; +/** + * @desc: create a connection line between this task and predecessor + * @param: predecessorTaskId - ID of the predecessor Task + * @type: public + * @topic: 0 + */ +GanttTask.prototype.setPredecessor = function(predecessorTaskId) +{ + if (predecessorTaskId == "") this.clearPredTask(); + else + { + var task = this.TaskInfo; + if (task.Id == predecessorTaskId) { + this.Chart.Error.throwError("DATA_INSERT_ERROR", 36); + return false; + } + + var predTaskObj = this.Project.getTaskById(predecessorTaskId); + if (!predTaskObj) { + this.Chart.Error.throwError("DATA_INSERT_ERROR", 27, [predecessorTaskId]); + return false; + } + var predTask = predTaskObj.TaskInfo; + var a1 = predTask.ParentTask == null, a2 = task.ParentTask == null; + if (a1 && !a2 || !a1 && a2 || !a1 && !a2 && (predTask.ParentTask.Id != task.ParentTask.Id)) { + this.Chart.Error.throwError("DATA_INSERT_ERROR", 32, [predTask.Id,task.Id]); + return false; + } + + // remove current connection + this.clearPredTask(); + + if (!this.Chart.checkPosPredecessorTask(predTask, task)) { + this.Chart.correctPosPredecessorTask(predTask, task, this); + } + + task.PredecessorTaskId = predecessorTaskId; + task.PredecessorTask = predTask; + this.predTask = predTaskObj; + predTaskObj.childPredTask.push(this); + + this.cTaskItem[1] = this.createConnectingLinesDS(); + } + return true; +}; + +/** + * @desc: remove references and connections to predecessor task + * @type: private + * @topic: 0 + */ +GanttTask.prototype.clearPredTask = function() { + if (this.predTask) { + var ch = this.predTask.childPredTask; + for (var i = 0; i < ch.length; i++) { + if (ch[i] == this) { + ch.splice(i, 1); + break; + } + } + for (var i = 0; i < this.cTaskItem[1].length; i++) { + this.cTaskItem[1][i].parentNode.removeChild(this.cTaskItem[1][i]); + } + this.cTaskItem[1] = []; + + this.TaskInfo.PredecessorTaskId = null; + this.TaskInfo.PredecessorTask = null; + this.predTask = null; + } +}; + +/** + * @desc: shifts the task + * @param: est - est of current Task + * @param: shiftChild - (true/false) to shift children or not + * @type: public + * @topic: 0 + */ +GanttTask.prototype.setEST = function(est, shiftChild) +{ + this.moveChild = shiftChild; + this.getMoveInfo(); + + var pos = this.Chart.getPosOnDate(est); + if ((parseInt(this.cTaskItem[0].firstChild.firstChild.width) + pos > this.maxPosXMove) && (this.maxPosXMove != -1)) + { + this.Chart.Error.throwError("DATA_INSERT_ERROR", 12, [this.TaskInfo.Id]); + this.maxPosXMove = -1; + this.minPosXMove = -1; + return false; + } + + if (pos < this.minPosXMove) + { + this.Chart.Error.throwError("DATA_INSERT_ERROR", 11, [this.TaskInfo.Id]); + this.maxPosXMove = -1; + this.minPosXMove = -1; + return false; + } + + this.cTaskItem[0].style.left = pos; + + var width = pos - this.posX; + this.moveCurrentTaskItem(width, shiftChild); + this.Project.shiftProjectItem(); + if (this.Chart.isShowDescTask)this.descrTask.innerHTML = this.getDescStr(); + this.addDayInPanelTime(); + this.posX = 0; + this.maxPosXMove = -1; + this.minPosXMove = -1; + return true; +}; +/** + * @desc: set duration of the current task + * @param: duration - (int) duration of current task in hours + * @type: public + * @topic: 0 + */ +GanttTask.prototype.setDuration = function(duration) +{ + this.getResizeInfo(); + var width = this.Chart.getWidthOnDuration(duration); + if ((width > this.maxWidthResize) && (this.maxWidthResize != -1)) + { + this.Chart.Error.throwError("DATA_INSERT_ERROR", 10, [this.TaskInfo.Id]); + return false; + } else if (width < this.minWidthResize) + { + this.Chart.Error.throwError("DATA_INSERT_ERROR", 9, [this.TaskInfo.Id]); + return false; + } else { + this.taskItemWidth = parseInt(this.cTaskItem[0].firstChild.firstChild.width); + this.resizeTaskItem(width); + this.endResizeItem(); + if (this.Chart.isShowDescTask)this.descrTask.innerHTML = this.getDescStr(); + return true; + } + +}; +/** + * @desc: establishes percent completed of the current task + * @param: percentCompleted - (int) percent completed of current task + * @type: public + * @topic: 0 + */ +GanttTask.prototype.setPercentCompleted = function(percentCompleted) +{ + percentCompleted = parseInt(percentCompleted); + if (isNaN(percentCompleted)) + { + this.Chart.Error.throwError("DATA_INSERT_ERROR", 6, null); + return false; + } + + if (percentCompleted > 100) + { + this.Chart.Error.throwError("DATA_INSERT_ERROR", 7, null); + return false; + } + if (percentCompleted < 0) + { + this.Chart.Error.throwError("DATA_INSERT_ERROR", 8, null); + return false; + } + + if ((percentCompleted != 0) && (percentCompleted != 100)) + { + if ((this.TaskInfo.PercentCompleted != 0) && (this.TaskInfo.PercentCompleted != 100)) + { + this.cTaskItem[0].childNodes[0].firstChild.rows[0].cells[0].width = percentCompleted + "%"; + this.cTaskItem[0].childNodes[0].firstChild.rows[0].cells[1].width = 100 - percentCompleted + "%"; + + } else if ((this.TaskInfo.PercentCompleted == 0) || (this.TaskInfo.PercentCompleted == 100)) + { + this.cTaskItem[0].childNodes[0].firstChild.rows[0].cells[0].parentNode.removeChild(this.cTaskItem[0].childNodes[0].firstChild.rows[0].cells[0]); + + var cellTblTask = document.createElement("td"); + this.cTaskItem[0].childNodes[0].firstChild.rows[0].appendChild(cellTblTask); + cellTblTask.height = this.Chart.heightTaskItem + "px"; + cellTblTask.width = percentCompleted + "%"; + + var imgPrF = document.createElement("img"); + imgPrF.style.width = (percentCompleted * this.TaskInfo.Duration * this.Chart.hourInPixelsWork) / 100 + "px"; + imgPrF.style.height = this.Chart.heightTaskItem + "px"; + cellTblTask.appendChild(imgPrF); + imgPrF.src = this.Chart.imgs + "progress_filled.png"; + + cellTblTask = document.createElement("td"); + this.cTaskItem[0].childNodes[0].firstChild.rows[0].appendChild(cellTblTask); + cellTblTask.height = this.Chart.heightTaskItem + "px"; + cellTblTask.width = (100 - percentCompleted) + "%"; + + imgPrF = document.createElement("img"); + imgPrF.style.width = ((100 - percentCompleted) * this.TaskInfo.Duration * this.Chart.hourInPixelsWork) / 100 + "px"; + imgPrF.style.height = this.Chart.heightTaskItem + "px"; + cellTblTask.appendChild(imgPrF); + imgPrF.src = this.Chart.imgs + "progress_bg.png"; + } + } else if (percentCompleted == 0) + { + if ((this.TaskInfo.PercentCompleted != 0) && (this.TaskInfo.PercentCompleted != 100)) + { + this.cTaskItem[0].childNodes[0].firstChild.rows[0].cells[0].parentNode.removeChild(this.cTaskItem[0].childNodes[0].firstChild.rows[0].cells[0]); + this.cTaskItem[0].childNodes[0].firstChild.rows[0].cells[0].width = 100 + "%"; + + } else + { + this.cTaskItem[0].childNodes[0].firstChild.rows[0].cells[0].firstChild.src = this.Chart.imgs + "progress_bg.png"; + } + + } else if (percentCompleted == 100) + { + + if ((this.TaskInfo.PercentCompleted != 0) && (this.TaskInfo.PercentCompleted != 100)) + { + this.cTaskItem[0].childNodes[0].firstChild.rows[0].cells[1].parentNode.removeChild(this.cTaskItem[0].childNodes[0].firstChild.rows[0].cells[1]); + this.cTaskItem[0].childNodes[0].firstChild.rows[0].cells[0].width = 100 + "%"; + + } else + { + this.cTaskItem[0].childNodes[0].firstChild.rows[0].cells[0].firstChild.src = this.Chart.imgs + "progress_filled.png"; + } + } + + this.TaskInfo.PercentCompleted = percentCompleted; + this.taskItemWidth = parseInt(this.cTaskItem[0].firstChild.firstChild.width); + this.resizeTaskItem(this.taskItemWidth); + this.endResizeItem(); + if (this.Chart.isShowDescTask)this.descrTask.innerHTML = this.getDescStr(); + return true; +}; +/** + * @desc: set name of the current task + * @param: name - (string) name of the current task + * @type: public + * @topic: 0 + */ +GanttTask.prototype.setName = function(name) +{ + + if ((name != "") && (name != null)) { + this.TaskInfo.Name = name; + if (this.Chart._showTreePanel) + { + this.cTaskNameItem[0].innerHTML = name; + this.cTaskNameItem[0].title = name; + this.checkWidthTaskNameItem(); + } + if (this.Chart.isShowDescTask)this.descrTask.innerHTML = this.getDescStr(); + this.addDayInPanelTime(); + + } +}; +/** + * @desc: get projectInfo by id + * @param: id - Project id + * @type: private + * @topic: 2 + */ +GanttChart.prototype.getProjectInfoById = function(id) +{ + + for (var i = 0; i < this.Project.length; i++) + { + if (this.Project[i].Id == id) + { + return this.Project[i]; + } + } + return null; +}; + +/** + * @desc: load xml data from string or file + * @param: content - (string) XML string or fileName + * @param: isFile - (true/false) if the content is a file name or XML string. if youload from file, setLoadPath() url is used, fileName is passed in "path" field + * @param: isLocal - (true/false) if the file is a local file (for debugging purposes) or remote (server-side) + * @type: public + * @topic: 6 + */ +GanttChart.prototype.loadData = function(content, isFile, isLocal) +{ + this.clearData(); + + if ((isFile == null) || (isFile == 'undefined')) + { + isFile = false; + } + if ((isLocal == null) || (isLocal == 'undefined')) + { + isLocal = false; + } + this.loadXML(content, isFile, isLocal); + + this.Project.sort(this.sort_byStartDate); + this.startDate = this.getStartDate(); + + this.clearItems(); + //this.panelTime.removeChild(this.panelTime.firstChild); + //this.panelTime.appendChild(this.createPanelTime()); + + for (var i = 0; i < this.Project.length; i++) + { + for (var k = 0; k < this.Project[i].ParentTasks.length; k++) + { + if ((this.Project[i].ParentTasks[k].EST != null) && (this.Project[i].ParentTasks[k].EST != '')) { + this.setESTChild(this.Project[i].ParentTasks[k]); + } + else { + this.Error.throwError("DATA_ERROR", 25, [this.Project[i].ParentTasks[k].Id]); + return; + } + + if (this.setPredTask(this.Project[i])) return; + } + + for (var k = 0; k < this.Project[i].ParentTasks.length; k++) { + if (this.Project[i].ParentTasks[k].EST < this.Project[i].StartDate) { + this.Error.throwError("DATA_ERROR", 24, [this.Project[i].ParentTasks[k].Id,this.Project[i].Id]); + return; + } + if (this.checkPosParentTaskInTree(this.Project[i].ParentTasks[k])) return; + } + + this.sortTasksByEST(this.Project[i]); + + } + + for (var i = 0; i < this.Project.length; i++) + { + + var project = new GanttProject(this, this.Project[i]); + + if (this.arrProjects.length > 0) + { + var previousProject = this.arrProjects[this.arrProjects.length - 1]; + project.previousProject = previousProject; + previousProject.nextProject = project; + } + + project.create(); + + this.checkHeighPanelTasks(); + this.arrProjects.push(project); + this.createTasks(project); + + } + +}; + +/** + * @desc: Clearing of a control + * @type: public + * @topic: 1 + */ +GanttChart.prototype.clearAll = function() +{ + this._oDataHeight = 0; + this.startDate = null; + this._isError = false; + + this.hidePanelErrors(); + this.clearData(); + this.clearItems(); + +}; +/** + * @desc: deleting of a data + * @type: private + * @topic: 1 + */ +GanttChart.prototype.clearData = function() +{ + this._oDataHeight = 0; + this.startDate = null; + this._isError = false; + + this.hidePanelErrors(); + + this.Project = []; + this.arrProjects = []; +}; +/** + * @desc: deleting of items of a control + * @type: private + * @topic: 1 + */ +GanttChart.prototype.clearItems = function() +{ + this.oData.removeChild(this.oData.firstChild); + this.oData.appendChild(this.createPanelTasks()); + this.oData.firstChild.appendChild(this.divInfo); + this.oData.firstChild.appendChild(this.panelErrors); + if (this._showTreePanel) + { + this.panelNames.removeChild(this.panelNames.firstChild); + this.panelNames.appendChild(this.createPanelNamesTasks()); + } + this.panelTime.removeChild(this.panelTime.firstChild); + this.panelTime.appendChild(this.createPanelTime()); +}; + +/** + * @desc: load xml data + * @param: content - (string) XML string or fileName + * @param: isFile - (true/false) if the content is a file name or XML string + * @param: isLocal - (true/false) if the file is a local file (for debugging purposes) or remote (server-side) + * @type: private + * @topic: 6 + */ +GanttChart.prototype.loadXML = function(content, isFile, isLocal) +{ + if (isFile && (content == null || content == "")) + { + this.Error.throwError("DATA_SEND_ERROR", 4, null); + return; + } + + this.xmlLoader = new dtmlXMLLoaderObject(null, this, false); + + try + { + if (!isFile) + try { + this.xmlLoader.loadXMLString(content); + } catch (e) { + this.Error.throwError("DATA_LOAD_ERROR", 37, [content]); + } else + if (!isLocal) + { + this.xmlLoader.loadXML(this.loadPath + "?path=" + content + "&rnd=" + (new Date() - 0), false); + + } else + { + this.xmlLoader.loadXML(content + "?rnd=" + (new Date() - 0), false); + } + this.doLoadDetails(isLocal); + + } catch(e) + { + this.Error.throwError("DATA_LOAD_ERROR", 5, [content]); + } + +}; +/** + * @desc: parsing of XML data + * @type: private + * @topic: 4 + */ +GanttChart.prototype.doLoadDetails = function(isLocal) +{ + switch (this.xmlLoader.xmlDoc.status) { + case 0: + if (!isLocal) + { + this.Error.throwError("DATA_LOAD_ERROR", 1, null); + return; + } + break; + case 404: + if (!isLocal) + { + this.Error.throwError("DATA_LOAD_ERROR", 5, [this.loadPath]); + + } else + { + this.Error.throwError("DATA_LOAD_ERROR", 5, [this.xmlLoader.filePath]) + } + return; + break; + case 500: + this.Error.throwError("DATA_LOAD_ERROR", 2, null); + return; + break; + default: + break; + } + + var name = null; + var id = null; + var est = null; + var duration = null; + var percentCompleted = null; + var predecessorTaskId = null; + + //var prArr = []; + //var tsArr = []; + //var rootTagProject = this.xmlLoader.getXMLTopNode("projects"); + var projectArr = this.xmlLoader.doXPath("//project"); + + for (var j = 0; j < projectArr.length; j++) + { + var startDateTemp = projectArr[j].getAttribute("startdate"); + var startDate = startDateTemp.split(","); + var project = new GanttProjectInfo(projectArr[j].getAttribute("id"), projectArr[j].getAttribute("name"), new Date(startDate[0], (parseInt(startDate[1]) - 1), startDate[2])); + + var taskArr = this.xmlLoader.doXPath("./task", projectArr[j]); + + for (var i = 0; i < taskArr.length; i++) { + + id = taskArr[i].getAttribute("id"); + name = (this.xmlLoader.doXPath("./name", taskArr[i])[0].firstChild == null) ? "" : this.xmlLoader.doXPath("./name", taskArr[i])[0].firstChild.nodeValue; + var estTemp = (this.xmlLoader.doXPath("./est", taskArr[i])[0].firstChild == null) ? "" : this.xmlLoader.doXPath("./est", taskArr[i])[0].firstChild.nodeValue; + est = estTemp.split(","); + duration = (this.xmlLoader.doXPath("./duration", taskArr[i])[0].firstChild == null) ? "" : this.xmlLoader.doXPath("./duration", taskArr[i])[0].firstChild.nodeValue; + percentCompleted = (this.xmlLoader.doXPath("./percentcompleted", taskArr[i])[0].firstChild == null) ? "" : this.xmlLoader.doXPath("./percentcompleted", taskArr[i])[0].firstChild.nodeValue; + predecessorTaskId = (this.xmlLoader.doXPath("./predecessortasks", taskArr[i])[0].firstChild == null) ? "" : this.xmlLoader.doXPath("./predecessortasks", taskArr[i])[0].firstChild.nodeValue; + + var task = new GanttTaskInfo(id, name, new Date(est[0], (parseInt(est[1]) - 1), est[2]), duration, percentCompleted, predecessorTaskId); + var childTasksNode = this.xmlLoader.doXPath("./childtasks", taskArr[i]); + var childTasksArr = this.xmlLoader.doXPath("./task", childTasksNode[0]); + + if (childTasksArr.length != 0) this.readChildTasksXML(task, childTasksArr); + + project.addTask(task); + + } + + this.addProject(project); + } +}; +/** + * @desc: parsing of XML data + * @param: parentTask - Parent Task object + * @param: childTasksArrXML - Array of child tasks (xml) + * @type: private + * @topic: 4 + */ +GanttChart.prototype.readChildTasksXML = function(parentTask, childTasksArrXML) +{ + + var name = null; + var id = null; + var est = null; + var duration = null; + var percentCompleted = null; + var predecessorTaskId = null; + + for (var i = 0; i < childTasksArrXML.length; i ++) + { + id = childTasksArrXML[i].getAttribute("id"); + name = (this.xmlLoader.doXPath("./name", childTasksArrXML[i])[0].firstChild == null) ? "" : this.xmlLoader.doXPath("./name", childTasksArrXML[i])[0].firstChild.nodeValue; + var estTemp = (this.xmlLoader.doXPath("./est", childTasksArrXML[i])[0].firstChild == null) ? "" : this.xmlLoader.doXPath("./est", childTasksArrXML[i])[0].firstChild.nodeValue; + est = estTemp.split(","); + duration = (this.xmlLoader.doXPath("./duration", childTasksArrXML[i])[0].firstChild == null) ? "" : this.xmlLoader.doXPath("./duration", childTasksArrXML[i])[0].firstChild.nodeValue; + percentCompleted = (this.xmlLoader.doXPath("./percentcompleted", childTasksArrXML[i])[0].firstChild == null) ? "" : this.xmlLoader.doXPath("./percentcompleted", childTasksArrXML[i])[0].firstChild.nodeValue; + predecessorTaskId = (this.xmlLoader.doXPath("./predecessortasks", childTasksArrXML[i])[0].firstChild == null) ? "" : this.xmlLoader.doXPath("./predecessortasks", childTasksArrXML[i])[0].firstChild.nodeValue; + var task = new GanttTaskInfo(id, name, new Date(est[0], (parseInt(est[1]) - 1), est[2]), duration, percentCompleted, predecessorTaskId); + task.ParentTask = parentTask; + + parentTask.addChildTask(task); + + var childTasksNode = this.xmlLoader.doXPath("./childtasks", childTasksArrXML[i]); + var childTasksArr = this.xmlLoader.doXPath("./task", childTasksNode[0]); + if (childTasksArr.length != 0) + { + this.readChildTasksXML(task, childTasksArr); + } + + } + +}; +/** + * @desc: create XML string from the chart content + * @type: public + * @topic: 6 + */ +GanttChart.prototype.getXML = function() +{ + var strXML = ""; + + for (var i = 0; i < this.Project.length; i++) + { + strXML += ""; + + for (var j = 0; j < this.Project[i].ParentTasks.length; j++) + { + strXML += ""; + strXML += "" + this.Project[i].ParentTasks[j].Name + ""; + strXML += "" + this.Project[i].ParentTasks[j].EST.getFullYear() + "," + (this.Project[i].ParentTasks[j].EST.getMonth() + 1) + "," + this.Project[i].ParentTasks[j].EST.getDate() + ""; + strXML += "" + this.Project[i].ParentTasks[j].Duration + ""; + strXML += "" + this.Project[i].ParentTasks[j].PercentCompleted + ""; + strXML += "" + this.Project[i].ParentTasks[j].PredecessorTaskId + ""; + strXML += ""; + strXML += this.createChildTasksXML(this.Project[i].ParentTasks[j].ChildTasks); + strXML += ""; + strXML += ""; + + } + + strXML += ""; + + } + strXML += ""; + return strXML; + +}; +/** + * @desc: create XML + * @type: private + * @topic: 4 + */ +GanttChart.prototype.createChildTasksXML = function(childTasks) +{ + var strXML = ""; + for (var n = 0; n < childTasks.length; n++) + { + strXML += ""; + strXML += "" + childTasks[n].Name + ""; + strXML += "" + childTasks[n].EST.getFullYear() + "," + (childTasks[n].EST.getMonth() + 1) + "," + childTasks[n].EST.getDate() + ""; + strXML += "" + childTasks[n].Duration + ""; + strXML += "" + childTasks[n].PercentCompleted + ""; + strXML += "" + childTasks[n].PredecessorTaskId + ""; + if (childTasks[n].ChildTasks) + { + strXML += ""; + strXML += this.createChildTasksXML(childTasks[n].ChildTasks); + strXML += ""; + } + strXML += ""; + } + return strXML; + +}; +/** + * @desc: function of sorting by EST + * @type: private + * @topic: 4 + */ +GanttChart.prototype.sort_byEST = function(a, b) +{ + if (a.EST < b.EST) return -1; + if (a.EST > b.EST) return 1; + return 0; +}; +/** + * @desc: function of sorting by start date + * @type: private + * @topic: 4 + */ +GanttChart.prototype.sort_byStartDate = function(a, b) +{ + if (a["StartDate"] < b["StartDate"]) return -1; + if (a["StartDate"] > b["StartDate"]) return 1; + return 0; +}; + +/** + * @desc: set the date to child tasks + * @param: parentTask - (object) parent task + * @type: private + * @topic: 4 + */ +GanttChart.prototype.setESTChild = function(parentTask) +{ + for (var t = 0; t < parentTask.ChildTasks.length; t++) + { + if ((parentTask.ChildTasks[t].EST == null ) || (parentTask.ChildTasks[t].EST == "")) + { + parentTask.ChildTasks[t].EST = parentTask.EST; + } + + if (parentTask.ChildTasks[t].ChildTasks.length != 0) this.setESTChild(parentTask.ChildTasks[t]); + } + +}; + +/** + * @desc: creation of the panel containing tasks + * @type: private + * @topic: 4 + */ +GanttChart.prototype.createPanelTasks = function() +{ + var divTasks = document.createElement("div"); + divTasks.className = "taskPanel"; + divTasks.style.cssText = "position:relative;"; + divTasks.style.height = this.contentHeight - 63 + "px"; + var w = this.startDate ? (this.startDate.getDay()-1) : ((new Date(0)).getDay()-1); + if (w==-1) w=6; + divTasks.style.background = "url(" + this.imgs + "bg_week.png) -"+(w*24)+"px 0px"; + this.panelTasks = divTasks; + return divTasks; +}; +/** + * @desc: creation of the panel containing names of tasks + * @type: private + * @topic: 4 + */ +GanttChart.prototype.createPanelNamesTasks = function() +{ + var divListNames = document.createElement("div"); + divListNames.innerHTML = " "; + divListNames.style.cssText = "position:relative;background:url(" + this.imgs + "bg.png)"; + divListNames.style.height = this.contentHeight - 63 + "px"; + divListNames.style.width = this.maxWidthPanelNames + "px"; + + return divListNames; +}; +/** + * @desc: creation a window with the data of task + * @type: private + * @topic: 4 + */ +GanttChart.prototype.createPopUpInfo = function() +{ + var divTaskInfo = document.createElement("div"); + divTaskInfo.style.cssText = 'display: none;'; + + var tblTaskInfo = document.createElement("table"); + tblTaskInfo.style.cssText = "position:absolute;top:0px;left:0px"; + tblTaskInfo.className = "poPupInfo"; + divTaskInfo.appendChild(tblTaskInfo); + + var rowTaskInfo = tblTaskInfo.insertRow(tblTaskInfo.rows.length); + var cellTaskInfo = document.createElement("td"); + rowTaskInfo.appendChild(cellTaskInfo); + this.divInfo = divTaskInfo; + + return divTaskInfo; +}; +/** + * @desc: creation a window with the current date + * @type: private + * @topic: 4 + */ +GanttChart.prototype.createPopUpTimeInfo = function() +{ + var divTimeInfo = document.createElement("div"); + divTimeInfo.style.display = "none"; + + var tblTimeInfo = document.createElement("table"); + tblTimeInfo.className = "poPupTime"; + divTimeInfo.appendChild(tblTimeInfo); + + var rowTimeInfo = tblTimeInfo.insertRow(tblTimeInfo.rows.length); + var cellTimeInfo = document.createElement("td"); + cellTimeInfo.align = "center"; + rowTimeInfo.appendChild(cellTimeInfo); + + return divTimeInfo; +}; +/** + * @desc: create a panel with the days + * @type: private + * @topic: 4 + */ +GanttChart.prototype.createPanelTime = function() +{ + var panelTime = document.createElement("div"); + panelTime.style.position = "relative"; + + var tblTime = document.createElement("table"); + panelTime.appendChild(tblTime); + tblTime.cellPadding = "0px"; + tblTime.border = "0px"; + tblTime.cellSpacing = "0px"; + tblTime.bgColor = "#FFFFFF"; + tblTime.style.marginTop = "0px"; + + var monthRow = tblTime.insertRow(tblTime.rows.length); + + var newRow = tblTime.insertRow(tblTime.rows.length); + + //creating cells for tblTime + for (var i = 0; i < this.countDays; i++) + { + this.addPointInTimePanel(newRow, panelTime); + this.addDayInPanelTime(newRow); + } + + return panelTime; +}; +/** + * @desc: creation of point in panel time + * @param: row - current row + * @param: panelTime -Panel which contains days + * @type: private + * @topic: 4 + */ +GanttChart.prototype.addPointInTimePanel = function(row, panelTime) +{ + var leftLine = document.createElement("div"); + leftLine.style.cssText = "position:absolute;left:" + ( row.cells.length * this.dayInPixels ) + "px;top:20px;height:20px;width:1px;font-size:1px;margin-left:0px;margin-right:0px;margin-top:0px;margin-bottom:0px;background:#f1f3f1;"; + panelTime.appendChild(leftLine); +}; +GanttChart.prototype._calculateMonthColSpan = function(date, maxLen) { + var m1 = date.getMonth(); + for(var i=1; i<=maxLen; i++) { + date.setDate(date.getDate() + 1); + var m2 = date.getMonth(); + if (m2 != m1) return i; + } + return maxLen; +}; +/** + * @desc: Returns a string representation of current month for the month scale row. You may override this function to customize the label. + * @param: date - {JavaScript Date object}, the date of month for which you should render month label. + * @type: public, overridable + * @topic: 3 + */ +GanttChart.prototype.getMonthScaleLabel = function(date) { + return (this._useShortMonthNames ? this.shortMonthNames : this.monthNames)[date.getMonth()] + " '" + (""+date.getFullYear()).substring(2); +}; +/** + * @desc: Use short or full month name in the month label axis. Default is true. + * @param: flag - {true|false} + * @type: public + * @topic: 3 + * @before_init: 1 + */ +GanttChart.prototype.useShortMonthNames = function(flag) { + this._useShortMonthNames = flag; +}; +/** + * @desc: Define short month names for your locale + * @param: names - an array of strings, ["Jan", "Feb", ...] + * @type: public + * @topic: 3 + * @before_init: 1 + */ +GanttChart.prototype.setShortMonthNames = function(names) { + this.shortMonthNames = names; +}; +/** + * @desc: Define full month names for your locale + * @param: names - an array of strings, ["January", "February", ...] + * @type: public + * @topic: 3 + * @before_init: 1 + */ +GanttChart.prototype.setMonthNames = function(names) { + this.monthNames = names; +}; +/** + * @desc: Add day in panel time + * @param: row - row, which contains days + * @type: private + * @topic: 4 + */ +GanttChart.prototype.addDayInPanelTime = function(row) +{ + var self = this, idx = row.cells.length, date = new Date(this.startDate); + + var newCell = row.insertCell(idx); + newCell.style.height = "20px"; + newCell.style.width = this.dayInPixels + "px"; + newCell.className = "dayNumber"; + + date.setDate(date.getDate() + parseInt(idx)); + var day = date.getDate() + newCell.innerHTML = day; + newCell.setAttribute("idx", idx); + + var monthRow = row.parentNode.parentNode.rows[0]; + if (idx==0 || day==1) { + var newCell2 = monthRow.insertCell(monthRow.cells.length); + newCell2.className = "monthName"; + newCell2.style.height = "20px"; + if (monthRow.cells.length%2 == 0) newCell2.style.backgroundColor = "#f7f8f7"; + newCell2.colSpan = this._calculateMonthColSpan(new Date(date), Math.max(1,this.countDays-idx)); + newCell2.innerHTML = this.getMonthScaleLabel(date); + } else { + var n = monthRow.cells.length, cs=0; + for(var i=0; i=cs) monthRow.cells[n-1].colSpan += 1; + } + + var w = date.getDay(); + if (w==0 || w==6) newCell.style.backgroundColor = "#f7f8f7"; +}; +/** + * @desc: increment Height of Panel Tasks + * @type: private + * @topic: 4 + */ +GanttChart.prototype.incHeightPanelTasks = function(height) +{ + var containerTasks = this.oData.firstChild; + containerTasks.style.height = parseInt(containerTasks.style.height) + height + "px"; +}; +/** + * @desc: increment Height of Panel Names + * @type: private + * @topic: 4 + */ +GanttChart.prototype.incHeightPanelNames = function(height) +{ + var containerNames = this.panelNames.firstChild; + containerNames.style.height = parseInt(containerNames.style.height) + height + "px"; +}; +/** + * @desc: check Heigh of Panel Tasks + * @type: private + * @topic: 4 + */ +GanttChart.prototype.checkHeighPanelTasks = function() +{ + this._oDataHeight += 11 + this.heightTaskItem; + if ((parseInt(this.oData.firstChild.style.height) <= this._oDataHeight)) { + this.incHeightPanelTasks(this.heightTaskItem + 11); + if (this._showTreePanel) this.incHeightPanelNames(this.heightTaskItem + 11); + } +}; +/** + * @desc: sorting of tasks by EST in the current project + * @param: project - current project + * @type: private + * @topic: 4 + */ +GanttChart.prototype.sortTasksByEST = function(project) +{ + project.ParentTasks.sort(this.sort_byEST); + + for (var i = 0; i < project.ParentTasks.length; i++) + { + project.ParentTasks[i] = this.sortChildTasks(project.ParentTasks[i]); + } + +}; +/** + * @desc: sorting of child tasks in the parent task + * @param: parenttask - (object) parent task + * @type: private + * @topic: 4 + */ +GanttChart.prototype.sortChildTasks = function(parenttask) +{ + parenttask.ChildTasks.sort(this.sort_byEST); + + for (var i = 0; i < parenttask.ChildTasks.length; i++) + { + if (parenttask.ChildTasks[i].ChildTasks.length > 0) this.sortChildTasks(parenttask.ChildTasks[i]); + } + return parenttask; +}; +/** + * @desc: Handler of data errors + * @param: type - type of error + * @param: descr - description of error + * @param: params - current data + * @type: private + * @topic: 5 + */ +GanttChart.prototype.errorDataHandler = function(type, descr, params) +{ + if (!this._isError) + { + this.clearData(); + this.showPanelErrors(); + this._isError = true; + } + this.addErrorInPanelErrors(type, descr); +}; +/** + * @desc: creation of Panel Errors + * @type: private + * @topic: 4 + */ +GanttChart.prototype.createPanelErrors = function() +{ + var tbl = document.createElement("table"); + tbl.width = "100%"; + tbl.style.display = "none"; + tbl.className = "panelErrors"; + this.panelErrors = tbl; + + return tbl; + +}; +/** + * @desc: show of Panel Errors + * @type: private + * @topic: 4 + */ +GanttChart.prototype.showPanelErrors = function() +{ + this.panelErrors.style.display = "inline"; +}; +/** + * @desc: hide of Panel Errors + * @type: private + * @topic: 4 + */ +GanttChart.prototype.hidePanelErrors = function() +{ + for (var i = 0; i < this.panelErrors.rows.length; i++) { + + this.panelErrors.rows[i].parentNode.removeChild(this.panelErrors.rows[i]); + } + this.panelErrors.style.display = "none"; +}; +/** + * @desc: add error message in Panel Errors + * @type: private + * @topic: 4 + */ +GanttChart.prototype.addErrorInPanelErrors = function(type, descr) +{ + var row = this.panelErrors.insertRow(this.panelErrors.rows.length); + var cell = document.createElement("td"); + cell.style.height = "20px"; + cell.style.width = "100px"; + cell.innerHTML = type; + row.appendChild(cell); + + cell = document.createElement("td"); + row.appendChild(cell); + cell.innerHTML = descr; +}; +/** + * @desc: Handler of errors + * @param: type - type of error + * @param: descr - description of error + * @param: params - current data + * @type: private + * @topic: 5 + */ +GanttChart.prototype.errorSendDataHandler = function(type, descr, params) +{ + alert(descr); +}; +/** + * @desc: Handler of errors + * @param: type - type of error + * @param: descr - description of error + * @param: params - current data + * @type: private + * @topic: 5 + */ +GanttChart.prototype.errorLoadDataHandler = function(type, descr, params) +{ + alert(descr); +}; +/** + * @desc: Handler of API errors + * @param: type - type of error + * @param: descr - description of error + * @param: params - current data + * @type: private + * @topic: 5 + */ +GanttChart.prototype.errorAPIHandler = function(type, descr, params) +{ + alert(descr); +}; +/** + * @desc: saves data to server, using setSavePath() url and "application/x-www-form-urlencoded" encoding + * @param: fileName - passed to server as "filename" field, xml content is passed in "data" field + * @type: public + * @topic: 6 + */ +GanttChart.prototype.saveData = function(fileName) +{ + try { + + if (!this.dhtmlXMLSenderObject.isProcessed) + { + this.dhtmlXMLSenderObject.sendData(fileName, this.savePath, this.getXML()); + } + + } catch (e) { + this.Error.throwError("DATA_SEND_ERROR", e, null); + } +}; +/** + * @desc: creation of GanttChart + * @param: divId - id of div in which the control lays + * @param: xmlFile - path to XML document + * @type: public + * @topic: 0 + */ +GanttChart.prototype.create = function(divId) +{ + var self = this; + var content = document.getElementById(divId); + this.content = content; + this.getBrowserType(); + + // + if (this._isIE) { + document.body.attachEvent('onselectstart', function() { + window.event.returnValue = false; + }); + + document.body.attachEvent('onkeydown', function() { + if (event.keyCode == 65 && event.ctrlKey) window.event.returnValue = false; + }); + + } else { + content.addEventListener('mousedown', function(e) { + e.preventDefault(); + }, true); + document.addEventListener('keydown', function(e) { + if (e.keyCode == 65 && e.ctrlKey) e.preventDefault(); + }, true); + } + + //init handlers + this.Error.catchError("DATA_ERROR", function(type, descr, params) { + self.errorDataHandler(type, descr, params) + }); + this.Error.catchError("DATA_SEND_ERROR", function(type, descr, params) { + self.errorSendDataHandler(type, descr, params) + }); + this.Error.catchError("DATA_INSERT_ERROR", function(type, descr, params) { + self.errorAPIHandler(type, descr, params) + }); + this.Error.catchError("DATA_LOAD_ERROR", function(type, descr, params) { + self.errorLoadDataHandler(type, descr, params) + }); + + //create Table + var tableControl = document.createElement("table"); + tableControl.cellPadding = "0"; + tableControl.cellSpacing = "0"; + tableControl.style.cssText = "width: 100%; position: relative;"; + var newRowTblControl = tableControl.insertRow(tableControl.rows.length); + var newCellTblControl; + + //Add to content Table + this.contentHeight = content.offsetHeight; + this.contentWidth = content.offsetWidth; + content.appendChild(tableControl); + + this.countDays = this.getCountDays(); + + this.Project.sort(this.sort_byStartDate); + this.startDate = this.getStartDate(); + + //Creation panel of time + this.panelTime = document.createElement("div"); + this.panelTime.appendChild(this.createPanelTime()); + this.panelTime.style.cssText = "position:relative;overflow:hidden;height:40px;top:0px;left:1px"; + + //Creation panel oData + this.oData = document.createElement("div"); + this.oData.appendChild(this.createPanelTasks()); + this.oData.style.cssText = "position:relative;overflow:scroll;height:" + (this.contentHeight - 40) + "px;border-left:#f1f3f1 1px solid"; + + this.oData.firstChild.appendChild(this.createPanelErrors()); + + //Creation panel of names + if (this._showTreePanel) + { + this.panelNames = document.createElement("div"); + newCellTblControl = document.createElement("td"); + newCellTblControl.vAlign = "top"; + + this.panelNames.appendChild(this.createPanelNamesTasks()); + this.panelNames.style.cssText = "position:relative;top:40px;overflow:hidden;border-left:#f1f3f1 1px solid;border-bottom:#f1f3f1 1px solid"; + newCellTblControl.appendChild(this.panelNames); + newRowTblControl.appendChild(newCellTblControl); + } + + //add oData and oDataTime + newCellTblControl = document.createElement("td"); + var divCell = document.createElement("div"); + divCell.style.cssText = "position: relative;"; + divCell.appendChild(this.panelTime); + divCell.appendChild(this.oData); + newCellTblControl.appendChild(divCell); + newRowTblControl.appendChild(newCellTblControl); + + //Show panel of names + if (this._showTreePanel) { + this.panelNames.style.height = (this.contentHeight - 56) + "px"; + this.panelNames.style.width = this.maxWidthPanelNames + "px"; + this.oData.style.width = (this.contentWidth - this.maxWidthPanelNames) + "px"; + this.panelTasks.style.width = this.dayInPixels * this.countDays + "px"; + this.panelTime.style.width = (this.contentWidth - this.maxWidthPanelNames - 0*18) + "px"; + this.panelTime.firstChild.style.width = this.dayInPixels * this.countDays + "px"; + if (this.isShowConMenu && this.contextMenu == null) this.contextMenu = new contextMenu(this); + } else { + this.oData.style.width = this.contentWidth + "px"; + this.panelTime.style.width = (this.contentWidth - 16) + "px"; + } + + if (this._isOpera) { + this.oData.onmousewheel = function() { + return false; + } + } + + this.oData.onscroll = function() { + self.panelTime.scrollLeft = this.scrollLeft; + + if (self.panelNames) { + self.panelNames.scrollTop = this.scrollTop; + if (self.isShowConMenu) self.contextMenu.hideContextMenu(); + } + + }; + + //create pop up time info + this.divTimeInfo = this.createPopUpTimeInfo(); + divCell.appendChild(this.divTimeInfo); + + //create pop up info task + this.oData.firstChild.appendChild(this.createPopUpInfo()); + + //this.Project.sort(this.sort_byStartDate); + //this.startDate = this.getStartDate(); + + for (var i = 0; i < this.Project.length; i++) + { + + for (var k = 0; k < this.Project[i].ParentTasks.length; k++) + { + if (this.isEmpty(this.Project[i].ParentTasks[k].EST)) { + this.Project[i].ParentTasks[k].EST = this.Project[i].StartDate; + } + this.setESTChild(this.Project[i].ParentTasks[k]); + + if (this.setPredTask(this.Project[i])) return; + } + + for (var k = 0; k < this.Project[i].ParentTasks.length; k++) { + if (this.Project[i].ParentTasks[k].EST < this.Project[i].StartDate) { + + if (!this.correctError) { + this.Error.throwError("DATA_ERROR", 24, [this.Project[i].ParentTasks[k].Id,this.Project[i].Id]); + return; + } else { + this.Project[i].ParentTasks[k].EST = this.Project[i].StartDate; + } + } + if (this.checkPosParentTaskInTree(this.Project[i].ParentTasks[k])) return; + } + + this.sortTasksByEST(this.Project[i]); + + } + + for (var i = 0; i < this.Project.length; i++) + { + //creation project + var project = new GanttProject(this, this.Project[i]); + + if (this.arrProjects.length > 0) + { + var previousProject = this.arrProjects[this.arrProjects.length - 1]; + project.previousProject = previousProject; + previousProject.nextProject = project; + } + project.create(); + + this.checkHeighPanelTasks(); + this.arrProjects.push(project); + this.createTasks(project); + + } + + return this; +}; + +GanttChart.prototype.isEmpty = function(value) +{ + return (value == null || value == ''); +}; + +/** + * @desc: returns chart in html format suitable for printing, full-sized and without scrollbars + * @type: public + * @topic: 7 + */ +GanttChart.prototype.getPrintableHTML = function() +{ + var w = parseInt(this.oData.firstChild.style.width) - parseInt(this.oData.style.width); + var h = parseInt(this.panelTasks.style.height) - parseInt(this.panelTasks.parentNode.style.height); + + this.oData.setAttribute("id","ganttPrint02"); + this.panelNames.setAttribute("id","ganttPrint03"); + + var res = 'onload=function(){var w=' + w + ',h=' + h + + ',c1=document.getElementById("ganttPrint01"),c2=document.getElementById("ganttPrint02"),c3=document.getElementById("ganttPrint03");' + + 'c2.style.width=parseInt(c2.style.width)+w+"px";c2.previousSibling.style.width=c2.style.width;c1.style.width=parseInt(c1.style.width)+w+"px";c2.style.height=parseInt(c2.style.height)+h+"px";' + + 'c2.style.overflow="hidden";c3.style.height=c3.firstChild.style.height;c1.style.height=parseInt(c1.style.height)+h+"px";}' + + '
' + this.content.innerHTML + '
'; + + this.oData.setAttribute("id",null); + this.panelNames.setAttribute("id",null); + + return res; +}; + +/** + * @desc: opens chart in a new window, from where you can print it as you like - you can use browser's "Print preview" menu button to layout the chart on your page, choose a paper size etc. + * @param: message - (string) this message will appear in alert window to instruct user what to do for printing. Set it to null to skip this alert. By default it says "Use browser's menu File->Print preview to setup page layout." + * @type: public + * @topic: 7 + */ +GanttChart.prototype.printToWindow = function(message) +{ + var o = window.open(); + o.document.write(this.getPrintableHTML()); + o.document.close(); + if (message!==null) { + o.alert(message ? message : "Use browser's menu \"File->Print preview\" to setup page layout." ); + } +}; + +/** + * @desc: Calculation of Start Date + * @type: private + * @topic: 4 + */ +GanttChart.prototype.getStartDate = function() +{ + for (var i = 0; i < this.Project.length; i++) { + + if (this.startDate) { + if (this.Project[i].StartDate < this.startDate) { + this.startDate = new Date(this.Project[i].StartDate); + } + } + else { + this.startDate = new Date(this.Project[i].StartDate); + } + } + + this.initialPos = 24 * this.hourInPixels; + if (this.startDate) { + return new Date(this.startDate.setHours(this.startDate.getHours() - 24)); + } + else { + return new Date(); + } + +}; +/** + * @desc: Calculation of Count Days + * @type: private + * @topic: 4 + */ +GanttChart.prototype.getCountDays = function() +{ + + if (this._showTreePanel) { + return parseInt((this.contentWidth - this.maxWidthPanelNames) / (this.hourInPixels * 24)); + + } else { + return parseInt((this.contentWidth) / (this.hourInPixels * 24)); + } + +}; +/** + * @desc: Creation of tasks + * @param: project - (object)project + * @type: private + * @topic: 4 + */ +GanttChart.prototype.createTasks = function(project) +{ + for (var j = 0; j < project.Project.ParentTasks.length; j++) + { + if (j > 0) + { + project.Project.ParentTasks[j - 1].nextParentTask = project.Project.ParentTasks[j]; + project.Project.ParentTasks[j].previousParentTask = project.Project.ParentTasks[j - 1]; + } + + var task = new GanttTask(project.Project.ParentTasks[j], project, this); + project.arrTasks.push(task); + task.create(); + + this.checkHeighPanelTasks(); + + if (project.Project.ParentTasks[j].ChildTasks.length > 0) + { + this.createChildItemControls(project.Project.ParentTasks[j].ChildTasks, project); + } + } +}; +/** + * @desc: Creation of tasks + * @param: arrChildTasks - array of child tasks + * @param: project - (object)project + * @type: private + * @topic: 4 + */ +GanttChart.prototype.createChildItemControls = function(arrChildTasks, project) +{ + for (var i = 0; i < arrChildTasks.length; i++) { + + if (i > 0) + { + arrChildTasks[i].previousChildTask = arrChildTasks[i - 1]; + arrChildTasks[i - 1].nextChildTask = arrChildTasks[i]; + } + var task = new GanttTask(arrChildTasks[i], project, this); + task.create(); + + this.checkHeighPanelTasks(); + + if (arrChildTasks[i].ChildTasks.length > 0) + { + this.createChildItemControls(arrChildTasks[i].ChildTasks, project); + } + } + +}; +/** + * @desc: show a small window with the data of task + * @param: event - (object)event + * @type: private + * @topic: 4 + */ +GanttTask.prototype.getPopUpInfo = function(object, event) +{ + //this.cTaskItem[0] + var posY = object.offsetTop + this.Chart.heightTaskItem + 6; + var posX = object.offsetLeft + ((event.layerX == null) ? event.offsetX : event.layerX); + + //data of task + var tblInfo = this.Chart.divInfo.lastChild; + tblInfo.rows[0].cells[0].innerHTML = "
" + this.TaskInfo.Name + "
"; + tblInfo.rows[0].cells[0].innerHTML += "EST: " + this.TaskInfo.EST.getDate() + "." + (this.TaskInfo.EST.getMonth() + 1) + "." + this.TaskInfo.EST.getFullYear() + "
"; + tblInfo.rows[0].cells[0].innerHTML += "Duration: " + this.TaskInfo.Duration + " hours
"; + tblInfo.rows[0].cells[0].innerHTML += "Percent Complete: " + this.TaskInfo.PercentCompleted + "%
"; + + //show predecessor task + if (this.predTask) + { + tblInfo.rows[0].cells[0].innerHTML += "Predecessor Task: "; + tblInfo.rows[0].cells[0].innerHTML += "*" + this.TaskInfo.PredecessorTask.Name + ""; + } + + //show child tasks + if (this.TaskInfo.ChildTasks.length != 0) { + tblInfo.rows[0].cells[0].innerHTML += "Child Tasks: "; + for (var i = 0; i < this.TaskInfo.ChildTasks.length; i++) + { + tblInfo.rows[0].cells[0].innerHTML += (i == this.TaskInfo.ChildTasks.length - 1) ? ("*" + this.TaskInfo.ChildTasks[i].Name + "") : ("*" + this.TaskInfo.ChildTasks[i].Name + ""); + } + } + + //show parent task + if (this.TaskInfo.ParentTask) { + tblInfo.rows[0].cells[0].innerHTML += "Parent Task: "; + tblInfo.rows[0].cells[0].innerHTML += "*" + this.TaskInfo.ParentTask.Name + ""; + } + + this.Chart.divInfo.style.cssText = "z-index:2;position: absolute;display: inline;"; + + if (posY + this.Chart.divInfo.lastChild.offsetHeight + 10 > this.Chart.oData.offsetHeight + this.Chart.oData.scrollTop) { + this.Chart.divInfo.style.top = (posY - this.Chart.divInfo.lastChild.offsetHeight - 10 - this.Chart.heightTaskItem) + "px"; + } + else { + this.Chart.divInfo.style.top = posY + "px"; + } + + if (this.Chart.divInfo.lastChild.offsetWidth + posX + 10 > this.Chart.oData.offsetWidth + this.Chart.oData.scrollLeft) { + this.Chart.divInfo.style.left = posX - (this.Chart.divInfo.lastChild.offsetWidth + posX + 20 - (this.Chart.oData.offsetWidth + this.Chart.oData.scrollLeft)) + "px"; + + } else { + this.Chart.divInfo.style.left = posX + "px"; + } + +}; +/** + * @desc: close a window in browser with the data of task + * @type: private + * @topic: 4 + */ +GanttTask.prototype.closePopUpInfo = function() +{ + this.Chart.divInfo.style.display = "none"; +}; +/** + * @desc: creation connecting lines in panel of names + * @type: private + * @topic: 4 + */ +GanttTask.prototype.createConnectingLinesPN = function() +{ + var arrConnectingLinesNames = []; + + /*var lineVerticalLeft = document.createElement("div"); + lineVerticalLeft.style.cssText = "border-width: 0px 0px 0px 1px; border-style: dotted; border-color: #C0C4C0; margin: 0px; padding: 0px;z-index:10;position: absolute;" + + "height:" + (this.cTaskNameItem[0].offsetTop - this.parentTask.cTaskNameItem[0].offsetTop) + "px;" + + "top:" + (this.parentTask.cTaskNameItem[0].offsetTop + 5) + "px;" + + "left:" + (this.parentTask.cTaskNameItem[0].offsetLeft - 9) + "px;"; + lineVerticalLeft.innerHTML = " "; + this.Chart.panelNames.firstChild.appendChild(lineVerticalLeft); + + var LineHorizontalLeft = document.createElement("div"); + LineHorizontalLeft.noShade = true; + LineHorizontalLeft.color = "#000000"; + LineHorizontalLeft.style.cssText = "left:" + (this.parentTask.cTaskNameItem[0].offsetLeft - 9) + "px;top:" + (this.cTaskNameItem[0].offsetTop + 5) + "px;z-index:10;" + + "height:" + 1 + "px;width:" + (this.cTaskNameItem[0].offsetLeft - this.parentTask.cTaskNameItem[0].offsetLeft + 4 ) + "px;position: absolute;border-width: 1px 0px 0px 0px;font-size: 1px;border-style: dotted; border-color: #C0C4C0;margin: 0px; padding: 0px;"; + this.Chart.panelNames.firstChild.appendChild(LineHorizontalLeft); + + arrConnectingLinesNames.push(lineVerticalLeft); + arrConnectingLinesNames.push(LineHorizontalLeft);*/ + + return arrConnectingLinesNames; + +}; +/** + * @desc: creation connecting lines in panel oData + * @type: private + * @topic: 4 + */ +GanttTask.prototype.createConnectingLinesDS = function() +{ + var oData = this.Chart.oData.firstChild; + var arrLines = []; + + var arrowImg = new Image(); + arrowImg.src = this.Chart.imgs + "arr.gif"; + + //vertical line + var lineVerticalRight = document.createElement("div"); + + //horizontal line + var lineHorizontal = document.createElement("div"); + + var posXPredecessorTask = parseInt(this.predTask.cTaskItem[0].style.left); + var posYPredecessorTask = parseInt(this.predTask.cTaskItem[0].style.top); + + var posXChildTask = parseInt(this.cTaskItem[0].style.left); + var posYChildTask = this.posY + 2; + + //width task item + var widthChildTask = parseInt(this.predTask.cTaskItem[0].firstChild.firstChild.width); + var widthPredecessorTask = parseInt(this.predTask.cTaskItem[0].firstChild.firstChild.width); + + if (posYPredecessorTask < posYChildTask) + { + lineVerticalRight.style.cssText = "border-width: 0px 0px 0px 1px; border-style: solid; border-color: #4A8F43;margin: 0px; padding: 0px;z-index:0;font-size: 1px;position: absolute;" + + "height:" + (posYChildTask - this.Chart.heightTaskItem / 2 - posYPredecessorTask - 3) + "px;width:" + 1 + "px;left:" + (posXPredecessorTask + widthPredecessorTask - 20 ) + "px;top:" + (posYPredecessorTask + this.Chart.heightTaskItem) + "px;"; + + lineHorizontal.style.cssText = "height:1px;border-color: #4A8F43;border-style: solid;border-width: 1px 0px 0px 0px;margin: 0px; padding: 0px;z-index:0;position: absolute;" + + "width:" + (15 + (posXChildTask - (widthPredecessorTask + posXPredecessorTask))) + "px;left:" + (posXPredecessorTask + widthPredecessorTask - 20 ) + "px;top:" + (posYChildTask + 2) + "px;"; + + arrowImg.style.cssText = "margin: 0px; padding: 0px;width:7px;height:14px;position: absolute;left:" + (posXChildTask - 7) + "px;top:" + (posYChildTask - 1) + "px;"; + } else { + lineVerticalRight.style.cssText = "border-width: 0px 0px 0px 1px; border-style: solid; border-color: #4A8F43;margin: 0px; padding: 0px;z-index:0;font-size: 1px;position: absolute;" + + "height:" + (posYPredecessorTask + 2 - posYChildTask) + "px;width:" + 1 + "px;left:" + (posXPredecessorTask + widthPredecessorTask - 20 ) + "px;top:" + (posYChildTask + 2) + "px;"; + + lineHorizontal.style.cssText = "height:1px;border-color: #4A8F43;border-style: solid;border-width: 1px 0px 0px 0px;margin: 0px; padding: 0px;z-index:0;position: absolute;" + + "width:" + (15 + (posXChildTask - (widthPredecessorTask + posXPredecessorTask))) + "px;left:" + (posXPredecessorTask + widthPredecessorTask - 20 ) + "px;top:" + (posYChildTask + 2) + "px;"; + + arrowImg.style.cssText = "margin: 0px; padding: 0px;width:7px;height:14px;position: absolute;left:" + (posXChildTask - 7) + "px;top:" + (posYChildTask - 1) + "px;"; + } + oData.appendChild(lineVerticalRight); + oData.appendChild(lineHorizontal); + oData.appendChild(arrowImg); + + arrLines.push(lineVerticalRight); + arrLines.push(arrowImg); + arrLines.push(lineHorizontal); + + return arrLines; +}; +/** + * @desc: Shows current tasks + * @param: task - GanttTask object. + * @type: private + * @topic: 3 + */ +GanttTask.prototype.showChildTasks = function(task, isOpen) +{ + if (isOpen) + { + for (var i = 0; i < task.childTask.length; i++) + { + if (task.childTask[i].cTaskItem[0].style.display == "none") { + task.childTask[i].cTaskItem[0].style.display = "inline"; + task.childTask[i].cTaskNameItem[0].style.display = "inline"; + if (this.Chart.isShowDescTask) { + task.childTask[i].showDescTask(); + } + + task.isHide = false; + + if (task.childTask[i].cTaskNameItem[2]) { + task.childTask[i].cTaskNameItem[2].style.display = "inline"; + isOpen = task.childTask[i]._isOpen; + } + + for (var k = 0; k < task.childTask[i].cTaskItem[1].length; k++) { + task.childTask[i].cTaskItem[1][k].style.display = "inline"; + + } + for (var k = 0; k < task.childTask[i].cTaskNameItem[1].length; k++) { + task.childTask[i].cTaskNameItem[1][k].style.display = "inline"; + } + + this._heightHideTasks += this.Chart.heightTaskItem + 11; + + if (task.childTask[i].childTask.length > 0) { + this.showChildTasks(task.childTask[i], isOpen); + } + + } + } + } +}; +/** + * @desc: hide child task + * @param: task - (object) GanttTask + * @type: private + * @topic: 3 + */ +GanttTask.prototype.hideChildTasks = function(task) +{ + for (var i = 0; i < task.childTask.length; i++) + { + if (task.childTask[i].cTaskItem[0].style.display != "none") + { + task.childTask[i].cTaskItem[0].style.display = "none"; + task.childTask[i].cTaskNameItem[0].style.display = "none"; + if (this.Chart.isShowDescTask) { + task.childTask[i].hideDescTask(); + } + task.isHide = true; + + if (task.childTask[i].cTaskNameItem[2]) { + task.childTask[i].cTaskNameItem[2].style.display = "none"; + } + + for (var k = 0; k < task.childTask[i].cTaskItem[1].length; k++) { + task.childTask[i].cTaskItem[1][k].style.display = "none"; + } + for (var k = 0; k < task.childTask[i].cTaskNameItem[1].length; k++) { + task.childTask[i].cTaskNameItem[1][k].style.display = "none"; + } + + this._heightHideTasks += this.Chart.heightTaskItem + 11; + + if (task.childTask[i].childTask.length > 0) { + this.hideChildTasks(task.childTask[i]); + } + + } + } +}; +/** + * @desc: shift current tasks + * @param: task - (object) GanttTask + * @param: height - specifies height on which tasks are shifted + * @type: private + * @topic: 4 + */ +GanttTask.prototype.shiftCurrentTasks = function(task, height) +{ + this.shiftNextTask(this, height); + task.Project.shiftNextProject(task.Project, height); +}; + +GanttProject.prototype.shiftNextProject = function(project, height) +{ + if (project.nextProject) { + project.nextProject.shiftProject(height); + this.shiftNextProject(project.nextProject, height); + } + +}; +GanttProject.prototype.shiftProject = function(height) +{ + this.projectItem[0].style.top = parseInt(this.projectItem[0].style.top) + height + "px"; + if (this.Chart.isShowDescProject) { + this.descrProject.style.top = parseInt(this.descrProject.style.top) + height + "px"; + } + + if (this.Chart._showTreePanel) { + this.projectNameItem.style.top = parseInt(this.projectNameItem.style.top) + height + "px"; + } + if (this.arrTasks.length > 0) + this.shiftNextParentTask(this.arrTasks[0], height); + +}; +GanttProject.prototype.shiftTask = function(task, height) +{ + if (this.Chart._showTreePanel) { + + task.cTaskNameItem[0].style.top = parseInt(task.cTaskNameItem[0].style.top) + height + "px"; + if (task.cTaskNameItem[2]) { + task.cTaskNameItem[2].style.top = parseInt(task.cTaskNameItem[2].style.top) + height + "px"; + } + if (task.parentTask && task.cTaskNameItem[1][0]) + { + task.cTaskNameItem[1][0].style.top = parseInt(task.cTaskNameItem[1][0].style.top) + height + "px"; + task.cTaskNameItem[1][1].style.top = parseInt(task.cTaskNameItem[1][1].style.top) + height + "px"; + } + } + + task.cTaskItem[0].style.top = parseInt(task.cTaskItem[0].style.top) + height + "px"; + if (this.Chart.isShowDescTask) { + task.descrTask.style.top = parseInt(task.descrTask.style.top) + height + "px"; + } + if (task.cTaskItem[1][0]) + { + task.cTaskItem[1][0].style.top = parseInt(task.cTaskItem[1][0].style.top) + height + "px"; + task.cTaskItem[1][1].style.top = parseInt(task.cTaskItem[1][1].style.top) + height + "px"; + task.cTaskItem[1][2].style.top = parseInt(task.cTaskItem[1][2].style.top) + height + "px"; + } +}; +GanttProject.prototype.shiftNextParentTask = function(task, height) +{ + this.shiftTask(task, height); + this.shiftChildTasks(task, height); + + if (task.nextParentTask) { + this.shiftNextParentTask(task.nextParentTask, height); + } + +}; +GanttProject.prototype.shiftChildTasks = function(task, height) +{ + for (var i = 0; i < task.childTask.length; i++) + { + this.shiftTask(task.childTask[i], height); + if (task.childTask[i].childTask.length > 0) { + this.shiftChildTasks(task.childTask[i], height); + } + + } +}; + +GanttTask.prototype.shiftTask = function(task, height) +{ + if (this.Chart._showTreePanel) { + task.cTaskNameItem[0].style.top = parseInt(task.cTaskNameItem[0].style.top) + height + "px"; + if (task.cTaskNameItem[2]) { + task.cTaskNameItem[2].style.top = parseInt(task.cTaskNameItem[2].style.top) + height + "px"; + } + if (task.parentTask) + { + if (task.cTaskNameItem[1].length > 0) if ((parseInt(this.cTaskNameItem[0].style.top) > parseInt(task.parentTask.cTaskNameItem[0].style.top)) + && (task.cTaskNameItem[1][0].style.display != "none")) { + task.cTaskNameItem[1][0].style.height = parseInt(task.cTaskNameItem[1][0].style.height) + height + "px"; + } else { + task.cTaskNameItem[1][0].style.top = parseInt(task.cTaskNameItem[1][0].style.top) + height + "px"; + } + if (task.cTaskNameItem[1].length > 1) task.cTaskNameItem[1][1].style.top = parseInt(task.cTaskNameItem[1][1].style.top) + height + "px"; + } + } + + task.cTaskItem[0].style.top = parseInt(task.cTaskItem[0].style.top) + height + "px"; + if (this.Chart.isShowDescTask) { + task.descrTask.style.top = parseInt(task.descrTask.style.top) + height + "px"; + } + if (task.predTask) + { + if (task.cTaskItem[1].length > 0) if (((parseInt(this.cTaskItem[0].style.top) > parseInt(task.predTask.cTaskItem[0].style.top)) || + (this.cTaskItem[0].id == task.predTask.TaskInfo.Id)) && + task.cTaskItem[1][0].style.display != "none") { + task.cTaskItem[1][0].style.height = parseInt(task.cTaskItem[1][0].style.height) + height + "px"; + } else { + task.cTaskItem[1][0].style.top = parseInt(task.cTaskItem[1][0].style.top) + height + "px"; + } + if (task.cTaskItem[1].length > 2) { + task.cTaskItem[1][1].style.top = parseInt(task.cTaskItem[1][1].style.top) + height + "px"; + task.cTaskItem[1][2].style.top = parseInt(task.cTaskItem[1][2].style.top) + height + "px"; + } + } +}; +GanttTask.prototype.shiftNextTask = function(task, height) +{ + if (task.nextChildTask) { + this.shiftTask(task.nextChildTask, height); + this.shiftChildTask(task.nextChildTask, height); + this.shiftNextTask(task.nextChildTask, height); + + } else if (task.parentTask) { + this.shiftNextTask(task.parentTask, height); + + } else if (task.nextParentTask) { + this.shiftTask(task.nextParentTask, height); + this.shiftChildTask(task.nextParentTask, height); + this.shiftNextTask(task.nextParentTask, height); + } +}; +GanttTask.prototype.shiftChildTask = function(task, height) +{ + for (var i = 0; i < task.childTask.length; i++) + { + this.shiftTask(task.childTask[i], height); + if (task.childTask[i].childTask.length > 0) { + this.shiftChildTask(task.childTask[i], height); + } + } +}; + +/** + * @desc: get position of the task on EST + * @param: est - time of the beginning of the task + * @type: private + * @topic: 4 + */ +GanttChart.prototype.getPosOnDate = function(est) +{ + return (est - this.startDate) / (60 * 60 * 1000) * this.hourInPixels; +}; +/** + * @desc: get width on duration + * @param: duration - duration of current task + * @type: private + * @topic: 4 + */ +GanttChart.prototype.getWidthOnDuration = function(duration) +{ + return Math.round(this.hourInPixelsWork * duration); +}; +/** + * @desc: end of dragging of task + * @type: private + * @topic: 5 + */ +GanttTask.prototype.endMove = function() +{ + var width = parseInt(this.cTaskItem[0].style.left) - this.posX; + var est = this.getDateOnPosition(parseInt(this.cTaskItem[0].style.left)); + est = this.checkPos(est); + + this.wasMoved = this.TaskInfo.EST.valueOf() != est.valueOf(); + + if (this.checkMove) { + width = this.Chart.getPosOnDate(est) - this.posX; + this.moveCurrentTaskItem(width, this.moveChild); + this.Project.shiftProjectItem(); + } + + this.checkMove = false; + this.posX = 0; + this.maxPosXMove = -1; + this.minPosXMove = -1; + this.cTaskItem[0].childNodes[1].firstChild.rows[0].cells[0].innerHTML = ""; + + if (this.Chart._isFF) document.body.style.cursor = ""; + if (this.Chart._isIE) this.cTaskItem[0].childNodes[2].childNodes[0].style.cursor = ""; +}; + +GanttTask.prototype.checkPos = function(est) +{ + var h = est.getHours(); + if (h >= 12) + { + est.setDate(est.getDate() + 1); + est.setHours(0); + + if ((parseInt(this.cTaskItem[0].firstChild.firstChild.width) + this.Chart.getPosOnDate(est) > this.maxPosXMove) && (this.maxPosXMove != -1)) + { + est.setDate(est.getDate() - 1); + est.setHours(0); + } + + + } else if ((h < 12) && (h != 0)) + { + est.setHours(0); + if ((this.Chart.getPosOnDate(est) < this.minPosXMove)) + { + est.setDate(est.getDate() + 1); + } + } + this.cTaskItem[0].style.left = this.Chart.getPosOnDate(est) + "px"; + + return est; + +}; + +/** + * @desc: returns max position of child task + * @type: private + * @topic: 4 + */ +GanttTask.prototype.getMaxPosPredChildTaskItem = function() +{ + var posPredChildTaskItem = 0; + var nextPosPredChildTaskItem = 0; + + for (var i = 0; i < this.childPredTask.length; i++) + { + nextPosPredChildTaskItem = this.getMaxPosPredChildTaskItemInTree(this.childPredTask[i]); + if (nextPosPredChildTaskItem > posPredChildTaskItem) + { + posPredChildTaskItem = nextPosPredChildTaskItem; + } + } + return posPredChildTaskItem; + +}; +/** + * @desc: returns max position of child task in tree + * @param: task - (object) task + * @type: private + * @topic: 4 + */ +GanttTask.prototype.getMaxPosPredChildTaskItemInTree = function(task) +{ + var currentPos = parseInt(task.cTaskItem[0].firstChild.firstChild.width) + parseInt(task.cTaskItem[0].style.left); + var posPredChildTaskItem = 0; + var nextPosPredChildTaskItem = 0; + + for (var i = 0; i < task.childPredTask.length; i++) + { + nextPosPredChildTaskItem = this.getMaxPosPredChildTaskItemInTree(task.childPredTask[i]); + if (nextPosPredChildTaskItem > posPredChildTaskItem) + { + posPredChildTaskItem = nextPosPredChildTaskItem; + } + } + + if (posPredChildTaskItem > currentPos) + { + return posPredChildTaskItem; + } + else + { + return currentPos; + } + +}; +/** + * @desc: get task by id + * @param: id - Id of GanttTask + * @type: public + * @topic: 2 + */ +GanttProject.prototype.getTaskById = function(id) +{ + for (var i = 0; i < this.arrTasks.length; i++) + { + var task = this.searchTaskInTree(this.arrTasks[i], id); + if (task) return task; + + } + return null; +}; +/** + * @desc: search GanttTask in child tasks + * @param: task - (object) parent GanttTask + * @param: id - Id of GanttTask + * @type: private + * @topic: 2 + */ +GanttProject.prototype.searchTaskInTree = function(task, id) +{ + if (task.TaskInfo.Id == id) + { + return task; + + } else + { + for (var i = 0; i < task.childTask.length; i++) + { + if (task.childTask[i].TaskInfo.Id == id) + { + return task.childTask[i]; + } + else + { + if (task.childTask[i].childTask.length > 0) + { + var cTask = this.searchTaskInTree(task.childTask[i], id); + if (cTask) return cTask; + } + } + } + } + + return null; +}; +/** + * @desc: shift current projectItem + * @type: private + * @topic: 4 + */ +GanttProject.prototype.shiftProjectItem = function() +{ + var posItemL = null; + var posItemR = null; + var posProjectItemL = parseInt(this.projectItem[0].style.left); + var posProjectItemR = parseInt(this.projectItem[0].firstChild.style.width) + parseInt(this.projectItem[0].style.left); + var widthProjectItem = parseInt(this.projectItem[0].firstChild.style.width); + + for (var t = 0; t < this.arrTasks.length; t++) + { + var tmpPosItemL = parseInt(this.arrTasks[t].cTaskItem[0].style.left); + var tmpPosItemR = parseInt(this.arrTasks[t].cTaskItem[0].style.left) + parseInt(this.arrTasks[t].cTaskItem[0].firstChild.firstChild.width); + + if (!posItemL) { + posItemL = tmpPosItemL; + } + if (!posItemR) { + posItemR = tmpPosItemR; + } + + + if (posItemL > tmpPosItemL) { + posItemL = tmpPosItemL; + } + + if (posItemR < tmpPosItemR) { + posItemR = tmpPosItemR; + } + + } + + if (posItemL != posProjectItemL) + { + this.Project.StartDate = new Date(this.Chart.startDate); + this.Project.StartDate.setHours(this.Project.StartDate.getHours() + (posItemL / this.Chart.hourInPixels)); + } + + this.projectItem[0].style.left = posItemL + "px"; + this.resizeProjectItem(posItemR - posItemL); + + this.Duration = Math.round(parseInt(this.projectItem[0].firstChild.width) / (this.Chart.hourInPixelsWork)); + if (this.Chart.isShowDescProject) { + this.moveDescrProject(); + } + this.addDayInPanelTime(); + +}; +/** + * @desc: add one day + * @type: private + * @topic: 4 + */ +GanttProject.prototype.addDayInPanelTime = function() +{ + var width = parseInt(this.projectItem[0].style.left) + parseInt(this.projectItem[0].firstChild.style.width) + 20; + if (this.Chart.isShowDescProject) { + width += this.descrProject.offsetWidth; + } + + var table = this.Chart.panelTime.firstChild, tbody = table.firstChild; + if (parseInt(tbody.offsetWidth) < width) + { + var countDays = Math.round((width - parseInt(tbody.offsetWidth)) / this.Chart.dayInPixels); + var row = tbody.rows[1]; + for (var n = 0; n < countDays; n++) + { + this.Chart.addPointInTimePanel(row, table); + this.Chart.addDayInPanelTime(row); + } + var w = this.Chart.dayInPixels * (row.cells.length); + tbody.style.width = w + "px"; + this.Chart.panelTasks.style.width = (w-18) + "px"; + } +}; +/** + * @desc: add event + * @param: elm - current element + * @param: evType - string that specifies any of the standard DHTML Events + * @param: fn - pointer that specifies the function to call when sEvent fires + * @type: private + * @topic: 5 + */ +GanttProject.prototype.addEvent = function (elm, evType, fn, useCapture) +{ + if (elm.addEventListener) { + elm.addEventListener(evType, fn, useCapture); + return true; + } + else if (elm.attachEvent) { + return elm.attachEvent('on' + evType, fn); + } + else { + elm['on' + evType] = fn; + } +}; +/** + * @desc: shows popup info + * @param: event - (object)event + * @type: private + * @topic: 4 + */ +GanttProject.prototype.getPopUpInfo = function(object, event) +{ + //this.projectItem[0] + var posX = object.offsetLeft + ((event.layerX == null) ? event.offsetX : event.layerX); + var posY = object.offsetTop + this.Chart.heightTaskItem + 6; + + var tblInfo = this.Chart.divInfo.lastChild; + tblInfo.rows[0].cells[0].innerHTML = "
" + this.Project.Name + "
"; + tblInfo.rows[0].cells[0].innerHTML += "Start Date: " + this.Project.StartDate.getDate() + "." + (this.Project.StartDate.getMonth() + 1) + "." + this.Project.StartDate.getFullYear() + "
"; + tblInfo.rows[0].cells[0].innerHTML += "Duration: " + this.Duration + " hours
"; + tblInfo.rows[0].cells[0].innerHTML += "Percent Complete: " + this.percentCompleted + "%
"; + + this.Chart.divInfo.style.cssText = "z-index:2;position: absolute;display: inline;"; + + if (posY + this.Chart.divInfo.lastChild.offsetHeight + 6 > this.Chart.oData.offsetHeight + this.Chart.oData.scrollTop) + { + this.Chart.divInfo.style.top = (posY - this.Chart.divInfo.lastChild.offsetHeight - 10 - this.Chart.heightTaskItem) + "px"; + } + else { + this.Chart.divInfo.style.top = posY + "px"; + } + + if (this.Chart.divInfo.lastChild.offsetWidth + posX + 10 > this.Chart.oData.offsetWidth + this.Chart.oData.scrollLeft) + { + this.Chart.divInfo.style.left = posX - (this.Chart.divInfo.lastChild.offsetWidth + posX + 20 - (this.Chart.oData.offsetWidth + this.Chart.oData.scrollLeft)) + "px"; + + } else { + this.Chart.divInfo.style.left = posX + "px"; + } +}; +/** + * @desc: hides pop up info + * @type: private + * @topic: 4 + */ +GanttProject.prototype.closePopUpInfo = function() +{ + this.Chart.divInfo.style.display = "none"; +}; +/** + * @desc: resize projectItem + * @param: width - new width + * @type: private + * @topic: 4 + */ +GanttProject.prototype.resizeProjectItem = function(width) +{ + var percentCompleted = this.percentCompleted; + if (percentCompleted > 0 && percentCompleted < 100) + { + this.projectItem[0].firstChild.style.width = width + "px"; + this.projectItem[0].firstChild.width = width + "px"; + this.projectItem[0].style.width = width + "px"; + this.projectItem[0].firstChild.rows[0].cells[0].firstChild.style.width = Math.round(width * percentCompleted / 100) + "px"; + this.projectItem[0].firstChild.rows[0].cells[1].firstChild.style.width = Math.round(width * (100 - percentCompleted) / 100) + "px"; + this.projectItem[0].lastChild.firstChild.width = width + "px"; + + } else if (percentCompleted == 0 || percentCompleted == 100) + { + this.projectItem[0].firstChild.style.width = width + "px"; + this.projectItem[0].firstChild.width = width + "px"; + this.projectItem[0].style.width = width + "px"; + this.projectItem[0].firstChild.rows[0].cells[0].firstChild.style.width = width + "px"; + this.projectItem[0].lastChild.firstChild.width = width + "px"; + } +}; +/** + * @desc: Moving of current task + * @param: width - length of shift of the task + * @param: moveChild - true, if move children together + * @type: private + * @topic: 4 + */ +GanttTask.prototype.moveCurrentTaskItem = function(width, moveChild) +{ + var taskItem = this.cTaskItem[0]; + this.TaskInfo.EST = new Date(this.Chart.startDate); + this.TaskInfo.EST.setHours(this.TaskInfo.EST.getHours() + (parseInt(taskItem.style.left) / this.Chart.hourInPixels)); + if (this.Chart.isShowDescTask) { + this.showDescTask(); + } + + if (this.cTaskItem[1].length > 0) { + this.cTaskItem[1][2].style.width = parseInt(this.cTaskItem[1][2].style.width) + width + "px"; + this.cTaskItem[1][1].style.left = parseInt(this.cTaskItem[1][1].style.left) + width + "px"; + } + + for (var i = 0; i < this.childTask.length; i++) { + if (!this.childTask[i].predTask) { + this.moveChildTaskItems(this.childTask[i], width, moveChild); + } + } + + for (var i = 0; i < this.childPredTask.length; i++) { + this.moveChildTaskItems(this.childPredTask[i], width, moveChild); + } + +}; +/** + * @desc: Moving of child tasks + * @param: task - (object) GanttTask + * @param: width - length of shift of the task + * @param: moveChild - true, if move children together + * @type: private + * @topic: 4 + */ +GanttTask.prototype.moveChildTaskItems = function(task, width, moveChild) +{ + var taskItem = task.cTaskItem[0]; + + if (moveChild) + { + taskItem.style.left = parseInt(taskItem.style.left) + width + "px"; + task.addDayInPanelTime(); + task.TaskInfo.EST = new Date(this.Chart.startDate); + task.TaskInfo.EST.setHours(task.TaskInfo.EST.getHours() + (parseInt(taskItem.style.left) / this.Chart.hourInPixels)); + + for (var n = 0; n < task.cTaskItem[1].length; n++) { + task.cTaskItem[1][n].style.left = parseInt(task.cTaskItem[1][n].style.left) + width + "px"; + } + + for (var i = 0; i < task.childTask.length; i++) { + if (!task.childTask[i].predTask) { + this.moveChildTaskItems(task.childTask[i], width, moveChild); + } + } + + for (var i = 0; i < task.childPredTask.length; i++) { + this.moveChildTaskItems(task.childPredTask[i], width, moveChild); + } + } + else + { + if (task.cTaskItem[1].length > 0) + { + task.cTaskItem[1][2].style.left = parseInt(task.cTaskItem[1][2].style.left) + width + "px"; + task.cTaskItem[1][2].style.width = parseInt(task.cTaskItem[1][2].style.width) - width + "px"; + task.cTaskItem[1][0].style.left = parseInt(task.cTaskItem[1][0].style.left) + width + "px"; + } + } + if (this.Chart.isShowDescTask) { + task.moveDescTask(); + } +}; +/** + * @desc: Addition of new day in panel of time + * @type: private + * @topic: 4 + */ +GanttTask.prototype.addDayInPanelTime = function() +{ + var taskItem = this.cTaskItem[0]; + var width = parseInt(taskItem.style.left) + parseInt(taskItem.firstChild.firstChild.width) + 20; + if (this.Chart.isShowDescTask) { + width += this.descrTask.offsetWidth; + } + + var table = this.Chart.panelTime.firstChild, tbody = table.firstChild; + if (parseInt(tbody.offsetWidth) < width) + { + var row = tbody.rows[1]; + var countDays = Math.round((width + 20 - parseInt(tbody.offsetWidth)) / this.Chart.dayInPixels); + for (var n = 0; n < countDays; n++) + { + this.Chart.addPointInTimePanel(row, table); + this.Chart.addDayInPanelTime(row); + } + var w = this.Chart.dayInPixels * (row.cells.length); + tbody.style.width = w + "px"; + this.Chart.panelTasks.style.width = (w-18) + "px"; + } +}; +/** + * @desc: return of date on position of task + * @param: position - current position of task + * @type: private + * @topic: 4 + */ +GanttTask.prototype.getDateOnPosition = function(position) +{ + var date = new Date(this.Chart.startDate); + date.setHours(date.getHours() + (position / this.Chart.hourInPixels)); + return date; +}; +/** + * @desc: moving of current task + * @param: event - (object) event + * @type: private + * @topic: 4 + */ +GanttTask.prototype.moveItem = function(event) +{ + var pageX = event.screenX; + var posTaskItem = (this.posX + (pageX - this.MouseX)); + var widthTaskItem = parseInt(this.cTaskItem[0].childNodes[0].firstChild.width); + var posTaskItemR = posTaskItem + widthTaskItem; + + if (this.checkMove) + { + var date = this.getDateOnPosition(posTaskItem); + var res = this.Chart.callEvent("onTaskDragging", [this,date])!==false; + if (res && ((this.minPosXMove <= posTaskItem)) + && ((posTaskItemR <= this.maxPosXMove) || (this.maxPosXMove == -1))) + { + this.moveTaskItem(posTaskItem); + } + } +}; +/** + * @desc: shift taskItem + * @param: posX - position of task + * @type: private + * @topic: 4 + */ +GanttTask.prototype.moveTaskItem = function(posX) +{ + this.addDayInPanelTime(); + this.cTaskItem[0].style.left = posX + "px"; + var date = this.getDateOnPosition(posX); + this.cTaskItem[0].childNodes[1].firstChild.rows[0].cells[0].innerHTML = date.getDate() + '.' + (date.getMonth() + 1) + '.' + date.getUTCFullYear(); +}; +/** + * @desc: resize current task + * @param: event - (object) event + * @type: private + * @topic: 4 + */ +GanttTask.prototype.resizeItem = function(event) +{ + if (this.checkResize) + { + var MouseX = event.screenX; + var widthTaskItem = this.taskItemWidth + (MouseX - this.MouseX); + + var countHours = Math.round(widthTaskItem / this.Chart.hourInPixelsWork); + if (this.Chart.callEvent("onTaskResizing", [this,countHours])===false) return; + + if (widthTaskItem >= this.taskItemWidth) + { + if ((widthTaskItem <= this.maxWidthResize) || (this.maxWidthResize == -1)) + { + this.resizeTaskItem(widthTaskItem); + this.addDayInPanelTime(); + + } else if ((this.maxWidthResize != -1) && (widthTaskItem > this.maxWidthResize)) + { + this.resizeTaskItem(this.maxWidthResize); + } + } else if (widthTaskItem <= this.taskItemWidth) + { + if (widthTaskItem >= this.minWidthResize) + { + this.resizeTaskItem(widthTaskItem); + } + else if (widthTaskItem < this.minWidthResize) + { + this.resizeTaskItem(this.minWidthResize); + } + } + } +}; +/** + * @desc: resize current taskItem + * @param: width - width of current taskItem + * @type: private + * @topic: 4 + */ +GanttTask.prototype.resizeTaskItem = function(width) +{ + var taskItem = this.cTaskItem[0]; + var countHours = Math.round(width / this.Chart.hourInPixelsWork); + var c = taskItem.childNodes[0].firstChild.rows[0].cells[0]; + if (c) + { + c.firstChild.style.width = parseInt(c.width) * width / 100 + "px"; + } + c = taskItem.childNodes[0].firstChild.rows[0].cells[1]; + if (c) + { + c.firstChild.style.width = parseInt(c.width) * width / 100 + "px"; + } + + taskItem.childNodes[0].firstChild.width = width + "px"; + taskItem.childNodes[1].firstChild.width = width + "px"; + + //resize info + this.cTaskItem[0].childNodes[1].firstChild.rows[0].cells[0].innerHTML = countHours; + taskItem.childNodes[2].childNodes[0].style.width = width + "px"; + taskItem.childNodes[2].childNodes[1].style.left = width - 10 + "px"; +}; +/** + * @desc: end of stretch of task + * @param: event - (object) event + * @type: private + * @topic: 4 + */ +GanttTask.prototype.endResizeItem = function() +{ + var taskItem = this.cTaskItem[0]; + this.wasResized = this.taskItemWidth != parseInt(taskItem.childNodes[0].firstChild.width); + if (this.wasResized) + { + var posXL = taskItem.offsetLeft; + var posXR = taskItem.offsetLeft + parseInt(taskItem.childNodes[0].firstChild.width); + this.TaskInfo.Duration = Math.round((posXR - posXL) / this.Chart.hourInPixelsWork); + if (this.childPredTask.length > 0) + { + for (var j = 0; j < this.childPredTask.length; j++) + { + this.childPredTask[j].cTaskItem[1][2].style.width = parseInt(this.childPredTask[j].cTaskItem[1][2].style.width) - (parseInt(taskItem.childNodes[0].firstChild.width) - this.taskItemWidth) + "px"; + this.childPredTask[j].cTaskItem[1][2].style.left = parseInt(this.childPredTask[j].cTaskItem[1][2].style.left) + (parseInt(taskItem.childNodes[0].firstChild.width) - this.taskItemWidth) + "px"; + this.childPredTask[j].cTaskItem[1][0].style.left = parseInt(this.childPredTask[j].cTaskItem[1][0].style.left) + (parseInt(taskItem.childNodes[0].firstChild.width) - this.taskItemWidth) + "px"; + } + } + } + this.cTaskItem[0].childNodes[1].firstChild.rows[0].cells[0].innerHTML = ""; + this.checkResize = false; + this.taskItemWidth = 0; + this.MouseX = 0; + if (this.Chart.isShowDescTask) { + this.showDescTask(); + } + this.Project.shiftProjectItem(); + + if (this.Chart._isFF) document.body.style.cursor = ""; +}; + +GanttProject.prototype.moveDescrProject = function() +{ + this.descrProject.style.left = (parseInt(this.projectItem[0].style.left) + this.Duration * this.Chart.hourInPixelsWork + 10); + this.descrProject.innerHTML = this.getDescStr(); +}; + +GanttProject.prototype.showDescrProject = function() +{ + var posX = (parseInt(this.projectItem[0].style.left) + this.Duration * this.Chart.hourInPixelsWork + 10); + this.descrProject.style.left = posX + "px"; + this.descrProject.style.visibility = 'visible'; + this.descrProject.innerHTML = this.getDescStr(); +}; + +GanttProject.prototype.hideDescrProject = function() +{ + this.descrProject.style.visibility = 'hidden'; +}; + +GanttProject.prototype.getDescStr = function() +{ + var str = '', delim = ", "; + + for (var i = 0; i < this.Chart.paramShowProject.length; i++) { + + switch (this.Chart.paramShowProject[i]) { + case "Name": + if (str != "")str += delim; + str += this.Project[this.Chart.paramShowProject[i]]; + break; + case "StartDate": + if (str != "")str += delim; + var d = this.Project[this.Chart.paramShowProject[i]]; + str += d.getDate() + "." + (d.getMonth() + 1) + "." + d.getFullYear(); + break; + case "Duration": + if (str != "")str += delim; + str += this[this.Chart.paramShowProject[i]] + "h"; + break; + case "percentCompleted": + if (str != "")str += delim; + str += this[this.Chart.paramShowProject[i]] + "%"; + break; + + default: + break; + } + + } + return str; +}; + + +GanttProject.prototype.createDescrProject = function() +{ + var posX = (this.posX + this.Duration * this.Chart.hourInPixelsWork + 10); + var divDesc = document.createElement("div"); + divDesc.style.cssText += ";z-index:1;position:absolute;left:" + posX + "px;top:" + this.posY + "px;"; + divDesc.innerHTML = this.getDescStr(); + divDesc.className = "descProject"; + this.descrProject = divDesc; + + if (this.Project.ParentTasks.length == 0) { + this.descrProject.style.visibility = 'hidden'; + } + + if (this.Chart._showTooltip) + { + var self = this; + var getPopUpInfo = function(e) { + if ((!self.Chart._isMove) && (!self.Chart._isResize)) self.getPopUpInfo(self.descrProject, e); + }; + var closePopUpInfo = function() { + self.closePopUpInfo(); + }; + + this.addEvent(divDesc, 'mouseover', getPopUpInfo, false); + this.addEvent(divDesc, 'mouseout', closePopUpInfo, false); + } + return divDesc; +}; + +/** + * @desc: creation of projectItem + * @type: private + * @topic: 0 + */ +GanttProject.prototype.createProjectItem = function() +{ + var self = this; + this.percentCompleted = this.getPercentCompleted(); + this.Duration = this.getDuration(); + + var projectItem = document.createElement("div"); + projectItem.id = this.Project.Id; + projectItem.style.cssText = ";z-index:1;position: absolute;left:" + this.posX + "px;top:" + this.posY + "px;"; + projectItem.style.width = this.Duration * this.Chart.hourInPixelsWork + "px"; + + var tblProjectItem = document.createElement("table"); + projectItem.appendChild(tblProjectItem); + tblProjectItem.cellPadding = "0"; + tblProjectItem.cellSpacing = "0"; + tblProjectItem.style.cssText = "border: solid 1px #BC810D;"; + var width = this.Duration * this.Chart.hourInPixelsWork; + tblProjectItem.width = ((width == 0) ? 1 : width) + "px"; + tblProjectItem.style.width = ((width == 0) ? 1 : width) + "px"; + + var rowprojectItem = tblProjectItem.insertRow(tblProjectItem.rows.length); + + if (this.percentCompleted != -1) + { + if (this.percentCompleted != 0) + { + var cellprojectItem = document.createElement("TD"); + rowprojectItem.appendChild(cellprojectItem); + cellprojectItem.width = this.percentCompleted + "%"; + cellprojectItem.style.lineHeight = "1px"; + var imgPr = document.createElement("img"); + imgPr.style.width = (this.percentCompleted * this.Duration * this.Chart.hourInPixelsWork) / 100 + "px"; + imgPr.style.height = this.Chart.heightTaskItem + "px"; + cellprojectItem.appendChild(imgPr); + imgPr.src = this.Chart.imgs + "parentnode_filled.png"; + + } + + if (this.percentCompleted != 100) + { + var cellprojectItem = document.createElement("TD"); + rowprojectItem.appendChild(cellprojectItem); + cellprojectItem.width = (100 - this.percentCompleted) + "%"; + cellprojectItem.style.lineHeight = "1px"; + var imgPr = document.createElement("img"); + imgPr.style.width = ((100 - this.percentCompleted) * this.Duration * this.Chart.hourInPixelsWork) / 100 + "px"; + imgPr.style.height = this.Chart.heightTaskItem + "px"; + cellprojectItem.appendChild(imgPr); + imgPr.src = this.Chart.imgs + "progress_bg.png"; + } + + } else + { + var cellprojectItem = document.createElement("TD"); + rowprojectItem.appendChild(cellprojectItem); + cellprojectItem.width = "1px"; + cellprojectItem.style.lineHeight = "1px"; + var imgPr = document.createElement("img"); + imgPr.style.width = "1px"; + imgPr.style.height = this.Chart.heightTaskItem; + cellprojectItem.appendChild(imgPr); + imgPr.src = this.Chart.imgs + "progress_bg.png"; + + } + + var divTaskInfo = document.createElement("div"); + divTaskInfo.style.cssText = "text-align:center;z-index:2;position:absolute;left:0px;top:0px;"; + // + + var tblTaskInfo = document.createElement("table"); + divTaskInfo.appendChild(tblTaskInfo); + tblTaskInfo.cellPadding = "0"; + tblTaskInfo.cellSpacing = "0"; + tblTaskInfo.height = this.Chart.heightTaskItem + "px"; + tblTaskInfo.width = ((this.Duration * this.Chart.hourInPixelsWork == 0) ? 1 : this.Duration * this.Chart.hourInPixelsWork) + "px"; + + var rowTaskInfo = tblTaskInfo.insertRow(0); + var cellTaskInfo = document.createElement("td"); + cellTaskInfo.align = "center"; + cellTaskInfo.vAlign = "top"; + cellTaskInfo.height = this.Chart.heightTaskItem + "px"; + cellTaskInfo.className = "moveInfo"; + cellTaskInfo.style.cssText = ";white-space:nowrap;"; + rowTaskInfo.appendChild(cellTaskInfo); + projectItem.appendChild(divTaskInfo); + + if (this.Project.ParentTasks.length == 0) + { + projectItem.style.display = "none"; + + } + + if (this.Chart._showTooltip) + { + var getPopUpInfo = function(e) { + if ((!self.Chart._isMove) && (!self.Chart._isResize)) self.getPopUpInfo(self.projectItem[0], e); + }; + var closePopUpInfo = function() { + self.closePopUpInfo(); + }; + + this.addEvent(divTaskInfo, 'mouseover', getPopUpInfo, false); + this.addEvent(divTaskInfo, 'mouseout', closePopUpInfo, false); + } + return projectItem; +}; +/** + * @desc: Creation of projectNameItem + * @type: private + * @topic: 0 + */ +GanttProject.prototype.createProjectNameItem = function() +{ + var self = this; + var divName = document.createElement("div"); + divName.style.cssText = "cursor:pointer;color:#003366;font-weight:bold;font-size:12px;font-family:Tahoma,Arial;white-space:nowrap;height:15px;z-index:1;position:absolute;left:" + 5 + "px;top:" + this.posY + "px;"; + divName.innerHTML = this.Project.Name; + divName.title = this.Project.Name; + if (this.Chart.isShowConMenu) + { + var showContMenu = function(event) { + + if (self.Chart.contextMenu.clear) self.Chart.contextMenu.clear(); + + var hideContMenu = null; + if (!self.Chart._isIE) + { + hideContMenu = function() { + self.Chart.contextMenu.hideContextMenu(); + self.Chart.content.removeEventListener("mousedown", hideContMenu, false); + }; + + } else + { + hideContMenu = function() { + self.Chart.contextMenu.hideContextMenu(); + self.Chart.content.detachEvent("mousedown", hideContMenu); + }; + } + + self.Chart.content.onmousedown = hideContMenu; + + if (!self.Chart._isIE) + { + event.stopPropagation(); + + } else + { + event.cancelBubble = true; + } + + self.Chart._showContextMenu(event, self); + + }; + + if (this.Chart._isIE) + { + this.addEvent(divName, "contextmenu", function(e) { + showContMenu(e); + return false; + }, false); + + } else + { + this.addEvent(divName, "contextmenu", function(e) { + e.preventDefault(); + showContMenu(e); + }, false); + } + + } + return divName; +}; +/** + * @desc: calculates and returns percent completed of project + * @type: public + * @topic: 0 + */ +GanttProject.prototype.getPercentCompleted = function() +{ + var sum = 0; + var percentCompleted = 0; + + for (var i = 0; i < this.Project.ParentTasks.length; i++) { + sum += parseInt(this.Project.ParentTasks[i].PercentCompleted); + } + if (this.Project.ParentTasks.length != 0) { + return percentCompleted = Math.round(sum / this.Project.ParentTasks.length); + } + else { + return percentCompleted = -1; + } +}; +/** + * @desc: calculates and returns the duration of project in hours + * @type: public + * @topic: 0 + */ +GanttProject.prototype.getDuration = function() +{ + var duration = 0; + var tmpDuration = 0; + if (this.Project.ParentTasks.length > 0) + { + for (var i = 0; i < this.Project.ParentTasks.length; i++) + { + tmpDuration = this.Project.ParentTasks[i].Duration * 24 / this.Chart.hoursInDay + (this.Project.ParentTasks[i].EST - this.Chart.startDate) / (60 * 60 * 1000); + if (tmpDuration > duration) + { + duration = tmpDuration; + } + } + return ((duration - this.posX) / 24) * this.Chart.hoursInDay; + + } else + { + return 0; + } + +}; +/** + * @desc: returns id of project. + * @type: public + * @topic: 0 + */ +GanttProject.prototype.getId = function() +{ + return this.Project.Id; +}; +/** + * @desc: returns name of project. + * @type: public + * @topic: 0 + */ +GanttProject.prototype.getName = function() +{ + return this.Project.Name; +}; +/** + * @desc: returns start date of project. + * @type: public + * @topic: 0 + */ +GanttProject.prototype.getStartDate = function() +{ + return this.Project.StartDate; +}; + +/** + * @desc: add event + * @param: elm - current element + * @param: evType - string that specifies any of the standard DHTML Events + * @param: fn - pointer that specifies the function to call when sEvent fires + * @type: private + * @topic: 5 + */ +GanttTask.prototype.addEvent = function (elm, evType, fn, useCapture) +{ + if (elm.addEventListener) { + elm.addEventListener(evType, fn, useCapture); + return true; + } + else if (elm.attachEvent) { + return elm.attachEvent('on' + evType, fn); + } + else { + elm['on' + evType] = fn; + } +}; +/** + * @desc: the beginning of movement of task + * @param: event - (object)event + * @type: private + * @topic: 5 + */ +GanttTask.prototype.startMove = function (event) +{ + this.moveChild = event.ctrlKey; + this.MouseX = event.screenX; + + this.getMoveInfo(); + + this.checkMove = true; + + if (this.Chart.isShowDescTask) { + this.hideDescTask(); + } + if (this.Chart._isFF) document.body.style.cursor = "move"; + if (this.Chart._isIE) event.srcElement.style.cursor = "move"; +}; + +GanttTask.prototype.showDescTask = function() +{ + var posX = (parseInt(this.cTaskItem[0].style.left) + this.TaskInfo.Duration * this.Chart.hourInPixelsWork + 10); + this.descrTask.style.left = posX + "px"; + this.descrTask.innerHTML = this.getDescStr(); + this.descrTask.style.visibility = 'visible'; + +}; +GanttTask.prototype.hideDescTask = function() +{ + this.descrTask.style.visibility = 'hidden'; +}; +GanttTask.prototype.getDescStr = function() +{ + var str = '', delim = ", "; + for (var i = 0; i < this.Chart.paramShowTask.length; i++) { + var prop = this.Chart.paramShowTask[i], propValue = this.TaskInfo[prop]; + switch (prop) { + case "Name": + if (str != "")str += delim; + str += propValue; + break; + case "EST": + if (str != "")str += delim; + str += propValue.getDate() + "." + (propValue.getMonth() + 1) + "." + propValue.getFullYear(); + break; + case "S-F": + if (str != "")str += delim; + propValue = this.TaskInfo["EST"]; + str += propValue.getDate() + "." + (propValue.getMonth() + 1) + "." + propValue.getFullYear() + " - "; + propValue = this.getFinishDate(); + str += propValue.getDate() + "." + (propValue.getMonth() + 1) + "." + propValue.getFullYear(); + break; + case "Duration": + if (str != "")str += delim; + str += propValue + "h"; + break; + case "PercentCompleted": + if (str != "")str += delim; + str += propValue + "%"; + break; + default: + break; + } + } + return str; +}; +/** + * @desc: returns id of task + * @type: public + * @topic: 0 + */ +GanttTask.prototype.getId = function() +{ + return this.TaskInfo.Id; +}; +/** + * @desc: returns name of task + * @type: public + * @topic: 0 + */ +GanttTask.prototype.getName = function() +{ + return this.TaskInfo.Name; +}; +/** + * @desc: returns duration of task (in hours) + * @type: public + * @topic: 0 + */ +GanttTask.prototype.getDuration = function() +{ + return this.TaskInfo.Duration; +}; +/** + * @desc: returns EST of task + * @type: public + * @topic: 0 + */ +GanttTask.prototype.getEST = function() +{ + return this.TaskInfo.EST; +}; +/** + * @desc: calculates and returns FinishDate of task + * @type: public + * @topic: 0 + */ +GanttTask.prototype.getFinishDate = function() +{ + var date = new Date(this.TaskInfo.EST); + date.setDate(date.getDate() + parseInt((this.TaskInfo["Duration"]-1)/this.Chart.hoursInDay+1)-1); + return date; +}; +/** + * @desc: returns PercentCompleted of task + * @type: public + * @topic: 0 + */ +GanttTask.prototype.getPercentCompleted = function() +{ + return this.TaskInfo.PercentCompleted; +}; +/** + * @desc: returns PredecessorTaskId of task + * @type: public + * @topic: 0 + */ +GanttTask.prototype.getPredecessorTaskId = function() +{ + return this.TaskInfo.PredecessorTaskId ? this.TaskInfo.PredecessorTaskId : null; +}; +/** + * @desc: returns ParentTaskId of task + * @type: public + * @topic: 0 + */ +GanttTask.prototype.getParentTaskId = function() +{ + return this.parentTask ? this.parentTask.getId() : null; +}; + +GanttTask.prototype.moveDescTask = function() +{ + var posX = (parseInt(this.cTaskItem[0].style.left) + this.TaskInfo.Duration * this.Chart.hourInPixelsWork + 10); + this.descrTask.style.left = posX + "px"; +}; + +/** + * @desc: Defines max and min position of movement + * @type: private + * @topic: 4 + */ +GanttTask.prototype.getMoveInfo = function() +{ + this.posX = parseInt(this.cTaskItem[0].style.left); + var widthTaskItem = parseInt(this.cTaskItem[0].childNodes[0].firstChild.width); + var posParentTaskItem = (this.parentTask == null) ? 0 : parseInt(this.parentTask.cTaskItem[0].style.left); + var posPredTaskItem = (this.predTask == null) ? 0 : parseInt(this.predTask.cTaskItem[0].style.left) + parseInt(this.predTask.cTaskItem[0].childNodes[0].firstChild.width); + var widthParentTaskItem = (this.parentTask == null) ? 0 : parseInt(this.parentTask.cTaskItem[0].childNodes[0].firstChild.width); + + var childPredPosX = 0; + var childParentPosX = 0; + var childParentPosXR = 0; + if (this.childPredTask.length > 0) + { + var posChildTaskItem = null; + for (var n = 0; n < this.childPredTask.length; n++) + { + if ((!posChildTaskItem) || ((posChildTaskItem) && (posChildTaskItem > parseInt(this.childPredTask[n].cTaskItem[0].style.left)))) + { + posChildTaskItem = parseInt(this.childPredTask[n].cTaskItem[0].style.left); + } + } + childPredPosX = posChildTaskItem; + } + if (this.childTask.length > 0) + { + var posChildTaskItemR = null; + for (var n = 0; n < this.childTask.length; n++) + { + if ((!posChildTaskItemR) || ((posChildTaskItemR) && (posChildTaskItemR > (parseInt(this.childTask[n].cTaskItem[0].style.left))))) + { + posChildTaskItemR = parseInt(this.childTask[n].cTaskItem[0].style.left); + } + } + childParentPosXR = posChildTaskItemR; + + var posChildTaskItem = null; + for (var n = 0; n < this.childTask.length; n++) + { + if ((!posChildTaskItem) || ((posChildTaskItem) && (posChildTaskItem < (parseInt(this.childTask[n].cTaskItem[0].style.left) + parseInt(this.childTask[n].cTaskItem[0].firstChild.firstChild.width))))) + { + posChildTaskItem = parseInt(this.childTask[n].cTaskItem[0].style.left) + parseInt(this.childTask[n].cTaskItem[0].firstChild.firstChild.width); + } + } + + childParentPosX = posChildTaskItem; + } + + if (!this.moveChild) + { + if (this.childPredTask.length > 0) { + if (this.maxPosXMove < childPredPosX) this.maxPosXMove = childPredPosX; + } + if (this.childTask.length > 0) { + if ((this.childPredTask.length > 0) && (this.maxPosXMove - widthTaskItem) > childParentPosXR) this.maxPosXMove = this.maxPosXMove - ((this.maxPosXMove - widthTaskItem) - childParentPosXR); + if (!(this.childPredTask.length > 0)) this.maxPosXMove = childParentPosXR + widthTaskItem; + this.minPosXMove = (childParentPosX - widthTaskItem); + } + + if (posParentTaskItem > 0) + { + if ((!(this.childPredTask.length > 0)) && (this.childTask.length > 0)) { + if (this.maxPosXMove > posParentTaskItem + widthParentTaskItem) { + this.maxPosXMove = posParentTaskItem + widthParentTaskItem; + } + } + if (this.minPosXMove <= posParentTaskItem) { + this.minPosXMove = posParentTaskItem; + } + if ((!(this.childTask.length > 0)) && (!(this.childPredTask.length > 0))) { + this.maxPosXMove = posParentTaskItem + widthParentTaskItem; + + } else if ((!(this.childTask.length > 0)) && (this.childPredTask.length > 0)) { + if ((posParentTaskItem + widthParentTaskItem) > posPredTaskItem) { + this.maxPosXMove = childPredPosX; + } + } + } + + if (posPredTaskItem > 0) { + if (this.minPosXMove <= posPredTaskItem) { + this.minPosXMove = posPredTaskItem; + } + } + if ((posPredTaskItem == 0) && (posParentTaskItem == 0)) { + if (this.minPosXMove <= this.Chart.initialPos) { + this.minPosXMove = this.Chart.initialPos; + } + } + } else + { + if ((posParentTaskItem > 0) && (posPredTaskItem == 0)) + { + this.minPosXMove = posParentTaskItem; + this.maxPosXMove = posParentTaskItem + widthParentTaskItem; + + } else if ((posParentTaskItem == 0) && (posPredTaskItem == 0)) + { + this.minPosXMove = this.Chart.initialPos; + this.maxPosXMove = -1; + + } else if ((posParentTaskItem > 0) && (posPredTaskItem > 0)) + { + this.minPosXMove = posPredTaskItem; + this.maxPosXMove = posParentTaskItem + widthParentTaskItem; + + } else if ((posParentTaskItem == 0) && (posPredTaskItem > 0)) + { + this.minPosXMove = posPredTaskItem; + this.maxPosXMove = -1; + } + + if ((this.parentTask) && (this.childPredTask.length > 0)) + { + var posChildTaskItem = this.getMaxPosPredChildTaskItem(this); + var posParentTaskItem = parseInt(this.parentTask.cTaskItem[0].style.left) + parseInt(this.parentTask.cTaskItem[0].firstChild.firstChild.width); + this.maxPosXMove = this.posX + widthTaskItem + posParentTaskItem - posChildTaskItem; + } + } +}; +/** + * @desc: The beginning of extension of task + * @param: event - (object) event + * @type: private + * @topic: 5 + */ +GanttTask.prototype.startResize = function(event) +{ + this.MouseX = event.screenX; + this.getResizeInfo(); + if (this.Chart.isShowDescTask) { + this.hideDescTask(); + } + this.checkResize = true; + this.taskItemWidth = parseInt(this.cTaskItem[0].firstChild.firstChild.width); + if (this.Chart._isFF)document.body.style.cursor = "e-resize"; + +}; +/** + * @desc: Defines max and min position of stretchings + * @type: private + * @topic: 4 + */ +GanttTask.prototype.getResizeInfo = function() +{ + var taskItem = this.cTaskItem[0]; + var posParentTaskItem = (this.parentTask == null) ? 0 : parseInt(this.parentTask.cTaskItem[0].style.left); + var widthParentTaskItem = (this.parentTask == null) ? 0 : parseInt(this.parentTask.cTaskItem[0].childNodes[0].firstChild.width); + var posTaskItem = parseInt(this.cTaskItem[0].style.left); + + var childPredPosX = 0; + var childParentPosX = 0; + if (this.childPredTask.length > 0) + { + var posChildTaskItem = null; + for (var n = 0; n < this.childPredTask.length; n++) + { + if ((!posChildTaskItem) || ((posChildTaskItem) && (posChildTaskItem > parseInt(this.childPredTask[n].cTaskItem[0].style.left)))) + { + posChildTaskItem = parseInt(this.childPredTask[n].cTaskItem[0].style.left); + + } + } + childPredPosX = posChildTaskItem; + } + + if (this.childTask.length > 0) + { + var posChildTaskItem = null; + for (var n = 0; n < this.childTask.length; n++) + { + if ((!posChildTaskItem) || ((posChildTaskItem) && (posChildTaskItem < (parseInt(this.childTask[n].cTaskItem[0].style.left) + parseInt(this.childTask[n].cTaskItem[0].firstChild.firstChild.width))))) + { + posChildTaskItem = parseInt(this.childTask[n].cTaskItem[0].style.left) + parseInt(this.childTask[n].cTaskItem[0].firstChild.firstChild.width); + } + } + + childParentPosX = posChildTaskItem; + } + + this.minWidthResize = this.Chart.dayInPixels; + + if (this.childTask.length > 0) + { + this.minWidthResize = childParentPosX - posTaskItem; + } + + if ((this.childPredTask.length > 0) && (!this.parentTask)) + { + this.maxWidthResize = childPredPosX - posTaskItem; + + } else if ((this.childPredTask.length > 0) && (this.parentTask)) + { + var w1 = posParentTaskItem + widthParentTaskItem - posTaskItem; + var w2 = childPredPosX - posTaskItem; + this.maxWidthResize = Math.min(w1, w2); + + } else if ((this.childPredTask.length == 0) && (this.parentTask)) + { + this.maxWidthResize = posParentTaskItem + widthParentTaskItem - posTaskItem; + } + +}; +/** + * @desc: creation of taskItem + * @type: private + * @topic: 0 + */ +GanttTask.prototype.createTaskItem = function() +{ + var self = this; + this.posX = this.Chart.getPosOnDate(this.TaskInfo.EST); + + var itemControl = document.createElement("div"); + itemControl.id = this.TaskInfo.Id; + itemControl.style.cssText = ";z-index:1;position:absolute;left:" + this.posX + "px;top:" + this.posY + "px;"; + + var divTaskItem = document.createElement("div"); + itemControl.appendChild(divTaskItem); + divTaskItem.style.cssText = "z-index:1;position: absolute;left:0px;top:0px;"; + + var tblTaskItem = document.createElement("table"); + divTaskItem.appendChild(tblTaskItem); + tblTaskItem.cellPadding = "0"; + tblTaskItem.cellSpacing = "0"; + tblTaskItem.width = this.TaskInfo.Duration * this.Chart.hourInPixelsWork + "px"; + tblTaskItem.style.cssText = "border: solid 1px #6589A9;"; + + var rowTblTask = tblTaskItem.insertRow(tblTaskItem.rows.length); + + if (this.TaskInfo.PercentCompleted != 0) + { + var cellTblTask = document.createElement("td"); + rowTblTask.appendChild(cellTblTask); + cellTblTask.height = this.Chart.heightTaskItem + "px"; + cellTblTask.width = this.TaskInfo.PercentCompleted + "%"; + cellTblTask.style.lineHeight = "1px"; + var imgPr = document.createElement("img"); + imgPr.style.width = (this.TaskInfo.PercentCompleted * this.TaskInfo.Duration * this.Chart.hourInPixelsWork) / 100 + "px"; + imgPr.style.height = this.Chart.heightTaskItem + "px"; + cellTblTask.appendChild(imgPr); + imgPr.src = this.Chart.imgs + "progress_filled.png"; + } + + if (this.TaskInfo.PercentCompleted != 100) + { + var cellTblTask = document.createElement("td"); + rowTblTask.appendChild(cellTblTask); + cellTblTask.height = this.Chart.heightTaskItem + "px"; + cellTblTask.width = (100 - this.TaskInfo.PercentCompleted) + "%"; + cellTblTask.style.lineHeight = "1px"; + var imgPrF = document.createElement("img"); + imgPrF.style.width = ((100 - this.TaskInfo.PercentCompleted) * this.TaskInfo.Duration * this.Chart.hourInPixelsWork) / 100 + "px"; + imgPrF.style.height = this.Chart.heightTaskItem + "px"; + cellTblTask.appendChild(imgPrF); + imgPrF.src = this.Chart.imgs + "progress_bg.png"; + + } + + if (this.Chart.isEditable) + { + var divTaskInfo = document.createElement("div"); + divTaskInfo.style.cssText = "text-align:center;font-size:9px;z-index:2;position: absolute;left:0px;top:0px;"; + + var tblTaskInfo = document.createElement("table"); + divTaskInfo.appendChild(tblTaskInfo); + tblTaskInfo.cellPadding = "0"; + tblTaskInfo.cellSpacing = "0"; + tblTaskInfo.height = this.Chart.heightTaskItem + "px"; + tblTaskInfo.width = this.TaskInfo.Duration * this.Chart.hourInPixelsWork + "px"; + + var rowTaskInfo = tblTaskInfo.insertRow(0); + var cellTaskInfo = document.createElement("TD"); + cellTaskInfo.align = "center"; + cellTaskInfo.vAlign = "top"; + cellTaskInfo.height = this.Chart.heightTaskItem + "px"; + cellTaskInfo.className = "moveInfo"; + cellTaskInfo.style.cssText = ";white-space:nowrap;font-size:9px"; + rowTaskInfo.appendChild(cellTaskInfo); + itemControl.appendChild(divTaskInfo); + } + + var divTaskName = document.createElement("div"); + itemControl.appendChild(divTaskName); + divTaskName.style.cssText = ";z-index:2;position: absolute;left:0px;top:0px;"; + + var divMove = document.createElement("div"); + divMove.innerHTML = ""; + if (this.Chart._isIE) + { + divMove.style.background = "#000000"; + divMove.style.filter = "alpha(opacity=0)"; + } + divMove.style.height = this.Chart.heightTaskItem + "px"; + divMove.style.width = this.TaskInfo.Duration * this.Chart.hourInPixelsWork + "px"; + divTaskName.appendChild(divMove); + + if (this.Chart._showTooltip) + { + var getPopUpInfo = function(e) { + if ((!self.Chart._isMove) && (!self.Chart._isResize)) self.getPopUpInfo(self.cTaskItem[0], e); + }; + var closePopUpInfo = function() { + self.closePopUpInfo(); + }; + + this.addEvent(divMove, 'mouseover', getPopUpInfo, false); + this.addEvent(divMove, 'mouseout', closePopUpInfo, false); + } + + var taskClick = function() { + self.Chart.callEvent("onTaskClick", [self]); + }; + this.addEvent(divMove, 'click', taskClick, false); + + if (this.Chart.isEditable) + { + //Create resize area + var divResize = document.createElement("div"); + divResize.style.cssText = ";z-index:10;position: absolute;left:" + (this.TaskInfo.Duration * this.Chart.hourInPixelsWork - 10) + "px;top:0px;"; + divResize.style.height = this.Chart.heightTaskItem + "px"; + divResize.style.width = "10px"; + divResize.innerHTML = ""; + divTaskName.appendChild(divResize); + + var startMove = function(e) { + if (self.Chart.callEvent("onTaskStartDrag", [self])===false) return; + + var moveItem = function(e1) { + if (self.checkMove) self.moveItem(e1); + }; + var endMove = function() { + if (self.checkMove) { + self.endMove(); + self.Chart._isMove = false; + if (self.Chart._isIE) + { + document.body.releaseCapture(); + document.detachEvent("onmousemove", moveItem); + document.detachEvent("onmouseup", endMove); + } else { + document.removeEventListener("mousemove", moveItem, true); + document.removeEventListener("mouseup", endMove, true); + } + if (self.wasMoved) self.Chart.callEvent("onTaskEndDrag", [self]); + } + }; + self.addEvent(document, 'mousemove', moveItem, true); + self.addEvent(document, 'mouseup', endMove, true); + + if (self.Chart._showTooltip) self.closePopUpInfo(); + self.startMove(e); + self.Chart._isMove = true; + if (self.Chart._isIE) document.body.setCapture(false); + }; + + var startResize = function(e) { + if (self.Chart.callEvent("onTaskStartResize", [self])===false) return; + + var resizeItem = function(e1) { + if (self.checkResize)self.resizeItem(e1); + }; + + var endResizeItem = function() { + if (self.checkResize) { + self.endResizeItem(); + self.Chart._isResize = false; + if (self.Chart._isIE) + { + document.body.releaseCapture(); + document.detachEvent("onmousemove", resizeItem); + document.detachEvent("onmouseup", endResizeItem); + } else { + document.removeEventListener("mousemove", resizeItem, true); + document.removeEventListener("mouseup", endResizeItem, true); + } + if (self.wasResized) self.Chart.callEvent("onTaskEndResize", [self]); + } + }; + + self.addEvent(document, 'mousemove', resizeItem, false); + self.addEvent(document, 'mouseup', endResizeItem, false); + + self.startResize(e); + if (self.Chart._isIE) document.body.setCapture(false); + self.Chart._isResize = true; + }; + + this.addEvent(divMove, 'mousedown', startMove, false); + this.addEvent(divResize, 'mousedown', startResize, false); + + var setCursorResize = function(e2) { + if (!self.Chart._isMove) (e2.srcElement?e2.srcElement:e2.target).style.cursor = "e-resize"; + }; + var setCursorStandart = function(e3) { + if (!self.checkResize) (e3.srcElement?e3.srcElement:e3.target).style.cursor = ""; + }; + + this.addEvent(divResize, 'mouseover', setCursorResize, false); + this.addEvent(divResize, 'mouseout', setCursorStandart, false); + } + return itemControl; +}; +/** + * @desc: creation of taskNameItem + * @type: private + * @topic: 0 + */ +GanttTask.prototype.createTaskNameItem = function(hasChildren) +{ + var self = this; + var divName = document.createElement("div"); + divName.id = this.TaskInfo.Id; + divName.style.cssText = "cursor:pointer;white-space:nowrap;height:15px;z-index:1;position:absolute;left:20px;top: " + this.posY + "px;"; + if (hasChildren) divName.style.fontWeight = "bold"; + divName.className = "taskNameItem"; + divName.title = this.TaskInfo.Name; + divName.innerHTML = this.TaskInfo.Name; + if (this.Chart.isShowConMenu) + { + var showContMenu = function(event) { + + if (self.Chart.contextMenu.clear) self.Chart.contextMenu.clear(); + + var hideContMenu = function() { + self.Chart.contextMenu.hideContextMenu(); + if (self.Chart._isIE) + self.Chart.content.detachEvent("mousedown", hideContMenu); + else + self.Chart.content.removeEventListener("mousedown", hideContMenu, false); + }; + + self.Chart.content.onmousedown = hideContMenu; + + if (!self.Chart._isIE) + { + event.stopPropagation(); + } else + { + event.cancelBubble = true; + } + + self.Chart._showContextMenu(event, self); + + }; + + if (this.Chart._isIE) + { + this.addEvent(divName, "contextmenu", function(e) { + showContMenu(e); + return false; + }, false); + + } else + { + this.addEvent(divName, "contextmenu", function(e) { + e.preventDefault(); + showContMenu(e); + }, false); + } + } + return divName; +}; + + +GanttTask.prototype.createTaskDescItem = function() +{ + var posX = (this.posX + this.TaskInfo.Duration * this.Chart.hourInPixelsWork + 10); + var divDesc = document.createElement("div"); + divDesc.style.cssText += ";z-index:1;position:absolute;left:" + posX + "px;top:" + this.posY + "px;"; + divDesc.innerHTML = this.getDescStr(); + divDesc.className = "descTask"; + this.descrTask = divDesc; + + if (this.Chart._showTooltip) + { + var self = this; + var getPopUpInfo = function(e) { + if ((!self.Chart._isMove) && (!self.Chart._isResize)) self.getPopUpInfo(self.descrTask, e); + }; + var closePopUpInfo = function() { + self.closePopUpInfo(); + }; + + this.addEvent(divDesc, 'mouseover', getPopUpInfo, false); + this.addEvent(divDesc, 'mouseout', closePopUpInfo, false); + } + return divDesc; +}; + +/** + * @desc: check Width of taskNameItem + * @type: private + * @topic: 4 + */ +GanttTask.prototype.checkWidthTaskNameItem = function() +{ + if (this.cTaskNameItem[0].offsetWidth + this.cTaskNameItem[0].offsetLeft > this.Chart.maxWidthPanelNames) + { + var width = this.cTaskNameItem[0].offsetWidth + this.cTaskNameItem[0].offsetLeft - this.Chart.maxWidthPanelNames; + var countChar = Math.round(width / (this.cTaskNameItem[0].offsetWidth / this.cTaskNameItem[0].firstChild.length)); + var tName = this.TaskInfo.Name.substring(0, this.cTaskNameItem[0].firstChild.length - countChar - 3); + tName += "..."; + this.cTaskNameItem[0].innerHTML = tName; + } + +}; +/** + * @desc: creation of GanttTask + * @type: private + * @topic: 0 + */ +GanttTask.prototype.create = function() +{ + var containerTasks = this.Chart.oData.firstChild; + var containerNames = null; + if (this.Chart._showTreePanel) containerNames = this.Chart.panelNames.firstChild; + var predecessorTask = this.TaskInfo.PredecessorTask; + var parentTask = this.TaskInfo.ParentTask; + var isCParentTask = (this.TaskInfo.ChildTasks.length > 0); + var self = this; + + this.cTaskItem = []; + this.cTaskNameItem = []; + + //creation arrTasks + if (!parentTask) + { + if (this.TaskInfo.previousParentTask) { + this.previousParentTask = this.Project.getTaskById(this.TaskInfo.previousParentTask.Id); + var lastChildTask = this.Chart.getLastChildTask(this.previousParentTask); + this.posY = parseInt(lastChildTask.cTaskItem[0].style.top) + this.Chart.heightTaskItem + 11; + this.previousParentTask.nextParentTask = this; + + } else { + this.posY = parseInt(this.Project.projectItem[0].style.top) + this.Chart.heightTaskItem + 11; + } + } + + if (parentTask) { + var task = this.Project.getTaskById(this.TaskInfo.ParentTask.Id); + this.parentTask = task; + + if (this.TaskInfo.previousChildTask) { + this.previousChildTask = this.Project.getTaskById(this.TaskInfo.previousChildTask.Id); + var lastChildTask = this.Chart.getLastChildTask(this.previousChildTask); + this.posY = parseInt(lastChildTask.cTaskItem[0].style.top) + this.Chart.heightTaskItem + 11; + this.previousChildTask.nextChildTask = this; + + } else { + this.posY = parseInt(task.cTaskItem[0].style.top) + this.Chart.heightTaskItem + 11; + } + task.childTask.push(this); + } + + if (predecessorTask) { + var task = this.Project.getTaskById(predecessorTask.Id); + this.predTask = task; + task.childPredTask.push(this); + } + + //creation task item + this.cTaskItem.push(this.createTaskItem()); + containerTasks.appendChild(this.cTaskItem[0]); + + if (this.Chart.panelNames) { + this.cTaskNameItem.push(this.createTaskNameItem(isCParentTask)); + this.Chart.panelNames.firstChild.appendChild(this.cTaskNameItem[0]); + } + + if (this.Chart.isShowDescTask) { + containerTasks.appendChild(this.createTaskDescItem()); + } + + //Create Connecting Lines + var arrConnectingLines = []; + if (predecessorTask) arrConnectingLines = this.createConnectingLinesDS(); + this.cTaskItem.push(arrConnectingLines); + + if (this.Chart.panelNames) + { + //Create Connecting Lines + var arrConnectingLinesNames = []; + if (parentTask) + { + this.cTaskNameItem[0].style.left = parseInt(this.parentTask.cTaskNameItem[0].style.left) + 15 + "px"; + arrConnectingLinesNames = this.createConnectingLinesPN(); + } + this.checkWidthTaskNameItem(); + + var treeImg = null; + if (isCParentTask) treeImg = this.createTreeImg(); + + this.cTaskNameItem.push(arrConnectingLinesNames); + this.cTaskNameItem.push(treeImg); + } + this.addDayInPanelTime(); + return this; +}; + +/** + * @desc: creation of image of node + * @type: private + * @topic: 4 + */ +GanttTask.prototype.createTreeImg = function() +{ + var self = this; + var treeImg = new Image(); + treeImg.src = this.Chart.imgs + "minus.gif"; + treeImg.id = this.TaskInfo.Id; + + treeImg.onclick = function() + { + if (self._isOpen) + { + this.src = self.Chart.imgs + "plus.gif"; + self._isOpen = false; + self.hideChildTasks(self); + self.shiftCurrentTasks(self, -self._heightHideTasks); + } + else + { + this.src = self.Chart.imgs + "minus.gif"; + self._isOpen = true; + self.shiftCurrentTasks(self, self._heightHideTasks); + self.showChildTasks(self, true); + self._heightHideTasks = 0; + } + }; + + this.Chart.panelNames.firstChild.appendChild(treeImg); + treeImg.style.cssText = "cursor:pointer;left:" + (parseInt(this.cTaskNameItem[0].style.left) - 12) + "px;top:" + (parseInt(this.cTaskNameItem[0].style.top) + 3) + "px;z-index:12;position:absolute;"; + + return treeImg; +}; +/** + * @desc: returns last child of GanttTask + * @type: private + * @topic: 2 + */ +GanttChart.prototype.getLastChildTask = function(task) +{ + if (task.childTask.length > 0) + { + return this.getLastChildTask(task.childTask[task.childTask.length - 1]); + + } else + { + return task; + } + +}; +/** + * @desc: dhtmlXMLSenderObject constructor + * @type: public + * @topic: 0 + */ +dhtmlXMLSenderObject = function(ganttChart) +{ + this.xmlHttp = this.createXMLHttpRequest(); + this.isProcessed = false; + this.path = null; + this.filename = null; + this.Chart = ganttChart; +}; +/** + * @desc: creation (object) XMLHttpRequest + * @type: private + * @topic: 4 + */ +dhtmlXMLSenderObject.prototype.createXMLHttpRequest = function() +{ + if (window.XMLHttpRequest) { + return new XMLHttpRequest(); + } + else if (window.ActiveXObject) { + return new ActiveXObject("Microsoft.XMLHTTP"); + } +}; +/** + * @desc: Sends the data on a server + * @type: private + * @topic: 6 + */ +dhtmlXMLSenderObject.prototype.sendData = function(filename, path, xmlData) +{ + var self = this; + this.path = path; + this.filename = filename; + + if ((this.path == null) || (this.path == "")) + { + this.Chart.Error.throwError("DATA_SEND_ERROR", 3, null); + return; + } + if ((this.filename == null) || (this.filename == "")) + { + this.Chart.Error.throwError("DATA_SEND_ERROR", 4, null); + return; + } + + this.isProcessed = true; + this.xmlHttp.open("POST", this.path, true); + if (this.Chart._isFF) + { + this.xmlHttp.onerror = function() { + self.xmlHttp.onreadystatechange = null; + self.xmlHttp.abort(); + self.isProcessed = false; + } + } + this.xmlHttp.onreadystatechange = function() { + self.getStatus(); + }; + this.xmlHttp.setRequestHeader("Content-Type", "application/x-www-form-urlencoded"); + this.xmlHttp.send("data=" + encodeURI(xmlData) + "&filename=" + filename); + + +}; +/** + * @desc: Returns the status of operation + * @type: private + * @topic: 4 + */ +dhtmlXMLSenderObject.prototype.getStatus = function() +{ + if (this.xmlHttp.readyState == 4) + { + + var _status = ""; + try { + _status = this.xmlHttp.status; + + } catch(e) { + this.Chart.Error.throwError("DATA_SEND_ERROR", 1, null); + return 0; + } + + switch (_status) { + + case 0: + this.Chart.Error.throwError("DATA_SEND_ERROR", 1, null); + //this.xmlHttp.abort(); + break; + case 404: + this.Chart.Error.throwError("DATA_SEND_ERROR", 5, [this.path]); + //this.xmlHttp.abort(); + break; + case 500: + this.Chart.Error.throwError("DATA_SEND_ERROR", 2, null); + //this.xmlHttp.abort(); + break; + case 12029: + this.Chart.Error.throwError("DATA_SEND_ERROR", 1, null); + //this.xmlHttp.abort(); + break; + default: + if (!(_status >= 200 && _status < 300 || _status == 304)) + { + this.Chart.Error.throwError("DATA_SEND_ERROR", 0, null); + //this.xmlHttp.abort(); + } + break; + } + this.isProcessed = false; + + } +}; +/** + * @desc: GanttError constructor + * @type: private + * @topic: 0 + */ +function GanttError() { + + this.catches = []; + this._errors = []; + this._init(); + + return this; +} +/** + * @desc: initialization of control errors + * @type: private + * @topic: 4 + */ +GanttError.prototype._init = function() +{ + //connection errors + this._errors[0] = "Connection error"; + this._errors[1] = "Cannot connect"; + this._errors[2] = "Server error"; + this._errors[3] = "Path is null or empty"; + this._errors[4] = "Filename is null or empty"; + this._errors[5] = "File (%0) is not found"; + + //API errors + this._errors[6] = "Percent Complete should be a number"; + this._errors[7] = "Percent Complete should be <= 100"; + this._errors[8] = "Percent Complete should be >= 0"; + this._errors[9] = "Increase duration of task(%0)"; + this._errors[10] = "Reduce duration of task(%0)"; + this._errors[11] = "Increase EST of child task (%0)"; + this._errors[12] = "Reduce EST of task (%0)"; + this._errors[13] = "The project (%0) is added"; + this._errors[14] = "Start Date of the project < start Date of the control"; + this._errors[15] = "Task (%0) cannot be the child of predecessor task(%1)"; + this._errors[16] = "Time of the termination of predecessor task(%0) > EST of child task(%1)"; + this._errors[17] = "The Predecessor (%0) task does not exist"; + this._errors[18] = "The EST of task (%0) < start date of the control"; + this._errors[19] = "Time of the termination of parent task (%0) < time of the termination of child task(%1)"; + this._errors[20] = "The EST of task (%0) < EST of parent task(%1)"; + this._errors[21] = "The parent task (%0) does not exist"; + this._errors[22] = "The task (%0) is added"; + this._errors[23] = "The project (%0) is added"; + this._errors[24] = "Task (%0) EST < project (%1) startDate"; + this._errors[25] = "Parent task (%0) EST cannot be null"; + this._errors[26] = "Predecessor task (%0) position error. Reduce duration of predecessor task (%0) or increase EST of child task (%1)"; + this._errors[27] = "Predecessor task (%0) does not exist"; + this._errors[28] = "Increase duration of parent task (%0) or reduce EST of child task (%1) or reduce duration of child task(%1)"; + this._errors[29] = "Reduce EST of parent task (%0) or increase EST of child task (%1)"; + this._errors[30] = "The task(%0) does not exist"; + this._errors[31] = "The project(%0) does not exist"; + this._errors[32] = "Predecessor task(%0) and child task(%1) should have the same parent"; + this._errors[33] = "Reduce EST of parent task (%0) or increase EST of child task (%1)"; + this._errors[34] = "EST of task(%0) < start date of the project(%1)"; + this._errors[35] = "Percent Complete should be <= 100 and >= 0"; + this._errors[36] = "You may not connect a task to itself."; + this._errors[37] = "Cannot parse this XML string."; +}; +/** + * @desc: bind type of exception with handler + * @param: type - type of error + * @param: handler - handler name + * @type: private + * @topic: 4 + */ +GanttError.prototype.catchError = function(type, handler) { + + this.catches[type] = handler; +}; +/** + * @desc: get error string + * @param: str - error message + * @param: params - replace %i params in message + * @type: private + * @topic: 4 + */ +GanttError.prototype.getErrorString = function(str, params) +{ + if (!params) { + return str; + } else { + for (var i = 0; i < params.length; i++) { + + var re = new RegExp("%" + i, "gi"); + str = str.replace(re, params[i]); + + } + return str; + } +}; +/** + * @desc: throw error + * @param: type - type of error + * @param: description - description of error + * @param: params - current data + * @type: private + * @topic: 4 + */ +GanttError.prototype.throwError = function(type, description, params) { + if (this.catches[type]) + { + var index = parseInt(description); + var errorStr = this.getErrorString(this._errors[index], params); + return this.catches[type](type, errorStr, params); + } + return null; +}; + +function contextMenu(chart) +{ + this.Chart = chart; + this.TabContainer = null; + this.MenuPanel = null; + this.tabPanel = null; + this.arrTabs = []; + this.isShow = false; + this.hideDiv = null; + this._init(); +} + +contextMenu.prototype._init = function() +{ + this.createMenuPanel(); + this.createHideDiv(); + this.createTabContainer(); + this.createTabPanel(); + + var self = this; + var arrItems = []; + + var tab1 = this.createTab(1, "Rename task", "t", true, this); + tab1.addItem(1, "New name", document.createElement("input"), "text", function() { + tab1.arrItems[0].control.focus(); + }); + tab1.addItem(2, "Rename", document.createElement("input"), "button", + function() { + var name = tab1.arrItems[0].control.value; + try { + tab1.object.setName(name); + tab1.hide(); + } catch(e) { + + } + } + ); + + var tab2 = this.createTab(2, "Delete task", "t", true, this); + tab2.addItem(1, "Delete", document.createElement("input"), "button", + function() + { + try { + tab2.object.Project.deleteTask(tab2.object.TaskInfo.Id); + tab2.hide(); + } + catch(e) { + + } + } + ); + var tab3 = this.createTab(3, "Set EST", "t", true, this); + tab3.addItem(1, "EST", document.createElement("input"), "text", function() { + tab3.arrItems[0].control.focus(); + }); + tab3.addItem(2, "Move children", document.createElement("input"), "checkbox", function() { + tab3.arrItems[1].control.focus(); + }); + tab3.addItem(3, "Update", document.createElement("input"), "button", + function() { + var isMoveChild = tab3.arrItems[1].control.checked; + var arr = tab3.arrItems[0].control.value.split("."); + var est = (arr.length < 3) ? null : (new Date(arr[2], parseInt(arr[1]) - 1, arr[0])); + try { + if (tab3.object.setEST(est, isMoveChild)) tab3.hide(); + } catch(e) { + + } + } + ); + + var tab4 = this.createTab(4, "Set duration", "t", true, this); + tab4.addItem(1, "Duration", document.createElement("input"), "text", function() { + tab4.arrItems[0].control.focus(); + }); + tab4.addItem(2, "Update", document.createElement("input"), "button", + function() { + var d = tab4.arrItems[0].control.value; + try { + if (tab4.object.setDuration(d)) tab4.hide(); + } catch(e) { + + } + } + ); + + var tab5 = this.createTab(5, "Set % complete", "t", true, this); + tab5.addItem(1, "Percent Complete", document.createElement("input"), "text", function() { + tab5.arrItems[0].control.focus(); + }); + tab5.addItem(2, "Update", document.createElement("input"), "button", + function() { + var p = tab5.arrItems[0].control.value; + try { + if (tab5.object.setPercentCompleted(p)) tab5.hide(); + } catch(e) { + + } + } + ); + + var tab13 = this.createTab(13, "Set predecessor", "t", true, this); + tab13.addItem(1, "Predecessor", document.createElement("input"), "text", function() { + tab13.arrItems[0].control.focus(); + }); + tab13.addItem(2, "Update", document.createElement("input"), "button", + function() { + var p = tab13.arrItems[0].control.value; + try { + if (tab13.object.setPredecessor(p)) tab13.hide(); + } catch(e) { + + } + } + ); + + var tab6 = this.createTab(6, "Rename project", "p", true, this); + tab6.addItem(1, "New name", document.createElement("input"), "text", function() { + tab6.arrItems[0].control.focus(); + }); + tab6.addItem(2, "Rename", document.createElement("input"), "button", + function() { + var name = tab6.arrItems[0].control.value; + try { + tab6.object.setName(name); + tab6.hide(); + } catch(e) { + + } + } + ); + + var tab7 = this.createTab(7, "Delete project", "p", true, this); + tab7.addItem(1, "Delete", document.createElement("input"), "button", + function() { + try { + tab7.object.Chart.deleteProject(tab7.object.Project.Id); + tab7.hide(); + } catch(e) { + + } + } + ); + + var tab8 = this.createTab(8, "Set % complete", "p", true, this); + tab8.addItem(1, "Percent Complete", document.createElement("input"), "text", function() { + tab8.arrItems[0].control.focus(); + }); + tab8.addItem(2, "Update", document.createElement("input"), "button", + function() { + var p = tab8.arrItems[0].control.value; + try { + if (tab8.object.setPercentCompleted(p)) tab8.hide(); + } catch(e) { + + } + } + ); + + var tab9 = this.createTab(9, "Add new task", "p", true, this); + tab9.addItem(1, "Id", document.createElement("input"), "text", function() { + tab9.arrItems[0].control.focus(); + }); + tab9.addItem(2, "Name", document.createElement("input"), "text", function() { + tab9.arrItems[1].control.focus(); + }); + tab9.addItem(3, "EST", document.createElement("input"), "text", function() { + tab9.arrItems[2].control.focus(); + }); + tab9.addItem(4, "Duration", document.createElement("input"), "text", function() { + tab9.arrItems[3].control.focus(); + }); + tab9.addItem(5, "Percent complete", document.createElement("input"), "text", function() { + tab9.arrItems[4].control.focus(); + }); + tab9.addItem(6, "Parent task id", document.createElement("input"), "text", function() { + tab9.arrItems[5].control.focus(); + }); + tab9.addItem(7, "Pred task id", document.createElement("input"), "text", function() { + tab9.arrItems[6].control.focus(); + }); + + tab9.addItem(9, "Insert", document.createElement("input"), "button", + function() { + try { + var id = tab9.arrItems[0].control.value; + var name = tab9.arrItems[1].control.value; + var arr = tab9.arrItems[2].control.value.split("."); + var est = (arr.length < 3) ? null : (new Date(arr[2], parseInt(arr[1]) - 1, arr[0])); + var duration = tab9.arrItems[3].control.value; + var pc = tab9.arrItems[4].control.value; + var parentTaskId = tab9.arrItems[5].control.value; + var predTaskId = tab9.arrItems[6].control.value; + if (tab9.object.insertTask(id, name, est, duration, pc, predTaskId, parentTaskId)) tab9.hide(); + + } catch(e) { + + } + } + ); + + var tab11 = this.createTab(11, "Add successor task", "t", true, this); + tab11.addItem(1, "Id", document.createElement("input"), "text", function() { + tab11.arrItems[0].control.focus(); + }); + tab11.addItem(2, "Name", document.createElement("input"), "text", function() { + tab11.arrItems[1].control.focus(); + }); + tab11.addItem(3, "EST", document.createElement("input"), "text", function() { + tab11.arrItems[2].control.focus(); + }); + tab11.addItem(4, "Duration", document.createElement("input"), "text", function() { + tab11.arrItems[3].control.focus(); + }); + tab11.addItem(5, "Percent complete", document.createElement("input"), "text", function() { + tab11.arrItems[4].control.focus(); + }); + tab11.addItem(6, "Insert", document.createElement("input"), "button", + function() { + try { + var pr = tab11.object.Project; + var id = tab11.arrItems[0].control.value; + var name = tab11.arrItems[1].control.value; + var arr = tab11.arrItems[2].control.value.split("."); + var est = (arr.length < 3) ? null : (new Date(arr[2], parseInt(arr[1]) - 1, arr[0])); + var duration = tab11.arrItems[3].control.value; + var pc = tab11.arrItems[4].control.value; + var parentTaskId = (tab11.object.parentTask == null) ? "" : tab11.object.parentTask.TaskInfo.Id; + var predTaskId = tab11.object.TaskInfo.Id; + if (pr.insertTask(id, name, est, duration, pc, predTaskId, parentTaskId)) tab11.hide(); + + } catch(e) { + // + } + } + ); + + var tab10 = this.createTab(10, "Add child task", "t", true, this); + tab10.addItem(1, "Id", document.createElement("input"), "text", function() { + tab10.arrItems[0].control.focus(); + }); + tab10.addItem(2, "Name", document.createElement("input"), "text", function() { + tab10.arrItems[1].control.focus(); + }); + tab10.addItem(3, "EST", document.createElement("input"), "text", function() { + tab10.arrItems[2].control.focus(); + }); + tab10.addItem(4, "Duration", document.createElement("input"), "text", function() { + tab10.arrItems[3].control.focus(); + }); + tab10.addItem(5, "Percent complete", document.createElement("input"), "text", function() { + tab10.arrItems[4].control.focus(); + }); + tab10.addItem(6, "Insert", document.createElement("input"), "button", + function() { + try { + var pr = tab10.object.Project; + var id = tab10.arrItems[0].control.value; + var name = tab10.arrItems[1].control.value; + var arr = tab10.arrItems[2].control.value.split("."); + var est = (arr.length < 3) ? null : (new Date(arr[2], parseInt(arr[1]) - 1, arr[0])); + var duration = tab10.arrItems[3].control.value; + var pc = tab10.arrItems[4].control.value; + var parentTaskId = tab10.object.TaskInfo.Id; + var predTaskId = ""; + if (pr.insertTask(id, name, est, duration, pc, predTaskId, parentTaskId)) tab10.hide(); + + } catch(e) { + // + } + } + ); + + var tab12 = this.createTab(12, "-Insert new project-", "p", false, this); + tab12.addItem(1, "Id", document.createElement("input"), "text", function() { + tab12.arrItems[0].control.focus(); + }); + tab12.addItem(2, "Name", document.createElement("input"), "text", function() { + tab12.arrItems[1].control.focus(); + }); + tab12.addItem(3, "Start date", document.createElement("input"), "text", function() { + tab12.arrItems[2].control.focus(); + }); + tab12.addItem(4, "Insert", document.createElement("input"), "button", + function() { + try { + + var id = tab12.arrItems[0].control.value; + var namePr = tab12.arrItems[1].control.value; + var arr = tab12.arrItems[2].control.value.split("."); + var startDatePr = (arr.length < 3) ? null : (new Date(arr[2], parseInt(arr[1]) - 1, arr[0])); + if (self.Chart.insertProject(id, namePr, startDatePr)) tab12.hide(); + + } catch(e) { + + } + } + ); +}; + +contextMenu.prototype.createHideDiv = function() +{ + this.hideDiv = document.createElement("div"); + this.hideDiv.style.position = "absolute"; + this.hideDiv.style.left = "0px"; + this.hideDiv.style.top = "0px"; + this.Chart.content.appendChild(this.hideDiv); + this.hideDiv.style.zIndex = 12; + this.hideDiv.style.display = "none"; + this.hideDiv.style.background = "#7D7E7D"; + this.hideDiv.style.cssText += ";-moz-opacity: 0.5;filter: alpha(opacity=50);opacity:.50;"; + this.hideDiv.style.width = this.Chart.content.offsetWidth + 2 + "px"; + this.hideDiv.style.height = this.Chart.content.offsetHeight + 2 + "px"; + +}; + +contextMenu.prototype.createMenuPanel = function() +{ + this.MenuPanel = document.createElement("div"); + this.MenuPanel.style.visibility = "hidden"; + this.MenuPanel.style.cssText += ";z-index:10;"; + this.MenuPanel.style.position = "absolute"; + this.Chart.content.appendChild(this.MenuPanel); + this.MenuPanel.innerHTML = "
"; + this.MenuPanel.firstChild.className = "contextMenu"; + + this.MenuPanel.firstChild.cellPadding = 0; + this.MenuPanel.firstChild.cellSpacing = 0; + this.MenuPanel.firstChild.style.cssText += ";background:url(" + this.Chart.imgs + "menu/menu_bg.png);"; +}; +contextMenu.prototype.createTabPanel = function() +{ + this.tabPanel = document.createElement("div"); + this.tabPanel.style.visibility = "hidden"; + this.tabPanel.style.zIndex = "30"; + this.TabContainer.firstChild.rows[0].cells[0].appendChild(this.tabPanel); + this.tabPanel.style.width = "385px"; + this.tabPanel.style.height = "290px"; + this.tabPanel.innerHTML = "
"; + this.tabPanel.firstChild.cellPadding = 0; + this.tabPanel.firstChild.cellSpacing = 0; + this.tabPanel.firstChild.style.cssText = "width:385px;border: 1px solid #808080;"; + this.tabPanel.firstChild.rows[0].cells[0].style.cssText = ";height:26px;background:url(" + this.Chart.imgs + "/menu/window_tr.png);background-repeat: no-repeat;color:#fff;font-size:14px;font-weight: bold;font-family: Tahoma, Arial"; + this.tabPanel.firstChild.rows[0].cells[0].align = "center"; + this.tabPanel.firstChild.rows[1].cells[0].style.cssText = ";height:270px;background:#F7F7F7;"; + this.tabPanel.firstChild.rows[1].cells[0].innerHTML = "
"; + this.tabPanel.firstChild.rows[1].cells[0].firstChild.style.cssText = "width:250px;font-size:11px;font-family:Tahoma,Arial;"; + this.tabPanel.firstChild.rows[1].cells[0].align = "center"; +}; + +contextMenu.prototype.addItemMenuPanel = function(tab) +{ + var self = this; + var row = this.MenuPanel.firstChild.insertRow(this.MenuPanel.firstChild.rows.length); + var cell = document.createElement('td'); + cell.innerHTML = tab.Description; + cell.style.cssText = "padding-left:10px;height:18px;"; + + this.addEvent(cell, "mousedown", function() { + tab.show(); + }, false); + + + cell.onmouseover = function() { + this.style.background = "url(" + self.Chart.imgs + "menu/menu_selection.png)"; + }; + cell.onmouseout = function() { + this.style.background = ""; + }; + + row.appendChild(cell); +}; + +contextMenu.prototype.showContextMenu = function(x, y, object) +{ + if (object.constructor == GanttTask) + { + for (var i = 0; i < this.arrTabs.length; i++) { + if (this.arrTabs[i].type == "t") + { + this.arrTabs[i].object = object; + this.addItemMenuPanel(this.arrTabs[i]); + } + } + } else if (object.constructor == GanttProject) + { + for (var i = 0; i < this.arrTabs.length; i++) { + if (this.arrTabs[i].type == "p") + { + this.arrTabs[i].object = object; + this.addItemMenuPanel(this.arrTabs[i]); + } + } + } + + this.isShow = true; + this.MenuPanel.style.cssText += ";z-index:15;"; + this.MenuPanel.style.visibility = "visible"; + + this.MenuPanel.style.top = parseInt(y) + this.Chart.heightTaskItem - this.Chart.oData.scrollTop + 5 + "px"; + this.MenuPanel.style.left = x; + +}; +contextMenu.prototype.hideContextMenu = function() +{ + this.isShow = false; + this.MenuPanel.style.visibility = "hidden"; + +}; +contextMenu.prototype.clear = function() +{ + this.MenuPanel.removeChild(this.MenuPanel.firstChild); + this.MenuPanel.innerHTML = "
"; + this.MenuPanel.firstChild.className = "contextMenu"; + this.MenuPanel.firstChild.cellPadding = 0; + this.MenuPanel.firstChild.cellSpacing = 0; + this.MenuPanel.firstChild.style.cssText += ";background:url(" + this.Chart.imgs + "menu/menu_bg.png);"; +}; +contextMenu.prototype.createTab = function(id, desc, type, showOInfo, menu) +{ + var tab = new contextMenuTab(id, desc, type, showOInfo, menu); + this.arrTabs.push(tab); + return tab; +}; +contextMenu.prototype.createTabContainer = function() +{ + this.TabContainer = document.createElement("div"); + this.TabContainer.style.position = "absolute"; + this.TabContainer.style.top = "0px"; + this.TabContainer.style.left = "0px"; + this.TabContainer.style.visibility = "hidden"; + this.TabContainer.style.zIndex = "50"; + this.Chart.content.appendChild(this.TabContainer); + this.TabContainer.innerHTML = "
"; + this.TabContainer.firstChild.style.cssText = ";width:100%;height:100%;"; + this.TabContainer.firstChild.rows[0].cells[0].align = "center"; + this.TabContainer.style.width = this.Chart.content.offsetWidth + 2 + "px"; + this.TabContainer.style.height = this.Chart.content.offsetHeight + 2 + "px"; + +}; + +contextMenu.prototype.getTabById = function(id) +{ + for (var i = 0; i < this.arrTabs.length; i++) { + if (this.arrTabs[i].Id == id) { + return this.arrTabs[i]; + } + } + return null; +}; +function contextMenuTab(id, description, type, showOInfo, contextMenu) +{ + this.Id = id; + this.arrItems = []; + this.TabItemContainer = null; + this.Description = description; + this.contextMenu = contextMenu; + this.type = type; + this.object = null; + this.showObjectInfo = showOInfo; + +} + +/** + * @desc: add event + * @param: elm - current element + * @param: evType - string that specifies any of the standard DHTML Events + * @param: fn - pointer that specifies the function to call when sEvent fires + * @type: private + * @topic: 5 + */ +contextMenu.prototype.addEvent = function (elm, evType, fn, useCapture) +{ + if (elm.addEventListener) { + elm.addEventListener(evType, fn, useCapture); + return true; + } + else if (elm.attachEvent) { + return elm.attachEvent('on' + evType, fn); + } + else { + elm['on' + evType] = fn; + } +}; + +contextMenuTab.prototype.addItem = function(id, name, control, type, handler) +{ + if (handler) { + control.onclick = handler; + } + control.type = type; + if (type == "button") + { + control.value = name; + } + var tabItem = new contextMenuTabItem(id, name, control, this); + this.arrItems.push(tabItem); +}; + +contextMenuTab.prototype.show = function() +{ + this.contextMenu.hideDiv.style.display = "inline"; + this.contextMenu.TabContainer.style.visibility = "visible"; + + var self = this; + this.contextMenu.tabPanel.firstChild.rows[0].cells[0].innerHTML = this.Description; + this.contextMenu.tabPanel.style.visibility = "visible"; + var t = this.contextMenu.tabPanel.firstChild.rows[1].cells[0].firstChild; + var c,c2,r = null; + + if (this.showObjectInfo) + { + if (this.object) { + if (this.object.constructor == GanttTask) { + this.insertData(t, "Id", this.object.TaskInfo.Id); + this.insertData(t, "Name", this.object.TaskInfo.Name); + this.insertData(t, "Duration", this.object.TaskInfo.Duration + " hrs"); + this.insertData(t, "Percent complete", this.object.TaskInfo.PercentCompleted + "%"); + this.insertData(t, "EST", this.object.TaskInfo.EST.getDate() + "." + (this.object.TaskInfo.EST.getMonth() + 1) + "." + this.object.TaskInfo.EST.getFullYear()); + this.insertData(t, "Predecessor", this.object.TaskInfo.PredecessorTaskId); + } else + { + this.insertData(t, "Id", this.object.Project.Id); + this.insertData(t, "Name", this.object.Project.Name); + this.insertData(t, "Start date", this.object.Project.StartDate.getDate() + "." + (this.object.Project.StartDate.getMonth() + 1) + "." + this.object.Project.StartDate.getFullYear()); + } + } + } + + var btnCell = null; + for (var i = 0; i < this.arrItems.length; i++) { + if (this.arrItems[i].control.type == "button") + { + r = t.insertRow(t.rows.length); + c = r.insertCell(r.cells.length); + btnCell = r.insertCell(r.cells.length); + btnCell.appendChild(this.arrItems[i].control); + + } else + { + r = t.insertRow(t.rows.length); + c = r.insertCell(r.cells.length); + c2 = r.insertCell(r.cells.length); + c.innerHTML = this.arrItems[i].Name; + c2.appendChild(this.arrItems[i].control); + + } + } + + var b = document.createElement("input"); + b.type = "button"; + b.value = "Cancel"; + b.onclick = function() + { + self.hide(); + }; + + if (!btnCell) { + r = t.insertRow(t.rows.length); + c = r.insertCell(r.cells.length); + btnCell = r.insertCell(r.cells.length); + } else { + b.style.marginLeft = "10px"; + } + btnCell.appendChild(b); +}; +contextMenuTab.prototype.hide = function() +{ + this.contextMenu.tabPanel.style.visibility = "hidden"; + var t = this.contextMenu.tabPanel.firstChild.rows[1].cells[0].firstChild; + t.parentNode.removeChild(t); + this.contextMenu.tabPanel.firstChild.rows[1].cells[0].innerHTML = "
"; + this.contextMenu.tabPanel.firstChild.rows[1].cells[0].firstChild.style.cssText = "width:250px;font-size:11px;font-family:Tahoma,Arial;"; + + this.contextMenu.hideDiv.style.display = "none"; + this.contextMenu.TabContainer.style.visibility = "hidden"; +}; + +contextMenuTab.prototype.insertData = function(t, name, value) +{ + var c,c2,r = null; + r = t.insertRow(t.rows.length); + c = r.insertCell(r.cells.length); + c.style.cssText = "width:100px"; + c.innerHTML = name; + c2 = r.insertCell(r.cells.length); + c2.innerHTML = value; + +}; +contextMenuTab.prototype.insertControl = function(t, name, value) +{ + var c,c2,r = null; + r = t.insertRow(t.rows.length); + c = r.insertCell(r.cells.length); + c.innerHTML = name; + c2 = r.insertCell(r.cells.length); + c2.appendChild(value); +}; + +function contextMenuTabItem(id, name, control, tab) +{ + this.Id = id; + this.Name = name; + this.control = control; + this.tab = tab; + +} diff --git a/addons/base_gantt/static/src/gantt.js b/addons/base_gantt/static/src/gantt.js new file mode 100644 index 00000000000..0e65fb48b5b --- /dev/null +++ b/addons/base_gantt/static/src/gantt.js @@ -0,0 +1,227 @@ +/*--------------------------------------------------------- + * OpenERP base_gantt + *---------------------------------------------------------*/ + +openerp.base.gantt = function (openerp) { +openerp.base.views.add('gantt', 'openerp.base.GanttView'); +openerp.base.GanttView = openerp.base.Controller.extend({ + + init: function(view_manager, session, element_id, dataset, view_id) { + this._super(session, element_id); + this.view_manager = view_manager; + this.dataset = dataset; + this.model = dataset.model; + this.view_id = view_id; + this.fields_views = {}; + this.widgets = {}; + this.widgets_counter = 0; + this.fields = {}; + this.datarecord = {}; + this.calendar_fields = {}; + }, + do_show: function () { + // TODO: re-trigger search + this.$element.show(); + }, + do_hide: function () { + this.$element.hide(); + }, + start: function() { + this.rpc("/base_gantt/ganttview/load", {"model": this.model, "view_id": this.view_id}, this.on_loaded); + }, + on_loaded: function(data) { + this.fields_view = data.fields_view; + var self = this; + this.name = this.fields_view.name || this.fields_view.arch.attrs.string; + this.view_id = this.fields_view.view_id; + + this.date_start = this.fields_view.arch.attrs.date_start; + this.date_delay = this.fields_view.arch.attrs.date_delay; + this.date_stop = this.fields_view.arch.attrs.date_stop; + this.color_field = this.fields_view.arch.attrs.color; + + this.day_length = this.fields_view.arch.attrs.day_length || 8; + this.colors = this.fields_view.arch.attrs.colors; + this.fields = this.fields_view.fields; + + this.text = this.fields_view.arch.children[0].children[0].attrs.name; + this.parent = this.fields_view.arch.children[0].attrs.link; + + this.calendar_fields['parent'] = {'name': this.parent}; + this.calendar_fields['date_start'] = {'name': this.date_start}; + this.calendar_fields['text'] = {'name': this.text}; + if(this.date_delay) + this.calendar_fields['date_delay'] = {'name': this.date_delay}; + if(this.date_stop) + this.calendar_fields['date_stop'] = {'name': this.date_stop}; + + this.calendar_fields['day_length'] = this.day_length; + this.rpc('/base_gantt/ganttview/get_events', + {'model': this.model, + 'fields': this.fields, + 'color_field': this.color_field, + 'day_length': this.day_length, + 'calendar_fields': this.calendar_fields, + 'colors': this.colors, + 'info_fields': this.info_fields + }, + function(res) { + self.create_gantt(); + self.load_event(res); + }) + this.$element.html(QWeb.render("GanttView", {"view": this, "fields_view": this.fields_view})); + + }, + convert_date_format: function(date) { + date=date+""; + if(typeof (date)!="string"||date.length===0){ + return null; + } + var iso=date.split("-"); + if(iso.length===0){ + return null; + } + var day = iso[2]; + var iso_hours = day.split(' '); + + if (iso_hours.length > 1) { + day = iso_hours[0]; + var iso_date_hours = iso_hours[1].split(':') + var new_date = new Date(iso[0], iso[1] - 1, day); + new_date.setHours(iso_date_hours[0]); + new_date.setMinutes(iso_date_hours[1]); + new_date.setSeconds(iso_date_hours[2]); + } + else { + var new_date = new Date(iso[0], iso[1] - 1, day); + } + new_date.setFullYear(iso[0]); + new_date.setMonth(iso[1]-1); + new_date.setDate(day); + return new_date; + }, + + create_gantt: function() { + ganttChartControl = new GanttChart(); + ganttChartControl.setImagePath("/base_gantt/static/lib/dhtmlxGantt/codebase/imgs/"); + ganttChartControl.setEditable(true); + ganttChartControl.showTreePanel(true); + ganttChartControl.showContextMenu(true); + ganttChartControl.showDescTask(true,'d,s-f'); + ganttChartControl.showDescProject(true,'n,d'); + }, + load_event: function(res) { + var self = this + var result = res.result; + var sidebar = res.sidebar; + var project_id = new Array(); + var project = new Array(); + var j = -1; + var self = this; + for (i in result) { + + var parent_id = result[i]['parent'][0]; + var parent_name = result[i]['parent'][1]; + + if (jQuery.inArray(parent_id, project_id) == -1){ + if (parent_id == undefined){ + parent_name = ""; + } + j = j + 1; + project[j] = new GanttProjectInfo(parent_id, parent_name, new Date(2011, 1, 1)); + project_id[j] = parent_id; + } + + var id = result[i]['id']; + var text = result[i]['text']; + var start_date = this.convert_date_format(result[i]['start_date']); + var duration = result[i]['duration']; + + var task = new GanttTaskInfo(id, text, start_date, duration, 100, ""); + + k = project_id.indexOf(parent_id); + project[k].addTask(task); + + } + for (i in project_id){ + ganttChartControl.addProject(project[i]); + } + ganttChartControl.create("GanttDiv"); + ganttChartControl.attachEvent("onTaskEndResize", function(task) {self.on_task_end_resize(task);}) + ganttChartControl.attachEvent("onTaskEndDrag", function(task) {self.on_task_end_drag(task);}) + + //Create Sidebar + if (jQuery('#cal-sidebar-option').length == 0){ + jQuery('#gantt-sidebar').append( + jQuery('',{'width':'100%','cellspacing': 0, 'cellpadding': 0, 'id':'cal-sidebar-option'}) + ) + for(s in sidebar) { + jQuery('#cal-sidebar-option').append( + jQuery('').append( + jQuery(' From f55d7b5e8504bdb6d46d8187fa4209f4ca9c2164 Mon Sep 17 00:00:00 2001 From: Xavier Morel Date: Thu, 7 Apr 2011 15:27:26 +0200 Subject: [PATCH 095/259] [IMP] make headers display disablable on list view bzr revid: xmo@openerp.com-20110407132726-j04x68lzq5ylkaki --- addons/base/static/src/js/list.js | 5 ++++- addons/base/static/src/xml/base.xml | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/addons/base/static/src/js/list.js b/addons/base/static/src/js/list.js index 296f8d09759..7b2514b4b28 100644 --- a/addons/base/static/src/js/list.js +++ b/addons/base/static/src/js/list.js @@ -4,7 +4,9 @@ openerp.base.ListView = openerp.base.Controller.extend( /** @lends openerp.base.ListView# */ { defaults: { // records can be selected one by one - 'selectable': true + 'selectable': true, + // whether the column headers should be displayed + 'header': true }, /** * @constructs @@ -15,6 +17,7 @@ openerp.base.ListView = openerp.base.Controller.extend( * @param {String} view_id the listview's identifier, if any * @param {Object} options A set of options used to configure the view * @param {Boolean} [options.selectable=true] determines whether view rows are selectable (e.g. via a checkbox) + * @param {Boolean} [options.header=true] should the list's header be displayed */ init: function(view_manager, session, element_id, dataset, view_id, options) { this._super(session, element_id); diff --git a/addons/base/static/src/xml/base.xml b/addons/base/static/src/xml/base.xml index 1dcb30006d4..79428989c95 100644 --- a/addons/base/static/src/xml/base.xml +++ b/addons/base/static/src/xml/base.xml @@ -170,7 +170,7 @@
').append( + jQuery('
') + .append( + jQuery('', + { + 'type': 'checkbox', + 'id':sidebar[s][0], + 'value':sidebar[s][0] + }).bind('click',function(){ + self.reload_gantt(self.color_field,self.model) + }), + sidebar[s][1] + ) + .css('background-color',sidebar[s][sidebar[s].length-1]) + ) + ) + ) + } + } + }, + reload_gantt: function(color_field, model) { + var domain = []; + var self = this; + jQuery('input[type=checkbox]:checked','#cal-sidebar-option').each(function() { + domain.push(parseInt(jQuery(this).attr('id'))) + }); + this.rpc('/base_gantt/ganttview/reload_gantt',{ + 'domain':domain, + 'color_field':color_field, + 'model': model + },function(res) { + ganttChartControl.clearAll(); + jQuery("#GanttDiv").children().remove(); + self.load_event(res); + }); + }, + reverse_convert_date_format: function(date) { + return date.getFullYear()+"-"+(date.getMonth()+1)+"-"+date.getDate(); + }, + + on_task_end_resize : function(task) { + this.rpc('/base_gantt/ganttview/on_event_resize', + {'id' : task.getId(), + 'end_date' : this.reverse_convert_date_format(task.getFinishDate()), + 'duration' : task.getDuration() + }, + function(result) { + }) + }, + on_task_end_drag : function(task) { + this.rpc('/base_gantt/ganttview/on_event_drag', + {'id' : task.getId(), + 'start_date' : this.reverse_convert_date_format(task.getEST()), + 'end_date' : this.reverse_convert_date_format(task.getFinishDate()), + 'duration' : task.getDuration() + }, + function(result) { + }) + }, + +}); + +// here you may tweak globals object, if any, and play with on_* or do_* callbacks on them + +}; + +// vim:et fdc=0 fdl=0: From bae6364c249059c5535ab17747983eb969b1b048 Mon Sep 17 00:00:00 2001 From: "Quentin (OpenERP)" Date: Thu, 7 Apr 2011 14:35:15 +0200 Subject: [PATCH 089/259] [IMP] account_followup: improved report bzr revid: qdp-launchpad@openerp.com-20110407123515-s56jq5qtwxoddevr --- addons/account_followup/report/account_followup_print.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addons/account_followup/report/account_followup_print.py b/addons/account_followup/report/account_followup_print.py index 54ead894c67..9081e862cfe 100644 --- a/addons/account_followup/report/account_followup_print.py +++ b/addons/account_followup/report/account_followup_print.py @@ -69,7 +69,7 @@ class report_rappel(report_sxw.rml_parse): line_cur[line.currency_id.id] = {'line': []} currency = line.currency_id or line.company_id.currency_id line_data = { - 'name': line.name, + 'name': line.move_id.name, 'ref': line.ref, 'date':line.date, 'date_maturity': line.date_maturity, From acaf85e7625de11622a4ef4addffb455816dbf92 Mon Sep 17 00:00:00 2001 From: Xavier Morel Date: Thu, 7 Apr 2011 14:38:24 +0200 Subject: [PATCH 090/259] [TEST] that selectable=false leads to no insertion of selection checkbox bzr revid: xmo@openerp.com-20110407123824-6zys5lutnqt90zya --- addons/base/static/test/list.js | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/addons/base/static/test/list.js b/addons/base/static/test/list.js index ed055d0bb8a..92c0a092ee1 100644 --- a/addons/base/static/test/list.js +++ b/addons/base/static/test/list.js @@ -44,5 +44,18 @@ $(document).ready(function () { start(); }); }); - + asyncTest('render no checkbox if selectable=false', 1, function () { + + var listview = new openerp.base.ListView( + {}, null, + 'qunit-fixture', {model: null}, false, + {selectable: false}); + + listview.on_loaded(fvg); + + listview.do_fill_table([{}, {}, {}]).then(function () { + equal(listview.$element.find('tbody th').length, 0); + start(); + }); + }); }); From 3b4a87a7317545babf4c2d6d3838273f9cb478c6 Mon Sep 17 00:00:00 2001 From: niv-openerp Date: Thu, 7 Apr 2011 14:45:18 +0200 Subject: [PATCH 091/259] [IMP] wip bzr revid: nicolas.vanhoren@openerp.com-20110407124518-sp9rn78cdvapngmx --- addons/base/static/src/js/views.js | 1 - 1 file changed, 1 deletion(-) diff --git a/addons/base/static/src/js/views.js b/addons/base/static/src/js/views.js index 39646472437..1707a4db54a 100644 --- a/addons/base/static/src/js/views.js +++ b/addons/base/static/src/js/views.js @@ -312,7 +312,6 @@ openerp.base.handle_action = function(session, action) { dialog.dialog({ title: action.name }); - debugger; var viewmanager = new openerp.base.ViewManagerAction(session,element_id, action, false); viewmanager.start(); } From 02636b462291084c1c2097967abde3bef12c2fc9 Mon Sep 17 00:00:00 2001 From: Xavier Morel Date: Thu, 7 Apr 2011 14:46:39 +0200 Subject: [PATCH 092/259] [ADD] method to get the selection (list of identifiers) from a list view bzr revid: xmo@openerp.com-20110407124639-tua9qkcl4w8mhtdc --- addons/base/static/src/js/list.js | 14 ++++++++++++++ addons/base/static/test/list.js | 16 +++++++++++++++- 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/addons/base/static/src/js/list.js b/addons/base/static/src/js/list.js index 65f503649b8..296f8d09759 100644 --- a/addons/base/static/src/js/list.js +++ b/addons/base/static/src/js/list.js @@ -143,6 +143,20 @@ openerp.base.ListView = openerp.base.Controller.extend( do_update: function () { var self = this; self.dataset.fetch(self.dataset.fields, 0, self.limit, self.do_fill_table); + }, + /** + * Gets the ids of all currently selected records, if any + * @returns a list of ids, empty if no record is selected (or the list view is not selectable + */ + get_selection: function () { + if (!this.options.selectable) { + return []; + } + var rows = this.rows; + return this.$element.find('th.oe-record-selector input:checked') + .closest('tr').map(function () { + return rows[$(this).prevAll().length].id; + }).get(); } }); diff --git a/addons/base/static/test/list.js b/addons/base/static/test/list.js index 92c0a092ee1..e7d8152dee1 100644 --- a/addons/base/static/test/list.js +++ b/addons/base/static/test/list.js @@ -45,7 +45,6 @@ $(document).ready(function () { }); }); asyncTest('render no checkbox if selectable=false', 1, function () { - var listview = new openerp.base.ListView( {}, null, 'qunit-fixture', {model: null}, false, @@ -58,4 +57,19 @@ $(document).ready(function () { start(); }); }); + asyncTest('select a bunch of records', 2, function () { + var listview = new openerp.base.ListView( + {}, null, 'qunit-fixture', {model: null}); + listview.on_loaded(fvg); + + listview.do_fill_table([{id: 1}, {id: 2}, {id: 3}]).then(function () { + listview.$element.find('tbody th input:eq(2)') + .attr('checked', true); + deepEqual(listview.get_selection(), [3]); + listview.$element.find('tbody th input:eq(1)') + .attr('checked', true); + deepEqual(listview.get_selection(), [2, 3]); + start(); + }); + }); }); From 70d622c151562d97ffaa3f4c061e9c79aace725a Mon Sep 17 00:00:00 2001 From: "vda (OpenERP)" Date: Thu, 7 Apr 2011 18:36:23 +0530 Subject: [PATCH 093/259] [FIX] Specific Shape accordingly node will display. bzr revid: vda@tinyerp.com-20110407130623-iw7nf7vv0dc4jiqk --- addons/base/static/src/xml/base.xml | 2 +- addons/base_diagram/static/src/js/diagram.js | 50 ++++++++++++-------- 2 files changed, 30 insertions(+), 22 deletions(-) diff --git a/addons/base/static/src/xml/base.xml b/addons/base/static/src/xml/base.xml index 8d8040fd48e..1ad8f56511e 100644 --- a/addons/base/static/src/xml/base.xml +++ b/addons/base/static/src/xml/base.xml @@ -169,7 +169,7 @@

-
+

diff --git a/addons/base_diagram/static/src/js/diagram.js b/addons/base_diagram/static/src/js/diagram.js index cc0f69b9eb5..af56c256ee7 100644 --- a/addons/base_diagram/static/src/js/diagram.js +++ b/addons/base_diagram/static/src/js/diagram.js @@ -97,19 +97,6 @@ openerp.base.DiagramView = openerp.base.Controller.extend({ } this.$element.html(QWeb.render("DiagramView", {"fields_view": this.fields_view})); - -// g.addEdge("strawberry", "cherry"); -// g.addEdge("strawberry", "apple"); -// g.addEdge("strawberry", "tomato"); -// -// g.addEdge("tomato", "apple"); -// g.addEdge("tomato", "kiwi"); -// -// g.addEdge("cherry", "apple"); -// g.addEdge("cherry", "kiwi"); - - - if(this.id) { this.rpc( '/base_diagram/diagram/get_diagram_info', @@ -138,27 +125,48 @@ openerp.base.DiagramView = openerp.base.Controller.extend({ draw_diagram: function(result) { console.log('this>>>',this) var g = new Graph(); - +// var raphel = new this.in_transition_field = result['in_transition_field']; this.out_transition_field = result['out_transition_field']; var res_nodes = result['nodes']; var res_connectors = result['conn']; -// for(nd in res_nodes) { -// var res_node = res_nodes[nd]; -// console.log('nodes',res_node, res_node['shape']) -// var state; -// } + + var render = function(r, n) { + var set; + if (n.node.shape == 'ellipse') { + set = r.set().push( + r.ellipse(n.node.x - 30, n.node.y - 13, 40, 40).attr({ + "fill": n.node.color, + r: "12px", + "stroke-width": n.distance == 0 ? "3px" : "1px" + })).push(r.text(n.node.x - 30, n.node.y - 10, (n.label || n.id))); + } else { + set = r.set().push( + r.rect(n.node.x-30, n.node.y-13, 60, 44).attr({"fill": n.node.color, r : "12px", "stroke-width" : n.distance == 0 ? "3px" : "1px" })).push( + r.text(n.point[0], n.point[1] + 10, (n.label || n.id) + "\n(" + (n.distance == undefined ? "Infinity" : n.distance) + ")")); + + } + return set; + }; + + for(nd in res_nodes) { + var res_node = res_nodes[nd]; + g.addNode(res_node['name'], + { + node: res_node, + render: render + }); + } for(cr in res_connectors) { var res_connector = res_connectors[cr]; g.addEdge(res_connector['source'], res_connector['destination']); - } var layouter = new Graph.Layout.Spring(g); layouter.layout(); - var renderer = new Graph.Renderer.Raphael('dia-canvas', g, 800, 500); + var renderer = new Graph.Renderer.Raphael('dia-canvas', g, 800, 800); renderer.draw(); }, From 2acfa4ba061a2a10f24106f79a8925c8929cf92c Mon Sep 17 00:00:00 2001 From: Fabien Meghazi Date: Thu, 7 Apr 2011 15:07:25 +0200 Subject: [PATCH 094/259] [ADD] form: Basic new record support bzr revid: fme@openerp.com-20110407130725-0o4d8j2kgko8b7jn --- addons/base/controllers/main.py | 6 +++ addons/base/static/src/css/base.css | 8 +-- addons/base/static/src/js/data.js | 7 ++- addons/base/static/src/js/form.js | 75 +++++++++++++++++++---------- addons/base/static/src/xml/base.xml | 30 ++++++------ 5 files changed, 79 insertions(+), 47 deletions(-) diff --git a/addons/base/controllers/main.py b/addons/base/controllers/main.py index 9db66638b22..92987ffa639 100644 --- a/addons/base/controllers/main.py +++ b/addons/base/controllers/main.py @@ -347,6 +347,12 @@ class DataSet(openerpweb.Controller): r = getattr(m, method)(ids, *args) return {'result': r} + @openerpweb.jsonrequest + def default_get(self, req, model, fields, context={}): + m = req.session.model(model) + r = m.default_get(fields, context) + return {'result': r} + class View(openerpweb.Controller): def fields_view_get(self, session, model, view_id, view_type, transform=True): Model = session.model(model) diff --git a/addons/base/static/src/css/base.css b/addons/base/static/src/css/base.css index 61b1f68879b..7b686f53fb4 100644 --- a/addons/base/static/src/css/base.css +++ b/addons/base/static/src/css/base.css @@ -419,17 +419,13 @@ body.openerp { .openerp .required.error { border: 1px solid #900; } -.openerp .oe_form_buttons { +.openerp .oe_form_buttons, .openerp .oe_list_buttons { float: left; } -.openerp .oe_form_pager { +.openerp .oe_form_pager, .openerp .oe_list_pager { float: right; } -.openerp .oe_list_pager { - text-align: right; -} - /* Inputs */ .openerp input[type="text"], .openerp input[type="password"], .openerp select, .openerp textarea { -moz-box-sizing: border-box; diff --git a/addons/base/static/src/js/data.js b/addons/base/static/src/js/data.js index 4dbfb47dd28..c0187e77684 100644 --- a/addons/base/static/src/js/data.js +++ b/addons/base/static/src/js/data.js @@ -82,7 +82,12 @@ openerp.base.DataSet = openerp.base.Controller.extend( /** @lends openerp.base. }); } }, - default_get: function() { + default_get: function(fields, callback) { + this.rpc('/base/dataset/default_get', { + model: this.model, + fields: fields, + context: this.context + }, callback); }, create: function() { }, diff --git a/addons/base/static/src/js/form.js b/addons/base/static/src/js/form.js index a1ba84e14af..9bb1eda6ca3 100644 --- a/addons/base/static/src/js/form.js +++ b/addons/base/static/src/js/form.js @@ -50,6 +50,7 @@ openerp.base.FormView = openerp.base.Controller.extend( /** @lends openerp.base this.$element.find('div.oe_form_buttons button.oe_form_button_save').click(this.do_save); this.$element.find('div.oe_form_buttons button.oe_form_button_save_edit').click(this.do_save_edit); this.$element.find('div.oe_form_buttons button.oe_form_button_cancel').click(this.do_cancel); + this.$element.find('div.oe_form_buttons button.oe_form_button_new').click(this.on_button_new); // sidebar stuff if (this.view_manager.sidebar) { @@ -71,6 +72,15 @@ openerp.base.FormView = openerp.base.Controller.extend( /** @lends openerp.base for (var f in this.fields) { this.fields[f].set_value(this.datarecord[f]); } + if (!record.id) { + // Second pass in order to trigger the onchanges in case of new record + for (var f in this.fields) { + var field = this.fields[f]; + if (field.node.attrs.on_change) { + this.do_onchange(field); + } + } + } this.on_form_changed(); this.ready = true; } else { @@ -79,13 +89,14 @@ openerp.base.FormView = openerp.base.Controller.extend( /** @lends openerp.base this.do_update_pager(); }, on_form_changed: function(widget) { - for (var w in this.widgets) { - w = this.widgets[w]; - w.process_attrs(); - w.update_dom(); - } if (widget && widget.node.attrs.on_change) { this.do_onchange(widget); + } else { + for (var w in this.widgets) { + w = this.widgets[w]; + w.process_attrs(); + w.update_dom(); + } } }, on_pager_action: function(action) { @@ -113,24 +124,29 @@ openerp.base.FormView = openerp.base.Controller.extend( /** @lends openerp.base this.$element.find('span.oe_pager_count').html(this.dataset.count); }, do_onchange: function(widget) { - var self = this; - this.ready = false; - var onchange = _.trim(widget.node.attrs.on_change); - var call = onchange.match(/^\s?(.*?)\((.*?)\)\s?$/); - if (call) { - var method = call[1], args = []; - _.each(call[2].split(','), function(a) { - var field = _.trim(a); - if (self.fields[field]) { - args.push(self.fields[field].value); - } else { - args.push(false); - this.log("warning : on_change can't find field " + field, onchange); - } - }); - this.dataset.call(method, [this.datarecord.id], args, this.on_processed_onchange); - } else { - this.log("Wrong on_change format", on_change); + if (widget.node.attrs.on_change) { + var self = this; + this.ready = false; + var onchange = _.trim(widget.node.attrs.on_change); + var call = onchange.match(/^\s?(.*?)\((.*?)\)\s?$/); + if (call) { + var method = call[1], args = []; + _.each(call[2].split(','), function(a) { + var field = _.trim(a); + if (self.fields[field]) { + var value = self.fields[field].value; + args.push(value == null ? false : value); + } else { + args.push(false); + this.log("warning : on_change can't find field " + field, onchange); + } + }); + console.info("Calling onchange :", onchange); + // TODO: no async for onchange + this.dataset.call(method, (this.datarecord.id == null ? [] : [this.datarecord.id]), args, this.on_processed_onchange); + } else { + this.log("Wrong on_change format", on_change); + } } }, on_processed_onchange: function(response) { @@ -143,13 +159,13 @@ openerp.base.FormView = openerp.base.Controller.extend( /** @lends openerp.base var value = result.value[f]; if (field.value != value) { field.set_value(value); - // TODO: Recursive on_change - // this.on_form_changed(field); + this.do_onchange(field); } } else { this.log("warning : on_processed_onchange can't find field " + field, result); } } + this.on_form_changed(); } if (result.warning) { $(QWeb.render("DialogWarning", result.warning)).dialog({ @@ -166,6 +182,12 @@ openerp.base.FormView = openerp.base.Controller.extend( /** @lends openerp.base } this.ready = true; }, + on_button_new: function() { + var self = this; + this.dataset.default_get(_.keys(this.fields), function(result) { + self.on_record_loaded(result.result); + }); + }, do_save: function() { if (!this.ready) { return false; @@ -462,6 +484,7 @@ openerp.base.form.Field = openerp.base.form.Widget.extend({ set_value: function(value) { this.value = value; this.invalid = false; + this.update_dom(); }, get_value: function() { return this.value; @@ -710,7 +733,7 @@ openerp.base.form.FieldOne2Many = openerp.base.form.Field.extend({ this.viewmanager = new openerp.base.form.FieldOne2ManyViewManager(this.view.session, this.element_id, this.dataset, views); this.viewmanager.start(); }, - set_value: function(value) { + set_value_CASSEEEEEEEEEEEEEEEEE: function(value) { this.value = value; this.log("o2m.set_value",value); this.viewmanager.dataset.ids = value; diff --git a/addons/base/static/src/xml/base.xml b/addons/base/static/src/xml/base.xml index 7a982e631fe..98665214992 100644 --- a/addons/base/static/src/xml/base.xml +++ b/addons/base/static/src/xml/base.xml @@ -156,15 +156,21 @@ -
- - +
+
+ +
+
+ + - 0 / 0 + 0 / 0 - - + + +
+
@@ -184,9 +190,10 @@

- + - + +
@@ -199,11 +206,6 @@
-
- -
Unhandled widget @@ -218,7 +220,7 @@ t-att-nowrap="td.is_field_label ? 'true' : undefined" t-att-valign="td.table ? 'top' : undefined" t-att-id="td.element_id" - t-att-class="'container_' + td.type" + t-att-class="'oe_form_' + (td.is_field_label ? 'label' : (td.field ? 'field_' + td.type : td.type))" >
- + From 16b7ad769f4fb4ea87213de3686e455770b02d17 Mon Sep 17 00:00:00 2001 From: Fabien Meghazi Date: Thu, 7 Apr 2011 15:36:44 +0200 Subject: [PATCH 096/259] [FIX] Use deffered for views#do_show() bzr revid: fme@openerp.com-20110407133644-7dzjpg761cibudmi --- addons/base/static/src/js/form.js | 4 +--- addons/base/static/src/js/views.js | 2 +- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/addons/base/static/src/js/form.js b/addons/base/static/src/js/form.js index 9bb1eda6ca3..15246779e21 100644 --- a/addons/base/static/src/js/form.js +++ b/addons/base/static/src/js/form.js @@ -58,9 +58,7 @@ openerp.base.FormView = openerp.base.Controller.extend( /** @lends openerp.base } }, do_show: function () { - // this should not append as start return a deferred resolved when fields_view is known - if(this.fields_view && this.fields_view.fields) - this.dataset.read_index(_.keys(this.fields_view.fields), this.on_record_loaded); + this.dataset.read_index(_.keys(this.fields_view.fields), this.on_record_loaded); this.$element.show(); }, do_hide: function () { diff --git a/addons/base/static/src/js/views.js b/addons/base/static/src/js/views.js index fff4224274a..6adc0fc3d38 100644 --- a/addons/base/static/src/js/views.js +++ b/addons/base/static/src/js/views.js @@ -93,7 +93,7 @@ openerp.base.ViewManager = openerp.base.Controller.extend({ for (var i in this.views) { if (this.views[i].controller) { if (i === view_type) { - this.views[i].controller.do_show(); + $.when(view_promise).then(this.views[i].controller.do_show); } else { this.views[i].controller.do_hide(); } From 56532b80be7c837dda97cc7e35c079af78c6a215 Mon Sep 17 00:00:00 2001 From: Fabien Meghazi Date: Thu, 7 Apr 2011 15:50:42 +0200 Subject: [PATCH 097/259] [ADD] in rpc_ajax, first parameter can be url or $.ajax option object (with url inside) bzr revid: fme@openerp.com-20110407135042-plwyesu7o7minf9i --- addons/base/static/src/js/chrome.js | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/addons/base/static/src/js/chrome.js b/addons/base/static/src/js/chrome.js index db2db6b91e5..3f2358d4a8c 100644 --- a/addons/base/static/src/js/chrome.js +++ b/addons/base/static/src/js/chrome.js @@ -283,7 +283,13 @@ openerp.base.Session = openerp.base.BasicController.extend( /** @lends openerp.b rpc_ajax: function(url, payload, success_callback, error_callback) { var self = this; this.on_rpc_request(); - return $.ajax({ + // url can be an $.ajax option object + if (_.isString(url)) { + url = { + url: url + } + } + var ajax = _.extend({ type: "POST", url: url, dataType: 'json', @@ -314,7 +320,8 @@ openerp.base.Session = openerp.base.BasicController.extend( /** @lends openerp.b }; error_callback(error); } - }); + }, url); + return $.ajax(ajax); }, on_rpc_request: function() { }, From b95da502b06b42dd770fd9dbe389560a00b4b88c Mon Sep 17 00:00:00 2001 From: Fabien Meghazi Date: Thu, 7 Apr 2011 15:57:32 +0200 Subject: [PATCH 098/259] [ADD] return deffered in dataset bzr revid: fme@openerp.com-20110407135732-n6ukk0mw6rwr1vpe --- addons/base/static/src/js/data.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/addons/base/static/src/js/data.js b/addons/base/static/src/js/data.js index c0187e77684..f40de2f28ce 100644 --- a/addons/base/static/src/js/data.js +++ b/addons/base/static/src/js/data.js @@ -83,7 +83,7 @@ openerp.base.DataSet = openerp.base.Controller.extend( /** @lends openerp.base. } }, default_get: function(fields, callback) { - this.rpc('/base/dataset/default_get', { + return this.rpc('/base/dataset/default_get', { model: this.model, fields: fields, context: this.context @@ -92,7 +92,7 @@ openerp.base.DataSet = openerp.base.Controller.extend( /** @lends openerp.base. create: function() { }, write: function (id, data, callback) { - this.rpc('/base/dataset/save', { + return this.rpc('/base/dataset/save', { model: this.model, id: id, data: data, @@ -104,7 +104,7 @@ openerp.base.DataSet = openerp.base.Controller.extend( /** @lends openerp.base. call: function (method, ids, args, callback) { ids = ids || []; args = args || []; - this.rpc('/base/dataset/call', { + return this.rpc('/base/dataset/call', { model: this.model, method: method, ids: ids, From 8aebdc308c7d66d358694db5cd622cf54dd0ddba Mon Sep 17 00:00:00 2001 From: Bogdan Stanciu Date: Thu, 7 Apr 2011 17:06:57 +0200 Subject: [PATCH 099/259] [FIX] for bug 753651 cannot select account for bank statement lp bug: https://launchpad.net/bugs/753651 fixed bzr revid: bogdanovidiu.stanciu@gmail.com-20110407150657-76j88ckl5y1pd1jd --- addons/account/account_bank_statement.py | 1 + 1 file changed, 1 insertion(+) diff --git a/addons/account/account_bank_statement.py b/addons/account/account_bank_statement.py index 76ccad9e68a..7a885fb2cad 100644 --- a/addons/account/account_bank_statement.py +++ b/addons/account/account_bank_statement.py @@ -161,6 +161,7 @@ class account_bank_statement(osv.osv): 'balance_start': _default_balance_start, 'journal_id': _default_journal_id, 'period_id': _get_period, + 'company_id': lambda self,cr,uid,c: self.pool.get('res.company')._company_default_get(cr, uid, 'account.bank.statement',context=c), } def onchange_date(self, cr, user, ids, date, context=None): From e8a6a4e1e2a24a105270a989ceba462d828c61cc Mon Sep 17 00:00:00 2001 From: Xavier Morel Date: Thu, 7 Apr 2011 17:13:19 +0200 Subject: [PATCH 100/259] [ADD] delete button per row bzr revid: xmo@openerp.com-20110407151319-vr7sc3n497y4ily0 --- addons/base/static/src/js/list.js | 16 +++++++++++++++ addons/base/static/src/xml/base.xml | 3 +++ addons/base/static/test/list.js | 31 +++++++++++++++++++++++++++++ 3 files changed, 50 insertions(+) diff --git a/addons/base/static/src/js/list.js b/addons/base/static/src/js/list.js index 7b2514b4b28..89bc2f013ae 100644 --- a/addons/base/static/src/js/list.js +++ b/addons/base/static/src/js/list.js @@ -5,6 +5,8 @@ openerp.base.ListView = openerp.base.Controller.extend( defaults: { // records can be selected one by one 'selectable': true, + // list rows can be deleted + 'deletable': true, // whether the column headers should be displayed 'header': true }, @@ -18,6 +20,7 @@ openerp.base.ListView = openerp.base.Controller.extend( * @param {Object} options A set of options used to configure the view * @param {Boolean} [options.selectable=true] determines whether view rows are selectable (e.g. via a checkbox) * @param {Boolean} [options.header=true] should the list's header be displayed + * @param {Boolean} [options.deletable=true] are the list rows deletable */ init: function(view_manager, session, element_id, dataset, view_id, options) { this._super(session, element_id); @@ -54,6 +57,8 @@ openerp.base.ListView = openerp.base.Controller.extend( // linking feature e.stopImmediatePropagation(); }); + this.$element.find('table').delegate( + 'td.oe-record-delete button', 'click', this.do_delete); this.$element.find('table').delegate( 'tr', 'click', this.on_select_row); @@ -147,6 +152,17 @@ openerp.base.ListView = openerp.base.Controller.extend( var self = this; self.dataset.fetch(self.dataset.fields, 0, self.limit, self.do_fill_table); }, + /** + * Handles the signal to delete a line from the DOM + * + * @param e + */ + do_delete: function (e) { + // don't link to forms + e.stopImmediatePropagation(); + this.dataset.unlink( + [this.rows[$(e.currentTarget).closest('tr').prevAll().length].id]); + }, /** * Gets the ids of all currently selected records, if any * @returns a list of ids, empty if no record is selected (or the list view is not selectable diff --git a/addons/base/static/src/xml/base.xml b/addons/base/static/src/xml/base.xml index 79428989c95..c3682051e54 100644 --- a/addons/base/static/src/xml/base.xml +++ b/addons/base/static/src/xml/base.xml @@ -205,6 +205,9 @@ + + +

diff --git a/addons/base/static/test/list.js b/addons/base/static/test/list.js index e7d8152dee1..9e675125004 100644 --- a/addons/base/static/test/list.js +++ b/addons/base/static/test/list.js @@ -72,4 +72,35 @@ $(document).ready(function () { start(); }); }); + asyncTest('render deletion button if list is deletable', 1, function () { + var listview = new openerp.base.ListView( + {}, null, 'qunit-fixture', {model: null}); + + listview.on_loaded(fvg); + + listview.do_fill_table([{id: 1}, {id: 2}, {id: 3}]).then(function () { + equal( + listview.$element.find('tbody tr td.oe-record-delete button').length, + 3); + start(); + }); + }); + asyncTest('deletion button should lead on deletion in the dataset', + 2, function () { + var deleted; + var listview = new openerp.base.ListView( + {}, null, 'qunit-fixture', {model: null, unlink: function (ids) { + deleted = ids; + }}); + + listview.on_loaded(fvg); + + listview.do_fill_table([{id: 1}, {id: 2}, {id: 3}]).then(function () { + listview.$element.find('tbody td.oe-record-delete:eq(2) button').click(); + deepEqual(deleted, [3]); + listview.$element.find('tbody td.oe-record-delete:eq(0) button').click(); + deepEqual(deleted, [1]); + start(); + }); + }); }); From 0fe1fdb06a6873aa780a60a7946a9e90b08749aa Mon Sep 17 00:00:00 2001 From: Xavier Morel Date: Thu, 7 Apr 2011 17:35:27 +0200 Subject: [PATCH 101/259] [ADD] multiple records deletion bzr revid: xmo@openerp.com-20110407153527-6r8cb7oym1fp5r6x --- addons/base/static/src/js/list.js | 19 +++++++++++++++++++ addons/base/static/src/xml/base.xml | 8 ++++++++ addons/base/static/test/list.js | 20 ++++++++++++++++++++ 3 files changed, 47 insertions(+) diff --git a/addons/base/static/src/js/list.js b/addons/base/static/src/js/list.js index 89bc2f013ae..cb9409327f2 100644 --- a/addons/base/static/src/js/list.js +++ b/addons/base/static/src/js/list.js @@ -50,7 +50,15 @@ openerp.base.ListView = openerp.base.Controller.extend( return _.extend({id: name, tag: field.tag}, field.attrs, fields[name]); }).value(); + this.visible_columns = _.filter(this.columns, function (column) { + return column.invisible !== '1'; + }); this.$element.html(QWeb.render("ListView", this)); + + // Head hook + this.$element.find('#oe-list-delete').click(this.do_delete_selected); + + // Cell events this.$element.find('table').delegate( 'th.oe-record-selector', 'click', function (e) { // A click in the selection cell should not activate the @@ -59,6 +67,8 @@ openerp.base.ListView = openerp.base.Controller.extend( }); this.$element.find('table').delegate( 'td.oe-record-delete button', 'click', this.do_delete); + + // Global rows handlers this.$element.find('table').delegate( 'tr', 'click', this.on_select_row); @@ -163,6 +173,15 @@ openerp.base.ListView = openerp.base.Controller.extend( this.dataset.unlink( [this.rows[$(e.currentTarget).closest('tr').prevAll().length].id]); }, + /** + * Handles deletion of all selected lines + */ + do_delete_selected: function () { + var selection = this.get_selection(); + if (selection.length) { + this.dataset.unlink(selection); + } + }, /** * Gets the ids of all currently selected records, if any * @returns a list of ids, empty if no record is selected (or the list view is not selectable diff --git a/addons/base/static/src/xml/base.xml b/addons/base/static/src/xml/base.xml index c3682051e54..4fb208c6088 100644 --- a/addons/base/static/src/xml/base.xml +++ b/addons/base/static/src/xml/base.xml @@ -171,6 +171,13 @@
+ + + + + @@ -180,6 +187,7 @@ +
diff --git a/addons/base/static/test/list.js b/addons/base/static/test/list.js index 9e675125004..4a5bb3795fe 100644 --- a/addons/base/static/test/list.js +++ b/addons/base/static/test/list.js @@ -103,4 +103,24 @@ $(document).ready(function () { start(); }); }); + asyncTest('multiple records deletion', 1, function () { + var deleted; + var listview = new openerp.base.ListView( + {}, null, 'qunit-fixture', {model: null, unlink: function (ids) { + deleted = ids; + }}); + + listview.on_loaded(fvg); + + listview.do_fill_table([{id: 1}, {id: 2}, {id: 3}]).then(function () { + listview.$element.find('tbody th input:eq(2)') + .attr('checked', true); + listview.$element.find('tbody th input:eq(1)') + .attr('checked', true); + + listview.$element.find('#oe-list-delete').click(); + deepEqual(deleted, [2, 3]); + start(); + }); + }); }); From 90354c9220fb49828302cbc973cb2e7f05664f24 Mon Sep 17 00:00:00 2001 From: Xavier Morel Date: Thu, 7 Apr 2011 17:41:18 +0200 Subject: [PATCH 102/259] [IMP] add notification to DataSet.unlink so we can see it, change notification duration to 1500ms from 5000 bzr revid: xmo@openerp.com-20110407154118-leopn5315t974saj --- addons/base/static/src/js/chrome.js | 3 ++- addons/base/static/src/js/data.js | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/addons/base/static/src/js/chrome.js b/addons/base/static/src/js/chrome.js index 761ff532f1b..289f680e093 100644 --- a/addons/base/static/src/js/chrome.js +++ b/addons/base/static/src/js/chrome.js @@ -500,7 +500,8 @@ openerp.base.Notification = openerp.base.Controller.extend({ init: function(session, element_id) { this._super(session, element_id); this.$element.notify({ - speed: 500 + speed: 500, + expires: 1500 }); }, 'default': function(title, text) { diff --git a/addons/base/static/src/js/data.js b/addons/base/static/src/js/data.js index 4d90723b9a1..ca9cf83307e 100644 --- a/addons/base/static/src/js/data.js +++ b/addons/base/static/src/js/data.js @@ -120,7 +120,8 @@ openerp.base.DataSet = openerp.base.Controller.extend( /** @lends openerp.base. //context: this.context, }, callback); }, - unlink: function() { + unlink: function(ids) { + this.notification['default']("Unlink", ids); } }); From f29759941922bbac29c58de6f7d72cdc86737be9 Mon Sep 17 00:00:00 2001 From: Fabien Meghazi Date: Thu, 7 Apr 2011 17:59:36 +0200 Subject: [PATCH 103/259] [ADD] deffered onchanges part1 bzr revid: fme@openerp.com-20110407155936-rk1s4bgvdovsm5v2 --- addons/base/static/src/js/form.js | 65 ++++++++++++++++++++++--------- 1 file changed, 46 insertions(+), 19 deletions(-) diff --git a/addons/base/static/src/js/form.js b/addons/base/static/src/js/form.js index 15246779e21..119bceb8b64 100644 --- a/addons/base/static/src/js/form.js +++ b/addons/base/static/src/js/form.js @@ -139,31 +139,57 @@ openerp.base.FormView = openerp.base.Controller.extend( /** @lends openerp.base this.log("warning : on_change can't find field " + field, onchange); } }); - console.info("Calling onchange :", onchange); - // TODO: no async for onchange - this.dataset.call(method, (this.datarecord.id == null ? [] : [this.datarecord.id]), args, this.on_processed_onchange); + console.info("Calling onchange :", onchange, args); + var d = $.Deferred(); + this.dataset.call(method, (this.datarecord.id == null ? [] : [this.datarecord.id]), args, function(response) { + $.when(self.on_processed_onchange(response, onchange)).then(function() { + d.resolve(); + }); + }); + return d.promise(); } else { this.log("Wrong on_change format", on_change); } } }, - on_processed_onchange: function(response) { - console.log("onchange result :", response); - var result = response.result; - if (result.value) { - for (var f in result.value) { - var field = this.fields[f]; - if (field) { - var value = result.value[f]; - if (field.value != value) { - field.set_value(value); - this.do_onchange(field); - } - } else { - this.log("warning : on_processed_onchange can't find field " + field, result); - } + on_processed_changes: function(results) { + console.info("Process onchange :", results); + if (!results.length) { + return; + } + var self = this; + var result = results.shift(), + name = result[0], + value = result[1]; + var field = this.fields[name]; + if (field) { + console.info("Compare " + field.name + " : " + field.value + " == ", value); + if (field.value != value) { + var d = $.Deferred(); + console.info("Set " + field.name + " = ", value); + field.set_value(value); + $.when(this.do_onchange(field)).then(function() { + $.when(self.on_processed_changes(results)).then(function() { + d.resolve(); + }); + }); + return d.promise(); } - this.on_form_changed(); + } else { + this.log("warning : on_processed_onchange can't find field " + field, result); + } + }, + on_processed_onchange: function(response, onchange) { + var deferred, result = response.result; + console.info("Response onchange :", onchange, result.value); + if (result.value) { + var results = []; + for (var i in result.value) { + var tmp = [i, result.value[i]]; + results.push(tmp); + } + console.log("Generated results", results); + deferred = $.when(this.on_processed_changes(results)).then(this.on_form_changed); } if (result.warning) { $(QWeb.render("DialogWarning", result.warning)).dialog({ @@ -179,6 +205,7 @@ openerp.base.FormView = openerp.base.Controller.extend( /** @lends openerp.base // Will be removed ? } this.ready = true; + return deferred; }, on_button_new: function() { var self = this; From a590451a1b6d8f3928904225494e772c480db5a1 Mon Sep 17 00:00:00 2001 From: Antony Lesuisse Date: Thu, 7 Apr 2011 18:41:06 +0200 Subject: [PATCH 104/259] [MERGE] manually calendar view from trunk-proto61-dhtmlx-scheduler-vda bzr revid: al@openerp.com-20110407164106-odb0y1qogrg4x2js --- addons/base/static/src/base.html | 10 +- addons/base/static/src/js/base.js | 1 + addons/base/static/src/xml/base.xml | 57 +- addons/base_calendar/__init__.py | 1 + addons/base_calendar/controllers/__init__.py | 1 + addons/base_calendar/controllers/main.py | 357 ++ .../lib/dhtmlxScheduler/License_GPL.html | 73 + .../codebase/dhtmlxscheduler.css | 525 +++ .../codebase/dhtmlxscheduler.js | 3735 ++++++++++++++++ .../codebase/dhtmlxscheduler_debug.js | 3931 +++++++++++++++++ .../ext/dhtmlxscheduler_active_links.js | 9 + .../ext/dhtmlxscheduler_agenda_view.js | 9 + .../codebase/ext/dhtmlxscheduler_collision.js | 1 + .../codebase/ext/dhtmlxscheduler_cookie.js | 9 + .../codebase/ext/dhtmlxscheduler_editors.js | 9 + .../codebase/ext/dhtmlxscheduler_expand.js | 9 + .../codebase/ext/dhtmlxscheduler_ext.css | 1 + .../ext/dhtmlxscheduler_html_templates.js | 9 + .../codebase/ext/dhtmlxscheduler_key_nav.js | 9 + .../codebase/ext/dhtmlxscheduler_limit.js | 9 + .../codebase/ext/dhtmlxscheduler_map_view.js | 9 + .../codebase/ext/dhtmlxscheduler_minical.js | 9 + .../ext/dhtmlxscheduler_multiselect.js | 9 + .../ext/dhtmlxscheduler_multisource.js | 9 + .../codebase/ext/dhtmlxscheduler_outerdrag.js | 9 + .../codebase/ext/dhtmlxscheduler_pdf.js | 9 + .../codebase/ext/dhtmlxscheduler_readonly.js | 9 + .../ext/dhtmlxscheduler_recurring.css | 9 + .../codebase/ext/dhtmlxscheduler_recurring.js | 1 + .../codebase/ext/dhtmlxscheduler_serialize.js | 9 + .../codebase/ext/dhtmlxscheduler_timeline.js | 1 + .../codebase/ext/dhtmlxscheduler_tooltip.js | 1 + .../codebase/ext/dhtmlxscheduler_touch.css | 9 + .../codebase/ext/dhtmlxscheduler_touch.js | 9 + .../ext/dhtmlxscheduler_treetimeline.js | 1 + .../codebase/ext/dhtmlxscheduler_units.js | 9 + .../codebase/ext/dhtmlxscheduler_url.js | 9 + .../codebase/ext/dhtmlxscheduler_year_view.js | 9 + .../codebase/imgs/blue_tab.png | Bin 0 -> 180 bytes .../codebase/imgs/but_repeat.gif | Bin 0 -> 1149 bytes .../dhtmlxScheduler/codebase/imgs/buttons.png | Bin 0 -> 281 bytes .../codebase/imgs/calendar.gif | Bin 0 -> 622 bytes .../codebase/imgs/clock_big.gif | Bin 0 -> 1321 bytes .../codebase/imgs/clock_small.gif | Bin 0 -> 388 bytes .../codebase/imgs/colapce-expand-icon.gif | Bin 0 -> 452 bytes .../codebase/imgs/controls.gif | Bin 0 -> 2496 bytes .../dhtmlxScheduler/codebase/imgs/databg.png | Bin 0 -> 152 bytes .../codebase/imgs/databg_now.png | Bin 0 -> 152 bytes .../dhtmlxScheduler/codebase/imgs/icon.png | Bin 0 -> 230 bytes .../dhtmlxScheduler/codebase/imgs/loading.gif | Bin 0 -> 3951 bytes .../codebase/imgs/white_tab.png | Bin 0 -> 366 bytes .../static/lib/dhtmlxScheduler/readme.txt | 7 + .../lib/dhtmlxScheduler/sources/base.js | 133 + .../lib/dhtmlxScheduler/sources/clear.css | 106 + .../lib/dhtmlxScheduler/sources/config.js | 105 + .../lib/dhtmlxScheduler/sources/connector.js | 137 + .../sources/dataprocessor_hook.js | 78 + .../dhtmlxScheduler/sources/dhtmlxcommon.js | 901 ++++ .../sources/dhtmlxdataprocessor.js | 581 +++ .../sources/dhtmlxdataprocessor_debug.js | 164 + .../lib/dhtmlxScheduler/sources/event.js | 545 +++ .../lib/dhtmlxScheduler/sources/ext.css | 317 ++ .../sources/ext/ext_active_links.js | 21 + .../sources/ext/ext_agenda_view.js | 93 + .../sources/ext/ext_collision.js | 100 + .../dhtmlxScheduler/sources/ext/ext_cookie.js | 36 + .../sources/ext/ext_editors.js | 95 + .../dhtmlxScheduler/sources/ext/ext_expand.js | 54 + .../sources/ext/ext_html_templates.js | 15 + .../sources/ext/ext_key_nav.js | 32 + .../dhtmlxScheduler/sources/ext/ext_limit.js | 78 + .../sources/ext/ext_map_view.js | 396 ++ .../dhtmlxScheduler/sources/ext/ext_matrix.js | 573 +++ .../sources/ext/ext_minical.js | 378 ++ .../sources/ext/ext_monthheight.js | 27 + .../sources/ext/ext_multiselect.js | 63 + .../sources/ext/ext_multisource.js | 22 + .../sources/ext/ext_outerdrag.js | 38 + .../dhtmlxScheduler/sources/ext/ext_pdf.js | 196 + .../sources/ext/ext_readonly.js | 100 + .../sources/ext/ext_serialize.js | 66 + .../sources/ext/ext_tooltip.js | 133 + .../dhtmlxScheduler/sources/ext/ext_touch.js | 411 ++ .../sources/ext/ext_treetimeline.js | 275 ++ .../dhtmlxScheduler/sources/ext/ext_url.js | 30 + .../lib/dhtmlxScheduler/sources/ext/ext_wp.js | 13 + .../sources/ext/ext_year_view.js | 260 ++ .../lib/dhtmlxScheduler/sources/ical.js | 65 + .../lib/dhtmlxScheduler/sources/layout.css | 179 + .../lib/dhtmlxScheduler/sources/lightbox.css | 151 + .../lib/dhtmlxScheduler/sources/lightbox.js | 340 ++ .../lib/dhtmlxScheduler/sources/load.js | 184 + .../lib/dhtmlxScheduler/sources/locale.js | 40 + .../lib/dhtmlxScheduler/sources/locale_ar.js | 38 + .../lib/dhtmlxScheduler/sources/locale_ca.js | 41 + .../lib/dhtmlxScheduler/sources/locale_cn.js | 46 + .../lib/dhtmlxScheduler/sources/locale_cs.js | 40 + .../lib/dhtmlxScheduler/sources/locale_de.js | 39 + .../lib/dhtmlxScheduler/sources/locale_es.js | 41 + .../lib/dhtmlxScheduler/sources/locale_fi.js | 40 + .../lib/dhtmlxScheduler/sources/locale_fr.js | 38 + .../lib/dhtmlxScheduler/sources/locale_he.js | 40 + .../lib/dhtmlxScheduler/sources/locale_hu.js | 40 + .../lib/dhtmlxScheduler/sources/locale_id.js | 1 + .../lib/dhtmlxScheduler/sources/locale_it.js | 38 + .../lib/dhtmlxScheduler/sources/locale_jp.js | 42 + .../lib/dhtmlxScheduler/sources/locale_nl.js | 40 + .../lib/dhtmlxScheduler/sources/locale_no.js | 40 + .../lib/dhtmlxScheduler/sources/locale_pl.js | 40 + .../lib/dhtmlxScheduler/sources/locale_pt.js | 51 + .../sources/locale_recurring_cn.js | 2 + .../sources/locale_recurring_cs.js | 153 + .../sources/locale_recurring_de.js | 2 + .../sources/locale_recurring_es.js | 2 + .../sources/locale_recurring_fi.js | 2 + .../sources/locale_recurring_fr.js | 2 + .../sources/locale_recurring_it.js | 2 + .../sources/locale_recurring_nl.js | 2 + .../sources/locale_recurring_pl.js | 2 + .../sources/locale_recurring_pt.js | 1 + .../sources/locale_recurring_ru.js | 2 + .../sources/locale_recurring_sv.js | 1 + .../sources/locale_recurring_ua.js | 2 + .../lib/dhtmlxScheduler/sources/locale_ru.js | 38 + .../lib/dhtmlxScheduler/sources/locale_si.js | 40 + .../lib/dhtmlxScheduler/sources/locale_sv.js | 45 + .../lib/dhtmlxScheduler/sources/locale_ua.js | 40 + .../lib/dhtmlxScheduler/sources/note.css | 115 + .../lib/dhtmlxScheduler/sources/property.js | 175 + .../lib/dhtmlxScheduler/sources/recurring.css | 111 + .../lib/dhtmlxScheduler/sources/recurring.js | 596 +++ .../sources/repeat_template.html | 57 + .../sources/repeat_template_cn.html | 57 + .../sources/repeat_template_de.html | 60 + .../sources/repeat_template_es.html | 57 + .../sources/repeat_template_fr.html | 57 + .../sources/repeat_template_it.html | 57 + .../sources/repeat_template_nl.html | 65 + .../sources/repeat_template_ru.html | 57 + .../lib/dhtmlxScheduler/sources/scheduler.js | 642 +++ .../lib/dhtmlxScheduler/sources/touch.css | 116 + .../static/lib/dhtmlxScheduler/whatsnew.txt | 27 + .../static/openerp/js/base_calendar.js | 28 - .../base_calendar/static/src/js/calendar.js | 224 + openerpweb/openerpweb.py | 18 +- 145 files changed, 19900 insertions(+), 45 deletions(-) create mode 100644 addons/base_calendar/controllers/__init__.py create mode 100644 addons/base_calendar/controllers/main.py create mode 100644 addons/base_calendar/static/lib/dhtmlxScheduler/License_GPL.html create mode 100644 addons/base_calendar/static/lib/dhtmlxScheduler/codebase/dhtmlxscheduler.css create mode 100644 addons/base_calendar/static/lib/dhtmlxScheduler/codebase/dhtmlxscheduler.js create mode 100644 addons/base_calendar/static/lib/dhtmlxScheduler/codebase/dhtmlxscheduler_debug.js create mode 100644 addons/base_calendar/static/lib/dhtmlxScheduler/codebase/ext/dhtmlxscheduler_active_links.js create mode 100644 addons/base_calendar/static/lib/dhtmlxScheduler/codebase/ext/dhtmlxscheduler_agenda_view.js create mode 100644 addons/base_calendar/static/lib/dhtmlxScheduler/codebase/ext/dhtmlxscheduler_collision.js create mode 100644 addons/base_calendar/static/lib/dhtmlxScheduler/codebase/ext/dhtmlxscheduler_cookie.js create mode 100644 addons/base_calendar/static/lib/dhtmlxScheduler/codebase/ext/dhtmlxscheduler_editors.js create mode 100644 addons/base_calendar/static/lib/dhtmlxScheduler/codebase/ext/dhtmlxscheduler_expand.js create mode 100644 addons/base_calendar/static/lib/dhtmlxScheduler/codebase/ext/dhtmlxscheduler_ext.css create mode 100644 addons/base_calendar/static/lib/dhtmlxScheduler/codebase/ext/dhtmlxscheduler_html_templates.js create mode 100644 addons/base_calendar/static/lib/dhtmlxScheduler/codebase/ext/dhtmlxscheduler_key_nav.js create mode 100644 addons/base_calendar/static/lib/dhtmlxScheduler/codebase/ext/dhtmlxscheduler_limit.js create mode 100644 addons/base_calendar/static/lib/dhtmlxScheduler/codebase/ext/dhtmlxscheduler_map_view.js create mode 100644 addons/base_calendar/static/lib/dhtmlxScheduler/codebase/ext/dhtmlxscheduler_minical.js create mode 100644 addons/base_calendar/static/lib/dhtmlxScheduler/codebase/ext/dhtmlxscheduler_multiselect.js create mode 100644 addons/base_calendar/static/lib/dhtmlxScheduler/codebase/ext/dhtmlxscheduler_multisource.js create mode 100644 addons/base_calendar/static/lib/dhtmlxScheduler/codebase/ext/dhtmlxscheduler_outerdrag.js create mode 100644 addons/base_calendar/static/lib/dhtmlxScheduler/codebase/ext/dhtmlxscheduler_pdf.js create mode 100644 addons/base_calendar/static/lib/dhtmlxScheduler/codebase/ext/dhtmlxscheduler_readonly.js create mode 100644 addons/base_calendar/static/lib/dhtmlxScheduler/codebase/ext/dhtmlxscheduler_recurring.css create mode 100644 addons/base_calendar/static/lib/dhtmlxScheduler/codebase/ext/dhtmlxscheduler_recurring.js create mode 100644 addons/base_calendar/static/lib/dhtmlxScheduler/codebase/ext/dhtmlxscheduler_serialize.js create mode 100644 addons/base_calendar/static/lib/dhtmlxScheduler/codebase/ext/dhtmlxscheduler_timeline.js create mode 100644 addons/base_calendar/static/lib/dhtmlxScheduler/codebase/ext/dhtmlxscheduler_tooltip.js create mode 100644 addons/base_calendar/static/lib/dhtmlxScheduler/codebase/ext/dhtmlxscheduler_touch.css create mode 100644 addons/base_calendar/static/lib/dhtmlxScheduler/codebase/ext/dhtmlxscheduler_touch.js create mode 100644 addons/base_calendar/static/lib/dhtmlxScheduler/codebase/ext/dhtmlxscheduler_treetimeline.js create mode 100644 addons/base_calendar/static/lib/dhtmlxScheduler/codebase/ext/dhtmlxscheduler_units.js create mode 100644 addons/base_calendar/static/lib/dhtmlxScheduler/codebase/ext/dhtmlxscheduler_url.js create mode 100644 addons/base_calendar/static/lib/dhtmlxScheduler/codebase/ext/dhtmlxscheduler_year_view.js create mode 100644 addons/base_calendar/static/lib/dhtmlxScheduler/codebase/imgs/blue_tab.png create mode 100644 addons/base_calendar/static/lib/dhtmlxScheduler/codebase/imgs/but_repeat.gif create mode 100644 addons/base_calendar/static/lib/dhtmlxScheduler/codebase/imgs/buttons.png create mode 100644 addons/base_calendar/static/lib/dhtmlxScheduler/codebase/imgs/calendar.gif create mode 100644 addons/base_calendar/static/lib/dhtmlxScheduler/codebase/imgs/clock_big.gif create mode 100644 addons/base_calendar/static/lib/dhtmlxScheduler/codebase/imgs/clock_small.gif create mode 100644 addons/base_calendar/static/lib/dhtmlxScheduler/codebase/imgs/colapce-expand-icon.gif create mode 100644 addons/base_calendar/static/lib/dhtmlxScheduler/codebase/imgs/controls.gif create mode 100644 addons/base_calendar/static/lib/dhtmlxScheduler/codebase/imgs/databg.png create mode 100644 addons/base_calendar/static/lib/dhtmlxScheduler/codebase/imgs/databg_now.png create mode 100644 addons/base_calendar/static/lib/dhtmlxScheduler/codebase/imgs/icon.png create mode 100644 addons/base_calendar/static/lib/dhtmlxScheduler/codebase/imgs/loading.gif create mode 100644 addons/base_calendar/static/lib/dhtmlxScheduler/codebase/imgs/white_tab.png create mode 100644 addons/base_calendar/static/lib/dhtmlxScheduler/readme.txt create mode 100644 addons/base_calendar/static/lib/dhtmlxScheduler/sources/base.js create mode 100644 addons/base_calendar/static/lib/dhtmlxScheduler/sources/clear.css create mode 100644 addons/base_calendar/static/lib/dhtmlxScheduler/sources/config.js create mode 100644 addons/base_calendar/static/lib/dhtmlxScheduler/sources/connector.js create mode 100644 addons/base_calendar/static/lib/dhtmlxScheduler/sources/dataprocessor_hook.js create mode 100644 addons/base_calendar/static/lib/dhtmlxScheduler/sources/dhtmlxcommon.js create mode 100644 addons/base_calendar/static/lib/dhtmlxScheduler/sources/dhtmlxdataprocessor.js create mode 100644 addons/base_calendar/static/lib/dhtmlxScheduler/sources/dhtmlxdataprocessor_debug.js create mode 100644 addons/base_calendar/static/lib/dhtmlxScheduler/sources/event.js create mode 100644 addons/base_calendar/static/lib/dhtmlxScheduler/sources/ext.css create mode 100644 addons/base_calendar/static/lib/dhtmlxScheduler/sources/ext/ext_active_links.js create mode 100644 addons/base_calendar/static/lib/dhtmlxScheduler/sources/ext/ext_agenda_view.js create mode 100644 addons/base_calendar/static/lib/dhtmlxScheduler/sources/ext/ext_collision.js create mode 100644 addons/base_calendar/static/lib/dhtmlxScheduler/sources/ext/ext_cookie.js create mode 100644 addons/base_calendar/static/lib/dhtmlxScheduler/sources/ext/ext_editors.js create mode 100644 addons/base_calendar/static/lib/dhtmlxScheduler/sources/ext/ext_expand.js create mode 100644 addons/base_calendar/static/lib/dhtmlxScheduler/sources/ext/ext_html_templates.js create mode 100644 addons/base_calendar/static/lib/dhtmlxScheduler/sources/ext/ext_key_nav.js create mode 100644 addons/base_calendar/static/lib/dhtmlxScheduler/sources/ext/ext_limit.js create mode 100644 addons/base_calendar/static/lib/dhtmlxScheduler/sources/ext/ext_map_view.js create mode 100644 addons/base_calendar/static/lib/dhtmlxScheduler/sources/ext/ext_matrix.js create mode 100644 addons/base_calendar/static/lib/dhtmlxScheduler/sources/ext/ext_minical.js create mode 100644 addons/base_calendar/static/lib/dhtmlxScheduler/sources/ext/ext_monthheight.js create mode 100644 addons/base_calendar/static/lib/dhtmlxScheduler/sources/ext/ext_multiselect.js create mode 100644 addons/base_calendar/static/lib/dhtmlxScheduler/sources/ext/ext_multisource.js create mode 100644 addons/base_calendar/static/lib/dhtmlxScheduler/sources/ext/ext_outerdrag.js create mode 100644 addons/base_calendar/static/lib/dhtmlxScheduler/sources/ext/ext_pdf.js create mode 100644 addons/base_calendar/static/lib/dhtmlxScheduler/sources/ext/ext_readonly.js create mode 100644 addons/base_calendar/static/lib/dhtmlxScheduler/sources/ext/ext_serialize.js create mode 100644 addons/base_calendar/static/lib/dhtmlxScheduler/sources/ext/ext_tooltip.js create mode 100644 addons/base_calendar/static/lib/dhtmlxScheduler/sources/ext/ext_touch.js create mode 100644 addons/base_calendar/static/lib/dhtmlxScheduler/sources/ext/ext_treetimeline.js create mode 100644 addons/base_calendar/static/lib/dhtmlxScheduler/sources/ext/ext_url.js create mode 100644 addons/base_calendar/static/lib/dhtmlxScheduler/sources/ext/ext_wp.js create mode 100644 addons/base_calendar/static/lib/dhtmlxScheduler/sources/ext/ext_year_view.js create mode 100644 addons/base_calendar/static/lib/dhtmlxScheduler/sources/ical.js create mode 100644 addons/base_calendar/static/lib/dhtmlxScheduler/sources/layout.css create mode 100644 addons/base_calendar/static/lib/dhtmlxScheduler/sources/lightbox.css create mode 100644 addons/base_calendar/static/lib/dhtmlxScheduler/sources/lightbox.js create mode 100644 addons/base_calendar/static/lib/dhtmlxScheduler/sources/load.js create mode 100644 addons/base_calendar/static/lib/dhtmlxScheduler/sources/locale.js create mode 100644 addons/base_calendar/static/lib/dhtmlxScheduler/sources/locale_ar.js create mode 100644 addons/base_calendar/static/lib/dhtmlxScheduler/sources/locale_ca.js create mode 100644 addons/base_calendar/static/lib/dhtmlxScheduler/sources/locale_cn.js create mode 100644 addons/base_calendar/static/lib/dhtmlxScheduler/sources/locale_cs.js create mode 100644 addons/base_calendar/static/lib/dhtmlxScheduler/sources/locale_de.js create mode 100644 addons/base_calendar/static/lib/dhtmlxScheduler/sources/locale_es.js create mode 100644 addons/base_calendar/static/lib/dhtmlxScheduler/sources/locale_fi.js create mode 100644 addons/base_calendar/static/lib/dhtmlxScheduler/sources/locale_fr.js create mode 100644 addons/base_calendar/static/lib/dhtmlxScheduler/sources/locale_he.js create mode 100644 addons/base_calendar/static/lib/dhtmlxScheduler/sources/locale_hu.js create mode 100644 addons/base_calendar/static/lib/dhtmlxScheduler/sources/locale_id.js create mode 100644 addons/base_calendar/static/lib/dhtmlxScheduler/sources/locale_it.js create mode 100644 addons/base_calendar/static/lib/dhtmlxScheduler/sources/locale_jp.js create mode 100644 addons/base_calendar/static/lib/dhtmlxScheduler/sources/locale_nl.js create mode 100644 addons/base_calendar/static/lib/dhtmlxScheduler/sources/locale_no.js create mode 100644 addons/base_calendar/static/lib/dhtmlxScheduler/sources/locale_pl.js create mode 100644 addons/base_calendar/static/lib/dhtmlxScheduler/sources/locale_pt.js create mode 100644 addons/base_calendar/static/lib/dhtmlxScheduler/sources/locale_recurring_cn.js create mode 100644 addons/base_calendar/static/lib/dhtmlxScheduler/sources/locale_recurring_cs.js create mode 100644 addons/base_calendar/static/lib/dhtmlxScheduler/sources/locale_recurring_de.js create mode 100644 addons/base_calendar/static/lib/dhtmlxScheduler/sources/locale_recurring_es.js create mode 100644 addons/base_calendar/static/lib/dhtmlxScheduler/sources/locale_recurring_fi.js create mode 100644 addons/base_calendar/static/lib/dhtmlxScheduler/sources/locale_recurring_fr.js create mode 100644 addons/base_calendar/static/lib/dhtmlxScheduler/sources/locale_recurring_it.js create mode 100644 addons/base_calendar/static/lib/dhtmlxScheduler/sources/locale_recurring_nl.js create mode 100644 addons/base_calendar/static/lib/dhtmlxScheduler/sources/locale_recurring_pl.js create mode 100644 addons/base_calendar/static/lib/dhtmlxScheduler/sources/locale_recurring_pt.js create mode 100644 addons/base_calendar/static/lib/dhtmlxScheduler/sources/locale_recurring_ru.js create mode 100644 addons/base_calendar/static/lib/dhtmlxScheduler/sources/locale_recurring_sv.js create mode 100644 addons/base_calendar/static/lib/dhtmlxScheduler/sources/locale_recurring_ua.js create mode 100644 addons/base_calendar/static/lib/dhtmlxScheduler/sources/locale_ru.js create mode 100644 addons/base_calendar/static/lib/dhtmlxScheduler/sources/locale_si.js create mode 100644 addons/base_calendar/static/lib/dhtmlxScheduler/sources/locale_sv.js create mode 100644 addons/base_calendar/static/lib/dhtmlxScheduler/sources/locale_ua.js create mode 100644 addons/base_calendar/static/lib/dhtmlxScheduler/sources/note.css create mode 100644 addons/base_calendar/static/lib/dhtmlxScheduler/sources/property.js create mode 100644 addons/base_calendar/static/lib/dhtmlxScheduler/sources/recurring.css create mode 100644 addons/base_calendar/static/lib/dhtmlxScheduler/sources/recurring.js create mode 100644 addons/base_calendar/static/lib/dhtmlxScheduler/sources/repeat_template.html create mode 100644 addons/base_calendar/static/lib/dhtmlxScheduler/sources/repeat_template_cn.html create mode 100644 addons/base_calendar/static/lib/dhtmlxScheduler/sources/repeat_template_de.html create mode 100644 addons/base_calendar/static/lib/dhtmlxScheduler/sources/repeat_template_es.html create mode 100644 addons/base_calendar/static/lib/dhtmlxScheduler/sources/repeat_template_fr.html create mode 100644 addons/base_calendar/static/lib/dhtmlxScheduler/sources/repeat_template_it.html create mode 100644 addons/base_calendar/static/lib/dhtmlxScheduler/sources/repeat_template_nl.html create mode 100644 addons/base_calendar/static/lib/dhtmlxScheduler/sources/repeat_template_ru.html create mode 100644 addons/base_calendar/static/lib/dhtmlxScheduler/sources/scheduler.js create mode 100644 addons/base_calendar/static/lib/dhtmlxScheduler/sources/touch.css create mode 100644 addons/base_calendar/static/lib/dhtmlxScheduler/whatsnew.txt delete mode 100644 addons/base_calendar/static/openerp/js/base_calendar.js create mode 100644 addons/base_calendar/static/src/js/calendar.js diff --git a/addons/base/static/src/base.html b/addons/base/static/src/base.html index 3bfadba0782..fc539d96cc6 100644 --- a/addons/base/static/src/base.html +++ b/addons/base/static/src/base.html @@ -23,15 +23,23 @@ + + - + + + + + + + diff --git a/addons/base/static/src/js/data.js b/addons/base/static/src/js/data.js index 1e96dde23fc..8f5d6168e75 100644 --- a/addons/base/static/src/js/data.js +++ b/addons/base/static/src/js/data.js @@ -99,7 +99,7 @@ openerp.base.DataSet = openerp.base.Controller.extend( /** @lends openerp.base. context: this.context }, callback); }, - unlink: function() { + unlink: function(ids) { this.notification['default']("Unlink", ids); }, call: function (method, ids, args, callback) { @@ -111,7 +111,7 @@ openerp.base.DataSet = openerp.base.Controller.extend( /** @lends openerp.base. ids: ids, args: args }, callback); - }, + } }); openerp.base.DataSetStatic = openerp.base.DataSet.extend({ @@ -123,7 +123,7 @@ openerp.base.DataSetStatic = openerp.base.DataSet.extend({ }, read_slice: function (fields, offset, limit, callback) { this.read_ids(this.ids.slice(offset, offset + limit)); - }, + } }); openerp.base.DataSetSearch = openerp.base.DataSet.extend({ @@ -163,7 +163,7 @@ openerp.base.DataSetSearch = openerp.base.DataSet.extend({ } callback(records); }); - }, + } }); openerp.base.DataSetRelational = openerp.base.DataSet.extend( /** @lends openerp.base.DataSet# */{ diff --git a/addons/base/static/src/js/form.js b/addons/base/static/src/js/form.js index ff04f55314b..c5b45f5c870 100644 --- a/addons/base/static/src/js/form.js +++ b/addons/base/static/src/js/form.js @@ -140,7 +140,7 @@ openerp.base.FormView = openerp.base.Controller.extend( /** @lends openerp.base var ajax = { url: '/base/dataset/call', async: false - } + }; return this.rpc(ajax, { model: this.dataset.model, method: method, @@ -212,7 +212,7 @@ openerp.base.FormView = openerp.base.Controller.extend( /** @lends openerp.base if (invalid) { this.on_invalid(); } else { - this.log("About to save", values) + this.log("About to save", values); this.dataset.write(this.datarecord.id, values, this.on_saved); } }, @@ -244,8 +244,13 @@ openerp.base.FormView = openerp.base.Controller.extend( /** @lends openerp.base } }, do_search: function (domains, contexts, groupbys) { + this.notification['default']("Searching form"); }, on_action: function (action) { + this.notification['default']('Executing action ' + action); + }, + do_cancel: function () { + this.notification['default']("Cancelling form"); } }); @@ -698,7 +703,7 @@ openerp.base.form.FieldMany2One = openerp.base.form.Field.extend({ }, set_value: function(value) { this._super.apply(this, arguments); - var show_value = '' + var show_value = ''; if (value != null && value !== false) { show_value = value[1]; this.value = value[0]; @@ -713,17 +718,15 @@ openerp.base.form.FieldOne2ManyDatasSet = openerp.base.DataSetStatic.extend({ write: function (id, data, callback) { this._super(id, data, callback); }, - write: function (id, data, callback) { - this._super(id, data, callback); - }, unlink: function() { + this.notification['default']('Unlinking o2m ' + this.ids); } }); openerp.base.form.FieldOne2ManyViewManager = openerp.base.ViewManager.extend({ init: function(session, element_id, dataset, views) { this._super(session, element_id, dataset, views); - }, + } }); openerp.base.form.FieldOne2Many = openerp.base.form.Field.extend({ diff --git a/addons/base/static/src/js/list.js b/addons/base/static/src/js/list.js index 533ff0d9deb..da52bd75138 100644 --- a/addons/base/static/src/js/list.js +++ b/addons/base/static/src/js/list.js @@ -83,7 +83,6 @@ openerp.base.ListView = openerp.base.Controller.extend( * @returns {Promise} promise to the end of view rendering (list views are asynchronously filled for improved responsiveness) */ do_fill_table: function(records) { - console.log("listview do_fill",records) this.rows = records; var $table = this.$element.find('table'); @@ -148,7 +147,6 @@ openerp.base.ListView = openerp.base.Controller.extend( }, do_search: function (domains, contexts, groupbys) { var self = this; - console.log("listview do_search",domains) this.rpc('/base/session/eval_domain_and_context', { domains: domains, contexts: contexts, diff --git a/addons/base/static/src/js/views.js b/addons/base/static/src/js/views.js index 6adc0fc3d38..2b7d0abde45 100644 --- a/addons/base/static/src/js/views.js +++ b/addons/base/static/src/js/views.js @@ -141,7 +141,6 @@ openerp.base.ViewManagerAction = openerp.base.ViewManager.extend({ this.sidebar = new openerp.base.Sidebar(null, this); }, start: function() { - var self = this; var inital_view_loaded = this._super(); // init sidebar @@ -173,29 +172,30 @@ openerp.base.ViewManagerAction = openerp.base.ViewManager.extend({ this.sidebar.stop(); } this._super(); - }, + } }); openerp.base.BaseWidget = openerp.base.Controller.extend({ /** - * The name of the QWeb template that will be used for rendering. Must be redifined - * in subclasses or the render() method can not be used. + * The name of the QWeb template that will be used for rendering. Must be + * redefined in subclasses or the render() method can not be used. * * @type string */ template: null, /** - * The prefix used to generate an id automatically. Should be redifined in subclasses. - * If it is not defined, a default identifier will be used. + * The prefix used to generate an id automatically. Should be redefined in + * subclasses. If it is not defined, a default identifier will be used. * * @type string */ identifier_prefix: 'generic-identifier', /** - * Base class for widgets. Handle rendering (based on a QWeb template), identifier - * generation, parenting and destruction of the widget. - * Contructor. Also initialize the identifier. - * + * Base class for widgets. Handle rendering (based on a QWeb template), + * identifier generation, parenting and destruction of the widget. + * Also initialize the identifier. + * + * @constructs * @params {openerp.base.search.BaseWidget} parent The parent widget. */ init: function (parent, session) { @@ -242,8 +242,8 @@ openerp.base.BaseWidget = openerp.base.Controller.extend({ this._super(); }, /** - * Set the parent of this component, also unregister the previous parent if there - * was one. + * Set the parent of this component, also un-register the previous parent + * if there was one. * * @param {openerp.base.BaseWidget} parent The new parent. */ @@ -289,7 +289,7 @@ openerp.base.Sidebar = openerp.base.BaseWidget.extend({ this.$element.html(QWeb.render("ViewManager.sidebar.internal", _.extend({_:_}, this))); var self = this; this.$element.find("a").click(function(e) { - $this = jQuery(this); + var $this = jQuery(this); var i = $this.attr("data-i"); var j = $this.attr("data-i"); var action = self.sections[i].elements[j]; From da9ef6e6ed7d710efb389cf35bbb3dc472c5c234 Mon Sep 17 00:00:00 2001 From: "noz (OpenERP)" Date: Fri, 8 Apr 2011 16:28:06 +0530 Subject: [PATCH 113/259] [FIX] Minor starting for web chat. bzr revid: noz@tinyerp.com-20110408105806-cofc88534c7fab19 --- addons/web_chat/controllers/main.py | 42 ++++++++++++++++++----------- 1 file changed, 26 insertions(+), 16 deletions(-) diff --git a/addons/web_chat/controllers/main.py b/addons/web_chat/controllers/main.py index d8d33bac445..24409ebce65 100644 --- a/addons/web_chat/controllers/main.py +++ b/addons/web_chat/controllers/main.py @@ -2,7 +2,7 @@ import sys, time import simplejson - +import random import openerpweb #---------------------------------------------------------- @@ -17,13 +17,17 @@ class PollServerMessageQueue(object): # should contains: { # 'user1234' : { s:1, m:"status message", timestamp: last_contact_timestamp } # } - def userlist(): - # return user list - pass + def userlist(self, req): + userlist = [ + {"u": "Guest130205108745.47", "s": {"s": 1, "m": ""}, "g": "Users"}, + {"u": "Guest130209838956.76", "s": {"s": 1, "m": ""}, "g": "Users"}, + ] + + return userlist def write(self, m_type, m_sender, m_recipent, m_message, m_group): # appends messages to l - # when status message uupdate users + # when status message update users pass def read(self, recpient, timestamp): # return matching message @@ -38,6 +42,7 @@ class PollServer(openerpweb.Controller): @openerpweb.httprequest def login(self, req, **kw): + """ --> POST http://ajaxim.com/wp-content/plugins/im/ajaxim.php/login Form Data @@ -56,21 +61,26 @@ class PollServer(openerpweb.Controller): ] } """ - mq = req.applicationsession.setdefault("web_chat",PollServerMessageQueue()) - print "chat login",kw - # r = 'loggued in' + mq = req.applicationsession.setdefault("web_chat", PollServerMessageQueue()) + + #r = 'loggued in' #u = generate random.randint(0,2**32) #s = cherrypy cookie id #f = mq.userlist() - return """ + +# username = 'Guest'+ str(random.randint(0, 2**32)) +# +# if not req.applicationsession.get('users'): +# req.applicationsession['users'] = [{'u': username, 's':{'s':1, 'm':''}, 'g':'Users'}] +# else: +# req.applicationsession['users'].append({'u': username, 's':{'s':1, 'm':''}, 'g':'Users'}) + + return """ { "r":"logged in", "u":"Guest130213866190.85", "s":"f9e1811536f19ad5b9e00376f9ff1532", - "f":[ - {"u":"Guest130205108745.47","s":{"s":1,"m":""},"g":"Users"}, - {"u":"Guest130209838956.76","s":{"s":1,"m":""},"g":"Users"}, - ] + "f":""" + str(mq.userlist(req)) + """ } """ @@ -98,7 +108,7 @@ class PollServer(openerpweb.Controller): jsonp1302140441577([{"t":"s","s":"Guest130214038974.31","r":"","m":"0:"}]); receive message: - jsonp1302140191599([{"t":"m","s":"Guest130214008855.5","r":"Guest130214013134.26","m":"fuck"}]); + jsonp1302140191599([{"t":"m","s":"Guest130214008855.5","r":"Guest130214013134.26","m":"xxxxxx"}]); ('t' => $msg->type, 's' => $msg->from, 'r' => $msg->to, 'm' => $msg->message ) mag type s or m @@ -114,10 +124,10 @@ class PollServer(openerpweb.Controller): # sleep 2 # else # return emptylist - print "chat poll",kw + time.sleep(2) # it's http://localhost:8002/web_chat/pollserver/poll?method=long?callback=jsonp1302147330483&_1302147330483= - return '%s([{"t":"m","s":"Guest130214008855.5","r":"Guest130214013134.26","m":"fuck"}]);'%kw.get('callback','') + return '%s([{"t":"m","s":"Guest130214008855.5","r":"Guest130214013134.26","m":"xxxxxx"}]);'%kw.get('callback','') return None @openerpweb.jsonrequest From 9e44cd5bfe1e1fe30d0e1f98799fd7dc7a6dad6e Mon Sep 17 00:00:00 2001 From: "P. Christeas" Date: Fri, 8 Apr 2011 14:23:24 +0300 Subject: [PATCH 114/259] all: Fix execute permission and shebang at files Non-standalone python scripts shall not have a shebang. Others will need to be executable. (cherry picked from commit 6ec513d17cafcdd235b4805363d3cd6daa494f2f) bzr revid: p_christ@hol.gr-20110408112324-nc781po7efhjye21 --- addons/account/report/account_tax_code.py | 1 - addons/account/wizard/account_change_currency.py | 1 - .../plugin/openerp_report_designer/bin/OOo_run.sh | 0 addons/document/odt2txt.py | 0 addons/document/test_cindex.py | 0 addons/document_ftp/ftpserver/ftpserver.py | 0 addons/document_webdav/test_davclient.py | 0 addons/email_template/html2text.py | 10 +++++----- addons/fetchmail/__init__.py | 1 - addons/fetchmail/__openerp__.py | 1 - addons/hr_payroll/report/__init__.py | 1 - .../hr_payroll/report/report_emp_salary_structure.py | 8 -------- addons/hr_payroll/report/report_employees_detail.py | 2 -- addons/hr_payroll/report/report_payroll_advice.py | 3 +-- addons/hr_payroll/report/report_payroll_register.py | 3 +-- addons/hr_payroll/report/report_payslip.py | 1 - addons/hr_payroll/report/report_year_salary.py | 2 -- addons/l10n_ch/readme.txt | 0 addons/l10n_de/i18n/pt_BR.po | 0 addons/l10n_de/i18n/zh_CN.po | 0 addons/l10n_de/i18n/zh_TW.po | 0 .../scripts/openerp_mailgate/openerp_mailgate.py | 0 addons/sale_layout/i18n/fr.po | 0 .../plugin/openerp_plugin/defaults/preferences/tiny.js | 0 addons/wiki/web/widgets/rss/feedparser.py | 0 25 files changed, 7 insertions(+), 27 deletions(-) mode change 100644 => 100755 addons/base_report_designer/plugin/openerp_report_designer/bin/OOo_run.sh mode change 100644 => 100755 addons/document/odt2txt.py mode change 100644 => 100755 addons/document/test_cindex.py mode change 100644 => 100755 addons/document_ftp/ftpserver/ftpserver.py mode change 100644 => 100755 addons/document_webdav/test_davclient.py mode change 100644 => 100755 addons/email_template/html2text.py mode change 100755 => 100644 addons/l10n_ch/readme.txt mode change 100755 => 100644 addons/l10n_de/i18n/pt_BR.po mode change 100755 => 100644 addons/l10n_de/i18n/zh_CN.po mode change 100755 => 100644 addons/l10n_de/i18n/zh_TW.po mode change 100644 => 100755 addons/mail_gateway/scripts/openerp_mailgate/openerp_mailgate.py mode change 100755 => 100644 addons/sale_layout/i18n/fr.po mode change 100755 => 100644 addons/thunderbird/plugin/openerp_plugin/defaults/preferences/tiny.js mode change 100644 => 100755 addons/wiki/web/widgets/rss/feedparser.py diff --git a/addons/account/report/account_tax_code.py b/addons/account/report/account_tax_code.py index 86d3128cfe7..56895987b45 100644 --- a/addons/account/report/account_tax_code.py +++ b/addons/account/report/account_tax_code.py @@ -1,4 +1,3 @@ -#!/usr/bin/env python # -*- coding: utf-8 -*- ############################################################################## # diff --git a/addons/account/wizard/account_change_currency.py b/addons/account/wizard/account_change_currency.py index d915a1cd34b..4a4209dc757 100644 --- a/addons/account/wizard/account_change_currency.py +++ b/addons/account/wizard/account_change_currency.py @@ -1,4 +1,3 @@ -#!/usr/bin/env python # -*- encoding: utf-8 -*- ############################################################################## # diff --git a/addons/base_report_designer/plugin/openerp_report_designer/bin/OOo_run.sh b/addons/base_report_designer/plugin/openerp_report_designer/bin/OOo_run.sh old mode 100644 new mode 100755 diff --git a/addons/document/odt2txt.py b/addons/document/odt2txt.py old mode 100644 new mode 100755 diff --git a/addons/document/test_cindex.py b/addons/document/test_cindex.py old mode 100644 new mode 100755 diff --git a/addons/document_ftp/ftpserver/ftpserver.py b/addons/document_ftp/ftpserver/ftpserver.py old mode 100644 new mode 100755 diff --git a/addons/document_webdav/test_davclient.py b/addons/document_webdav/test_davclient.py old mode 100644 new mode 100755 diff --git a/addons/email_template/html2text.py b/addons/email_template/html2text.py old mode 100644 new mode 100755 index af7848fee2d..2479843777a --- a/addons/email_template/html2text.py +++ b/addons/email_template/html2text.py @@ -444,11 +444,11 @@ if __name__ == "__main__": encoding = 'utf8' if len(sys.argv) > 2: encoding = sys.argv[2] - f = open(arg, 'r') - try: - data = f.read().decode(encoding) - finally: - f.close() + f = open(arg, 'r') + try: + data = f.read().decode(encoding) + finally: + f.close() else: data = sys.stdin.read().decode('utf8') wrapwrite(html2text(data, baseurl)) diff --git a/addons/fetchmail/__init__.py b/addons/fetchmail/__init__.py index d58bfd1d81b..f9c384ce103 100644 --- a/addons/fetchmail/__init__.py +++ b/addons/fetchmail/__init__.py @@ -1,4 +1,3 @@ -#!/usr/bin/env python #-*- coding:utf-8 -*- ############################################################################## # diff --git a/addons/fetchmail/__openerp__.py b/addons/fetchmail/__openerp__.py index 6d72f6ea917..29029d2cc0e 100644 --- a/addons/fetchmail/__openerp__.py +++ b/addons/fetchmail/__openerp__.py @@ -1,4 +1,3 @@ -#!/usr/bin/env python #-*- coding:utf-8 -*- ############################################################################## # diff --git a/addons/hr_payroll/report/__init__.py b/addons/hr_payroll/report/__init__.py index 3113f281326..f7e464d3129 100644 --- a/addons/hr_payroll/report/__init__.py +++ b/addons/hr_payroll/report/__init__.py @@ -1,4 +1,3 @@ -#!/usr/bin/env python #-*- coding:utf-8 -*- ############################################################################## diff --git a/addons/hr_payroll/report/report_emp_salary_structure.py b/addons/hr_payroll/report/report_emp_salary_structure.py index 0da09d16562..28fdb6dec45 100644 --- a/addons/hr_payroll/report/report_emp_salary_structure.py +++ b/addons/hr_payroll/report/report_emp_salary_structure.py @@ -1,4 +1,3 @@ -#!/usr/bin/env python #-*- coding:utf-8 -*- ############################################################################## @@ -89,10 +88,3 @@ class salary_structure_report(report_sxw.rml_parse): report_sxw.report_sxw('report.salary.structure', 'hr.employee', 'hr_payroll/report/report_emp_salary_structure.rml', parser=salary_structure_report) # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: - - - - - - - diff --git a/addons/hr_payroll/report/report_employees_detail.py b/addons/hr_payroll/report/report_employees_detail.py index 0e1451e469c..522e36e742f 100644 --- a/addons/hr_payroll/report/report_employees_detail.py +++ b/addons/hr_payroll/report/report_employees_detail.py @@ -1,4 +1,3 @@ -#!/usr/bin/env python #-*- coding:utf-8 -*- ############################################################################## @@ -249,4 +248,3 @@ class employees_salary_report(report_sxw.rml_parse): report_sxw.report_sxw('report.employees.salary', 'hr.payslip', 'hr_payroll/report/report_employees_detail.rml', parser=employees_salary_report,header='internal landscape') # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: - diff --git a/addons/hr_payroll/report/report_payroll_advice.py b/addons/hr_payroll/report/report_payroll_advice.py index 5ac20d91d71..7d8c6fd953c 100644 --- a/addons/hr_payroll/report/report_payroll_advice.py +++ b/addons/hr_payroll/report/report_payroll_advice.py @@ -1,4 +1,3 @@ -#!/usr/bin/env python #-*- coding:utf-8 -*- ############################################################################## @@ -78,4 +77,4 @@ class payroll_advice_report(report_sxw.rml_parse): report_sxw.report_sxw('report.payroll.advice', 'hr.payroll.advice', 'hr_payroll/report/report_payroll_advice.rml', parser=payroll_advice_report) -# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: \ No newline at end of file +# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: diff --git a/addons/hr_payroll/report/report_payroll_register.py b/addons/hr_payroll/report/report_payroll_register.py index 9410a4eedb2..96dde962074 100644 --- a/addons/hr_payroll/report/report_payroll_register.py +++ b/addons/hr_payroll/report/report_payroll_register.py @@ -1,4 +1,3 @@ -#!/usr/bin/env python #-*- coding:utf-8 -*- ############################################################################## @@ -106,4 +105,4 @@ report_sxw.report_sxw( parser=report_payroll_register ) -# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: \ No newline at end of file +# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: diff --git a/addons/hr_payroll/report/report_payslip.py b/addons/hr_payroll/report/report_payslip.py index d5cd6532251..78e6ee2ff64 100644 --- a/addons/hr_payroll/report/report_payslip.py +++ b/addons/hr_payroll/report/report_payslip.py @@ -1,4 +1,3 @@ -#!/usr/bin/env python #-*- coding:utf-8 -*- ############################################################################## diff --git a/addons/hr_payroll/report/report_year_salary.py b/addons/hr_payroll/report/report_year_salary.py index bc7ac8fc93a..4c5a506d2d3 100644 --- a/addons/hr_payroll/report/report_year_salary.py +++ b/addons/hr_payroll/report/report_year_salary.py @@ -1,4 +1,3 @@ -#!/usr/bin/env python #-*- coding:utf-8 -*- ############################################################################## @@ -119,4 +118,3 @@ class year_salary_report(report_sxw.rml_parse): report_sxw.report_sxw('report.year.salary', 'hr.payslip', 'hr_payroll/report/report_year_report.rml', parser=year_salary_report,header='internal landscape') # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: - diff --git a/addons/l10n_ch/readme.txt b/addons/l10n_ch/readme.txt old mode 100755 new mode 100644 diff --git a/addons/l10n_de/i18n/pt_BR.po b/addons/l10n_de/i18n/pt_BR.po old mode 100755 new mode 100644 diff --git a/addons/l10n_de/i18n/zh_CN.po b/addons/l10n_de/i18n/zh_CN.po old mode 100755 new mode 100644 diff --git a/addons/l10n_de/i18n/zh_TW.po b/addons/l10n_de/i18n/zh_TW.po old mode 100755 new mode 100644 diff --git a/addons/mail_gateway/scripts/openerp_mailgate/openerp_mailgate.py b/addons/mail_gateway/scripts/openerp_mailgate/openerp_mailgate.py old mode 100644 new mode 100755 diff --git a/addons/sale_layout/i18n/fr.po b/addons/sale_layout/i18n/fr.po old mode 100755 new mode 100644 diff --git a/addons/thunderbird/plugin/openerp_plugin/defaults/preferences/tiny.js b/addons/thunderbird/plugin/openerp_plugin/defaults/preferences/tiny.js old mode 100755 new mode 100644 diff --git a/addons/wiki/web/widgets/rss/feedparser.py b/addons/wiki/web/widgets/rss/feedparser.py old mode 100644 new mode 100755 From 9262c3c00dfdad634a8f2829abe2d14b6540e63a Mon Sep 17 00:00:00 2001 From: Xavier Morel Date: Fri, 8 Apr 2011 14:40:20 +0200 Subject: [PATCH 115/259] [FIX] fuckup with deferred for rendering of list (when beyond one section), also only remove old body after new list has rendered otherwise we get an empty list flash even for lists with a bunch of elements bzr revid: xmo@openerp.com-20110408124020-25dprn6gu19y02m6 --- addons/base/static/src/js/list.js | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/addons/base/static/src/js/list.js b/addons/base/static/src/js/list.js index 4b1eeaaf993..4fc3ef07720 100644 --- a/addons/base/static/src/js/list.js +++ b/addons/base/static/src/js/list.js @@ -89,7 +89,7 @@ openerp.base.ListView = openerp.base.Controller.extend( var $table = this.$element.find('table'); // remove all data lines - $table.find('tbody').remove(); + var $old_body = $table.find('tbody'); // add new content var columns = this.columns, @@ -102,8 +102,8 @@ openerp.base.ListView = openerp.base.Controller.extend( body = 0, $body = $('').appendTo($table); + var rendered = $.Deferred(); var render_body = function () { - var rendered = $.Deferred(); setTimeout(function () { $body.append( QWeb.render("ListView.rows", { @@ -118,9 +118,12 @@ openerp.base.ListView = openerp.base.Controller.extend( rendered.resolve(); } }, 0); - return rendered.promise(); }; - return render_body(); + render_body(); + + return rendered.promise().then(function () { + $old_body.remove(); + }); }, on_select_row: function (event) { var $target = $(event.currentTarget); From b02cbab49f7b1b67e2b989c72b232838ecd29f90 Mon Sep 17 00:00:00 2001 From: "Tidiane Sy (Baamtu)" Date: Fri, 8 Apr 2011 16:23:10 +0200 Subject: [PATCH 116/259] [IMP] add CFA currency and rate bzr revid: tsy@baamtu.com-20110408142310-mas92mtjb4jupv8m --- openerp/addons/base/base_data.xml | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/openerp/addons/base/base_data.xml b/openerp/addons/base/base_data.xml index 89a9d254e6b..9a1cf95afd7 100644 --- a/openerp/addons/base/base_data.xml +++ b/openerp/addons/base/base_data.xml @@ -1033,7 +1033,7 @@ - + OpenERP S.A. @@ -1617,5 +1617,18 @@ + + + CFA + CFA + 1 + 4 + + + + 655.957 + + + From 29ed9f9be3053e62aae0fb12275500a8368d68b9 Mon Sep 17 00:00:00 2001 From: niv-openerp Date: Fri, 8 Apr 2011 17:25:08 +0200 Subject: [PATCH 117/259] [IMP] Action wip - popup is working. bzr revid: nicolas.vanhoren@openerp.com-20110408152508-5mes2key0yzq9avq --- addons/base/controllers/main.py | 43 +++++++++++++++++++++++++++ addons/base/static/src/js/views.js | 46 +++++++++++++++++++---------- addons/base/static/src/xml/base.xml | 2 +- 3 files changed, 75 insertions(+), 16 deletions(-) diff --git a/addons/base/controllers/main.py b/addons/base/controllers/main.py index a7782a508fe..ce2fdd531e8 100644 --- a/addons/base/controllers/main.py +++ b/addons/base/controllers/main.py @@ -9,6 +9,8 @@ import openerpweb import openerpweb.ast import openerpweb.nonliterals +import cherrypy + # Should move to openerpweb.Xml2Json class Xml2Json: # xml2json-direct @@ -168,6 +170,47 @@ class Session(openerpweb.Controller): 'domain': domain, 'group_by': group_by_sequence } + + @openerpweb.jsonrequest + def save_session_action(self, req, the_action): + """ + This method store an action object in the session object and returns an integer + identifying that action. The method get_session_action() can be used to get + back the action. + + :param the_action: The action to save in the session. + :type the_action: anything + :return: A key identifying the saved action. + :rtype: integer + """ + saved_actions = cherrypy.session.get('saved_actions') + if not saved_actions: + saved_actions = {"next":0, "actions":{}} + cherrypy.session['saved_actions'] = saved_actions + # we don't allow more than 10 stored actions + if len(saved_actions["actions"]) >= 10: + del saved_actions["actions"][min(saved_actions["actions"].keys())] + key = saved_actions["next"] + saved_actions["actions"][key] = the_action + saved_actions["next"] = key + 1 + return key + + @openerpweb.jsonrequest + def get_session_action(self, req, key): + """ + Gets back a previously saved action. This method can return None if the action + was saved since too much time (this case should be handled in a smart way). + + :param key: The key given by save_session_action() + :type key: integer + :return: The saved action or None. + :rtype: anything + """ + saved_actions = cherrypy.session.get('saved_actions') + if not saved_actions: + return None + return saved_actions["actions"].get(key) + def load_actions_from_ir_values(req, key, key2, models, meta, context): Values = req.session.model('ir.values') diff --git a/addons/base/static/src/js/views.js b/addons/base/static/src/js/views.js index 1707a4db54a..2828b832afd 100644 --- a/addons/base/static/src/js/views.js +++ b/addons/base/static/src/js/views.js @@ -159,10 +159,13 @@ openerp.base.ViewManagerAction = openerp.base.ViewManager.extend({ search_defaults[match[1]] = value; } }); - var searchview_loaded = this.setup_search_view(view_id,search_defaults); + var searchview_loaded = null; + if (view_id) { + searchview_loaded = this.setup_search_view(view_id,search_defaults); + } // schedule auto_search - if (this.action['auto_search']) { + if (searchview_loaded != null && this.action['auto_search']) { $.when(searchview_loaded, inital_view_loaded) .then(this.searchview.do_search); } @@ -291,9 +294,10 @@ openerp.base.Sidebar = openerp.base.BaseWidget.extend({ this.$element.find("a").click(function(e) { $this = jQuery(this); var i = $this.attr("data-i"); - var j = $this.attr("data-i"); + var j = $this.attr("data-j"); var action = self.sections[i].elements[j]; - openerp.base.handle_action(self.view_manager.session, action); + (new openerp.base.ExternalActionManager(self.view_manager.session, null)) + .handle_action(action); e.stopPropagation(); e.preventDefault(); }); @@ -304,19 +308,31 @@ openerp.base.Sidebar = openerp.base.BaseWidget.extend({ } }); -openerp.base.handle_action = function(session, action) { - if(action.type=="ir.actions.act_window") { - if(action.target=="new") { - var element_id = _.uniqueId("act_window_dialog"); - var dialog = $('
'); - dialog.dialog({ - title: action.name - }); - var viewmanager = new openerp.base.ViewManagerAction(session,element_id, action, false); - viewmanager.start(); +openerp.base.ExternalActionManager = openerp.base.Controller.extend({ + handle_action: function(action) { + if(action.type=="ir.actions.act_window") { + if(action.target=="new") { + var element_id = _.uniqueId("act_window_dialog"); + var dialog = $('
'); + dialog.dialog({ + title: action.name + }); + var viewmanager = new openerp.base.ViewManagerAction(this.session + ,element_id, action, false); + viewmanager.start(); + } else if (action.target == "current") { + this.rpc("/base/session/save_session_action", {the_action:action}, function(key) { + debugger; + var url = window.location.href; + //window.open(); + }); + } } + // TODO: show an error like "not implemented" here + // since we don't currently have any way to handle errors do you have any better idea + // than using todos? } -}; +}); openerp.base.views.add('calendar', 'openerp.base.CalendarView'); openerp.base.CalendarView = openerp.base.Controller.extend({ diff --git a/addons/base/static/src/xml/base.xml b/addons/base/static/src/xml/base.xml index 0b3fb9b050a..e96c639769f 100644 --- a/addons/base/static/src/xml/base.xml +++ b/addons/base/static/src/xml/base.xml @@ -492,7 +492,7 @@
  • - + From 77354e54921e1fafdd9d480537b422d0e2c27a26 Mon Sep 17 00:00:00 2001 From: Launchpad Translations on behalf of openerp <> Date: Sat, 9 Apr 2011 04:59:39 +0000 Subject: [PATCH 118/259] Launchpad automatic translations update. bzr revid: launchpad_translations_on_behalf_of_openerp-20110409045939-c79i91qgcjnua4c9 --- bin/addons/base/i18n/af.po | 4 +- bin/addons/base/i18n/am.po | 4 +- bin/addons/base/i18n/ar.po | 4 +- bin/addons/base/i18n/bg.po | 799 +++---- bin/addons/base/i18n/bs.po | 4 +- bin/addons/base/i18n/ca.po | 14 +- bin/addons/base/i18n/cs.po | 4 +- bin/addons/base/i18n/da.po | 4 +- bin/addons/base/i18n/de.po | 10 +- bin/addons/base/i18n/el.po | 4 +- bin/addons/base/i18n/en_GB.po | 4 +- bin/addons/base/i18n/es.po | 12 +- bin/addons/base/i18n/es_CL.po | 4 +- bin/addons/base/i18n/es_EC.po | 4 +- bin/addons/base/i18n/et.po | 71 +- bin/addons/base/i18n/eu.po | 4 +- bin/addons/base/i18n/fa.po | 4 +- bin/addons/base/i18n/fa_AF.po | 4 +- bin/addons/base/i18n/fi.po | 4 +- bin/addons/base/i18n/fr.po | 12 +- bin/addons/base/i18n/gl.po | 4 +- bin/addons/base/i18n/he.po | 4 +- bin/addons/base/i18n/hr.po | 6 +- bin/addons/base/i18n/hu.po | 4 +- bin/addons/base/i18n/id.po | 4 +- bin/addons/base/i18n/is.po | 4 +- bin/addons/base/i18n/it.po | 6 +- bin/addons/base/i18n/ja.po | 4 +- bin/addons/base/i18n/ko.po | 142 +- bin/addons/base/i18n/lt.po | 6 +- bin/addons/base/i18n/lv.po | 4 +- bin/addons/base/i18n/mn.po | 4 +- bin/addons/base/i18n/nb.po | 3407 ++++++++++++++++++++---------- bin/addons/base/i18n/nl.po | 6 +- bin/addons/base/i18n/nl_BE.po | 4 +- bin/addons/base/i18n/pl.po | 8 +- bin/addons/base/i18n/pt.po | 4 +- bin/addons/base/i18n/pt_BR.po | 413 ++-- bin/addons/base/i18n/ro.po | 20 +- bin/addons/base/i18n/ru.po | 6 +- bin/addons/base/i18n/sk.po | 4 +- bin/addons/base/i18n/sl.po | 4 +- bin/addons/base/i18n/sq.po | 4 +- bin/addons/base/i18n/sr.po | 4 +- bin/addons/base/i18n/sr@latin.po | 4 +- bin/addons/base/i18n/sv.po | 4 +- bin/addons/base/i18n/th.po | 4 +- bin/addons/base/i18n/tlh.po | 4 +- bin/addons/base/i18n/tr.po | 4 +- bin/addons/base/i18n/uk.po | 4 +- bin/addons/base/i18n/ur.po | 4 +- bin/addons/base/i18n/vi.po | 16 +- bin/addons/base/i18n/zh_CN.po | 4 +- bin/addons/base/i18n/zh_TW.po | 4 +- debian/po/bg.po | 4 +- debian/po/ca.po | 4 +- debian/po/cs.po | 4 +- debian/po/de.po | 4 +- debian/po/el.po | 4 +- debian/po/en_GB.po | 4 +- debian/po/es.po | 4 +- debian/po/es_CL.po | 4 +- debian/po/es_EC.po | 4 +- debian/po/fa.po | 4 +- debian/po/fi.po | 4 +- debian/po/fr.po | 4 +- debian/po/gl.po | 4 +- debian/po/he.po | 4 +- debian/po/hr.po | 4 +- debian/po/hu.po | 4 +- debian/po/it.po | 4 +- debian/po/ja.po | 4 +- debian/po/ko.po | 4 +- debian/po/lv.po | 4 +- debian/po/mn.po | 4 +- debian/po/nb.po | 4 +- debian/po/nl.po | 4 +- debian/po/pl.po | 4 +- debian/po/pt.po | 4 +- debian/po/pt_BR.po | 8 +- debian/po/ro.po | 4 +- debian/po/ru.po | 4 +- debian/po/sk.po | 4 +- debian/po/sq.po | 11 +- debian/po/sr.po | 4 +- debian/po/sv.po | 4 +- debian/po/tr.po | 4 +- debian/po/uk.po | 4 +- debian/po/vi.po | 4 +- debian/po/zh_CN.po | 4 +- debian/po/zh_TW.po | 4 +- 91 files changed, 3305 insertions(+), 1956 deletions(-) diff --git a/bin/addons/base/i18n/af.po b/bin/addons/base/i18n/af.po index 71d76f01aca..290fd5f2304 100644 --- a/bin/addons/base/i18n/af.po +++ b/bin/addons/base/i18n/af.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2011-02-16 04:49+0000\n" -"X-Generator: Launchpad (build 12351)\n" +"X-Launchpad-Export-Date: 2011-04-09 04:49+0000\n" +"X-Generator: Launchpad (build 12735)\n" #. module: base #: view:ir.filters:0 diff --git a/bin/addons/base/i18n/am.po b/bin/addons/base/i18n/am.po index 284ab652f88..4b094993afb 100644 --- a/bin/addons/base/i18n/am.po +++ b/bin/addons/base/i18n/am.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2011-02-16 04:50+0000\n" -"X-Generator: Launchpad (build 12351)\n" +"X-Launchpad-Export-Date: 2011-04-09 04:49+0000\n" +"X-Generator: Launchpad (build 12735)\n" #. module: base #: view:ir.filters:0 diff --git a/bin/addons/base/i18n/ar.po b/bin/addons/base/i18n/ar.po index 368d9b30e4a..8baa0e9c4ab 100644 --- a/bin/addons/base/i18n/ar.po +++ b/bin/addons/base/i18n/ar.po @@ -13,8 +13,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2011-02-16 04:50+0000\n" -"X-Generator: Launchpad (build 12351)\n" +"X-Launchpad-Export-Date: 2011-04-09 04:49+0000\n" +"X-Generator: Launchpad (build 12735)\n" #. module: base #: view:ir.filters:0 diff --git a/bin/addons/base/i18n/bg.po b/bin/addons/base/i18n/bg.po index 8f1cf6cf4b3..3c0c2397239 100644 --- a/bin/addons/base/i18n/bg.po +++ b/bin/addons/base/i18n/bg.po @@ -13,8 +13,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2011-02-16 04:50+0000\n" -"X-Generator: Launchpad (build 12351)\n" +"X-Launchpad-Export-Date: 2011-04-09 04:50+0000\n" +"X-Generator: Launchpad (build 12735)\n" #. module: base #: view:ir.filters:0 @@ -33,12 +33,12 @@ msgstr "Св. Елена" #. module: base #: view:ir.actions.report.xml:0 msgid "Other Configuration" -msgstr "" +msgstr "Други настройки" #. module: base #: selection:ir.property,type:0 msgid "DateTime" -msgstr "" +msgstr "Дата час" #. module: base #: code:addons/fields.py:534 @@ -47,6 +47,8 @@ msgid "" "The second argument of the many2many field %s must be a SQL table !You used " "%s, which is not a valid SQL table name." msgstr "" +"Вторият аргумент на many2many полето %s трябва да е SQL таблица ! Вие " +"използвате %s, което не е валидно SQL име на таблица." #. module: base #: view:ir.values:0 @@ -93,7 +95,7 @@ msgstr "Не може да бъде търсен" #. module: base #: selection:base.language.install,lang:0 msgid "Spanish (VE) / Español (VE)" -msgstr "" +msgstr "Испански (VE) / Español (VE)" #. module: base #: field:ir.actions.server,wkf_model_id:0 @@ -103,7 +105,7 @@ msgstr "Последователност от действия Вкл." #. module: base #: field:ir.actions.act_window,display_menu_tip:0 msgid "Display Menu Tips" -msgstr "" +msgstr "Показване подсказки на менютата" #. module: base #: view:ir.module.module:0 @@ -117,6 +119,8 @@ msgid "" "You can not write in this document (%s) ! Be sure your user belongs to one " "of these groups: %s." msgstr "" +"Не можете да пишете в този документ (%s)! Уверете се, че принадлежите на " +"някоя от следните групи: %s." #. module: base #: help:ir.model.fields,domain:0 @@ -129,7 +133,7 @@ msgstr "" #. module: base #: field:res.partner,ref:0 msgid "Reference" -msgstr "" +msgstr "Означение" #. module: base #: field:ir.actions.act_window,target:0 @@ -140,7 +144,7 @@ msgstr "Прозорец цел" #: code:addons/base/res/res_user.py:507 #, python-format msgid "Warning!" -msgstr "" +msgstr "Предупреждение!" #. module: base #: code:addons/base/ir/ir_model.py:304 @@ -154,7 +158,7 @@ msgstr "" #: code:addons/osv.py:133 #, python-format msgid "Constraint Error" -msgstr "" +msgstr "Ограничение за грешка" #. module: base #: model:ir.model,name:base.model_ir_ui_view_custom @@ -171,12 +175,12 @@ msgstr "Швейцария" #: code:addons/orm.py:3653 #, python-format msgid "created." -msgstr "" +msgstr "създаден." #. module: base #: model:res.partner.category,name:base.res_partner_category_woodsuppliers0 msgid "Wood Suppliers" -msgstr "" +msgstr "Доставчици на дървен материал" #. module: base #: code:addons/base/module/module.py:303 @@ -208,13 +212,14 @@ msgstr "" #. module: base #: view:res.partner:0 msgid "Search Partner" -msgstr "Търсене на партньор" +msgstr "Търсене на контрагент" #. module: base #: code:addons/base/res/res_user.py:132 #, python-format msgid "\"smtp_server\" needs to be set to send mails to users" msgstr "" +"\"smtp_server\" необходимо е да установите поща за изпращане за потребителите" #. module: base #: code:addons/base/module/wizard/base_export_language.py:60 @@ -235,7 +240,7 @@ msgstr "Брой на модулите" #. module: base #: help:multi_company.default,company_dest_id:0 msgid "Company to store the current record" -msgstr "" +msgstr "Компания, към която да се съхрани текущия запис" #. module: base #: field:res.partner.bank.type.field,size:0 @@ -260,7 +265,7 @@ msgstr "" #. module: base #: sql_constraint:res.lang:0 msgid "The name of the language must be unique !" -msgstr "" +msgstr "Името на езика трябва да буде уникално!" #. module: base #: selection:res.request,state:0 @@ -276,7 +281,7 @@ msgstr "Име на помощник" #: code:addons/orm.py:2160 #, python-format msgid "Invalid group_by" -msgstr "" +msgstr "Невалидно групиране по" #. module: base #: field:res.partner,credit_limit:0 @@ -291,7 +296,7 @@ msgstr "Обнови дата" #. module: base #: view:ir.attachment:0 msgid "Owner" -msgstr "" +msgstr "Собственик" #. module: base #: field:ir.actions.act_window,src_model:0 @@ -312,7 +317,7 @@ msgstr "ir.ui.view_sc" #: field:res.widget.user,widget_id:0 #: field:res.widget.wizard,widgets_list:0 msgid "Widget" -msgstr "" +msgstr "Добавка" #. module: base #: view:ir.model.access:0 @@ -398,7 +403,7 @@ msgstr "" #: code:addons/orm.py:904 #, python-format msgid "The read method is not implemented on this object !" -msgstr "" +msgstr "Метода за четене не е дефиниран за този обект !" #. module: base #: help:res.lang,iso_code:0 @@ -409,7 +414,7 @@ msgstr "" #. module: base #: view:base.module.upgrade:0 msgid "Your system will be updated." -msgstr "" +msgstr "Системата ви ще бъде обновена" #. module: base #: field:ir.actions.todo,note:0 @@ -436,7 +441,7 @@ msgstr "Планирай обновяване" #: code:addons/orm.py:838 #, python-format msgid "Key/value '%s' not found in selection field '%s'" -msgstr "" +msgstr "Ключ/стойност '%s' не го откривам в избраното поле '%s'" #. module: base #: help:res.country,code:0 @@ -460,7 +465,7 @@ msgstr "Продажби и поръчки" #. module: base #: view:ir.translation:0 msgid "Untranslated" -msgstr "" +msgstr "Непреведени" #. module: base #: help:ir.actions.act_window,context:0 @@ -478,7 +483,7 @@ msgstr "Помощници" #. module: base #: model:res.partner.category,name:base.res_partner_category_miscellaneoussuppliers0 msgid "Miscellaneous Suppliers" -msgstr "" +msgstr "Разни доставчици" #. module: base #: code:addons/base/ir/ir_model.py:255 @@ -494,7 +499,7 @@ msgstr "Изберете прозорец за действие, доклад, #. module: base #: view:res.config.users:0 msgid "New User" -msgstr "" +msgstr "Нов потребител" #. module: base #: view:base.language.export:0 @@ -525,7 +530,7 @@ msgstr "Йордания" #. module: base #: view:ir.module.module:0 msgid "Certified" -msgstr "" +msgstr "Сертифициран" #. module: base #: model:res.country,name:base.er @@ -536,12 +541,12 @@ msgstr "Еритрея" #: view:res.config:0 #: view:res.config.installer:0 msgid "description" -msgstr "" +msgstr "описание" #. module: base #: model:ir.ui.menu,name:base.menu_base_action_rule msgid "Automated Actions" -msgstr "" +msgstr "Автоматизирани действия" #. module: base #: model:ir.model,name:base.model_ir_actions_actions @@ -551,7 +556,7 @@ msgstr "ir.actions.actions" #. module: base #: view:partner.wizard.ean.check:0 msgid "Want to check Ean ? " -msgstr "" +msgstr "Желаете ли да проверите EAN? " #. module: base #: field:ir.values,key2:0 @@ -565,11 +570,14 @@ msgid "" "Launchpad.net, our open source project management facility. We use their " "online interface to synchronize all translations efforts." msgstr "" +"OpenERP преводи (ядро, модули, клиенти) се управляват през Launchpad.net, " +"our open source project management facility. We use their online interface " +"to synchronize all translations efforts." #. module: base #: field:res.partner,title:0 msgid "Partner Form" -msgstr "" +msgstr "Форма за контрагент" #. module: base #: selection:base.language.install,lang:0 @@ -602,27 +610,27 @@ msgstr "Последователност" #. module: base #: model:ir.model,name:base.model_base_language_import msgid "Language Import" -msgstr "" +msgstr "Импортиране на език" #. module: base #: model:ir.model,name:base.model_res_config_users msgid "res.config.users" -msgstr "" +msgstr "res.config.users" #. module: base #: selection:base.language.install,lang:0 msgid "Albanian / Shqip" -msgstr "" +msgstr "Албански / Shqip" #. module: base #: model:ir.ui.menu,name:base.menu_crm_config_opportunity msgid "Opportunities" -msgstr "" +msgstr "Възможности" #. module: base #: model:ir.model,name:base.model_base_language_export msgid "base.language.export" -msgstr "" +msgstr "base.language.export" #. module: base #: model:res.country,name:base.pg @@ -633,6 +641,7 @@ msgstr "Папуа Нова Гвинея" #: help:ir.actions.report.xml,report_type:0 msgid "Report Type, e.g. pdf, html, raw, sxw, odt, html2html, mako2html, ..." msgstr "" +"Тип на справка, напр. pdf, html, raw, sxw, odt, html2html, mako2html, ..." #. module: base #: model:res.partner.category,name:base.res_partner_category_4 @@ -652,7 +661,7 @@ msgstr "Мои партньори" #. module: base #: view:ir.actions.report.xml:0 msgid "XML Report" -msgstr "" +msgstr "XML отчет" #. module: base #: model:res.country,name:base.es @@ -674,7 +683,7 @@ msgstr "" #: model:ir.actions.act_window,name:base.action_view_base_module_upgrade #: model:ir.model,name:base.model_base_module_upgrade msgid "Module Upgrade" -msgstr "" +msgstr "Ъпгрейд на модул" #. module: base #: view:res.config.users:0 @@ -682,11 +691,13 @@ msgid "" "Groups are used to define access rights on objects and the visibility of " "screens and menus" msgstr "" +"Групите се използват за да се дефинират права за достъп до обекти, екрани и " +"менюта" #. module: base #: selection:base.language.install,lang:0 msgid "Spanish (UY) / Español (UY)" -msgstr "" +msgstr "Испански (UY) / Español (UY)" #. module: base #: field:res.partner,mobile:0 @@ -718,7 +729,7 @@ msgstr "Работни дни" #. module: base #: selection:ir.module.module,license:0 msgid "Other OSI Approved Licence" -msgstr "" +msgstr "Друг OSI одобрен лиценз" #. module: base #: help:res.config.users,context_lang:0 @@ -727,12 +738,13 @@ msgid "" "Sets the language for the user's user interface, when UI translations are " "available" msgstr "" +"Изберете език за потребителския интерфейс, когато има съответните преводи" #. module: base #: code:addons/orm.py:1043 #, python-format msgid "The unlink method is not implemented on this object !" -msgstr "" +msgstr "Метода unlink не е реализиран за този обект !" #. module: base #: model:ir.actions.act_window,name:base.act_menu_create @@ -770,7 +782,7 @@ msgstr "Подкатегории" #. module: base #: model:ir.model,name:base.model_ir_config_parameter msgid "ir.config_parameter" -msgstr "" +msgstr "ir.config_parameter" #. module: base #: selection:base.language.export,format:0 @@ -805,6 +817,8 @@ msgid "" "Language with code \"%s\" is not defined in your system !\n" "Define it through the Administration menu." msgstr "" +"Език с код \"%s\" не е дефиниран във вашата система!\n" +"Дефинирайте го през меню Администрация." #. module: base #: model:res.country,name:base.gu @@ -814,13 +828,13 @@ msgstr "Гуам (САЩ)" #. module: base #: model:ir.ui.menu,name:base.menu_hr_project msgid "Human Resources Dashboard" -msgstr "" +msgstr "Табло Човешки ресурси" #. module: base #: code:addons/base/res/res_user.py:507 #, python-format msgid "Setting empty passwords is not allowed for security reasons!" -msgstr "" +msgstr "Използване на празни пароли не е разрешено по причини за сигурност!" #. module: base #: selection:ir.actions.server,state:0 @@ -859,7 +873,7 @@ msgstr "" #. module: base #: field:ir.module.module,contributors:0 msgid "Contributors" -msgstr "" +msgstr "Сътрудници" #. module: base #: selection:ir.property,type:0 @@ -870,7 +884,7 @@ msgstr "" #: model:ir.actions.act_window,name:base.action_publisher_warranty_contract_form #: model:ir.ui.menu,name:base.menu_publisher_warranty_contract msgid "Contracts" -msgstr "" +msgstr "Договори" #. module: base #: selection:base.language.install,lang:0 @@ -885,7 +899,7 @@ msgstr "Уганда" #. module: base #: field:ir.model.access,perm_unlink:0 msgid "Delete Access" -msgstr "" +msgstr "Изтриване на достъп" #. module: base #: model:res.country,name:base.ne @@ -895,7 +909,7 @@ msgstr "Нигер" #. module: base #: selection:base.language.install,lang:0 msgid "Chinese (HK)" -msgstr "" +msgstr "Китайски (HK)" #. module: base #: model:res.country,name:base.ba @@ -909,11 +923,14 @@ msgid "" "Lauchpad's web interface (Rosetta). If you need to perform mass translation, " "Launchpad also allows uploading full .po files at once" msgstr "" +"За да подобрите или разширите официалните преводи, вие трябва да използвате " +"директно Lauchpad's web interface (Rosetta). Ако превеждате големи обеми, " +"Launchpad също предлага и качване на пълен .po файл наведнъж." #. module: base #: selection:base.language.install,lang:0 msgid "Spanish (GT) / Español (GT)" -msgstr "" +msgstr "Испански (GT) / Español (GT)" #. module: base #: view:res.lang:0 @@ -945,7 +962,7 @@ msgstr "URL на действие" #. module: base #: field:base.module.import,module_name:0 msgid "Module Name" -msgstr "" +msgstr "Име на модула" #. module: base #: model:res.country,name:base.mh @@ -956,7 +973,7 @@ msgstr "Маршалови острови" #: code:addons/base/ir/ir_model.py:328 #, python-format msgid "Changing the model of a field is forbidden!" -msgstr "" +msgstr "Промяна на модела на полете е забранена!" #. module: base #: model:res.country,name:base.ht @@ -989,7 +1006,7 @@ msgstr "" #: code:addons/base/res/res_user.py:206 #, python-format msgid "Operation Canceled" -msgstr "" +msgstr "Отказана операция" #. module: base #: help:base.language.export,lang:0 @@ -999,17 +1016,17 @@ msgstr "За да експортирате нов език, не избирай #. module: base #: view:res.request:0 msgid "Request Date" -msgstr "" +msgstr "Дата на заявка" #. module: base #: model:ir.ui.menu,name:base.menu_hr_dasboard msgid "Dashboard" -msgstr "" +msgstr "Табло" #. module: base #: model:ir.ui.menu,name:base.menu_purchase_root msgid "Purchases" -msgstr "" +msgstr "Покупки" #. module: base #: model:res.country,name:base.md @@ -1043,7 +1060,7 @@ msgstr "ir.exports" #: code:addons/base/module/wizard/base_update_translations.py:38 #, python-format msgid "No language with code \"%s\" exists" -msgstr "" +msgstr "Не съществува език с код \"%s\"" #. module: base #: code:addons/base/publisher_warranty/publisher_warranty.py:163 @@ -1065,7 +1082,7 @@ msgstr "" #. module: base #: view:res.lang:0 msgid "%Y - Year with century." -msgstr "" +msgstr "%Y - Годината с века." #. module: base #: report:ir.module.reference.graph:0 @@ -1084,12 +1101,12 @@ msgstr "" #: code:addons/orm.py:1744 #, python-format msgid "The search method is not implemented on this object !" -msgstr "" +msgstr "Методът ТЪРСЕНЕ не е реализиран в този обект!" #. module: base #: view:wizard.ir.model.menu.create:0 msgid "Create _Menu" -msgstr "" +msgstr "Създаване _Меню" #. module: base #: field:res.payterm,name:0 @@ -1113,12 +1130,12 @@ msgstr "ir.exports.line" msgid "" "If you check this box, your customized translations will be overwritten and " "replaced by the official ones." -msgstr "" +msgstr "Вашите преводи ще бъдат препокрити от официалните." #. module: base #: field:ir.actions.report.xml,report_rml:0 msgid "Main report file path" -msgstr "" +msgstr "Път към файла за Главен отчет" #. module: base #: model:ir.actions.act_window,name:base.ir_action_report_xml @@ -1166,6 +1183,8 @@ msgid "" "Access all the fields related to the current object using expressions, i.e. " "object.partner_id.name " msgstr "" +"Достъп до всичките полета, свързани с текущия обект с помоща на изрази. i.e. " +"object.partner_id.name " #. module: base #: model:ir.model,name:base.model_res_country_state @@ -1175,7 +1194,7 @@ msgstr "Провинция" #. module: base #: selection:ir.property,type:0 msgid "Float" -msgstr "" +msgstr "Плаваща запетая" #. module: base #: model:ir.model,name:base.model_res_request_link @@ -1192,7 +1211,7 @@ msgstr "Информация за помощник" #: model:ir.actions.act_window,name:base.action_wizard_lang_export #: model:ir.ui.menu,name:base.menu_wizard_lang_export msgid "Export Translation" -msgstr "" +msgstr "Експортиране на превод" #. module: base #: help:res.log,secondary:0 @@ -1242,7 +1261,7 @@ msgstr "wizard.ir.model.menu.create.line" #. module: base #: field:ir.attachment,res_id:0 msgid "Attached ID" -msgstr "" +msgstr "Прикачен ID" #. module: base #: view:ir.sequence:0 @@ -1306,7 +1325,7 @@ msgstr "" #: model:ir.actions.act_window,name:base.res_widget_act_window #: model:ir.ui.menu,name:base.menu_res_widget_act_window msgid "Homepage Widgets" -msgstr "" +msgstr "Притурки на началната страница" #. module: base #: help:ir.actions.server,message:0 @@ -1320,12 +1339,12 @@ msgstr "" #. module: base #: field:ir.attachment,res_model:0 msgid "Attached Model" -msgstr "" +msgstr "Прикачен модел" #. module: base #: view:ir.rule:0 msgid "Domain Setup" -msgstr "" +msgstr "Настойка на Домейн" #. module: base #: field:ir.actions.server,trigger_name:0 @@ -1375,7 +1394,7 @@ msgstr "Малави" #: code:addons/base/res/res_user.py:413 #, python-format msgid "%s (copy)" -msgstr "" +msgstr "%s (копие)" #. module: base #: field:res.partner.address,type:0 @@ -1385,7 +1404,7 @@ msgstr "Вид на адреса" #. module: base #: view:ir.ui.menu:0 msgid "Full Path" -msgstr "" +msgstr "Пълен път" #. module: base #: view:res.request:0 @@ -1406,7 +1425,7 @@ msgstr "" #. module: base #: view:ir.ui.view:0 msgid "Advanced" -msgstr "" +msgstr "Разширени" #. module: base #: model:res.country,name:base.fi @@ -1433,12 +1452,12 @@ msgstr "" #. module: base #: view:ir.actions.server:0 msgid "Create / Write / Copy" -msgstr "" +msgstr "Създаване / Писане / Копиране" #. module: base #: view:base.language.export:0 msgid "https://help.launchpad.net/Translations" -msgstr "" +msgstr "https://help.launchpad.net/Translations" #. module: base #: field:ir.actions.act_window,view_mode:0 @@ -1451,17 +1470,19 @@ msgid "" "When using CSV format, please also check that the first line of your file is " "one of the following:" msgstr "" +"Когато се използва CSV формат, трябва да се провери първият ред на файла да " +"има следния вид:" #. module: base #: code:addons/fields.py:114 #, python-format msgid "Not implemented search_memory method !" -msgstr "" +msgstr "Методът search_memory не е реализиран!" #. module: base #: view:res.log:0 msgid "Logs" -msgstr "" +msgstr "Логове" #. module: base #: selection:base.language.install,lang:0 @@ -1471,7 +1492,7 @@ msgstr "Испански / Español" #. module: base #: selection:base.language.install,lang:0 msgid "Korean (KP) / 한국어 (KP)" -msgstr "" +msgstr "Корейски (KP) / 한국어 (KP)" #. module: base #: view:base.module.update:0 @@ -1479,6 +1500,8 @@ msgid "" "This wizard will scan all module repositories on the server side to detect " "newly added modules as well as any change to existing modules." msgstr "" +"Този помощник ще сканира всички хранилища за модули на сървъра за нови и/или " +"актуализирани модули." #. module: base #: field:res.company,logo:0 @@ -1534,12 +1557,12 @@ msgstr "Брой обновени модули" #: code:addons/fields.py:100 #, python-format msgid "Not implemented set_memory method !" -msgstr "" +msgstr "Методът set_memory не е реализиран!" #. module: base #: view:workflow.activity:0 msgid "Workflow Activity" -msgstr "" +msgstr "Активност на работния поток" #. module: base #: view:ir.rule:0 @@ -1554,6 +1577,9 @@ msgid "" "Views allows you to personalize each view of OpenERP. You can add new " "fields, move fields, rename them or delete the ones that you do not need." msgstr "" +"Изгледите позволяват да се персонализира всеки екран на Open ЕРП. Могат се " +"да добавят нови полета, да местят полета, да се преименуват и да се трият " +"ненужните." #. module: base #: field:ir.actions.act_window,groups_id:0 @@ -1579,7 +1605,7 @@ msgstr "Групи" #. module: base #: selection:base.language.install,lang:0 msgid "Spanish (CL) / Español (CL)" -msgstr "" +msgstr "Испански (CL) / Español (CL)" #. module: base #: view:res.config.users:0 @@ -1588,6 +1614,10 @@ msgid "" "access to selected functionalities within the system. Click on 'Done' if you " "do not wish to add more users at this stage, you can always do this later." msgstr "" +"Като създавате нови потребители и ги правите членове на съответните групи ще " +"им позволите достъп до избраните функционалностти на системата. Натиснете " +"\"Готово\" ако не желаете да добавяте повече потребители на този етап. Вие " +"можете да направите това по-късно." #. module: base #: model:res.country,name:base.bz @@ -1616,11 +1646,12 @@ msgstr "" #, python-format msgid "A document was modified since you last viewed it (%s:%d)" msgstr "" +"Документът е променян на (%s:%d) след като сте го гледали за последне път" #. module: base #: view:workflow:0 msgid "Workflow Editor" -msgstr "" +msgstr "Редактор на работен поток" #. module: base #: selection:ir.module.module,state:0 @@ -1654,7 +1685,7 @@ msgstr "Поле" #. module: base #: view:ir.rule:0 msgid "Groups (no group = global)" -msgstr "" +msgstr "Групи (без прупа = глобална)" #. module: base #: model:res.country,name:base.fo @@ -1666,7 +1697,7 @@ msgstr "Фарьорски острови" #: selection:res.config.view,view:0 #: selection:res.users,view:0 msgid "Simplified" -msgstr "" +msgstr "Опростен" #. module: base #: model:res.country,name:base.st @@ -1681,7 +1712,7 @@ msgstr "Фактура" #. module: base #: selection:base.language.install,lang:0 msgid "Portugese (BR) / Português (BR)" -msgstr "" +msgstr "Португалски (BR) / Português (BR)" #. module: base #: model:res.country,name:base.bb @@ -1767,7 +1798,7 @@ msgstr "Зимбабве" #. module: base #: view:base.module.update:0 msgid "Please be patient, as this operation may take a few seconds..." -msgstr "" +msgstr "Моля, за търпение. Може да отнеме няколко секунди..." #. module: base #: help:ir.values,action_id:0 @@ -1778,7 +1809,7 @@ msgstr "" #. module: base #: field:ir.actions.server,email:0 msgid "Email Address" -msgstr "Адрес за е-поща" +msgstr "Имейл адрес" #. module: base #: selection:base.language.install,lang:0 @@ -1814,7 +1845,7 @@ msgstr "Свързване на полета" #. module: base #: view:base.language.export:0 msgid "Export Translations" -msgstr "" +msgstr "Експортиране на преводи" #. module: base #: model:ir.ui.menu,name:base.menu_custom @@ -1846,7 +1877,7 @@ msgstr "Литва" #: model:ir.model,name:base.model_partner_clear_ids #: view:partner.clear.ids:0 msgid "Clear IDs" -msgstr "" +msgstr "Изчисти IDs" #. module: base #: help:ir.cron,model:0 @@ -1859,12 +1890,12 @@ msgstr "" #: code:addons/orm.py:1040 #, python-format msgid "The perm_read method is not implemented on this object !" -msgstr "" +msgstr "Методът perm_read не е реализиран за този обект!" #. module: base #: view:res.lang:0 msgid "%y - Year without century [00,99]." -msgstr "" +msgstr "%y - Годината без века [00,99]." #. module: base #: model:res.country,name:base.si @@ -1880,12 +1911,12 @@ msgstr "Пакистан" #: code:addons/orm.py:1350 #, python-format msgid "Invalid Object Architecture!" -msgstr "" +msgstr "Невалидна архитектура на обект" #. module: base #: model:ir.ui.menu,name:base.menu_email_gateway_form msgid "Messages" -msgstr "" +msgstr "Съобщения" #. module: base #: code:addons/base/ir/ir_model.py:303 @@ -1897,7 +1928,7 @@ msgstr "" #: code:addons/base/module/wizard/base_update_translations.py:38 #, python-format msgid "Error!" -msgstr "" +msgstr "Грешка!" #. module: base #: view:res.lang:0 @@ -1912,7 +1943,7 @@ msgstr "Повтарящи се действия" #. module: base #: help:multi_company.default,company_id:0 msgid "Company where the user is connected" -msgstr "" +msgstr "Фирма, с която е свързан потребителят" #. module: base #: field:publisher_warranty.contract,date_stop:0 @@ -1931,6 +1962,8 @@ msgid "" "One of the records you are trying to modify has already been deleted " "(Document type: %s)." msgstr "" +"Един от записите, които се опитвате да промените е вече изтрит (Документ " +"тип: %s)" #. module: base #: model:ir.actions.act_window,help:base.action_country @@ -1953,12 +1986,12 @@ msgstr "Остров Норфолк" #. module: base #: selection:base.language.install,lang:0 msgid "Korean (KR) / 한국어 (KR)" -msgstr "" +msgstr "Корейски (KR) / 한국어 (KR)" #. module: base #: help:ir.model.fields,model:0 msgid "The technical name of the model this field belongs to" -msgstr "" +msgstr "Техническото име на модела, към който принадлежи това поле" #. module: base #: field:ir.actions.server,action_id:0 @@ -2005,7 +2038,7 @@ msgstr "res.partner.event" #. module: base #: model:res.widget,title:base.facebook_widget msgid "Facebook" -msgstr "" +msgstr "Фейсбук" #. module: base #: model:res.country,name:base.am @@ -2016,12 +2049,12 @@ msgstr "Армения" #: model:ir.actions.act_window,name:base.ir_property_form #: model:ir.ui.menu,name:base.menu_ir_property_form_all msgid "Configuration Parameters" -msgstr "" +msgstr "Праметри за настройка" #. module: base #: constraint:ir.cron:0 msgid "Invalid arguments" -msgstr "" +msgstr "Невалидни аргументи" #. module: base #: model:res.country,name:base.se @@ -2061,7 +2094,7 @@ msgstr "Тип на банкова сметка" #: field:res.config.users,config_logo:0 #: field:res.config.view,config_logo:0 msgid "Image" -msgstr "" +msgstr "Изображение" #. module: base #: view:ir.actions.server:0 @@ -2071,7 +2104,7 @@ msgstr "Настройка на повтарящо се действие" #. module: base #: selection:publisher_warranty.contract,state:0 msgid "Canceled" -msgstr "" +msgstr "Отменени" #. module: base #: model:res.country,name:base.at @@ -2083,7 +2116,7 @@ msgstr "Австрия" #: selection:base.module.import,state:0 #: selection:base.module.update,state:0 msgid "done" -msgstr "" +msgstr "готово" #. module: base #: selection:ir.actions.act_window.view,view_mode:0 @@ -2096,7 +2129,7 @@ msgstr "Календар" #. module: base #: field:res.partner.address,partner_id:0 msgid "Partner Name" -msgstr "" +msgstr "Име на контрагент" #. module: base #: field:workflow.activity,signal_send:0 @@ -2106,7 +2139,7 @@ msgstr "Сигнал (subflow.*)" #. module: base #: model:res.partner.category,name:base.res_partner_category_17 msgid "HR sector" -msgstr "" +msgstr "Сектор Чов. Рес." #. module: base #: code:addons/orm.py:3817 @@ -2132,7 +2165,7 @@ msgstr "Чернова" #: selection:res.config.view,view:0 #: selection:res.users,view:0 msgid "Extended" -msgstr "" +msgstr "Разширен" #. module: base #: model:ir.actions.act_window,help:base.action_partner_title_contact @@ -2200,11 +2233,13 @@ msgid "" "Please double-check that the file encoding is set to UTF-8 (sometimes called " "Unicode) when the translator exports it." msgstr "" +"Моля, проверете дали файлът е настроен на кодиране UTF-8 (понякога наричан " +"Unicode) при експорт." #. module: base #: selection:base.language.install,lang:0 msgid "Spanish (DO) / Español (DO)" -msgstr "" +msgstr "Испански (DO) / Español (DO)" #. module: base #: model:ir.model,name:base.model_workflow_activity @@ -2231,7 +2266,7 @@ msgstr "Уругвай" #. module: base #: selection:base.language.install,lang:0 msgid "Finnish / Suomi" -msgstr "" +msgstr "Фински / Suomi" #. module: base #: field:ir.rule,perm_write:0 @@ -2261,7 +2296,7 @@ msgstr "Свързване на полета" #. module: base #: selection:base.language.install,lang:0 msgid "Portugese / Português" -msgstr "" +msgstr "Португалски / Português" #. module: base #: model:res.partner.title,name:base.res_partner_title_sir @@ -2272,7 +2307,7 @@ msgstr "Сър" #: code:addons/orm.py:1622 #, python-format msgid "There is no view of type '%s' defined for the structure!" -msgstr "" +msgstr "Няма изглед от тип '%s' дефиниран за тази структура!" #. module: base #: field:ir.default,ref_id:0 @@ -2283,7 +2318,7 @@ msgstr "ID отпратка" #: model:ir.actions.server,name:base.action_start_configurator #: model:ir.ui.menu,name:base.menu_view_base_module_configuration msgid "Start Configuration" -msgstr "" +msgstr "Започни настройване" #. module: base #: model:res.country,name:base.mt @@ -2336,7 +2371,7 @@ msgstr "" #. module: base #: view:base.language.import:0 msgid "_Import" -msgstr "" +msgstr "_Импортиране" #. module: base #: view:res.partner.canal:0 @@ -2393,13 +2428,13 @@ msgstr "Отляво надясно" #: model:ir.model,name:base.model_ir_filters #: model:ir.ui.menu,name:base.menu_ir_filters msgid "Filters" -msgstr "" +msgstr "Филтри" #. module: base #: code:addons/orm.py:758 #, python-format msgid "Please check that all your lines have %d columns." -msgstr "" +msgstr "Моля проверете дали всичките ви редове имат %d колони." #. module: base #: model:ir.actions.act_window,name:base.ir_cron_act @@ -2419,12 +2454,14 @@ msgstr "Заглавие" #: help:ir.property,res_id:0 msgid "If not set, acts as a default value for new resources" msgstr "" +"Ако не е указано друго, използвай като стойност по подразбиране за нови " +"ресурси" #. module: base #: code:addons/orm.py:3448 #, python-format msgid "Recursivity Detected." -msgstr "" +msgstr "Устанена е рекурсия" #. module: base #: code:addons/base/module/module.py:262 @@ -2439,6 +2476,9 @@ msgid "" "loading a new language it becomes available as default interface language " "for users and partners." msgstr "" +"Този помощник ще ви помогне да добавите нови езици към вашата Open ERP " +"система. След зареждане новият език ще бъде наличен по подразбиране като " +"език на интерфейса за потребители и контрагенти." #. module: base #: view:ir.model:0 @@ -2457,7 +2497,7 @@ msgstr "" #. module: base #: model:ir.model,name:base.model_maintenance_contract msgid "maintenance.contract" -msgstr "" +msgstr "maintenance.contract" #. module: base #: model:res.country,name:base.ru @@ -2493,18 +2533,18 @@ msgstr "Правила на записа" #. module: base #: view:ir.property:0 msgid "Field Information" -msgstr "" +msgstr "Информация за поле" #. module: base #: view:ir.actions.todo:0 msgid "Search Actions" -msgstr "" +msgstr "Действия търсене" #. module: base #: model:ir.actions.act_window,name:base.action_view_partner_wizard_ean_check #: view:partner.wizard.ean.check:0 msgid "Ean check" -msgstr "" +msgstr "Проверка на EAN" #. module: base #: field:res.partner,vat:0 @@ -2529,7 +2569,7 @@ msgstr "%x - Подходящо представяне на датата." #. module: base #: view:res.lang:0 msgid "%d - Day of the month [01,31]." -msgstr "" +msgstr "%d - Ден от месеца [01,31]." #. module: base #: model:res.country,name:base.tj @@ -2544,7 +2584,7 @@ msgstr "GPL версия 2 или по-нова" #. module: base #: model:res.partner.title,shortcut:base.res_partner_title_sir msgid "M." -msgstr "" +msgstr "M." #. module: base #: code:addons/base/module/module.py:429 @@ -2563,6 +2603,8 @@ msgid "" "Operation prohibited by access rules, or performed on an already deleted " "document (Operation: read, Document type: %s)." msgstr "" +"Операцията е забранена от правила за достъп или изпълнена върху вече изтрит " +"документ (Operation: read, Document type: %s)." #. module: base #: model:res.country,name:base.nr @@ -2573,7 +2615,7 @@ msgstr "Науру" #: code:addons/base/module/module.py:200 #, python-format msgid "The certificate ID of the module must be unique !" -msgstr "" +msgstr "Сертифицираният ID на модула трябва да бъде уникален!" #. module: base #: model:ir.model,name:base.model_ir_property @@ -2650,7 +2692,7 @@ msgstr "EAN13" #: code:addons/orm.py:1622 #, python-format msgid "Invalid Architecture!" -msgstr "" +msgstr "Невалидна архитектура!" #. module: base #: model:res.country,name:base.pt @@ -2662,6 +2704,7 @@ msgstr "Португалия" msgid "" "You cannot have multiple records with the same id for the same module !" msgstr "" +"Не можете да имате множество записи с еднакви ID за един и същ модул!" #. module: base #: field:ir.module.module,certificate:0 @@ -2677,12 +2720,12 @@ msgstr "6. %d, %m ==> 05, 12" #: field:res.config.users,date:0 #: field:res.users,date:0 msgid "Last Connection" -msgstr "" +msgstr "Последна конекция" #. module: base #: field:ir.actions.act_window,help:0 msgid "Action description" -msgstr "" +msgstr "Описание на действие" #. module: base #: help:res.partner,customer:0 @@ -2755,12 +2798,12 @@ msgstr "Основно поле" #. module: base #: view:publisher_warranty.contract:0 msgid "Validate" -msgstr "" +msgstr "Потвърждаване" #. module: base #: field:ir.actions.todo,restart:0 msgid "Restart" -msgstr "" +msgstr "Рестартиране" #. module: base #: field:ir.actions.report.xml,report_sxw_content:0 @@ -2806,7 +2849,7 @@ msgstr "Задължителен" #. module: base #: view:res.users:0 msgid "Default Filters" -msgstr "" +msgstr "Филтри по подразбиране" #. module: base #: field:res.request.history,name:0 @@ -2816,7 +2859,7 @@ msgstr "Обобщение" #. module: base #: field:multi_company.default,expression:0 msgid "Expression" -msgstr "" +msgstr "Израз" #. module: base #: help:ir.actions.server,subject:0 @@ -2852,12 +2895,12 @@ msgstr "Модул в .zip формат" #. module: base #: field:ir.ui.view,xml_id:0 msgid "XML ID" -msgstr "" +msgstr "XML ID" #. module: base #: model:res.partner.category,name:base.res_partner_category_16 msgid "Telecom sector" -msgstr "" +msgstr "Телекомуникационен сектор" #. module: base #: field:workflow.transition,trigger_model:0 @@ -2867,7 +2910,7 @@ msgstr "Задействащ обект" #. module: base #: view:res.users:0 msgid "Current Activity" -msgstr "" +msgstr "Настояща активност" #. module: base #: view:workflow.activity:0 @@ -2883,7 +2926,7 @@ msgstr "Суринам" #. module: base #: model:ir.ui.menu,name:base.marketing_menu msgid "Marketing" -msgstr "" +msgstr "Маркетинг" #. module: base #: view:res.partner.bank:0 @@ -2894,7 +2937,7 @@ msgstr "Банкова сметка" #. module: base #: selection:base.language.install,lang:0 msgid "Spanish (HN) / Español (HN)" -msgstr "" +msgstr "Испански (HN) / Español (HN)" #. module: base #: view:ir.sequence.type:0 @@ -2904,7 +2947,7 @@ msgstr "Вид последователност" #. module: base #: view:ir.ui.view.custom:0 msgid "Customized Architecture" -msgstr "" +msgstr "Персонализирана архитектура" #. module: base #: field:ir.module.module,license:0 @@ -2914,12 +2957,12 @@ msgstr "Лиценз" #. module: base #: field:ir.attachment,url:0 msgid "Url" -msgstr "" +msgstr "Url" #. module: base #: selection:ir.actions.todo,restart:0 msgid "Always" -msgstr "" +msgstr "Винаги" #. module: base #: selection:ir.translation,type:0 @@ -2938,11 +2981,13 @@ msgid "" "The selected language has been successfully installed. You must change the " "preferences of the user and open a new menu to view the changes." msgstr "" +"Избраният език е успешно инсталиран. Трябва да промените настраойките на " +"потребителя и да отворите ново меню за да видите промените." #. module: base #: sql_constraint:ir.config_parameter:0 msgid "Key must be unique." -msgstr "" +msgstr "Ключът трябва да бъде уникален." #. module: base #: view:ir.actions.act_window:0 @@ -2991,11 +3036,14 @@ msgid "" "\n" "Click 'Continue' and enjoy your OpenERP experience..." msgstr "" +"Вашата база данни е напълно настроена.\n" +"\n" +"Натиснете 'Продължи' и се насладете на работата с OPEN ERP..." #. module: base #: selection:base.language.install,lang:0 msgid "Hebrew / עִבְרִי" -msgstr "" +msgstr "Иврид / עִבְרִי" #. module: base #: model:res.country,name:base.bo @@ -3039,12 +3087,12 @@ msgstr "" #. module: base #: view:base.module.upgrade:0 msgid "The selected modules have been updated / installed !" -msgstr "" +msgstr "Избраните модули бяха обновени / инсталирани!" #. module: base #: selection:base.language.install,lang:0 msgid "Spanish (PR) / Español (PR)" -msgstr "" +msgstr "Испански (PR) / Español (PR)" #. module: base #: model:res.country,name:base.gt @@ -3062,12 +3110,12 @@ msgstr "Последователности от действия" #. module: base #: field:ir.translation,xml_id:0 msgid "XML Id" -msgstr "" +msgstr "XML Id" #. module: base #: model:ir.actions.act_window,name:base.action_config_user_form msgid "Create Users" -msgstr "" +msgstr "Създаване на потребител" #. module: base #: model:ir.model,name:base.model_res_partner_title @@ -3082,7 +3130,7 @@ msgstr "tree_but_action, client_print_multi" #. module: base #: model:res.partner.category,name:base.res_partner_category_retailers0 msgid "Retailers" -msgstr "" +msgstr "Търговци на дребно" #. module: base #: help:ir.cron,priority:0 @@ -3118,33 +3166,33 @@ msgstr "Кения" #. module: base #: view:res.partner.event:0 msgid "Event" -msgstr "" +msgstr "Събитие" #. module: base #: model:ir.ui.menu,name:base.menu_custom_reports msgid "Custom Reports" -msgstr "" +msgstr "Персонализирани справки" #. module: base #: selection:base.language.install,lang:0 msgid "Abkhazian / аҧсуа" -msgstr "" +msgstr "Абхазки / аҧсуа" #. module: base #: view:base.module.configuration:0 msgid "System Configuration Done" -msgstr "" +msgstr "Настройката на системата е направена" #. module: base #: code:addons/orm.py:929 #, python-format msgid "Error occurred while validating the field(s) %s: %s" -msgstr "" +msgstr "Грешка при проверка на полета (s) %s: %s" #. module: base #: view:ir.property:0 msgid "Generic" -msgstr "" +msgstr "Общ" #. module: base #: model:res.country,name:base.sm @@ -3175,17 +3223,17 @@ msgstr "Бенин" #: code:addons/base/publisher_warranty/publisher_warranty.py:281 #, python-format msgid "That contract is already registered in the system." -msgstr "" +msgstr "Договорът е вече регистриран в системата" #. module: base #: help:ir.sequence,suffix:0 msgid "Suffix value of the record for the sequence" -msgstr "" +msgstr "Стойност на суфикса на записа за тази последователност" #. module: base #: selection:base.language.install,lang:0 msgid "Spanish (PY) / Español (PY)" -msgstr "" +msgstr "Испански (PY) / Español (PY)" #. module: base #: field:ir.config_parameter,key:0 @@ -3209,6 +3257,8 @@ msgid "" "You can not create this document (%s) ! Be sure your user belongs to one of " "these groups: %s." msgstr "" +"Не можете да създадете този документ (%s) ! Уверете се, че принадлежите към " +"някоя от следните групи: %s." #. module: base #: model:res.country,name:base.mu @@ -3219,7 +3269,7 @@ msgstr "Мавриций" #: view:ir.model.access:0 #: view:ir.rule:0 msgid "Full Access" -msgstr "" +msgstr "Пълен достъп" #. module: base #: view:ir.actions.act_window:0 @@ -3250,13 +3300,13 @@ msgstr "Инсталиран" #. module: base #: selection:base.language.install,lang:0 msgid "Ukrainian / українська" -msgstr "" +msgstr "Украински / українська" #. module: base #: model:ir.actions.act_window,name:base.action_translation #: model:ir.ui.menu,name:base.menu_action_translation msgid "Translation Terms" -msgstr "" +msgstr "Термини в превода" #. module: base #: model:res.country,name:base.sn @@ -3281,12 +3331,12 @@ msgstr "Бразилия" #. module: base #: view:res.lang:0 msgid "%M - Minute [00,59]." -msgstr "" +msgstr "%M - Минута [00,59]." #. module: base #: selection:ir.module.module,license:0 msgid "Affero GPL-3" -msgstr "" +msgstr "Affero GPL-3" #. module: base #: field:ir.sequence,number_next:0 @@ -3301,7 +3351,7 @@ msgstr "" #. module: base #: selection:base.language.install,lang:0 msgid "Spanish (PA) / Español (PA)" -msgstr "" +msgstr "Испански (PA) / Español (PA)" #. module: base #: view:res.currency:0 @@ -3333,7 +3383,7 @@ msgstr "" #. module: base #: view:base.module.upgrade:0 msgid "System update completed" -msgstr "" +msgstr "Обновяването на системата прикючи" #. module: base #: selection:res.request,state:0 @@ -3376,6 +3426,8 @@ msgstr "" #, python-format msgid "Cannot rename column to %s, because that column already exists!" msgstr "" +"Не може да се преименува колоната на %s, защото такава колона вече " +"съществува!" #. module: base #: view:ir.attachment:0 @@ -3429,7 +3481,7 @@ msgstr "Мексико" #. module: base #: model:ir.ui.menu,name:base.menu_base_config_plugins msgid "Plugins" -msgstr "" +msgstr "Добавки" #. module: base #: field:res.company,child_ids:0 @@ -3450,7 +3502,7 @@ msgstr "Никарагуа" #: code:addons/orm.py:1046 #, python-format msgid "The write method is not implemented on this object !" -msgstr "" +msgstr "Методът запис не е дефиниран за този обект !" #. module: base #: view:res.partner.event:0 @@ -3461,7 +3513,7 @@ msgstr "Главно описание" #: model:ir.actions.act_window,name:base.action_config_simple_view_form #: view:res.config.view:0 msgid "Configure Your Interface" -msgstr "" +msgstr "Настройка на интерфейс" #. module: base #: field:ir.values,meta:0 @@ -3471,7 +3523,7 @@ msgstr "Мета данни" #. module: base #: sql_constraint:ir.ui.view_sc:0 msgid "Shortcut for this menu already exists!" -msgstr "" +msgstr "Кратък път към това меню вече съществува!" #. module: base #: model:res.country,name:base.ve @@ -3500,7 +3552,7 @@ msgstr "" #. module: base #: field:res.partner,parent_id:0 msgid "Parent Partner" -msgstr "Главен партньор" +msgstr "Главен контрагент" #. module: base #: view:ir.module.module:0 @@ -3520,7 +3572,7 @@ msgstr "Казахстан" #. module: base #: view:res.lang:0 msgid "%w - Weekday number [0(Sunday),6]." -msgstr "" +msgstr "%w - Номер на ден от седмицата [0(Неделя),6]." #. module: base #: model:ir.actions.act_window,help:base.action_partner_form @@ -3594,6 +3646,8 @@ msgid "" "The user's timezone, used to perform timezone conversions between the server " "and the client." msgstr "" +"Часовата зона на потребителя се използва за да се прави конверсия между " +"сървър и клиент." #. module: base #: field:ir.module.module,demo:0 @@ -3608,7 +3662,7 @@ msgstr "английски (Великобритания)" #. module: base #: selection:base.language.install,lang:0 msgid "Japanese / 日本語" -msgstr "" +msgstr "Японски / 日本語" #. module: base #: help:workflow.transition,act_from:0 @@ -3647,7 +3701,7 @@ msgstr "английски (CA)" #. module: base #: model:ir.model,name:base.model_publisher_warranty_contract msgid "publisher_warranty.contract" -msgstr "" +msgstr "publisher_warranty.contract" #. module: base #: model:res.country,name:base.et @@ -3683,17 +3737,17 @@ msgstr "Групиране по" #: view:res.config:0 #: view:res.config.installer:0 msgid "title" -msgstr "" +msgstr "заглавие" #. module: base #: model:ir.model,name:base.model_base_language_install msgid "Install Language" -msgstr "" +msgstr "Инсталиране на език" #. module: base #: view:ir.translation:0 msgid "Translation" -msgstr "" +msgstr "Превод" #. module: base #: selection:res.request,state:0 @@ -3718,7 +3772,7 @@ msgstr "Запис на идентификатор" #. module: base #: model:ir.ui.menu,name:base.menu_product msgid "Products" -msgstr "" +msgstr "Продукти" #. module: base #: field:ir.actions.act_window,domain:0 @@ -3734,7 +3788,7 @@ msgstr "СМС конфигурация" #. module: base #: selection:base.language.install,lang:0 msgid "Spanish (BO) / Español (BO)" -msgstr "" +msgstr "Испански (BO) / Español (BO)" #. module: base #: model:ir.actions.act_window,name:base.ir_access_act @@ -3774,7 +3828,7 @@ msgstr "Инициализирай дата" #. module: base #: selection:base.language.install,lang:0 msgid "Gujarati / ગુજરાતી" -msgstr "" +msgstr "Гуджарати / ગુજરાતી" #. module: base #: code:addons/base/module/module.py:257 @@ -3799,6 +3853,7 @@ msgstr "Начало на процес" #, python-format msgid "module base cannot be loaded! (hint: verify addons-path)" msgstr "" +"Модулът base не може да бъде зареден! (подксазка: проверете пътя към Addons)" #. module: base #: view:res.partner.bank:0 @@ -3832,7 +3887,7 @@ msgstr "Гваделупа (Франция)" #: code:addons/base/res/res_lang.py:161 #, python-format msgid "User Error" -msgstr "" +msgstr "Потребителска грешка" #. module: base #: help:workflow.transition,signal:0 @@ -3845,7 +3900,7 @@ msgstr "" #. module: base #: help:multi_company.default,object_id:0 msgid "Object affected by this rule" -msgstr "" +msgstr "Обекти повлияни от това правило" #. module: base #: report:ir.module.reference.graph:0 @@ -3860,12 +3915,12 @@ msgstr "Име на меню" #. module: base #: view:ir.module.module:0 msgid "Author Website" -msgstr "" +msgstr "Уебсайт на автора" #. module: base #: view:ir.attachment:0 msgid "Month" -msgstr "" +msgstr "Месец" #. module: base #: model:res.country,name:base.my @@ -3876,7 +3931,7 @@ msgstr "Малайзия" #: view:base.language.install:0 #: model:ir.actions.act_window,name:base.action_view_base_language_install msgid "Load Official Translation" -msgstr "" +msgstr "Зареждане на официален превод" #. module: base #: model:ir.model,name:base.model_res_request_history @@ -3904,7 +3959,7 @@ msgstr "" #. module: base #: view:res.lang:0 msgid "%S - Seconds [00,61]." -msgstr "" +msgstr "%S - Секунди [00,61]." #. module: base #: model:res.country,name:base.cv @@ -3914,7 +3969,7 @@ msgstr "Кабо Верде" #. module: base #: view:base.module.import:0 msgid "Select module package to import (.zip file):" -msgstr "" +msgstr "Изберете пакета на модула за инсталация (.zip file):" #. module: base #: model:ir.actions.act_window,name:base.act_res_partner_event @@ -3933,13 +3988,14 @@ msgstr "ir.actions.url" #. module: base #: model:res.widget,title:base.currency_converter_widget msgid "Currency Converter" -msgstr "" +msgstr "Конвертор на валути" #. module: base #: code:addons/orm.py:156 #, python-format msgid "Wrong ID for the browse record, got %r, expected an integer." msgstr "" +"Грешен идентификатор на разглеждания запис, получено %r, очаквано цяло число" #. module: base #: model:ir.actions.act_window,name:base.action_partner_addess_tree @@ -3955,12 +4011,12 @@ msgstr "Брой добавени модули" #. module: base #: view:res.currency:0 msgid "Price Accuracy" -msgstr "" +msgstr "Прецизност на цените" #. module: base #: selection:base.language.install,lang:0 msgid "Latvian / latviešu valoda" -msgstr "" +msgstr "Латвийски / latviešu valoda" #. module: base #: view:res.config:0 @@ -3977,7 +4033,7 @@ msgstr "Френски / Français" #: code:addons/orm.py:1049 #, python-format msgid "The create method is not implemented on this object !" -msgstr "" +msgstr "Метода create не е реализиран за този обект !" #. module: base #: field:workflow.triggers,workitem_id:0 @@ -3987,7 +4043,7 @@ msgstr "Задача" #. module: base #: view:ir.actions.todo:0 msgid "Set as Todo" -msgstr "" +msgstr "Определи като \"Да се направи\"" #. module: base #: field:ir.actions.act_window.view,act_window_id:0 @@ -4013,12 +4069,12 @@ msgstr "ir.cron" #. module: base #: view:ir.rule:0 msgid "Combination of rules" -msgstr "" +msgstr "Комбинация от правила" #. module: base #: view:ir.sequence:0 msgid "Current Year without Century: %(y)s" -msgstr "" +msgstr "Текущата година без века: %(y)s" #. module: base #: field:ir.actions.server,trigger_obj_id:0 @@ -4028,7 +4084,7 @@ msgstr "Тригера включен" #. module: base #: sql_constraint:ir.rule:0 msgid "Rule must have at least one checked access right !" -msgstr "" +msgstr "Правилото трябва да има поне една отметка за право на достъп!" #. module: base #: model:res.country,name:base.fj @@ -4065,7 +4121,7 @@ msgstr "Менюта" #. module: base #: selection:base.language.install,lang:0 msgid "Serbian (Latin) / srpski" -msgstr "" +msgstr "Сръбски (Latin) / srpski" #. module: base #: model:res.country,name:base.il @@ -4120,7 +4176,7 @@ msgstr "Подпоследователност" #. module: base #: model:ir.model,name:base.model_res_config msgid "res.config" -msgstr "" +msgstr "res.config" #. module: base #: field:workflow.transition,signal:0 @@ -4138,7 +4194,7 @@ msgstr "Банки" #. module: base #: view:res.log:0 msgid "Unread" -msgstr "" +msgstr "Само непрочетени" #. module: base #: field:ir.cron,doall:0 @@ -4171,7 +4227,7 @@ msgstr "Обединено кралство" #: view:res.config.users:0 #: view:res.config.view:0 msgid "res_config_contents" -msgstr "" +msgstr "res_config_contents" #. module: base #: help:res.partner.category,active:0 @@ -4204,7 +4260,7 @@ msgstr "Добави автообновяване на изгледа" #. module: base #: help:res.partner,employee:0 msgid "Check this box if the partner is an Employee." -msgstr "" +msgstr "Отметнете ако контрагентът е служител." #. module: base #: field:ir.actions.report.xml,report_rml_content:0 @@ -4235,6 +4291,8 @@ msgid "" "You cannot perform this operation. New Record Creation is not allowed for " "this object as this object is for reporting purpose." msgstr "" +"Тази операция не може да бъде извършена. Не е разрешено създаването на нов " +"запис за този обект, защото е само с цел спавка." #. module: base #: view:base.language.import:0 @@ -4279,7 +4337,7 @@ msgstr "" #. module: base #: model:ir.ui.menu,name:base.menu_main_pm msgid "Project" -msgstr "" +msgstr "Проект" #. module: base #: field:ir.ui.menu,web_icon_hover_data:0 @@ -4289,28 +4347,28 @@ msgstr "" #. module: base #: view:base.module.import:0 msgid "Module file successfully imported!" -msgstr "" +msgstr "Модулът е успешно импортиран!" #. module: base #: selection:ir.actions.todo,state:0 msgid "Cancelled" -msgstr "" +msgstr "Отказани" #. module: base #: view:res.config.users:0 msgid "Create User" -msgstr "" +msgstr "Създаване на потребител" #. module: base #: view:partner.clear.ids:0 msgid "Want to Clear Ids ? " -msgstr "" +msgstr "Изкате да изчистите ID-тата ? " #. module: base #: field:publisher_warranty.contract,name:0 #: field:publisher_warranty.contract.wizard,name:0 msgid "Serial Key" -msgstr "" +msgstr "Сериен ключ" #. module: base #: selection:res.request,priority:0 @@ -4320,7 +4378,7 @@ msgstr "Нисък" #. module: base #: model:ir.ui.menu,name:base.menu_audit msgid "Audit" -msgstr "" +msgstr "Одит" #. module: base #: model:res.country,name:base.lc @@ -4342,7 +4400,7 @@ msgstr "" #. module: base #: field:res.partner,employee:0 msgid "Employee" -msgstr "" +msgstr "Служител" #. module: base #: field:ir.model.access,perm_create:0 @@ -4357,7 +4415,7 @@ msgstr "Област" #. module: base #: field:ir.actions.server,copy_object:0 msgid "Copy Of" -msgstr "" +msgstr "Копие на" #. module: base #: field:ir.model,osv_memory:0 @@ -4367,7 +4425,7 @@ msgstr "" #. module: base #: view:partner.clear.ids:0 msgid "Clear Ids" -msgstr "" +msgstr "Изисти Id-та" #. module: base #: model:res.country,name:base.io @@ -4379,7 +4437,7 @@ msgstr "Британска индоокеанска територия" #: field:res.config.view,view:0 #: field:res.users,view:0 msgid "Interface" -msgstr "" +msgstr "Интерфейс" #. module: base #: view:ir.actions.server:0 @@ -4389,7 +4447,7 @@ msgstr "Свързване на полета" #. module: base #: view:publisher_warranty.contract:0 msgid "Refresh Validation Dates" -msgstr "" +msgstr "Опресни датите на валидиране" #. module: base #: view:ir.model:0 @@ -4440,12 +4498,12 @@ msgstr "Подпис" #: code:addons/fields.py:664 #, python-format msgid "Not Implemented" -msgstr "" +msgstr "Не е внедрено" #. module: base #: model:ir.model,name:base.model_res_widget_user msgid "res.widget.user" -msgstr "" +msgstr "res.widget.user" #. module: base #: field:res.partner.category,complete_name:0 @@ -4455,7 +4513,7 @@ msgstr "Пълно име" #. module: base #: view:base.module.configuration:0 msgid "_Ok" -msgstr "" +msgstr "_Ok" #. module: base #: help:ir.filters,user_id:0 @@ -4466,7 +4524,7 @@ msgstr "" #: code:addons/base/module/module.py:198 #, python-format msgid "The name of the module must be unique !" -msgstr "" +msgstr "Името на модула трябва да бъде уникално!" #. module: base #: model:res.country,name:base.mz @@ -4476,7 +4534,7 @@ msgstr "Мозамбик" #. module: base #: model:ir.ui.menu,name:base.menu_project_long_term msgid "Long Term Planning" -msgstr "" +msgstr "Дългосрочно планиране" #. module: base #: field:ir.actions.server,message:0 @@ -4495,7 +4553,7 @@ msgstr "Върху множество документи" #: view:res.partner:0 #: field:res.partner,user_id:0 msgid "Salesman" -msgstr "" +msgstr "Търговец" #. module: base #: field:res.partner,address:0 @@ -4513,7 +4571,7 @@ msgstr "" #. module: base #: view:res.widget.wizard:0 msgid "Add" -msgstr "" +msgstr "Добави" #. module: base #: view:base.module.upgrade:0 @@ -4525,7 +4583,7 @@ msgstr "Приложи планираните обновявания" #. module: base #: view:res.widget:0 msgid "Widgets" -msgstr "" +msgstr "Добавки" #. module: base #: model:res.country,name:base.cz @@ -4535,7 +4593,7 @@ msgstr "Чехия" #. module: base #: view:res.widget.wizard:0 msgid "Widget Wizard" -msgstr "" +msgstr "Помощник за добавките" #. module: base #: model:ir.actions.act_window,help:base.act_ir_actions_todo_form @@ -4552,17 +4610,19 @@ msgid "" "Please use the change password wizard (in User Preferences or User menu) to " "change your own password." msgstr "" +"Моля, използвайте помощникът за промята на потребителска парола (в " +"Потребителски настройки или от меню Потребител) за да си смените пароалата." #. module: base #: code:addons/orm.py:1350 #, python-format msgid "Insufficient fields for Calendar View!" -msgstr "" +msgstr "Недостатъчни полета за Календарен изглед!" #. module: base #: selection:ir.property,type:0 msgid "Integer" -msgstr "" +msgstr "Цяло число" #. module: base #: help:ir.actions.report.xml,report_rml:0 @@ -4575,7 +4635,7 @@ msgstr "" #: help:res.config.users,company_id:0 #: help:res.users,company_id:0 msgid "The company this user is currently working for." -msgstr "" +msgstr "Фирмата, за която този потребител работи понастоящем." #. module: base #: model:ir.model,name:base.model_wizard_ir_model_menu_create @@ -4631,12 +4691,12 @@ msgstr "Затвори" #. module: base #: selection:base.language.install,lang:0 msgid "Spanish (MX) / Español (MX)" -msgstr "" +msgstr "Испански (MX) / Español (MX)" #. module: base #: view:res.log:0 msgid "My Logs" -msgstr "" +msgstr "Моите логове" #. module: base #: model:res.country,name:base.bt @@ -4646,7 +4706,7 @@ msgstr "Бутан" #. module: base #: help:ir.sequence,number_next:0 msgid "Next number of this sequence" -msgstr "" +msgstr "Следващ номер от този порядък" #. module: base #: model:res.partner.category,name:base.res_partner_category_11 @@ -4687,12 +4747,12 @@ msgstr "res.config.view" #: view:res.log:0 #: field:res.log,read:0 msgid "Read" -msgstr "" +msgstr "Прочитане" #. module: base #: sql_constraint:res.country:0 msgid "The name of the country must be unique !" -msgstr "" +msgstr "Името на държавата трябва да бъде уникално!" #. module: base #: model:ir.actions.act_window,help:base.action_country_state @@ -4732,7 +4792,7 @@ msgstr "Полета" #. module: base #: model:ir.actions.act_window,name:base.action_partner_employee_form msgid "Employees" -msgstr "" +msgstr "Служители" #. module: base #: help:res.log,read:0 @@ -4773,7 +4833,7 @@ msgstr "acc_number" #: model:ir.actions.act_window,name:base.action_partner_address_form #: model:ir.ui.menu,name:base.menu_partner_address_form msgid "Addresses" -msgstr "" +msgstr "Адреси" #. module: base #: model:res.country,name:base.mm @@ -4851,7 +4911,7 @@ msgstr "Допълнително поле" #. module: base #: field:ir.module.module,web:0 msgid "Has a web component" -msgstr "" +msgstr "Има уеб компонент" #. module: base #: model:res.country,name:base.cc @@ -4888,11 +4948,14 @@ msgid "" "\n" "This addon is already installed on your system" msgstr "" +"\n" +"\n" +"Тази добавка е вече инсталирана на вашата система" #. module: base #: help:ir.cron,interval_number:0 msgid "Repeat every x." -msgstr "" +msgstr "Повторение всеки x." #. module: base #: wizard_view:server.action.create,step_1:0 @@ -4908,7 +4971,7 @@ msgstr "1cm 28cm 20cm 28cm" #. module: base #: field:ir.module.module,maintainer:0 msgid "Maintainer" -msgstr "" +msgstr "Поддържащ" #. module: base #: field:ir.sequence,suffix:0 @@ -4938,7 +5001,7 @@ msgstr "Поле на Обекта" #. module: base #: selection:base.language.install,lang:0 msgid "Spanish (PE) / Español (PE)" -msgstr "" +msgstr "Испански (PE) / Español (PE)" #. module: base #: selection:base.language.install,lang:0 @@ -4952,17 +5015,19 @@ msgid "" "If specified, this action will be opened at logon for this user, in addition " "to the standard menu." msgstr "" +"Ако е оказано, това действи ще бъде отворено при вход на този потребител в " +"добавка на стандартното меню." #. module: base #: view:ir.values:0 msgid "Client Actions" -msgstr "" +msgstr "Действия на клиент" #. module: base #: code:addons/orm.py:1806 #, python-format msgid "The exists method is not implemented on this object !" -msgstr "" +msgstr "Съществуващият метод не е вграден в този обект!" #. module: base #: code:addons/base/module/module.py:336 @@ -4987,7 +5052,7 @@ msgstr "Свързване на събития с действие" #. module: base #: model:ir.model,name:base.model_base_update_translations msgid "base.update.translations" -msgstr "" +msgstr "base.update.translations" #. module: base #: field:ir.module.category,parent_id:0 @@ -5070,7 +5135,7 @@ msgstr "" #. module: base #: selection:ir.property,type:0 msgid "Many2One" -msgstr "" +msgstr "Много кън един" #. module: base #: model:res.country,name:base.ng @@ -5086,7 +5151,7 @@ msgstr "" #. module: base #: model:ir.actions.act_window,name:base.action_partner_sms_send msgid "SMS Send" -msgstr "" +msgstr "Изпращане на SMS" #. module: base #: field:res.company,user_ids:0 @@ -5096,7 +5161,7 @@ msgstr "Одобрени потребители" #. module: base #: field:ir.ui.menu,web_icon_data:0 msgid "Web Icon Image" -msgstr "" +msgstr "Уеб икона" #. module: base #: view:ir.values:0 @@ -5150,7 +5215,7 @@ msgstr "2. %a ,%A ==> Пет, Петък" #. module: base #: field:res.widget,content:0 msgid "Content" -msgstr "" +msgstr "Съдържание" #. module: base #: help:ir.rule,global:0 @@ -5191,7 +5256,7 @@ msgstr "Доминика" #: sql_constraint:publisher_warranty.contract:0 msgid "" "Your publisher warranty contract is already subscribed in the system !" -msgstr "" +msgstr "Вече ви е вписан гаранционния в договор в системата" #. module: base #: help:ir.cron,nextcall:0 @@ -5202,7 +5267,7 @@ msgstr "" #: help:res.config.users,view:0 #: help:res.users,view:0 msgid "Choose between the simplified interface and the extended one" -msgstr "" +msgstr "Изберете между опростен и разширен интерфейс" #. module: base #: model:res.country,name:base.np @@ -5355,12 +5420,12 @@ msgstr "_Затвори" #. module: base #: field:multi_company.default,company_dest_id:0 msgid "Default Company" -msgstr "" +msgstr "Фирма подразбиране" #. module: base #: selection:base.language.install,lang:0 msgid "Spanish (EC) / Español (EC)" -msgstr "" +msgstr "Испански (EC) / Español (EC)" #. module: base #: help:ir.ui.view,xml_id:0 @@ -5371,7 +5436,7 @@ msgstr "" #: model:ir.model,name:base.model_base_module_import #: model:ir.ui.menu,name:base.menu_view_base_module_import msgid "Import Module" -msgstr "" +msgstr "Импортиране на модул" #. module: base #: model:res.country,name:base.as @@ -5420,7 +5485,7 @@ msgstr "Повтаряне" #: code:addons/orm.py:3532 #, python-format msgid "UserError" -msgstr "" +msgstr "Потребителска грешка" #. module: base #: model:res.country,name:base.ae @@ -5475,7 +5540,7 @@ msgstr "AccessError" #. module: base #: view:res.request:0 msgid "Waiting" -msgstr "" +msgstr "Изчакване" #. module: base #: code:addons/__init__.py:834 @@ -5492,12 +5557,12 @@ msgstr "8. %I:%M:%S %p ==> 06:25:20 PM" #: code:addons/orm.py:1803 #, python-format msgid "The copy method is not implemented on this object !" -msgstr "" +msgstr "Метода copy не е реализиран за този обект !" #. module: base #: field:res.log,create_date:0 msgid "Creation Date" -msgstr "" +msgstr "Дата на създаване" #. module: base #: view:ir.translation:0 @@ -5513,7 +5578,7 @@ msgstr "Брой на остъпката" #. module: base #: view:ir.actions.report.xml:0 msgid "Report" -msgstr "" +msgstr "Справка" #. module: base #: model:res.country,name:base.ua @@ -5534,7 +5599,7 @@ msgstr "Категория на модула" #. module: base #: view:partner.wizard.ean.check:0 msgid "Ignore" -msgstr "" +msgstr "Пренебрегване" #. module: base #: report:ir.module.reference.graph:0 @@ -5544,7 +5609,7 @@ msgstr "Съответстващо упътване" #. module: base #: view:ir.ui.view:0 msgid "Architecture" -msgstr "" +msgstr "Архитектура" #. module: base #: model:res.country,name:base.ml @@ -5629,7 +5694,7 @@ msgstr "Потребителски клавишни комбинации" #. module: base #: selection:base.language.install,lang:0 msgid "Vietnamese / Tiếng Việt" -msgstr "" +msgstr "Виетнамски / Tiếng Việt" #. module: base #: model:res.country,name:base.dz @@ -5700,7 +5765,7 @@ msgstr "" #: code:addons/fields.py:103 #, python-format msgid "Not implemented get_memory method !" -msgstr "" +msgstr "Методът get_memory не е реализиран !" #. module: base #: view:ir.actions.server:0 @@ -5747,17 +5812,17 @@ msgstr "Неутрална зона" #. module: base #: selection:base.language.install,lang:0 msgid "Hindi / हिंदी" -msgstr "" +msgstr "Хинди / हिंदी" #. module: base #: view:ir.model:0 msgid "Custom" -msgstr "" +msgstr "Персонализиран" #. module: base #: view:res.request:0 msgid "Current" -msgstr "" +msgstr "Текущ" #. module: base #: model:res.partner.category,name:base.res_partner_category_9 @@ -5799,7 +5864,7 @@ msgstr "" #. module: base #: selection:publisher_warranty.contract.wizard,state:0 msgid "Finished" -msgstr "" +msgstr "Завършен" #. module: base #: model:res.country,name:base.de @@ -5883,12 +5948,12 @@ msgstr "" #. module: base #: field:base.language.import,name:0 msgid "Language Name" -msgstr "" +msgstr "Име на език" #. module: base #: selection:ir.property,type:0 msgid "Boolean" -msgstr "" +msgstr "Булев тип" #. module: base #: view:ir.model:0 @@ -5909,7 +5974,7 @@ msgstr "Описание на полетата" #: view:res.partner.address:0 #: view:workflow.activity:0 msgid "Group By..." -msgstr "" +msgstr "Групиране по..." #. module: base #: view:ir.model.fields:0 @@ -6037,7 +6102,7 @@ msgstr "" #. module: base #: selection:base.language.install,lang:0 msgid "Spanish (CO) / Español (CO)" -msgstr "" +msgstr "Испански (CO) / Español (CO)" #. module: base #: view:base.module.configuration:0 @@ -6054,7 +6119,7 @@ msgstr "Създай" #. module: base #: view:ir.sequence:0 msgid "Current Year with Century: %(year)s" -msgstr "" +msgstr "Текущата година с века: %(year)s" #. module: base #: field:ir.exports,export_fields:0 @@ -6069,7 +6134,7 @@ msgstr "Франция" #. module: base #: model:ir.model,name:base.model_res_log msgid "res.log" -msgstr "" +msgstr "res.log" #. module: base #: help:ir.translation,module:0 @@ -6119,7 +6184,7 @@ msgstr "Вид" #: code:addons/orm.py:3775 #, python-format msgid "This method does not exist anymore" -msgstr "" +msgstr "Методът повече не съществува" #. module: base #: field:res.bank,fax:0 @@ -6159,17 +6224,17 @@ msgstr "res.request" #. module: base #: view:ir.model:0 msgid "In Memory" -msgstr "" +msgstr "В паметта" #. module: base #: view:ir.actions.todo:0 msgid "Todo" -msgstr "" +msgstr "Да се направи" #. module: base #: field:ir.attachment,datas:0 msgid "File Content" -msgstr "" +msgstr "Съдържание на файл" #. module: base #: model:res.country,name:base.pa @@ -6191,7 +6256,7 @@ msgstr "" #: constraint:res.config.users:0 #: constraint:res.users:0 msgid "The chosen company is not in the allowed companies for this user" -msgstr "" +msgstr "Избраната фирма не е измежду разрешените фирми за този потребител" #. module: base #: model:res.country,name:base.gi @@ -6201,7 +6266,7 @@ msgstr "Гибралтар" #. module: base #: field:ir.actions.report.xml,report_name:0 msgid "Service Name" -msgstr "" +msgstr "Име на услуга" #. module: base #: model:res.country,name:base.pn @@ -6224,7 +6289,7 @@ msgstr "Правила на записа" #: field:res.config.users,name:0 #: field:res.users,name:0 msgid "User Name" -msgstr "" +msgstr "Име на потребител" #. module: base #: view:ir.sequence:0 @@ -6263,7 +6328,7 @@ msgstr "Изглед при търсене" #. module: base #: sql_constraint:res.lang:0 msgid "The code of the language must be unique !" -msgstr "" +msgstr "Кодът на езика трябва да бъде уникален!" #. module: base #: model:ir.actions.act_window,name:base.action_attachment @@ -6278,7 +6343,7 @@ msgstr "Прикачени файлове" #: model:ir.ui.menu,name:base.menu_sale_config_sales #: model:ir.ui.menu,name:base.menu_sales msgid "Sales" -msgstr "" +msgstr "Продажби" #. module: base #: field:ir.actions.server,child_ids:0 @@ -6306,7 +6371,7 @@ msgstr "Права за запис" #. module: base #: view:res.lang:0 msgid "%m - Month number [01,12]." -msgstr "" +msgstr "%m - Месец номер [01,12]." #. module: base #: field:res.bank,city:0 @@ -6330,7 +6395,7 @@ msgstr "Италия" #: view:ir.actions.todo:0 #: selection:ir.actions.todo,state:0 msgid "To Do" -msgstr "" +msgstr "Трябва да се направи" #. module: base #: selection:base.language.install,lang:0 @@ -6342,7 +6407,7 @@ msgstr "естонски / Eesti keel" #: field:res.partner,email:0 #: field:res.users,email:0 msgid "E-mail" -msgstr "" +msgstr "Имейл" #. module: base #: selection:ir.module.module,license:0 @@ -6364,7 +6429,7 @@ msgstr "Английски (Съединени Щати)" #: view:ir.model.data:0 #: model:ir.ui.menu,name:base.ir_model_data_menu msgid "Object Identifiers" -msgstr "" +msgstr "Идентификатори на обект" #. module: base #: model:ir.actions.act_window,help:base.action_partner_title_partner @@ -6403,7 +6468,7 @@ msgstr "Инсталирана версия" #. module: base #: selection:base.language.install,lang:0 msgid "Mongolian / монгол" -msgstr "" +msgstr "Монголски / монгол" #. module: base #: model:res.country,name:base.mr @@ -6418,7 +6483,7 @@ msgstr "ir.translation" #. module: base #: view:base.module.update:0 msgid "Module update result" -msgstr "" +msgstr "Резултат от ъпдейт на модул" #. module: base #: view:workflow.activity:0 @@ -6435,12 +6500,12 @@ msgstr "Пощенски адрес" #. module: base #: field:res.company,parent_id:0 msgid "Parent Company" -msgstr "Родителска компания" +msgstr "Фирма майка" #. module: base #: selection:base.language.install,lang:0 msgid "Spanish (CR) / Español (CR)" -msgstr "" +msgstr "Испански (CR) / Español (CR)" #. module: base #: field:res.currency.rate,rate:0 @@ -6465,7 +6530,7 @@ msgstr "Стойност по подразбиране" #. module: base #: model:ir.ui.menu,name:base.menu_tools msgid "Tools" -msgstr "" +msgstr "Инструменти" #. module: base #: model:res.country,name:base.kn @@ -6525,7 +6590,7 @@ msgstr "Икона" #. module: base #: help:ir.model.fields,model_id:0 msgid "The model this field belongs to" -msgstr "" +msgstr "Модел към, който това поле принадлежи" #. module: base #: model:res.country,name:base.mq @@ -6604,13 +6669,13 @@ msgstr "Проблем в конфигурацията 'Record Id' в Дейст #: code:addons/orm.py:2316 #, python-format msgid "ValidateError" -msgstr "" +msgstr "Грешка при валидиране" #. module: base #: view:base.module.import:0 #: view:base.module.update:0 msgid "Open Modules" -msgstr "" +msgstr "Отваряне на модули" #. module: base #: model:ir.actions.act_window,help:base.action_res_bank_form @@ -6644,7 +6709,7 @@ msgstr "Лаос" #: field:res.config.users,user_email:0 #: field:res.users,user_email:0 msgid "Email" -msgstr "Ел. поща" +msgstr "Имейл" #. module: base #: field:res.config.users,action_id:0 @@ -6659,6 +6724,8 @@ msgid "" "The sum of the data (2nd field) is null.\n" "We can't draw a pie chart !" msgstr "" +"Сумата на данните (2то поле) е нищо (null)\n" +"Не може да начертае кръгова диаграма." #. module: base #: model:ir.ui.menu,name:base.menu_lunch_reporting @@ -6670,7 +6737,7 @@ msgstr "" #: model:ir.ui.menu,name:base.next_id_73 #: model:ir.ui.menu,name:base.reporting_menu msgid "Reporting" -msgstr "" +msgstr "Отчитане" #. module: base #: model:res.country,name:base.tg @@ -6696,7 +6763,7 @@ msgstr "" #. module: base #: view:ir.model.data:0 msgid "Updatable" -msgstr "" +msgstr "Обновим" #. module: base #: view:res.lang:0 @@ -6711,7 +6778,7 @@ msgstr "Каскадно" #. module: base #: field:workflow.transition,group_id:0 msgid "Group Required" -msgstr "" +msgstr "Изисква се група" #. module: base #: view:ir.actions.configuration.wizard:0 @@ -6738,7 +6805,7 @@ msgstr "" #. module: base #: view:base.module.upgrade:0 msgid "Start update" -msgstr "" +msgstr "Започване на обновяване" #. module: base #: code:addons/base/publisher_warranty/publisher_warranty.py:144 @@ -6781,7 +6848,7 @@ msgstr "ir.ui.view" #. module: base #: constraint:res.partner:0 msgid "Error ! You can not create recursive associated members." -msgstr "" +msgstr "Грешка ! Не може да създадете рекурсивно свързани членове" #. module: base #: help:res.lang,code:0 @@ -6796,7 +6863,7 @@ msgstr "OpenERP партньори" #. module: base #: model:ir.ui.menu,name:base.menu_hr_manager msgid "HR Manager Dashboard" -msgstr "" +msgstr "Табло мениджър ЧР" #. module: base #: code:addons/base/module/module.py:253 @@ -6808,7 +6875,7 @@ msgstr "" #. module: base #: view:ir.module.module:0 msgid "Search modules" -msgstr "" +msgstr "Търси в модули" #. module: base #: model:res.country,name:base.by @@ -6848,13 +6915,13 @@ msgstr "Улица2" #. module: base #: model:ir.actions.act_window,name:base.action_view_base_module_update msgid "Module Update" -msgstr "" +msgstr "Обновяване на модул" #. module: base #: code:addons/base/module/wizard/base_module_upgrade.py:95 #, python-format msgid "Following modules are not installed or unknown: %s" -msgstr "" +msgstr "Следните модули са непознати или не са инсталирани: %s" #. module: base #: view:ir.cron:0 @@ -6883,7 +6950,7 @@ msgstr "Отвори прозорец" #. module: base #: field:ir.actions.act_window,auto_search:0 msgid "Auto Search" -msgstr "" +msgstr "Автоматично търсене" #. module: base #: field:ir.actions.act_window,filter:0 @@ -6893,7 +6960,7 @@ msgstr "Филтър" #. module: base #: model:res.partner.title,shortcut:base.res_partner_title_madam msgid "Ms." -msgstr "" +msgstr "Г-жа" #. module: base #: model:res.country,name:base.ch @@ -6923,13 +6990,15 @@ msgstr "Toчност на закръгляване" #. module: base #: view:base.language.install:0 msgid "Load" -msgstr "" +msgstr "Зареждане" #. module: base #: help:res.config.users,name:0 #: help:res.users,name:0 msgid "The new user's real name, used for searching and most listings" msgstr "" +"Истинското име на нов потребител, използвано в последствие за търсене в " +"повечето списъци" #. module: base #: code:addons/osv.py:154 @@ -6947,7 +7016,7 @@ msgstr "" #: code:addons/base/ir/ir_model.py:223 #, python-format msgid "Size of the field can never be less than 1 !" -msgstr "" +msgstr "Рамерът на полето никога не може да бъде по-малко от 1!" #. module: base #: model:res.country,name:base.so @@ -6957,7 +7026,7 @@ msgstr "Сомалия" #. module: base #: selection:publisher_warranty.contract,state:0 msgid "Terminated" -msgstr "" +msgstr "Прекратен" #. module: base #: model:res.partner.category,name:base.res_partner_category_13 @@ -6986,17 +7055,17 @@ msgstr "Аргументи" #: code:addons/orm.py:716 #, python-format msgid "Database ID doesn't exist: %s : %s" -msgstr "" +msgstr "База данни ID не съществува: %s : %s" #. module: base #: selection:ir.module.module,license:0 msgid "GPL Version 2" -msgstr "" +msgstr "GPL Версия 2" #. module: base #: selection:ir.module.module,license:0 msgid "GPL Version 3" -msgstr "" +msgstr "GPL Version 3" #. module: base #: code:addons/orm.py:836 @@ -7007,13 +7076,13 @@ msgstr "" #. module: base #: view:partner.wizard.ean.check:0 msgid "Correct EAN13" -msgstr "" +msgstr "Коректен EAN13" #. module: base #: code:addons/orm.py:2317 #, python-format msgid "The value \"%s\" for the field \"%s\" is not in the selection" -msgstr "" +msgstr "Стойността \"%s\" за поле \"%s\" не е в селекцията" #. module: base #: field:res.partner,customer:0 @@ -7026,7 +7095,7 @@ msgstr "Клиент" #. module: base #: selection:base.language.install,lang:0 msgid "Spanish (NI) / Español (NI)" -msgstr "" +msgstr "Испански (NI) / Español (NI)" #. module: base #: field:ir.module.module,shortdesc:0 @@ -7047,7 +7116,7 @@ msgstr "Час 00->24: %(h24)" #. module: base #: field:ir.cron,nextcall:0 msgid "Next Execution Date" -msgstr "" +msgstr "Дата на следващо изпълнение" #. module: base #: help:multi_company.default,field_id:0 @@ -7089,7 +7158,7 @@ msgstr "Тунис" #. module: base #: model:ir.ui.menu,name:base.menu_mrp_root msgid "Manufacturing" -msgstr "" +msgstr "Производство" #. module: base #: model:res.country,name:base.km @@ -7111,7 +7180,7 @@ msgstr "Прекъсни инсталацията" #. module: base #: field:ir.model.fields,selection:0 msgid "Selection Options" -msgstr "" +msgstr "Опции за селекция" #. module: base #: field:res.partner.category,parent_right:0 @@ -7126,7 +7195,7 @@ msgstr "Легенда на форматите за дата и време" #. module: base #: selection:ir.actions.server,state:0 msgid "Copy Object" -msgstr "" +msgstr "Копиране на обекта" #. module: base #: code:addons/base/res/res_user.py:581 @@ -7134,6 +7203,8 @@ msgstr "" msgid "" "Group(s) cannot be deleted, because some user(s) still belong to them: %s !" msgstr "" +"Групата(s) не може да бъде изтрита, защото има потребители, които и " +"принадлежат(s) все още: %s !" #. module: base #: model:ir.actions.act_window,name:base.action_country_state @@ -7204,7 +7275,7 @@ msgstr "Минута: %(min)s" #: model:ir.actions.act_window,name:base.action_wizard_update_translations #: model:ir.ui.menu,name:base.menu_wizard_update_translations msgid "Synchronize Translations" -msgstr "" +msgstr "Синхронизиране на преводи" #. module: base #: model:ir.ui.menu,name:base.next_id_10 @@ -7217,6 +7288,8 @@ msgid "" "Number of time the function is called,\n" "a negative number indicates no limit" msgstr "" +"Брой пъти за извикване на функция,\n" +"отрицателно число означава без лимит" #. module: base #: code:addons/base/ir/ir_model.py:331 @@ -7235,12 +7308,12 @@ msgstr "Потребителска справка" #: code:addons/base/res/res_user.py:580 #, python-format msgid "Warning !" -msgstr "" +msgstr "Предупреждение !" #. module: base #: model:res.widget,title:base.google_maps_widget msgid "Google Maps" -msgstr "" +msgstr "Google Maps" #. module: base #: model:ir.ui.menu,name:base.menu_base_config @@ -7329,7 +7402,7 @@ msgstr "Състояние" #. module: base #: selection:base.language.install,lang:0 msgid "Galician / Galego" -msgstr "" +msgstr "Галски / Galego" #. module: base #: model:res.country,name:base.no @@ -7350,7 +7423,7 @@ msgstr "Зареждане на официален превод" #. module: base #: view:res.currency:0 msgid "Miscelleanous" -msgstr "" +msgstr "Разни" #. module: base #: model:res.partner.category,name:base.res_partner_category_10 @@ -7381,12 +7454,12 @@ msgstr "workflow.triggers" #: code:addons/base/ir/ir_model.py:62 #, python-format msgid "Invalid search criterions" -msgstr "" +msgstr "Невалидни критерии за търсене" #. module: base #: view:ir.attachment:0 msgid "Created" -msgstr "" +msgstr "Създаден" #. module: base #: help:ir.actions.wizard,multi:0 @@ -7448,7 +7521,7 @@ msgstr "" #: model:ir.actions.act_window,name:base.action_view_base_import_language #: model:ir.ui.menu,name:base.menu_view_base_import_language msgid "Import Translation" -msgstr "" +msgstr "Импортиране на превод" #. module: base #: field:res.partner.bank.type,field_ids:0 @@ -7466,7 +7539,7 @@ msgstr "Категория" #: selection:ir.attachment,type:0 #: selection:ir.property,type:0 msgid "Binary" -msgstr "" +msgstr "двоичен" #. module: base #: field:ir.actions.server,sms:0 @@ -7482,7 +7555,7 @@ msgstr "Коста Рика" #. module: base #: view:workflow.activity:0 msgid "Conditions" -msgstr "" +msgstr "Условия" #. module: base #: model:ir.actions.act_window,name:base.action_partner_other_form @@ -7499,7 +7572,7 @@ msgstr "Валути" #. module: base #: sql_constraint:res.groups:0 msgid "The name of the group must be unique !" -msgstr "" +msgstr "Името на групата трябва да бъде уникално!" #. module: base #: view:ir.sequence:0 @@ -7546,12 +7619,12 @@ msgstr "10. %S ==> 20" #: code:addons/fields.py:106 #, python-format msgid "undefined get method !" -msgstr "" +msgstr "непознат метод get!" #. module: base #: selection:base.language.install,lang:0 msgid "Norwegian Bokmål / Norsk bokmål" -msgstr "" +msgstr "Норвежки Bokmål / Norsk bokmål" #. module: base #: help:res.config.users,new_password:0 @@ -7574,7 +7647,7 @@ msgstr "Естония" #. module: base #: model:ir.ui.menu,name:base.dashboard msgid "Dashboards" -msgstr "" +msgstr "Табла" #. module: base #: help:ir.attachment,type:0 @@ -7585,7 +7658,7 @@ msgstr "" #: field:res.config.users,new_password:0 #: field:res.users,new_password:0 msgid "Change password" -msgstr "" +msgstr "Променя на паролата" #. module: base #: model:res.country,name:base.nl @@ -7625,7 +7698,7 @@ msgstr "" #: model:ir.ui.menu,name:base.menu_emails #: model:ir.ui.menu,name:base.menu_mail_gateway msgid "Emails" -msgstr "" +msgstr "Имейли" #. module: base #: model:res.country,name:base.cd @@ -7702,7 +7775,7 @@ msgstr "Python код за изпълнение" #. module: base #: sql_constraint:res.country:0 msgid "The code of the country must be unique !" -msgstr "" +msgstr "Kодът на държавата трябва да бъде уникален!" #. module: base #: selection:ir.module.module.dependency,state:0 @@ -7723,7 +7796,7 @@ msgstr "Тригер" #. module: base #: model:ir.model,name:base.model_base_module_update msgid "Update Module" -msgstr "" +msgstr "Обновяване на модул" #. module: base #: view:ir.model.fields:0 @@ -7783,7 +7856,7 @@ msgstr "Доставчици" #. module: base #: view:publisher_warranty.contract.wizard:0 msgid "Register" -msgstr "" +msgstr "Регистриране" #. module: base #: field:res.request,ref_doc2:0 @@ -7861,12 +7934,12 @@ msgstr "От" #. module: base #: view:res.users:0 msgid "Preferences" -msgstr "" +msgstr "Предпочитания" #. module: base #: model:res.partner.category,name:base.res_partner_category_consumers0 msgid "Consumers" -msgstr "" +msgstr "Потребители" #. module: base #: view:res.config:0 @@ -7892,7 +7965,7 @@ msgstr "" #. module: base #: view:ir.actions.report.xml:0 msgid "Miscellaneous" -msgstr "" +msgstr "Разни" #. module: base #: model:res.country,name:base.cn @@ -8024,7 +8097,7 @@ msgstr "" #. module: base #: selection:base.language.install,lang:0 msgid "Slovak / Slovenský jazyk" -msgstr "" +msgstr "Словашки / Slovenský jazyk" #. module: base #: field:base.language.export,state:0 @@ -8036,7 +8109,7 @@ msgstr "неизвестен" #. module: base #: field:res.currency,symbol:0 msgid "Symbol" -msgstr "" +msgstr "Символ" #. module: base #: help:res.config.users,login:0 @@ -8047,7 +8120,7 @@ msgstr "" #. module: base #: view:base.update.translations:0 msgid "Synchronize Translation" -msgstr "" +msgstr "Синхронизиране на превод" #. module: base #: field:ir.ui.view_sc,res_id:0 @@ -8067,7 +8140,7 @@ msgstr "Ирак" #. module: base #: model:ir.ui.menu,name:base.menu_association msgid "Association" -msgstr "" +msgstr "Асоциация" #. module: base #: model:res.country,name:base.cl @@ -8079,7 +8152,7 @@ msgstr "Чили" #: model:ir.ui.menu,name:base.menu_config_address_book #: model:ir.ui.menu,name:base.menu_procurement_management_supplier msgid "Address Book" -msgstr "" +msgstr "Адресна книга" #. module: base #: model:ir.model,name:base.model_ir_sequence_type @@ -8094,7 +8167,7 @@ msgstr "CSV Файл" #. module: base #: field:res.company,account_no:0 msgid "Account No." -msgstr "" +msgstr "Сметка No." #. module: base #: code:addons/base/res/res_lang.py:157 @@ -8206,7 +8279,7 @@ msgstr "" #. module: base #: selection:ir.ui.view,type:0 msgid "Diagram" -msgstr "" +msgstr "Диаграма" #. module: base #: help:multi_company.default,name:0 @@ -8217,7 +8290,7 @@ msgstr "" #: model:ir.actions.act_window,name:base.grant_menu_access #: model:ir.ui.menu,name:base.menu_grant_menu_access msgid "Menu Items" -msgstr "" +msgstr "Елементи в менюто" #. module: base #: constraint:ir.rule:0 @@ -8228,7 +8301,7 @@ msgstr "" #: model:ir.ui.menu,name:base.menu_event_association #: model:ir.ui.menu,name:base.menu_event_main msgid "Events Organisation" -msgstr "" +msgstr "Организация на събития" #. module: base #: model:ir.actions.act_window,name:base.ir_sequence_actions @@ -8335,7 +8408,7 @@ msgstr "датски / Dansk" #. module: base #: selection:ir.model.fields,select_level:0 msgid "Advanced Search (deprecated)" -msgstr "" +msgstr "Разширено търсене (deprecated)" #. module: base #: model:res.country,name:base.cx @@ -8350,7 +8423,7 @@ msgstr "Конфигурация на други действия" #. module: base #: view:res.config.installer:0 msgid "Install Modules" -msgstr "" +msgstr "Инсталиране на модули" #. module: base #: model:ir.actions.act_window,name:base.res_partner_canal-act @@ -8363,7 +8436,7 @@ msgstr "Канали" #. module: base #: view:ir.ui.view:0 msgid "Extra Info" -msgstr "" +msgstr "Допълнителна информация" #. module: base #: model:ir.actions.act_window,name:base.act_values_form_action @@ -8379,7 +8452,7 @@ msgstr "Инсталирай" #. module: base #: model:ir.model,name:base.model_partner_wizard_ean_check msgid "Ean Check" -msgstr "" +msgstr "Проверка на EAN" #. module: base #: sql_constraint:res.config.users:0 @@ -8401,7 +8474,7 @@ msgstr "Изпрати" #: field:res.config.users,menu_tips:0 #: field:res.users,menu_tips:0 msgid "Menu Tips" -msgstr "" +msgstr "Подсказки на менютата" #. module: base #: field:ir.translation,src:0 @@ -8441,14 +8514,14 @@ msgstr "Започни настройката" #. module: base #: view:base.language.export:0 msgid "_Export" -msgstr "" +msgstr "_Експортиране" #. module: base #: field:base.language.install,state:0 #: field:base.module.import,state:0 #: field:base.module.update,state:0 msgid "state" -msgstr "" +msgstr "състояние" #. module: base #: selection:base.language.install,lang:0 @@ -8463,7 +8536,7 @@ msgstr "Доминиканска република" #. module: base #: selection:base.language.install,lang:0 msgid "Serbian (Cyrillic) / српски" -msgstr "" +msgstr "Сръбски (Cyrillic) / српски" #. module: base #: code:addons/orm.py:2161 @@ -8495,13 +8568,13 @@ msgstr "Зависимо поле" #. module: base #: view:res.partner.event:0 msgid "Event Logs" -msgstr "" +msgstr "Логове на събития" #. module: base #: code:addons/base/module/wizard/base_module_configuration.py:37 #, python-format msgid "System Configuration done" -msgstr "" +msgstr "Сисемната настройка е готова" #. module: base #: field:workflow.triggers,instance_id:0 @@ -8550,14 +8623,14 @@ msgstr "" #: code:addons/base/ir/ir_ui_menu.py:285 #, python-format msgid "Error ! You can not create recursive Menu." -msgstr "" +msgstr "Грешка! Не можете да създавате рекурсивни менюта." #. module: base #: model:ir.actions.act_window,name:base.action_publisher_warranty_contract_add_wizard #: model:ir.ui.menu,name:base.menu_publisher_warranty_contract_add #: view:publisher_warranty.contract.wizard:0 msgid "Register a Contract" -msgstr "" +msgstr "Регистриране на договор" #. module: base #: view:ir.rule:0 @@ -8615,12 +8688,12 @@ msgstr "" #. module: base #: selection:base.language.install,lang:0 msgid "Romanian / română" -msgstr "" +msgstr "Румънци / română" #. module: base #: view:res.log:0 msgid "System Logs" -msgstr "" +msgstr "Системни логове" #. module: base #: selection:workflow.activity,join_mode:0 @@ -8736,7 +8809,7 @@ msgstr "" #. module: base #: selection:base.language.install,lang:0 msgid "Persian / فارس" -msgstr "" +msgstr "Фарси / فارس" #. module: base #: view:ir.actions.act_window:0 @@ -8755,6 +8828,8 @@ msgid "" "Supported file formats: *.csv (Comma-separated values) or *.po (GetText " "Portable Objects)" msgstr "" +"Поддържани файлови формати: *.csv (Comma-separated values) или *.po (GetText " +"Portable Objects)" #. module: base #: code:addons/base/ir/ir_model.py:487 @@ -8763,11 +8838,13 @@ msgid "" "You can not delete this document (%s) ! Be sure your user belongs to one of " "these groups: %s." msgstr "" +"Не може да бъде изтрит този документ (%s)! Уверете се, че като потребител " +"принадлежите на някоя от следните групи: %s." #. module: base #: model:ir.model,name:base.model_base_module_configuration msgid "base.module.configuration" -msgstr "" +msgstr "base.module.configuration" #. module: base #: field:base.language.export,name:0 @@ -8836,7 +8913,7 @@ msgstr "Фирма" #. module: base #: view:res.users:0 msgid "Email & Signature" -msgstr "" +msgstr "Имейл и подпис" #. module: base #: view:publisher_warranty.contract:0 @@ -8851,12 +8928,12 @@ msgstr "" #. module: base #: model:ir.ui.menu,name:base.menu_aftersale msgid "After-Sale Services" -msgstr "" +msgstr "След гаранционно обслужване." #. module: base #: view:ir.actions.todo:0 msgid "Launch" -msgstr "" +msgstr "Стартиране" #. module: base #: field:ir.actions.act_window,limit:0 @@ -8907,7 +8984,7 @@ msgstr "Вирджински острови (Великобритания)" #: view:ir.property:0 #: model:ir.ui.menu,name:base.next_id_15 msgid "Parameters" -msgstr "" +msgstr "Параметри" #. module: base #: selection:base.language.install,lang:0 @@ -9014,7 +9091,7 @@ msgstr "Име на категория" #. module: base #: model:res.partner.category,name:base.res_partner_category_15 msgid "IT sector" -msgstr "" +msgstr "Сектор ИТ" #. module: base #: view:ir.actions.act_window:0 @@ -9029,7 +9106,7 @@ msgstr "%X - Правилно представяне на времето." #. module: base #: selection:base.language.install,lang:0 msgid "Spanish (SV) / Español (SV)" -msgstr "" +msgstr "Испански (SV) / Español (SV)" #. module: base #: help:res.lang,grouping:0 @@ -9108,7 +9185,7 @@ msgstr "Режим на разделяне" #. module: base #: view:base.module.upgrade:0 msgid "Note that this operation might take a few minutes." -msgstr "" +msgstr "Имайте в предвид, че тази операция може да отнеме няколко минути." #. module: base #: model:ir.ui.menu,name:base.menu_localisation @@ -9123,7 +9200,7 @@ msgstr "Действие за стартиране" #. module: base #: view:ir.cron:0 msgid "Execution" -msgstr "" +msgstr "Изпълнение" #. module: base #: field:ir.actions.server,condition:0 @@ -9161,7 +9238,7 @@ msgstr "" #. module: base #: view:res.lang:0 msgid "%j - Day of the year [001,366]." -msgstr "" +msgstr "%j - Ден от годината [001,366]." #. module: base #: field:ir.actions.server,mobile:0 @@ -9180,7 +9257,7 @@ msgstr "Категории на партньора" #. module: base #: view:base.module.upgrade:0 msgid "System Update" -msgstr "" +msgstr "Системна актуализация" #. module: base #: selection:ir.translation,type:0 @@ -9233,7 +9310,7 @@ msgstr "" #. module: base #: model:ir.actions.act_window,name:base.action_res_widget_wizard msgid "Homepage Widgets Management" -msgstr "" +msgstr "Управление на притурките на началната страница" #. module: base #: field:workflow,osv:0 @@ -9256,12 +9333,12 @@ msgstr "Функция" #. module: base #: view:res.widget:0 msgid "Search Widget" -msgstr "" +msgstr "Търси добавка" #. module: base #: selection:ir.actions.todo,restart:0 msgid "Never" -msgstr "" +msgstr "Никога" #. module: base #: selection:res.partner.address,type:0 @@ -9304,7 +9381,7 @@ msgstr "Създай обект" #: view:ir.filters:0 #: field:res.log,context:0 msgid "Context" -msgstr "" +msgstr "Съдържание" #. module: base #: field:res.bank,bic:0 diff --git a/bin/addons/base/i18n/bs.po b/bin/addons/base/i18n/bs.po index 6de94b82f8f..c85db96d9d0 100644 --- a/bin/addons/base/i18n/bs.po +++ b/bin/addons/base/i18n/bs.po @@ -13,8 +13,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2011-02-16 04:50+0000\n" -"X-Generator: Launchpad (build 12351)\n" +"X-Launchpad-Export-Date: 2011-04-09 04:49+0000\n" +"X-Generator: Launchpad (build 12735)\n" #. module: base #: view:ir.filters:0 diff --git a/bin/addons/base/i18n/ca.po b/bin/addons/base/i18n/ca.po index 6074d5f6059..50d6366292c 100644 --- a/bin/addons/base/i18n/ca.po +++ b/bin/addons/base/i18n/ca.po @@ -13,8 +13,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2011-02-16 04:51+0000\n" -"X-Generator: Launchpad (build 12351)\n" +"X-Launchpad-Export-Date: 2011-04-09 04:50+0000\n" +"X-Generator: Launchpad (build 12735)\n" #. module: base #: view:ir.filters:0 @@ -47,7 +47,7 @@ msgid "" "The second argument of the many2many field %s must be a SQL table !You used " "%s, which is not a valid SQL table name." msgstr "" -"El segon argument del camp many2many %s ha de ser una taula SQL! Has " +"El segon argument del camp many2many %s ha de ser una taula SQL! Heu " "utilitzat %s, que no és un nom de taula SQL vàlid." #. module: base @@ -1683,7 +1683,7 @@ msgid "" "'calendar', etc. (Default: tree,form)" msgstr "" "Llista separada per comes de les maneres de vista permesos, com 'form' " -"(formulari), 'tree' (llista), 'calendar' (calendari), etc (per defecte: " +"(formulari), 'tree' (llista), 'calendar' (calendari), etc. (per defecte: " "tree, form)" #. module: base @@ -2201,7 +2201,7 @@ msgid "" msgstr "" "S'ha indicat un \"order\" no vàlid. Una especificació \"order\" vàlida és " "una llista separada per comes de noms de camps vàlids (opcionalment seguits " -"per asc / desc per indicar l'adreça)" +"per asc / desc per indicar la direcció)" #. module: base #: model:ir.model,name:base.model_ir_module_module_dependency @@ -6040,8 +6040,8 @@ msgid "" "View type: set to 'tree' for a hierarchical tree view, or 'form' for other " "views" msgstr "" -"Tipus de vista: 'tree' per a una vista d'arbre jeràrquica, o 'form' per a " -"les altres vistes." +"Tipus de vista: 'Arbre' per a una vista d'arbre jeràrquica, o 'Formulari' " +"per a les altres vistes." #. module: base #: code:addons/base/res/res_config.py:421 diff --git a/bin/addons/base/i18n/cs.po b/bin/addons/base/i18n/cs.po index 09ba35712b5..5ef4fd42337 100644 --- a/bin/addons/base/i18n/cs.po +++ b/bin/addons/base/i18n/cs.po @@ -13,8 +13,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2011-02-16 04:51+0000\n" -"X-Generator: Launchpad (build 12351)\n" +"X-Launchpad-Export-Date: 2011-04-09 04:50+0000\n" +"X-Generator: Launchpad (build 12735)\n" #. module: base #: view:ir.filters:0 diff --git a/bin/addons/base/i18n/da.po b/bin/addons/base/i18n/da.po index df9927cfeb8..4f1a81e8101 100644 --- a/bin/addons/base/i18n/da.po +++ b/bin/addons/base/i18n/da.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2011-02-16 04:51+0000\n" -"X-Generator: Launchpad (build 12351)\n" +"X-Launchpad-Export-Date: 2011-04-09 04:50+0000\n" +"X-Generator: Launchpad (build 12735)\n" #. module: base #: view:ir.filters:0 diff --git a/bin/addons/base/i18n/de.po b/bin/addons/base/i18n/de.po index 8ad09db8a9a..6f16b160580 100644 --- a/bin/addons/base/i18n/de.po +++ b/bin/addons/base/i18n/de.po @@ -15,8 +15,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2011-02-16 04:52+0000\n" -"X-Generator: Launchpad (build 12351)\n" +"X-Launchpad-Export-Date: 2011-04-09 04:51+0000\n" +"X-Generator: Launchpad (build 12735)\n" #. module: base #: view:ir.filters:0 @@ -1095,7 +1095,7 @@ msgid "" "which gives the correct address" msgstr "" "Stellt das Feld zur Verfügung, aus dem die EMail Adresse geholt wird, zB für " -"eine Rechung (invoice), dann bringt ist `object.invoice_address_id.email` " +"eine Rechnung (invoice), dann bringt ist `object.invoice_address_id.email` " "das Fehld mit der richtigen Adresse" #. module: base @@ -3437,7 +3437,7 @@ msgid "" "the correct mobile number" msgstr "" "Stellt das Feld für die Mobiltelefon Nummer zur Verfügung. z.B. für " -"Rechungen (invoice) wird das Feld `object.invoice_address_id.mobile` die " +"Rechnungen (invoice) wird das Feld `object.invoice_address_id.mobile` die " "richtige Mobiltelefonnummer anzeigen." #. module: base @@ -5293,7 +5293,7 @@ msgstr "Hong Kong" msgid "Easy to Refer action by name e.g. One Sales Order -> Many Invoices" msgstr "" "Einfache Bezugnahme von Aktionen mittels Namen. Ein Verkaufsauftrag -> Viele " -"Rechungen." +"Rechnungen." #. module: base #: model:ir.actions.act_window,help:base.action_partner_address_form diff --git a/bin/addons/base/i18n/el.po b/bin/addons/base/i18n/el.po index 1e229abf51b..119131b5c99 100644 --- a/bin/addons/base/i18n/el.po +++ b/bin/addons/base/i18n/el.po @@ -12,8 +12,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2011-02-16 04:52+0000\n" -"X-Generator: Launchpad (build 12351)\n" +"X-Launchpad-Export-Date: 2011-04-09 04:52+0000\n" +"X-Generator: Launchpad (build 12735)\n" "X-Poedit-Country: GREECE\n" "X-Poedit-Language: Greek\n" "X-Poedit-SourceCharset: utf-8\n" diff --git a/bin/addons/base/i18n/en_GB.po b/bin/addons/base/i18n/en_GB.po index 8a31de5308f..5ccc7a440b8 100644 --- a/bin/addons/base/i18n/en_GB.po +++ b/bin/addons/base/i18n/en_GB.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2011-02-16 04:58+0000\n" -"X-Generator: Launchpad (build 12351)\n" +"X-Launchpad-Export-Date: 2011-04-09 04:57+0000\n" +"X-Generator: Launchpad (build 12735)\n" #. module: base #: view:ir.filters:0 diff --git a/bin/addons/base/i18n/es.po b/bin/addons/base/i18n/es.po index 09fb78d8a4b..844ecca994f 100644 --- a/bin/addons/base/i18n/es.po +++ b/bin/addons/base/i18n/es.po @@ -13,8 +13,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2011-02-16 04:56+0000\n" -"X-Generator: Launchpad (build 12351)\n" +"X-Launchpad-Export-Date: 2011-04-09 04:55+0000\n" +"X-Generator: Launchpad (build 12735)\n" #. module: base #: view:ir.filters:0 @@ -1691,7 +1691,7 @@ msgid "" "'calendar', etc. (Default: tree,form)" msgstr "" "Lista separada por comas de los modos de vista permitidos, como 'form' " -"(formulario), 'tree' (lista), 'calendar' (calendario), etc (por defecto: " +"(formulario), 'tree' (lista), 'calendar' (calendario), etc. (por defecto: " "tree,form)" #. module: base @@ -4869,7 +4869,7 @@ msgstr "res.config.vista" #: view:res.log:0 #: field:res.log,read:0 msgid "Read" -msgstr "Lectura" +msgstr "Leído" #. module: base #: sql_constraint:res.country:0 @@ -6054,8 +6054,8 @@ msgid "" "View type: set to 'tree' for a hierarchical tree view, or 'form' for other " "views" msgstr "" -"Tipo de vista: 'tree' para una vista de árbol jerárquica, o 'form' para las " -"otras vistas." +"Tipo de vista: 'Árbol' para una vista de árbol jerárquica, o 'Formulario' " +"para las otras vistas." #. module: base #: code:addons/base/res/res_config.py:421 diff --git a/bin/addons/base/i18n/es_CL.po b/bin/addons/base/i18n/es_CL.po index d6581c0cd5f..79375bd3876 100644 --- a/bin/addons/base/i18n/es_CL.po +++ b/bin/addons/base/i18n/es_CL.po @@ -13,8 +13,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2011-02-16 04:58+0000\n" -"X-Generator: Launchpad (build 12351)\n" +"X-Launchpad-Export-Date: 2011-04-09 04:57+0000\n" +"X-Generator: Launchpad (build 12735)\n" #. module: base #: view:ir.filters:0 diff --git a/bin/addons/base/i18n/es_EC.po b/bin/addons/base/i18n/es_EC.po index a704ddfba1d..a46ebe723d3 100644 --- a/bin/addons/base/i18n/es_EC.po +++ b/bin/addons/base/i18n/es_EC.po @@ -13,8 +13,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2011-02-16 04:59+0000\n" -"X-Generator: Launchpad (build 12351)\n" +"X-Launchpad-Export-Date: 2011-04-09 04:58+0000\n" +"X-Generator: Launchpad (build 12735)\n" #. module: base #: view:ir.filters:0 diff --git a/bin/addons/base/i18n/et.po b/bin/addons/base/i18n/et.po index 4c06d246420..3590c222e88 100644 --- a/bin/addons/base/i18n/et.po +++ b/bin/addons/base/i18n/et.po @@ -13,8 +13,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2011-02-16 04:51+0000\n" -"X-Generator: Launchpad (build 12351)\n" +"X-Launchpad-Export-Date: 2011-04-09 04:51+0000\n" +"X-Generator: Launchpad (build 12735)\n" #. module: base #: view:ir.filters:0 @@ -78,7 +78,7 @@ msgstr "Töövoog" #. module: base #: view:partner.sms.send:0 msgid "SMS - Gateway: clickatell" -msgstr "SMS - Värav: click" +msgstr "SMS-lüüs" #. module: base #: selection:base.language.install,lang:0 @@ -98,7 +98,7 @@ msgstr "" #. module: base #: field:ir.actions.server,wkf_model_id:0 msgid "Workflow On" -msgstr "Töövoog millel" +msgstr "Töövoog sisse lülitatud" #. module: base #: field:ir.actions.act_window,display_menu_tip:0 @@ -129,7 +129,7 @@ msgstr "" #. module: base #: field:res.partner,ref:0 msgid "Reference" -msgstr "" +msgstr "Viide" #. module: base #: field:ir.actions.act_window,target:0 @@ -140,7 +140,7 @@ msgstr "Sihtaken" #: code:addons/base/res/res_user.py:507 #, python-format msgid "Warning!" -msgstr "" +msgstr "Hoiatus!" #. module: base #: code:addons/base/ir/ir_model.py:304 @@ -154,7 +154,7 @@ msgstr "" #: code:addons/osv.py:133 #, python-format msgid "Constraint Error" -msgstr "" +msgstr "Piirangu viga" #. module: base #: model:ir.model,name:base.model_ir_ui_view_custom @@ -171,12 +171,12 @@ msgstr "Svaasimaa" #: code:addons/orm.py:3653 #, python-format msgid "created." -msgstr "" +msgstr "loodud." #. module: base #: model:res.partner.category,name:base.res_partner_category_woodsuppliers0 msgid "Wood Suppliers" -msgstr "" +msgstr "Puidu tarnijad" #. module: base #: code:addons/base/module/module.py:303 @@ -214,7 +214,7 @@ msgstr "Otsi partnerit" #: code:addons/base/res/res_user.py:132 #, python-format msgid "\"smtp_server\" needs to be set to send mails to users" -msgstr "" +msgstr "\"smtp_server\" peab olema määratud, et saata e-posti kasutajatele" #. module: base #: code:addons/base/module/wizard/base_export_language.py:60 @@ -245,7 +245,7 @@ msgstr "Maks. suurus" #. module: base #: field:res.partner.address,name:0 msgid "Contact Name" -msgstr "Kontakti nimi" +msgstr "Kontaktnimi" #. module: base #: code:addons/base/module/wizard/base_export_language.py:56 @@ -254,13 +254,13 @@ msgid "" "Save this document to a %s file and edit it with a specific software or a " "text editor. The file encoding is UTF-8." msgstr "" -"Salvest see dokument %s faili ja muuda seda spetsiaaltarkvaraga või " +"Salvesta see dokument %s faili ja muuda seda spetsiaaltarkvaraga või " "tekstiredaktoriga. Faili kodeering on UTF-8." #. module: base #: sql_constraint:res.lang:0 msgid "The name of the language must be unique !" -msgstr "" +msgstr "Keele nimi peab olema unikaalne" #. module: base #: selection:res.request,state:0 @@ -286,12 +286,12 @@ msgstr "Krediidilimiit" #. module: base #: field:ir.model.data,date_update:0 msgid "Update Date" -msgstr "Uuendamise kuupäev" +msgstr "" #. module: base #: view:ir.attachment:0 msgid "Owner" -msgstr "" +msgstr "Omanik" #. module: base #: field:ir.actions.act_window,src_model:0 @@ -312,7 +312,7 @@ msgstr "ir.ui.view_sc" #: field:res.widget.user,widget_id:0 #: field:res.widget.wizard,widgets_list:0 msgid "Widget" -msgstr "" +msgstr "Vidin" #. module: base #: view:ir.model.access:0 @@ -378,7 +378,7 @@ msgstr "Prantsuse Guyana" #. module: base #: selection:base.language.install,lang:0 msgid "Greek / Ελληνικά" -msgstr "Greeka / Ελληνικά" +msgstr "Kreeka / Ελληνικά" #. module: base #: selection:base.language.install,lang:0 @@ -398,12 +398,12 @@ msgstr "" #: code:addons/orm.py:904 #, python-format msgid "The read method is not implemented on this object !" -msgstr "" +msgstr "Lugemise meetod pole toetatud sellel objektil!" #. module: base #: help:res.lang,iso_code:0 msgid "This ISO code is the name of po files to use for translations" -msgstr "" +msgstr "See ISO kood on PO-faili nimi mida kasutatakse tõlgeteks" #. module: base #: view:base.module.upgrade:0 @@ -429,7 +429,7 @@ msgstr "Kolumbia" #. module: base #: view:ir.module.module:0 msgid "Schedule Upgrade" -msgstr "Planeeri uuendamisele" +msgstr "Planeeri uuendus" #. module: base #: code:addons/orm.py:838 @@ -449,7 +449,7 @@ msgstr "" #. module: base #: model:res.country,name:base.pw msgid "Palau" -msgstr "Palau" +msgstr "Belau" #. module: base #: view:res.partner:0 @@ -459,7 +459,7 @@ msgstr "Müügid ja ostud" #. module: base #: view:ir.translation:0 msgid "Untranslated" -msgstr "" +msgstr "Tõlkimata" #. module: base #: help:ir.actions.act_window,context:0 @@ -477,7 +477,7 @@ msgstr "Nõustajad" #. module: base #: model:res.partner.category,name:base.res_partner_category_miscellaneoussuppliers0 msgid "Miscellaneous Suppliers" -msgstr "" +msgstr "Täiendavad pakkujad" #. module: base #: code:addons/base/ir/ir_model.py:255 @@ -493,7 +493,7 @@ msgstr "Vali toimingu aken, aruanne, nõustaja mis käivitada" #. module: base #: view:res.config.users:0 msgid "New User" -msgstr "" +msgstr "Uus kasutaja" #. module: base #: view:base.language.export:0 @@ -524,7 +524,7 @@ msgstr "Jordaania" #. module: base #: view:ir.module.module:0 msgid "Certified" -msgstr "" +msgstr "Sertifitseeritud" #. module: base #: model:res.country,name:base.er @@ -535,7 +535,7 @@ msgstr "Eritrea" #: view:res.config:0 #: view:res.config.installer:0 msgid "description" -msgstr "" +msgstr "kirjeldus" #. module: base #: model:ir.ui.menu,name:base.menu_base_action_rule @@ -555,7 +555,7 @@ msgstr "" #. module: base #: field:ir.values,key2:0 msgid "Event Type" -msgstr "Sündmuse tüüp" +msgstr "Sündmuse liik" #. module: base #: view:base.language.export:0 @@ -568,7 +568,7 @@ msgstr "" #. module: base #: field:res.partner,title:0 msgid "Partner Form" -msgstr "" +msgstr "Partneri vorm" #. module: base #: selection:base.language.install,lang:0 @@ -601,7 +601,7 @@ msgstr "Jadad" #. module: base #: model:ir.model,name:base.model_base_language_import msgid "Language Import" -msgstr "" +msgstr "Keele import" #. module: base #: model:ir.model,name:base.model_res_config_users @@ -611,12 +611,12 @@ msgstr "" #. module: base #: selection:base.language.install,lang:0 msgid "Albanian / Shqip" -msgstr "" +msgstr "Albaania / Shqip" #. module: base #: model:ir.ui.menu,name:base.menu_crm_config_opportunity msgid "Opportunities" -msgstr "" +msgstr "Võimalused" #. module: base #: model:ir.model,name:base.model_base_language_export @@ -626,17 +626,18 @@ msgstr "" #. module: base #: model:res.country,name:base.pg msgid "Papua New Guinea" -msgstr "Papua Uus Guinea" +msgstr "Paapua Uus-Guinea" #. module: base #: help:ir.actions.report.xml,report_type:0 msgid "Report Type, e.g. pdf, html, raw, sxw, odt, html2html, mako2html, ..." msgstr "" +"Aruande tüüp, näiteks pdf, html, raw, sxw, odt, html2html, mako2html, ..." #. module: base #: model:res.partner.category,name:base.res_partner_category_4 msgid "Basic Partner" -msgstr "Elementaarne klient" +msgstr "Tavaline partner" #. module: base #: report:ir.module.reference.graph:0 @@ -651,7 +652,7 @@ msgstr "Minu partnerid" #. module: base #: view:ir.actions.report.xml:0 msgid "XML Report" -msgstr "" +msgstr "XML aruanne" #. module: base #: model:res.country,name:base.es @@ -673,7 +674,7 @@ msgstr "" #: model:ir.actions.act_window,name:base.action_view_base_module_upgrade #: model:ir.model,name:base.model_base_module_upgrade msgid "Module Upgrade" -msgstr "" +msgstr "Mooduli uuendus" #. module: base #: view:res.config.users:0 diff --git a/bin/addons/base/i18n/eu.po b/bin/addons/base/i18n/eu.po index 2ed8a74d1eb..3dbadd6a886 100644 --- a/bin/addons/base/i18n/eu.po +++ b/bin/addons/base/i18n/eu.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2011-02-16 04:50+0000\n" -"X-Generator: Launchpad (build 12351)\n" +"X-Launchpad-Export-Date: 2011-04-09 04:49+0000\n" +"X-Generator: Launchpad (build 12735)\n" #. module: base #: view:ir.filters:0 diff --git a/bin/addons/base/i18n/fa.po b/bin/addons/base/i18n/fa.po index fb6603e327d..e4b5dd3395f 100644 --- a/bin/addons/base/i18n/fa.po +++ b/bin/addons/base/i18n/fa.po @@ -9,8 +9,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2011-02-16 04:54+0000\n" -"X-Generator: Launchpad (build 12351)\n" +"X-Launchpad-Export-Date: 2011-04-09 04:54+0000\n" +"X-Generator: Launchpad (build 12735)\n" "X-Poedit-Country: IRAN, ISLAMIC REPUBLIC OF\n" "X-Poedit-Language: Persian\n" diff --git a/bin/addons/base/i18n/fa_AF.po b/bin/addons/base/i18n/fa_AF.po index e16edeb2999..83780362eca 100644 --- a/bin/addons/base/i18n/fa_AF.po +++ b/bin/addons/base/i18n/fa_AF.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2011-03-05 04:52+0000\n" -"X-Generator: Launchpad (build 12351)\n" +"X-Launchpad-Export-Date: 2011-04-09 04:58+0000\n" +"X-Generator: Launchpad (build 12735)\n" #. module: base #: view:ir.filters:0 diff --git a/bin/addons/base/i18n/fi.po b/bin/addons/base/i18n/fi.po index f503be3f4c8..32e145c153f 100644 --- a/bin/addons/base/i18n/fi.po +++ b/bin/addons/base/i18n/fi.po @@ -13,8 +13,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2011-02-16 04:51+0000\n" -"X-Generator: Launchpad (build 12351)\n" +"X-Launchpad-Export-Date: 2011-04-09 04:51+0000\n" +"X-Generator: Launchpad (build 12735)\n" #. module: base #: view:ir.filters:0 diff --git a/bin/addons/base/i18n/fr.po b/bin/addons/base/i18n/fr.po index 064f5b00010..11a14a34072 100644 --- a/bin/addons/base/i18n/fr.po +++ b/bin/addons/base/i18n/fr.po @@ -13,8 +13,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2011-02-16 04:52+0000\n" -"X-Generator: Launchpad (build 12351)\n" +"X-Launchpad-Export-Date: 2011-04-09 04:51+0000\n" +"X-Generator: Launchpad (build 12735)\n" #. module: base #: view:ir.filters:0 @@ -917,7 +917,7 @@ msgstr "Ouganda" #. module: base #: field:ir.model.access,perm_unlink:0 msgid "Delete Access" -msgstr "Supprimer l'accès" +msgstr "Accès en suppression" #. module: base #: model:res.country,name:base.ne @@ -3780,6 +3780,8 @@ msgid "" "For one2many fields, the field on the target model that implement the " "opposite many2one relationship" msgstr "" +"Pour les champs one2many, le champ du modèle cible qui réalise la relation " +"many2one correspondante" #. module: base #: model:ir.model,name:base.model_ir_actions_act_window_view @@ -5264,8 +5266,8 @@ msgstr "Nigéria" #, python-format msgid "For selection fields, the Selection Options must be given!" msgstr "" -"Pour les champs de sélection, les valeurs pour la sélection doivent être " -"renseignées !" +"Pour les champs de type liste déroulante, les valeurs de la liste doivent " +"être fournies !" #. module: base #: model:ir.actions.act_window,name:base.action_partner_sms_send diff --git a/bin/addons/base/i18n/gl.po b/bin/addons/base/i18n/gl.po index 083b4b2ca91..8be8f25f964 100644 --- a/bin/addons/base/i18n/gl.po +++ b/bin/addons/base/i18n/gl.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2011-02-16 04:52+0000\n" -"X-Generator: Launchpad (build 12351)\n" +"X-Launchpad-Export-Date: 2011-04-09 04:51+0000\n" +"X-Generator: Launchpad (build 12735)\n" #. module: base #: view:ir.filters:0 diff --git a/bin/addons/base/i18n/he.po b/bin/addons/base/i18n/he.po index d98869ddb97..47696150834 100644 --- a/bin/addons/base/i18n/he.po +++ b/bin/addons/base/i18n/he.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2011-02-16 04:52+0000\n" -"X-Generator: Launchpad (build 12351)\n" +"X-Launchpad-Export-Date: 2011-04-09 04:52+0000\n" +"X-Generator: Launchpad (build 12735)\n" #. module: base #: view:ir.filters:0 diff --git a/bin/addons/base/i18n/hr.po b/bin/addons/base/i18n/hr.po index d24adffc0b0..f5e875a42c1 100644 --- a/bin/addons/base/i18n/hr.po +++ b/bin/addons/base/i18n/hr.po @@ -13,8 +13,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2011-02-16 04:56+0000\n" -"X-Generator: Launchpad (build 12351)\n" +"X-Launchpad-Export-Date: 2011-04-09 04:55+0000\n" +"X-Generator: Launchpad (build 12735)\n" "Language: hr\n" #. module: base @@ -435,7 +435,7 @@ msgstr "Postavi za nadogradnju" #: code:addons/orm.py:838 #, python-format msgid "Key/value '%s' not found in selection field '%s'" -msgstr "" +msgstr "Ključ/podatak '%s' nije nađen u selekciji polja '%s'" #. module: base #: help:res.country,code:0 diff --git a/bin/addons/base/i18n/hu.po b/bin/addons/base/i18n/hu.po index 5a4532d093d..48d704160e7 100644 --- a/bin/addons/base/i18n/hu.po +++ b/bin/addons/base/i18n/hu.po @@ -13,8 +13,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2011-03-04 04:44+0000\n" -"X-Generator: Launchpad (build 12351)\n" +"X-Launchpad-Export-Date: 2011-04-09 04:52+0000\n" +"X-Generator: Launchpad (build 12735)\n" #. module: base #: view:ir.filters:0 diff --git a/bin/addons/base/i18n/id.po b/bin/addons/base/i18n/id.po index 92b79dd7f7a..784609da885 100644 --- a/bin/addons/base/i18n/id.po +++ b/bin/addons/base/i18n/id.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2011-02-23 04:36+0000\n" -"X-Generator: Launchpad (build 12351)\n" +"X-Launchpad-Export-Date: 2011-04-09 04:52+0000\n" +"X-Generator: Launchpad (build 12735)\n" #. module: base #: view:ir.filters:0 diff --git a/bin/addons/base/i18n/is.po b/bin/addons/base/i18n/is.po index b0e655cc1db..de51518f8d8 100644 --- a/bin/addons/base/i18n/is.po +++ b/bin/addons/base/i18n/is.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2011-02-16 04:53+0000\n" -"X-Generator: Launchpad (build 12351)\n" +"X-Launchpad-Export-Date: 2011-04-09 04:52+0000\n" +"X-Generator: Launchpad (build 12735)\n" #. module: base #: view:ir.filters:0 diff --git a/bin/addons/base/i18n/it.po b/bin/addons/base/i18n/it.po index 5e89132d6b2..4b658e70064 100644 --- a/bin/addons/base/i18n/it.po +++ b/bin/addons/base/i18n/it.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2011-03-31 04:35+0000\n" -"X-Generator: Launchpad (build 12559)\n" +"X-Launchpad-Export-Date: 2011-04-09 04:53+0000\n" +"X-Generator: Launchpad (build 12735)\n" #. module: base #: view:ir.filters:0 @@ -6446,7 +6446,7 @@ msgstr "" #: model:ir.actions.act_window,name:base.action_rule #: model:ir.ui.menu,name:base.menu_action_rule msgid "Record Rules" -msgstr "Registra Regole" +msgstr "Regole di accesso" #. module: base #: field:res.config.users,name:0 diff --git a/bin/addons/base/i18n/ja.po b/bin/addons/base/i18n/ja.po index 9b3978c44c5..0d71b875f72 100644 --- a/bin/addons/base/i18n/ja.po +++ b/bin/addons/base/i18n/ja.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2011-02-16 04:53+0000\n" -"X-Generator: Launchpad (build 12351)\n" +"X-Launchpad-Export-Date: 2011-04-09 04:53+0000\n" +"X-Generator: Launchpad (build 12735)\n" #. module: base #: view:ir.filters:0 diff --git a/bin/addons/base/i18n/ko.po b/bin/addons/base/i18n/ko.po index a1b575f18be..ae16ee197a6 100644 --- a/bin/addons/base/i18n/ko.po +++ b/bin/addons/base/i18n/ko.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2011-02-16 04:53+0000\n" -"X-Generator: Launchpad (build 12351)\n" +"X-Launchpad-Export-Date: 2011-04-09 04:53+0000\n" +"X-Generator: Launchpad (build 12735)\n" #. module: base #: view:ir.filters:0 @@ -34,7 +34,7 @@ msgstr "세인트 헬레나" #. module: base #: view:ir.actions.report.xml:0 msgid "Other Configuration" -msgstr "" +msgstr "기타 설정" #. module: base #: selection:ir.property,type:0 @@ -104,7 +104,7 @@ msgstr "워크플로우" #. module: base #: field:ir.actions.act_window,display_menu_tip:0 msgid "Display Menu Tips" -msgstr "" +msgstr "메뉴 팁 나타내기" #. module: base #: view:ir.module.module:0 @@ -130,7 +130,7 @@ msgstr "" #. module: base #: field:res.partner,ref:0 msgid "Reference" -msgstr "" +msgstr "참조" #. module: base #: field:ir.actions.act_window,target:0 @@ -141,7 +141,7 @@ msgstr "타겟 윈도우" #: code:addons/base/res/res_user.py:507 #, python-format msgid "Warning!" -msgstr "" +msgstr "경고!" #. module: base #: code:addons/base/ir/ir_model.py:304 @@ -149,13 +149,13 @@ msgstr "" msgid "" "Properties of base fields cannot be altered in this manner! Please modify " "them through Python code, preferably through a custom addon!" -msgstr "" +msgstr "기본 필드의 속성은 이 방법으로 변경이 안됩니다. 가급적 커스텀 부가기능으로 파이썬 코드를 수정하세요" #. module: base #: code:addons/osv.py:133 #, python-format msgid "Constraint Error" -msgstr "" +msgstr "제한에러" #. module: base #: model:ir.model,name:base.model_ir_ui_view_custom @@ -172,12 +172,12 @@ msgstr "" #: code:addons/orm.py:3653 #, python-format msgid "created." -msgstr "" +msgstr "생성됨." #. module: base #: model:res.partner.category,name:base.res_partner_category_woodsuppliers0 msgid "Wood Suppliers" -msgstr "" +msgstr "목재 공급자" #. module: base #: code:addons/base/module/module.py:303 @@ -186,6 +186,8 @@ msgid "" "Some installed modules depend on the module you plan to Uninstall :\n" " %s" msgstr "" +"인스톨된 모듈이 언인스톨 하는 모듈에 의존합니다:\n" +" %s" #. module: base #: field:ir.sequence,number_increment:0 @@ -206,7 +208,7 @@ msgstr "" #. module: base #: view:res.partner:0 msgid "Search Partner" -msgstr "" +msgstr "거래처 검색" #. module: base #: code:addons/base/res/res_user.py:132 @@ -287,7 +289,7 @@ msgstr "날짜 갱신" #. module: base #: view:ir.attachment:0 msgid "Owner" -msgstr "" +msgstr "소유자" #. module: base #: field:ir.actions.act_window,src_model:0 @@ -308,7 +310,7 @@ msgstr "" #: field:res.widget.user,widget_id:0 #: field:res.widget.wizard,widgets_list:0 msgid "Widget" -msgstr "" +msgstr "위젯" #. module: base #: view:ir.model.access:0 @@ -333,7 +335,7 @@ msgstr "액션 타입 선택" #. module: base #: model:res.country,name:base.tv msgid "Tuvalu" -msgstr "" +msgstr "투발루어" #. module: base #: selection:ir.model,state:0 @@ -354,7 +356,7 @@ msgstr "이메일" #. module: base #: model:res.country,name:base.an msgid "Netherlands Antilles" -msgstr "" +msgstr "네덜란드령 안틸레스" #. module: base #: code:addons/base/res/res_user.py:389 @@ -368,17 +370,17 @@ msgstr "" #. module: base #: model:res.country,name:base.gf msgid "French Guyana" -msgstr "" +msgstr "프랑스 가이아나" #. module: base #: selection:base.language.install,lang:0 msgid "Greek / Ελληνικά" -msgstr "" +msgstr "그리스" #. module: base #: selection:base.language.install,lang:0 msgid "Bosnian / bosanski jezik" -msgstr "" +msgstr "보스니아" #. module: base #: help:ir.actions.report.xml,attachment_use:0 @@ -396,12 +398,12 @@ msgstr "이 읽기 방식은 이 오브젝트에 적용되지 않음!" #. module: base #: help:res.lang,iso_code:0 msgid "This ISO code is the name of po files to use for translations" -msgstr "" +msgstr "이 ISO 코드는 번역에 사용될 po 파일이름 입니다." #. module: base #: view:base.module.upgrade:0 msgid "Your system will be updated." -msgstr "" +msgstr "시스템이 업데이트 됩니다" #. module: base #: field:ir.actions.todo,note:0 @@ -417,7 +419,7 @@ msgstr "국가 이름" #. module: base #: model:res.country,name:base.co msgid "Colombia" -msgstr "" +msgstr "콜롬비아" #. module: base #: view:ir.module.module:0 @@ -428,7 +430,7 @@ msgstr "스케줄 업그레이드" #: code:addons/orm.py:838 #, python-format msgid "Key/value '%s' not found in selection field '%s'" -msgstr "" +msgstr "'%s' 값이 '%s' 필드에 없습니다" #. module: base #: help:res.country,code:0 @@ -440,7 +442,7 @@ msgstr "두 문자로된 ISO 국가 코드" #. module: base #: model:res.country,name:base.pw msgid "Palau" -msgstr "" +msgstr "팔라우" #. module: base #: view:res.partner:0 @@ -450,13 +452,13 @@ msgstr "판매 및 구매" #. module: base #: view:ir.translation:0 msgid "Untranslated" -msgstr "" +msgstr "번역되지 않음" #. module: base #: help:ir.actions.act_window,context:0 msgid "" "Context dictionary as Python expression, empty by default (Default: {})" -msgstr "" +msgstr "파이썬 문법의 컨텍스트 사전, 디폴트: 비움 (Default:{})" #. module: base #: model:ir.actions.act_window,name:base.ir_action_wizard @@ -468,7 +470,7 @@ msgstr "위저드" #. module: base #: model:res.partner.category,name:base.res_partner_category_miscellaneoussuppliers0 msgid "Miscellaneous Suppliers" -msgstr "" +msgstr "기타 공급처" #. module: base #: code:addons/base/ir/ir_model.py:255 @@ -484,7 +486,7 @@ msgstr "액션 창, 리포트, 실행할 위저드를 선택하십시오." #. module: base #: view:res.config.users:0 msgid "New User" -msgstr "" +msgstr "새 사용자" #. module: base #: view:base.language.export:0 @@ -500,7 +502,7 @@ msgstr "모델 설명" #: help:ir.actions.act_window,src_model:0 msgid "" "Optional model name of the objects on which this action should be visible" -msgstr "" +msgstr "이 액션이 노출되는 오브젝트의 모델이름 (옵션)" #. module: base #: field:workflow.transition,trigger_expr_id:0 @@ -510,28 +512,28 @@ msgstr "트리거 표현식" #. module: base #: model:res.country,name:base.jo msgid "Jordan" -msgstr "" +msgstr "요르단" #. module: base #: view:ir.module.module:0 msgid "Certified" -msgstr "" +msgstr "인증됨" #. module: base #: model:res.country,name:base.er msgid "Eritrea" -msgstr "" +msgstr "에리트레아" #. module: base #: view:res.config:0 #: view:res.config.installer:0 msgid "description" -msgstr "" +msgstr "설명" #. module: base #: model:ir.ui.menu,name:base.menu_base_action_rule msgid "Automated Actions" -msgstr "" +msgstr "자동화 액션" #. module: base #: model:ir.model,name:base.model_ir_actions_actions @@ -541,7 +543,7 @@ msgstr "" #. module: base #: view:partner.wizard.ean.check:0 msgid "Want to check Ean ? " -msgstr "" +msgstr "Ean을 체크하시겠습니까? " #. module: base #: field:ir.values,key2:0 @@ -559,17 +561,17 @@ msgstr "" #. module: base #: field:res.partner,title:0 msgid "Partner Form" -msgstr "" +msgstr "거래처 양식" #. module: base #: selection:base.language.install,lang:0 msgid "Swedish / svenska" -msgstr "" +msgstr "스웨덴" #. module: base #: model:res.country,name:base.rs msgid "Serbia" -msgstr "" +msgstr "세르비아" #. module: base #: selection:ir.translation,type:0 @@ -592,7 +594,7 @@ msgstr "시퀀스" #. module: base #: model:ir.model,name:base.model_base_language_import msgid "Language Import" -msgstr "" +msgstr "언어 불러오기" #. module: base #: model:ir.model,name:base.model_res_config_users @@ -607,7 +609,7 @@ msgstr "" #. module: base #: model:ir.ui.menu,name:base.menu_crm_config_opportunity msgid "Opportunities" -msgstr "" +msgstr "기회" #. module: base #: model:ir.model,name:base.model_base_language_export @@ -617,12 +619,12 @@ msgstr "" #. module: base #: model:res.country,name:base.pg msgid "Papua New Guinea" -msgstr "" +msgstr "파푸아뉴기니" #. module: base #: help:ir.actions.report.xml,report_type:0 msgid "Report Type, e.g. pdf, html, raw, sxw, odt, html2html, mako2html, ..." -msgstr "" +msgstr "보고서 유형, 예: pdf, html, raw, sxw, odt, html2html, mako2html, ..." #. module: base #: model:res.partner.category,name:base.res_partner_category_4 @@ -637,17 +639,17 @@ msgstr "" #. module: base #: view:res.partner:0 msgid "My Partners" -msgstr "" +msgstr "내 거래처" #. module: base #: view:ir.actions.report.xml:0 msgid "XML Report" -msgstr "" +msgstr "XML 보고서" #. module: base #: model:res.country,name:base.es msgid "Spain" -msgstr "" +msgstr "스페인" #. module: base #: model:ir.ui.menu,name:base.menu_translation_export @@ -658,20 +660,20 @@ msgstr "가져오기 / 내보내기" #: help:ir.actions.act_window,domain:0 msgid "" "Optional domain filtering of the destination data, as a Python expression" -msgstr "" +msgstr "최종 데이타의 도메일 필터링 - 파이썬 문법 (선택)" #. module: base #: model:ir.actions.act_window,name:base.action_view_base_module_upgrade #: model:ir.model,name:base.model_base_module_upgrade msgid "Module Upgrade" -msgstr "" +msgstr "모듈 업그레이드" #. module: base #: view:res.config.users:0 msgid "" "Groups are used to define access rights on objects and the visibility of " "screens and menus" -msgstr "" +msgstr "그룹은 오브젝트의 접근권한 및 화면과 메뉴 노출 관리를 위해 사용됩니다" #. module: base #: selection:base.language.install,lang:0 @@ -687,7 +689,7 @@ msgstr "모바일" #. module: base #: model:res.country,name:base.om msgid "Oman" -msgstr "" +msgstr "오만" #. module: base #: model:ir.actions.act_window,name:base.action_payterm_form @@ -698,7 +700,7 @@ msgstr "결제 조건" #. module: base #: model:res.country,name:base.nu msgid "Niue" -msgstr "" +msgstr "나우에섬" #. module: base #: selection:ir.cron,interval_type:0 @@ -708,7 +710,7 @@ msgstr "근로일" #. module: base #: selection:ir.module.module,license:0 msgid "Other OSI Approved Licence" -msgstr "" +msgstr "다른 OSI 인증 라이센스" #. module: base #: help:res.config.users,context_lang:0 @@ -716,7 +718,7 @@ msgstr "" msgid "" "Sets the language for the user's user interface, when UI translations are " "available" -msgstr "" +msgstr "UI 번역 가용시 사용자 인터페이스의 언어를 설정합니다" #. module: base #: code:addons/orm.py:1043 @@ -733,13 +735,13 @@ msgstr "메뉴 생성" #. module: base #: model:res.country,name:base.in msgid "India" -msgstr "" +msgstr "인도" #. module: base #: model:ir.actions.act_window,name:base.res_request_link-act #: model:ir.ui.menu,name:base.menu_res_request_link_act msgid "Request Reference Types" -msgstr "" +msgstr "번호 유형을 요청" #. module: base #: view:ir.values:0 @@ -795,22 +797,24 @@ msgid "" "Language with code \"%s\" is not defined in your system !\n" "Define it through the Administration menu." msgstr "" +"'%s' 코드로 된 언어는 시스템에 정의 되어있지 않습니다!\n" +"어드민 메뉴를 통해 정의하십시오" #. module: base #: model:res.country,name:base.gu msgid "Guam (USA)" -msgstr "" +msgstr "괌" #. module: base #: model:ir.ui.menu,name:base.menu_hr_project msgid "Human Resources Dashboard" -msgstr "" +msgstr "인사관리 대시보드" #. module: base #: code:addons/base/res/res_user.py:507 #, python-format msgid "Setting empty passwords is not allowed for security reasons!" -msgstr "" +msgstr "보안을 위해 패스워드는 반드시 입력해야 합니다!" #. module: base #: selection:ir.actions.server,state:0 @@ -826,7 +830,7 @@ msgstr "유효하지 않은 뷰 아키텍처를 위한 XML !" #. module: base #: model:res.country,name:base.ky msgid "Cayman Islands" -msgstr "" +msgstr "케이맨 제도" #. module: base #: model:res.country,name:base.kr @@ -849,18 +853,18 @@ msgstr "" #. module: base #: field:ir.module.module,contributors:0 msgid "Contributors" -msgstr "" +msgstr "도움을 주신 분들" #. module: base #: selection:ir.property,type:0 msgid "Char" -msgstr "" +msgstr "Char" #. module: base #: model:ir.actions.act_window,name:base.action_publisher_warranty_contract_form #: model:ir.ui.menu,name:base.menu_publisher_warranty_contract msgid "Contracts" -msgstr "" +msgstr "계약서" #. module: base #: selection:base.language.install,lang:0 @@ -870,27 +874,27 @@ msgstr "" #. module: base #: model:res.country,name:base.ug msgid "Uganda" -msgstr "" +msgstr "우간다" #. module: base #: field:ir.model.access,perm_unlink:0 msgid "Delete Access" -msgstr "" +msgstr "접근 삭제" #. module: base #: model:res.country,name:base.ne msgid "Niger" -msgstr "" +msgstr "나이제르" #. module: base #: selection:base.language.install,lang:0 msgid "Chinese (HK)" -msgstr "" +msgstr "중국어 (홍콩)" #. module: base #: model:res.country,name:base.ba msgid "Bosnia-Herzegovina" -msgstr "" +msgstr "보스니아 헤르체고비나" #. module: base #: view:base.language.export:0 @@ -934,12 +938,12 @@ msgstr "액션 URL" #. module: base #: field:base.module.import,module_name:0 msgid "Module Name" -msgstr "" +msgstr "모듈 이름" #. module: base #: model:res.country,name:base.mh msgid "Marshall Islands" -msgstr "" +msgstr "마셜 제도" #. module: base #: code:addons/base/ir/ir_model.py:328 @@ -950,13 +954,13 @@ msgstr "" #. module: base #: model:res.country,name:base.ht msgid "Haiti" -msgstr "" +msgstr "아이티" #. module: base #: view:ir.ui.view:0 #: selection:ir.ui.view,type:0 msgid "Search" -msgstr "" +msgstr "찾아보기" #. module: base #: code:addons/osv.py:136 diff --git a/bin/addons/base/i18n/lt.po b/bin/addons/base/i18n/lt.po index 565e033923c..8cd0811d7cb 100644 --- a/bin/addons/base/i18n/lt.po +++ b/bin/addons/base/i18n/lt.po @@ -8,13 +8,13 @@ msgstr "" "Report-Msgid-Bugs-To: support@openerp.com\n" "POT-Creation-Date: 2011-01-11 11:14+0000\n" "PO-Revision-Date: 2011-01-16 11:33+0000\n" -"Last-Translator: Paulius Sladkevičius - http://www.inovera.lt \n" +"Last-Translator: Paulius Sladkevičius - inovera.lt \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: 2011-02-16 04:54+0000\n" -"X-Generator: Launchpad (build 12351)\n" +"X-Launchpad-Export-Date: 2011-04-09 04:53+0000\n" +"X-Generator: Launchpad (build 12735)\n" #. module: base #: view:ir.filters:0 diff --git a/bin/addons/base/i18n/lv.po b/bin/addons/base/i18n/lv.po index a1a1886a1d1..661d9b0509e 100644 --- a/bin/addons/base/i18n/lv.po +++ b/bin/addons/base/i18n/lv.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2011-02-16 04:54+0000\n" -"X-Generator: Launchpad (build 12351)\n" +"X-Launchpad-Export-Date: 2011-04-09 04:53+0000\n" +"X-Generator: Launchpad (build 12735)\n" #. module: base #: view:ir.filters:0 diff --git a/bin/addons/base/i18n/mn.po b/bin/addons/base/i18n/mn.po index 6a2a781c40d..eea96c609d7 100644 --- a/bin/addons/base/i18n/mn.po +++ b/bin/addons/base/i18n/mn.po @@ -13,8 +13,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2011-02-16 04:54+0000\n" -"X-Generator: Launchpad (build 12351)\n" +"X-Launchpad-Export-Date: 2011-04-09 04:53+0000\n" +"X-Generator: Launchpad (build 12735)\n" #. module: base #: view:ir.filters:0 diff --git a/bin/addons/base/i18n/nb.po b/bin/addons/base/i18n/nb.po index 5879b28eda1..5303a2e26cd 100644 --- a/bin/addons/base/i18n/nb.po +++ b/bin/addons/base/i18n/nb.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2011-02-16 04:54+0000\n" -"X-Generator: Launchpad (build 12351)\n" +"X-Launchpad-Export-Date: 2011-04-09 04:54+0000\n" +"X-Generator: Launchpad (build 12735)\n" #. module: base #: view:ir.filters:0 @@ -24,17 +24,17 @@ msgstr "" #: field:ir.rule,domain_force:0 #: field:res.partner.title,domain:0 msgid "Domain" -msgstr "" +msgstr "Domene" #. module: base #: model:res.country,name:base.sh msgid "Saint Helena" -msgstr "" +msgstr "St. Helena" #. module: base #: view:ir.actions.report.xml:0 msgid "Other Configuration" -msgstr "" +msgstr "Annen konfigurasjon" #. module: base #: selection:ir.property,type:0 @@ -59,12 +59,12 @@ msgstr "Metadata" #: field:ir.ui.view,arch:0 #: field:ir.ui.view.custom,arch:0 msgid "View Architecture" -msgstr "" +msgstr "Utsnittsoppbygging" #. module: base #: field:base.language.import,code:0 msgid "Code (eg:en__US)" -msgstr "" +msgstr "Kode (f.eks.:en__US)" #. module: base #: view:workflow:0 @@ -79,27 +79,27 @@ msgstr "Arbeidsflyt" #. module: base #: view:partner.sms.send:0 msgid "SMS - Gateway: clickatell" -msgstr "" +msgstr "SMS - Gateway: Telenor" #. module: base #: selection:base.language.install,lang:0 msgid "Hungarian / Magyar" -msgstr "" +msgstr "Ungarsk / Magyar" #. module: base #: selection:ir.model.fields,select_level:0 msgid "Not Searchable" -msgstr "" +msgstr "Ikke søkbar" #. module: base #: selection:base.language.install,lang:0 msgid "Spanish (VE) / Español (VE)" -msgstr "" +msgstr "Spansk (AR) / Español (AR)" #. module: base #: field:ir.actions.server,wkf_model_id:0 msgid "Workflow On" -msgstr "" +msgstr "Arbeidsflyt På" #. module: base #: field:ir.actions.act_window,display_menu_tip:0 @@ -109,7 +109,7 @@ msgstr "" #. module: base #: view:ir.module.module:0 msgid "Created Views" -msgstr "" +msgstr "Opprettede visninger" #. module: base #: code:addons/base/ir/ir_model.py:485 @@ -130,18 +130,18 @@ msgstr "" #. module: base #: field:res.partner,ref:0 msgid "Reference" -msgstr "" +msgstr "Referanse" #. module: base #: field:ir.actions.act_window,target:0 msgid "Target Window" -msgstr "" +msgstr "Målvindu" #. module: base #: code:addons/base/res/res_user.py:507 #, python-format msgid "Warning!" -msgstr "" +msgstr "Advarsel !" #. module: base #: code:addons/base/ir/ir_model.py:304 @@ -160,7 +160,7 @@ msgstr "" #. module: base #: model:ir.model,name:base.model_ir_ui_view_custom msgid "ir.ui.view.custom" -msgstr "" +msgstr "ir.ui.view.custom" #. module: base #: model:res.country,name:base.sz @@ -172,7 +172,7 @@ msgstr "Swaziland" #: code:addons/orm.py:3653 #, python-format msgid "created." -msgstr "" +msgstr "opprettet." #. module: base #: model:res.partner.category,name:base.res_partner_category_woodsuppliers0 @@ -186,17 +186,19 @@ msgid "" "Some installed modules depend on the module you plan to Uninstall :\n" " %s" msgstr "" +"Some installed modules depend on the module you plan to Uninstall :\n" +" %s" #. module: base #: field:ir.sequence,number_increment:0 msgid "Increment Number" -msgstr "" +msgstr "Inkrementnummer" #. module: base #: model:ir.actions.act_window,name:base.action_res_company_tree #: model:ir.ui.menu,name:base.menu_action_res_company_tree msgid "Company's Structure" -msgstr "" +msgstr "Firmastruktur" #. module: base #: selection:base.language.install,lang:0 @@ -218,17 +220,17 @@ msgstr "" #: code:addons/base/module/wizard/base_export_language.py:60 #, python-format msgid "new" -msgstr "" +msgstr "ny" #. module: base #: field:ir.actions.report.xml,multi:0 msgid "On multiple doc." -msgstr "" +msgstr "Feil på linje %d: %s" #. module: base #: field:ir.module.category,module_nr:0 msgid "Number of Modules" -msgstr "" +msgstr "Antall moduler" #. module: base #: help:multi_company.default,company_dest_id:0 @@ -238,12 +240,12 @@ msgstr "" #. module: base #: field:res.partner.bank.type.field,size:0 msgid "Max. Size" -msgstr "" +msgstr "Maks størrelse" #. module: base #: field:res.partner.address,name:0 msgid "Contact Name" -msgstr "" +msgstr "Kontaktnavn" #. module: base #: code:addons/base/module/wizard/base_export_language.py:56 @@ -252,6 +254,8 @@ msgid "" "Save this document to a %s file and edit it with a specific software or a " "text editor. The file encoding is UTF-8." msgstr "" +"Lagre dokument som %s fil og rediger derettet med tekst editor eller annen " +"egnet applikasjon. Enkodingen på filen er UTF-8" #. module: base #: sql_constraint:res.lang:0 @@ -261,12 +265,12 @@ msgstr "" #. module: base #: selection:res.request,state:0 msgid "active" -msgstr "" +msgstr "aktiv" #. module: base #: field:ir.actions.wizard,wiz_name:0 msgid "Wizard Name" -msgstr "" +msgstr "Veivisernavn" #. module: base #: code:addons/orm.py:2160 @@ -277,84 +281,84 @@ msgstr "" #. module: base #: field:res.partner,credit_limit:0 msgid "Credit Limit" -msgstr "" +msgstr "Kredittgrense" #. module: base #: field:ir.model.data,date_update:0 msgid "Update Date" -msgstr "" +msgstr "Dato oppdatert" #. module: base #: view:ir.attachment:0 msgid "Owner" -msgstr "" +msgstr "Eier" #. module: base #: field:ir.actions.act_window,src_model:0 msgid "Source Object" -msgstr "" +msgstr "Kildeobjekt" #. module: base #: view:ir.actions.todo:0 msgid "Config Wizard Steps" -msgstr "" +msgstr "Konfigurer trinn i veiviseren" #. module: base #: model:ir.model,name:base.model_ir_ui_view_sc msgid "ir.ui.view_sc" -msgstr "" +msgstr "ir.ui.view_sc" #. module: base #: field:res.widget.user,widget_id:0 #: field:res.widget.wizard,widgets_list:0 msgid "Widget" -msgstr "" +msgstr "Widget" #. module: base #: view:ir.model.access:0 #: field:ir.model.access,group_id:0 #: view:res.config.users:0 msgid "Group" -msgstr "" +msgstr "Gruppe" #. module: base #: field:ir.exports.line,name:0 #: field:ir.translation,name:0 #: field:res.partner.bank.type.field,name:0 msgid "Field Name" -msgstr "" +msgstr "Feltnavn" #. module: base #: wizard_view:server.action.create,init:0 #: wizard_field:server.action.create,init,type:0 msgid "Select Action Type" -msgstr "" +msgstr "Velg handlingstype" #. module: base #: model:res.country,name:base.tv msgid "Tuvalu" -msgstr "" +msgstr "Tuvalu" #. module: base #: selection:ir.model,state:0 msgid "Custom Object" -msgstr "" +msgstr "Egendefinert objekt" #. module: base #: field:res.lang,date_format:0 msgid "Date Format" -msgstr "" +msgstr "Datoformat" #. module: base #: field:res.bank,email:0 #: field:res.partner.address,email:0 msgid "E-Mail" -msgstr "" +msgstr "E-post" #. module: base #: model:res.country,name:base.an msgid "Netherlands Antilles" -msgstr "" +msgstr "De nederlandske Antillene" #. module: base #: code:addons/base/res/res_user.py:389 @@ -363,11 +367,13 @@ msgid "" "You can not remove the admin user as it is used internally for resources " "created by OpenERP (updates, module installation, ...)" msgstr "" +"Du kan ikke fjerne admin brukeren da den brukes internt for ressurser " +"opprettet av OpenERP (oppdateringer, modul installasjoner, ...)" #. module: base #: model:res.country,name:base.gf msgid "French Guyana" -msgstr "" +msgstr "Fransk Guyana" #. module: base #: selection:base.language.install,lang:0 @@ -377,7 +383,7 @@ msgstr "" #. module: base #: selection:base.language.install,lang:0 msgid "Bosnian / bosanski jezik" -msgstr "" +msgstr "Bosnisk / bosanski jezik" #. module: base #: help:ir.actions.report.xml,attachment_use:0 @@ -385,6 +391,8 @@ msgid "" "If you check this, then the second time the user prints with same attachment " "name, it returns the previous report." msgstr "" +"Hvis du krysser av denne, så vil den forrige rapporten returneres den andre " +"gangen brukeren skriver ut med samme vedleggsnavnet." #. module: base #: code:addons/orm.py:904 @@ -400,28 +408,28 @@ msgstr "" #. module: base #: view:base.module.upgrade:0 msgid "Your system will be updated." -msgstr "" +msgstr "Systemet ditt vil bli oppdatert." #. module: base #: field:ir.actions.todo,note:0 #: selection:ir.property,type:0 msgid "Text" -msgstr "" +msgstr "Tekst" #. module: base #: field:res.country,name:0 msgid "Country Name" -msgstr "" +msgstr "Navn på land" #. module: base #: model:res.country,name:base.co msgid "Colombia" -msgstr "" +msgstr "Colombia" #. module: base #: view:ir.module.module:0 msgid "Schedule Upgrade" -msgstr "" +msgstr "Planlegg oppgradering" #. module: base #: code:addons/orm.py:838 @@ -435,21 +443,23 @@ msgid "" "The ISO country code in two chars.\n" "You can use this field for quick search." msgstr "" +"ISO landekode (to karakterer).\n" +"Du kan bruke dette feltet for rask søking." #. module: base #: model:res.country,name:base.pw msgid "Palau" -msgstr "" +msgstr "Palau" #. module: base #: view:res.partner:0 msgid "Sales & Purchases" -msgstr "" +msgstr "Salg & Innkjøp" #. module: base #: view:ir.translation:0 msgid "Untranslated" -msgstr "" +msgstr "Ikke oversatt" #. module: base #: help:ir.actions.act_window,context:0 @@ -462,7 +472,7 @@ msgstr "" #: view:ir.actions.wizard:0 #: model:ir.ui.menu,name:base.menu_ir_action_wizard msgid "Wizards" -msgstr "" +msgstr "Veivisere" #. module: base #: model:res.partner.category,name:base.res_partner_category_miscellaneoussuppliers0 @@ -473,27 +483,27 @@ msgstr "" #: code:addons/base/ir/ir_model.py:255 #, python-format msgid "Custom fields must have a name that starts with 'x_' !" -msgstr "" +msgstr "Egendefinerte felter må ha et navn som starter med 'x_' !" #. module: base #: help:ir.actions.server,action_id:0 msgid "Select the Action Window, Report, Wizard to be executed." -msgstr "" +msgstr "Velg handling, vindu, rapport, veileder som skal eksekveres." #. module: base #: view:res.config.users:0 msgid "New User" -msgstr "" +msgstr "Ny bruker" #. module: base #: view:base.language.export:0 msgid "Export done" -msgstr "" +msgstr "Eksport fullført" #. module: base #: view:ir.model:0 msgid "Model Description" -msgstr "" +msgstr "Modellbeskrivelse" #. module: base #: help:ir.actions.act_window,src_model:0 @@ -504,12 +514,12 @@ msgstr "" #. module: base #: field:workflow.transition,trigger_expr_id:0 msgid "Trigger Expression" -msgstr "" +msgstr "Utløseruttrykk" #. module: base #: model:res.country,name:base.jo msgid "Jordan" -msgstr "" +msgstr "Jordan" #. module: base #: view:ir.module.module:0 @@ -519,23 +529,23 @@ msgstr "" #. module: base #: model:res.country,name:base.er msgid "Eritrea" -msgstr "" +msgstr "Eritrea" #. module: base #: view:res.config:0 #: view:res.config.installer:0 msgid "description" -msgstr "" +msgstr "beskrivelse" #. module: base #: model:ir.ui.menu,name:base.menu_base_action_rule msgid "Automated Actions" -msgstr "" +msgstr "Automatiserte handinger" #. module: base #: model:ir.model,name:base.model_ir_actions_actions msgid "ir.actions.actions" -msgstr "" +msgstr "ir.actions.actions" #. module: base #: view:partner.wizard.ean.check:0 @@ -545,7 +555,7 @@ msgstr "" #. module: base #: field:ir.values,key2:0 msgid "Event Type" -msgstr "" +msgstr "Arrangementstype" #. module: base #: view:base.language.export:0 @@ -554,6 +564,9 @@ msgid "" "Launchpad.net, our open source project management facility. We use their " "online interface to synchronize all translations efforts." msgstr "" +"De offisielle oversettelses pakkene til OpenERP/OpenObject moduler er " +"administret via launchpad. Vi bruker deres online grensesnitt for å " +"synkronisere alle oversettelsesbidrag." #. module: base #: field:res.partner,title:0 @@ -563,22 +576,22 @@ msgstr "" #. module: base #: selection:base.language.install,lang:0 msgid "Swedish / svenska" -msgstr "" +msgstr "Svensk" #. module: base #: model:res.country,name:base.rs msgid "Serbia" -msgstr "" +msgstr "Serbia" #. module: base #: selection:ir.translation,type:0 msgid "Wizard View" -msgstr "" +msgstr "Veiviser visning" #. module: base #: model:res.country,name:base.kh msgid "Cambodia, Kingdom of" -msgstr "" +msgstr "Kambodsja, Kongeriket Kambodsja" #. module: base #: model:ir.actions.act_window,name:base.ir_sequence_form @@ -586,22 +599,22 @@ msgstr "" #: model:ir.ui.menu,name:base.menu_ir_sequence_form #: model:ir.ui.menu,name:base.next_id_5 msgid "Sequences" -msgstr "" +msgstr "Sekvenser" #. module: base #: model:ir.model,name:base.model_base_language_import msgid "Language Import" -msgstr "" +msgstr "Importer språk" #. module: base #: model:ir.model,name:base.model_res_config_users msgid "res.config.users" -msgstr "" +msgstr "res.config.users" #. module: base #: selection:base.language.install,lang:0 msgid "Albanian / Shqip" -msgstr "" +msgstr "Albansk / Shqipëri" #. module: base #: model:ir.ui.menu,name:base.menu_crm_config_opportunity @@ -611,12 +624,12 @@ msgstr "" #. module: base #: model:ir.model,name:base.model_base_language_export msgid "base.language.export" -msgstr "" +msgstr "base.language.export" #. module: base #: model:res.country,name:base.pg msgid "Papua New Guinea" -msgstr "" +msgstr "Papua Ny-Guinea" #. module: base #: help:ir.actions.report.xml,report_type:0 @@ -631,7 +644,7 @@ msgstr "" #. module: base #: report:ir.module.reference.graph:0 msgid "," -msgstr "" +msgstr "," #. module: base #: view:res.partner:0 @@ -646,12 +659,12 @@ msgstr "" #. module: base #: model:res.country,name:base.es msgid "Spain" -msgstr "" +msgstr "Spania" #. module: base #: model:ir.ui.menu,name:base.menu_translation_export msgid "Import / Export" -msgstr "" +msgstr "Import / Eksport" #. module: base #: help:ir.actions.act_window,domain:0 @@ -663,7 +676,7 @@ msgstr "" #: model:ir.actions.act_window,name:base.action_view_base_module_upgrade #: model:ir.model,name:base.model_base_module_upgrade msgid "Module Upgrade" -msgstr "" +msgstr "Moduloppgradering" #. module: base #: view:res.config.users:0 @@ -671,43 +684,45 @@ msgid "" "Groups are used to define access rights on objects and the visibility of " "screens and menus" msgstr "" +"Grupper blir benyttet til å definere tilgangsrettigheter til hvert enkelt " +"skjermbilde og menyer" #. module: base #: selection:base.language.install,lang:0 msgid "Spanish (UY) / Español (UY)" -msgstr "" +msgstr "Spanish (UY) / Español (UY)" #. module: base #: field:res.partner,mobile:0 #: field:res.partner.address,mobile:0 msgid "Mobile" -msgstr "" +msgstr "Mobil" #. module: base #: model:res.country,name:base.om msgid "Oman" -msgstr "" +msgstr "Oman" #. module: base #: model:ir.actions.act_window,name:base.action_payterm_form #: model:ir.model,name:base.model_res_payterm msgid "Payment term" -msgstr "" +msgstr "Betalingsbetingelser" #. module: base #: model:res.country,name:base.nu msgid "Niue" -msgstr "" +msgstr "Niue" #. module: base #: selection:ir.cron,interval_type:0 msgid "Work Days" -msgstr "" +msgstr "Arbeidsdager" #. module: base #: selection:ir.module.module,license:0 msgid "Other OSI Approved Licence" -msgstr "" +msgstr "Andre OSI godkjente lisenser" #. module: base #: help:res.config.users,context_lang:0 @@ -727,12 +742,12 @@ msgstr "" #: model:ir.actions.act_window,name:base.act_menu_create #: view:wizard.ir.model.menu.create:0 msgid "Create Menu" -msgstr "" +msgstr "Opprett meny" #. module: base #: model:res.country,name:base.in msgid "India" -msgstr "" +msgstr "India" #. module: base #: model:ir.actions.act_window,name:base.res_request_link-act @@ -743,18 +758,18 @@ msgstr "" #. module: base #: view:ir.values:0 msgid "client_action_multi, client_action_relate" -msgstr "" +msgstr "client_action_multi, client_action_relate" #. module: base #: model:res.country,name:base.ad msgid "Andorra, Principality of" -msgstr "" +msgstr "Andorra" #. module: base #: field:ir.module.category,child_ids:0 #: field:res.partner.category,child_ids:0 msgid "Child Categories" -msgstr "" +msgstr "Underordnede kategorier" #. module: base #: model:ir.model,name:base.model_ir_config_parameter @@ -764,12 +779,12 @@ msgstr "" #. module: base #: selection:base.language.export,format:0 msgid "TGZ Archive" -msgstr "" +msgstr "TGZ arkiv" #. module: base #: view:res.lang:0 msgid "%B - Full month name." -msgstr "" +msgstr "%B - Fullt navn på måned." #. module: base #: view:ir.attachment:0 @@ -785,7 +800,7 @@ msgstr "" #: view:res.partner:0 #: view:res.partner.address:0 msgid "Type" -msgstr "" +msgstr "Type" #. module: base #: code:addons/orm.py:210 @@ -798,7 +813,7 @@ msgstr "" #. module: base #: model:res.country,name:base.gu msgid "Guam (USA)" -msgstr "" +msgstr "Guam (USA)" #. module: base #: model:ir.ui.menu,name:base.menu_hr_project @@ -815,22 +830,22 @@ msgstr "" #: selection:ir.actions.server,state:0 #: selection:workflow.activity,kind:0 msgid "Dummy" -msgstr "" +msgstr "Dummy" #. module: base #: constraint:ir.ui.view:0 msgid "Invalid XML for View Architecture!" -msgstr "" +msgstr "Ugyldig XML for Visningsarkitektur" #. module: base #: model:res.country,name:base.ky msgid "Cayman Islands" -msgstr "" +msgstr "Caymanøyene" #. module: base #: model:res.country,name:base.kr msgid "South Korea" -msgstr "Sør-Korea" +msgstr "Sør Korea" #. module: base #: model:ir.actions.act_window,name:base.action_workflow_transition_form @@ -859,27 +874,27 @@ msgstr "" #: model:ir.actions.act_window,name:base.action_publisher_warranty_contract_form #: model:ir.ui.menu,name:base.menu_publisher_warranty_contract msgid "Contracts" -msgstr "" +msgstr "Kontrakter" #. module: base #: selection:base.language.install,lang:0 msgid "Spanish (AR) / Español (AR)" -msgstr "" +msgstr "Spansk (AR) / Español (AR)" #. module: base #: model:res.country,name:base.ug msgid "Uganda" -msgstr "" +msgstr "Uganda" #. module: base #: field:ir.model.access,perm_unlink:0 msgid "Delete Access" -msgstr "" +msgstr "Slett tilgang" #. module: base #: model:res.country,name:base.ne msgid "Niger" -msgstr "" +msgstr "Niger" #. module: base #: selection:base.language.install,lang:0 @@ -889,7 +904,7 @@ msgstr "" #. module: base #: model:res.country,name:base.ba msgid "Bosnia-Herzegovina" -msgstr "" +msgstr "Bosnia-Herzegovina" #. module: base #: view:base.language.export:0 @@ -898,11 +913,14 @@ msgid "" "Lauchpad's web interface (Rosetta). If you need to perform mass translation, " "Launchpad also allows uploading full .po files at once" msgstr "" +"For å forbedre betegnelsene i den offisielle oversettelsen av OpenERP bør du " +"editere betegnelsene direkte i launchpad grensesnittet. Hvis du har gjort " +"mange oversettelser i din egen modul så kan du publisere alle på en gang." #. module: base #: selection:base.language.install,lang:0 msgid "Spanish (GT) / Español (GT)" -msgstr "" +msgstr "Spansk (AR) / Español (AR)" #. module: base #: view:res.lang:0 @@ -911,32 +929,35 @@ msgid "" "decimal number [00,53]. All days in a new year preceding the first Monday " "are considered to be in week 0." msgstr "" +"%W - Ukenummer i året (Mandag som første dag i uken) som et desimtall " +"[00,53]. Alle dager i et nytt år forut for den første mandagen blir ansett " +"til å være i uke 0." #. module: base #: field:ir.module.module,website:0 #: field:res.partner,website:0 msgid "Website" -msgstr "" +msgstr "Nettside" #. module: base #: model:res.country,name:base.gs msgid "S. Georgia & S. Sandwich Isls." -msgstr "" +msgstr "Sør-Georgia og Sør-Sandwichøyene" #. module: base #: field:ir.actions.url,url:0 msgid "Action URL" -msgstr "" +msgstr "URL til handling" #. module: base #: field:base.module.import,module_name:0 msgid "Module Name" -msgstr "" +msgstr "Modulnavn" #. module: base #: model:res.country,name:base.mh msgid "Marshall Islands" -msgstr "" +msgstr "Marshalløyene, Republikken Marshalløyene" #. module: base #: code:addons/base/ir/ir_model.py:328 @@ -947,13 +968,13 @@ msgstr "" #. module: base #: model:res.country,name:base.ht msgid "Haiti" -msgstr "" +msgstr "Haiti" #. module: base #: view:ir.ui.view:0 #: selection:ir.ui.view,type:0 msgid "Search" -msgstr "" +msgstr "Søk" #. module: base #: code:addons/osv.py:136 @@ -980,12 +1001,12 @@ msgstr "" #. module: base #: help:base.language.export,lang:0 msgid "To export a new language, do not select a language." -msgstr "" +msgstr "Ikke velg språk om du vil eksportere et nytt språk." #. module: base #: view:res.request:0 msgid "Request Date" -msgstr "" +msgstr "Forespørsels dato" #. module: base #: model:ir.ui.menu,name:base.menu_hr_dasboard @@ -995,35 +1016,35 @@ msgstr "" #. module: base #: model:ir.ui.menu,name:base.menu_purchase_root msgid "Purchases" -msgstr "" +msgstr "Innkjøp" #. module: base #: model:res.country,name:base.md msgid "Moldavia" -msgstr "" +msgstr "Moldavia" #. module: base #: view:ir.module.module:0 msgid "Features" -msgstr "" +msgstr "Funksjoner" #. module: base #: view:ir.module.module:0 #: report:ir.module.reference.graph:0 msgid "Version" -msgstr "" +msgstr "Versjon" #. module: base #: view:ir.model.access:0 #: field:ir.model.access,perm_read:0 #: view:ir.rule:0 msgid "Read Access" -msgstr "" +msgstr "Lesetilgang" #. module: base #: model:ir.model,name:base.model_ir_exports msgid "ir.exports" -msgstr "" +msgstr "ir.exports" #. module: base #: code:addons/base/module/wizard/base_update_translations.py:38 @@ -1044,16 +1065,19 @@ msgid "" "you select the invoice, then `object.invoice_address_id.email` is the field " "which gives the correct address" msgstr "" +"Tilgjengeliggjør felt som benyttes for å hente epostadressene, f.eks. når du " +"velger fakturaen så vil feltet `object.invoice_address_id.email` gi den " +"riktige addressen" #. module: base #: view:res.lang:0 msgid "%Y - Year with century." -msgstr "" +msgstr "%Y - År med århundre." #. module: base #: report:ir.module.reference.graph:0 msgid "-" -msgstr "" +msgstr "-" #. module: base #: view:publisher_warranty.contract.wizard:0 @@ -1072,24 +1096,24 @@ msgstr "" #. module: base #: view:wizard.ir.model.menu.create:0 msgid "Create _Menu" -msgstr "" +msgstr "Opprett _meny" #. module: base #: field:res.payterm,name:0 msgid "Payment Term (short name)" -msgstr "" +msgstr "Betalingsbetingelser (kortnavn)" #. module: base #: model:ir.model,name:base.model_res_bank #: view:res.bank:0 #: field:res.partner.bank,bank:0 msgid "Bank" -msgstr "" +msgstr "Bank" #. module: base #: model:ir.model,name:base.model_ir_exports_line msgid "ir.exports.line" -msgstr "" +msgstr "ir.exports.line" #. module: base #: help:base.language.install,overwrite:0 @@ -1108,7 +1132,7 @@ msgstr "" #: field:ir.module.module,reports_by_module:0 #: model:ir.ui.menu,name:base.menu_ir_action_report_xml msgid "Reports" -msgstr "" +msgstr "Rapporter" #. module: base #: help:ir.actions.act_window.view,multi:0 @@ -1117,11 +1141,13 @@ msgid "" "If set to true, the action will not be displayed on the right toolbar of a " "form view." msgstr "" +"Hvis satt til sann, så vil ikke handlingen vises på den høyre verktøylinjen " +"i skjemavisning." #. module: base #: field:workflow,on_create:0 msgid "On Create" -msgstr "" +msgstr "Ved opprettelse" #. module: base #: code:addons/base/ir/ir_model.py:607 @@ -1130,13 +1156,16 @@ msgid "" "'%s' contains too many dots. XML ids should not contain dots ! These are " "used to refer to other modules data, as in module.reference_id" msgstr "" +"\"%s\" inneholder for mange punktum. XML identer skal ikke inneholde punktum " +"! Disse er forbeholdt å referere til data i andre moduler, f.eks. som i " +"module.reference_id" #. module: base #: field:partner.sms.send,user:0 #: field:res.config.users,login:0 #: field:res.users,login:0 msgid "Login" -msgstr "" +msgstr "Login" #. module: base #: view:ir.actions.server:0 @@ -1148,7 +1177,7 @@ msgstr "" #. module: base #: model:ir.model,name:base.model_res_country_state msgid "Country state" -msgstr "" +msgstr "Navn på stat" #. module: base #: selection:ir.property,type:0 @@ -1158,19 +1187,19 @@ msgstr "" #. module: base #: model:ir.model,name:base.model_res_request_link msgid "res.request.link" -msgstr "" +msgstr "res.request.link" #. module: base #: field:ir.actions.wizard,name:0 msgid "Wizard Info" -msgstr "" +msgstr "Veiviser informasjon" #. module: base #: view:base.language.export:0 #: model:ir.actions.act_window,name:base.action_wizard_lang_export #: model:ir.ui.menu,name:base.menu_wizard_lang_export msgid "Export Translation" -msgstr "" +msgstr "Eksporter oversettelse" #. module: base #: help:res.log,secondary:0 @@ -1182,7 +1211,7 @@ msgstr "" #. module: base #: model:res.country,name:base.tp msgid "East Timor" -msgstr "" +msgstr "Øst Timor" #. module: base #: model:res.company,follow_up_msg:base.main_company @@ -1205,7 +1234,7 @@ msgstr "" #. module: base #: field:res.currency,accuracy:0 msgid "Computational Accuracy" -msgstr "" +msgstr "Beregningspresisjon" #. module: base #: selection:base.language.install,lang:0 @@ -1215,37 +1244,37 @@ msgstr "" #. module: base #: model:ir.model,name:base.model_wizard_ir_model_menu_create_line msgid "wizard.ir.model.menu.create.line" -msgstr "" +msgstr "wizard.ir.model.menu.create.line" #. module: base #: field:ir.attachment,res_id:0 msgid "Attached ID" -msgstr "" +msgstr "Vedlagt ID" #. module: base #: view:ir.sequence:0 msgid "Day: %(day)s" -msgstr "" +msgstr "Dag: %(day)s" #. module: base #: model:res.country,name:base.mv msgid "Maldives" -msgstr "" +msgstr "Maldivene" #. module: base #: help:ir.values,res_id:0 msgid "Keep 0 if the action must appear on all resources." -msgstr "" +msgstr "Hold igjen 0 hvis handlingen skal omfatte alle ressurser." #. module: base #: model:ir.model,name:base.model_ir_rule msgid "ir.rule" -msgstr "" +msgstr "ir.rule" #. module: base #: selection:ir.cron,interval_type:0 msgid "Days" -msgstr "" +msgstr "Dager" #. module: base #: help:ir.actions.server,condition:0 @@ -1253,25 +1282,27 @@ msgid "" "Condition that is to be tested before action is executed, e.g. " "object.list_price > object.cost_price" msgstr "" +"Betingelse som skal testes før en handling blir utført, f.eks. " +"object.list_price > object.cost_price" #. module: base #: code:addons/base/res/partner/partner.py:155 #: code:addons/base/res/res_company.py:66 #, python-format msgid " (copy)" -msgstr "" +msgstr " (kopi)" #. module: base #: view:res.lang:0 msgid "7. %H:%M:%S ==> 18:25:20" -msgstr "" +msgstr "7. %H:%M:%S ==> 18:25:20" #. module: base #: view:res.partner:0 #: view:res.partner.category:0 #: field:res.partner.category,partner_ids:0 msgid "Partners" -msgstr "" +msgstr "Partnere" #. module: base #: field:res.partner.category,parent_left:0 @@ -1290,59 +1321,61 @@ msgid "" "Specify the message. You can use the fields from the object. e.g. `Dear [[ " "object.partner_id.name ]]`" msgstr "" +"Spesifiser meldingen. Du kan bruke feltene fra objektet. F.eks. Kjære [[ " +"objetc.partner_id.name]]'" #. module: base #: field:ir.attachment,res_model:0 msgid "Attached Model" -msgstr "" +msgstr "Tilknyttet modell" #. module: base #: view:ir.rule:0 msgid "Domain Setup" -msgstr "" +msgstr "Domene oppsett" #. module: base #: field:ir.actions.server,trigger_name:0 msgid "Trigger Name" -msgstr "" +msgstr "Utløsernavn" #. module: base #: model:ir.model,name:base.model_ir_model_access msgid "ir.model.access" -msgstr "" +msgstr "ir.model.access" #. module: base #: field:ir.cron,priority:0 #: field:res.request,priority:0 #: field:res.request.link,priority:0 msgid "Priority" -msgstr "" +msgstr "Prioritet" #. module: base #: field:workflow.transition,act_from:0 msgid "Source Activity" -msgstr "" +msgstr "Aktivitetskilde" #. module: base #: view:ir.sequence:0 msgid "Legend (for prefix, suffix)" -msgstr "" +msgstr "Legend (for prefix, suffix)" #. module: base #: selection:ir.server.object.lines,type:0 msgid "Formula" -msgstr "" +msgstr "Formel" #. module: base #: code:addons/base/res/res_user.py:389 #, python-format msgid "Can not remove root user!" -msgstr "" +msgstr "Kan ikke fjerne root brukereren!" #. module: base #: model:res.country,name:base.mw msgid "Malawi" -msgstr "" +msgstr "Malawi" #. module: base #: code:addons/base/res/res_user.py:51 @@ -1354,17 +1387,17 @@ msgstr "" #. module: base #: field:res.partner.address,type:0 msgid "Address Type" -msgstr "" +msgstr "Adressetype" #. module: base #: view:ir.ui.menu:0 msgid "Full Path" -msgstr "" +msgstr "Full sti" #. module: base #: view:res.request:0 msgid "References" -msgstr "" +msgstr "Referanser" #. module: base #: view:res.lang:0 @@ -1373,6 +1406,9 @@ msgid "" "decimal number [00,53]. All days in a new year preceding the first Sunday " "are considered to be in week 0." msgstr "" +"%U - Ukenummer i året (Søndag som den første dagen i uken) som et " +"desimaltall [00,53]. Alle dager i det nye året forut for den første søndagen " +"blir ansett for å være i uke 0." #. module: base #: view:ir.ui.view:0 @@ -1382,7 +1418,7 @@ msgstr "" #. module: base #: model:res.country,name:base.fi msgid "Finland" -msgstr "" +msgstr "Finland" #. module: base #: selection:ir.actions.act_window,view_type:0 @@ -1391,28 +1427,29 @@ msgstr "" #: selection:ir.ui.view,type:0 #: selection:wizard.ir.model.menu.create.line,view_type:0 msgid "Tree" -msgstr "" +msgstr "Tre" #. module: base #: help:res.config.users,password:0 msgid "" "Keep empty if you don't want the user to be able to connect on the system." msgstr "" +"Behold feltet blankt om du ikke vil at brukeren skal kunne logge på systemet." #. module: base #: view:ir.actions.server:0 msgid "Create / Write / Copy" -msgstr "" +msgstr "Opprett / Skriv / Kopier" #. module: base #: view:base.language.export:0 msgid "https://help.launchpad.net/Translations" -msgstr "" +msgstr "https://help.launchpad.net/Translations" #. module: base #: field:ir.actions.act_window,view_mode:0 msgid "View Mode" -msgstr "" +msgstr "Visningsmodus" #. module: base #: view:base.language.import:0 @@ -1430,12 +1467,12 @@ msgstr "" #. module: base #: view:res.log:0 msgid "Logs" -msgstr "" +msgstr "Logger" #. module: base #: selection:base.language.install,lang:0 msgid "Spanish / Español" -msgstr "" +msgstr "Spansk / Español" #. module: base #: selection:base.language.install,lang:0 @@ -1452,7 +1489,7 @@ msgstr "" #. module: base #: field:res.company,logo:0 msgid "Logo" -msgstr "" +msgstr "Logo" #. module: base #: view:res.partner.address:0 @@ -1462,18 +1499,18 @@ msgstr "" #. module: base #: view:ir.module.module:0 msgid "Uninstall (beta)" -msgstr "" +msgstr "Avinstaller (beta)" #. module: base #: selection:ir.actions.act_window,target:0 #: selection:ir.actions.url,target:0 msgid "New Window" -msgstr "" +msgstr "Nytt vindu" #. module: base #: model:res.country,name:base.bs msgid "Bahamas" -msgstr "" +msgstr "Bahamas" #. module: base #: code:addons/base/res/partner/partner.py:250 @@ -1481,21 +1518,23 @@ msgstr "" msgid "" "Couldn't generate the next id because some partners have an alphabetic id !" msgstr "" +"Kunne ikke opprette neste id på grunn av en eller flere partnere har en " +"alfanumerisk id!" #. module: base #: view:ir.attachment:0 msgid "Attachment" -msgstr "" +msgstr "Vedlegg" #. module: base #: model:res.country,name:base.ie msgid "Ireland" -msgstr "" +msgstr "Irland" #. module: base #: field:base.module.update,update:0 msgid "Number of modules updated" -msgstr "" +msgstr "Antall moduler oppdatert" #. module: base #: code:addons/fields.py:100 @@ -1541,12 +1580,12 @@ msgstr "" #: view:res.users:0 #: field:res.users,groups_id:0 msgid "Groups" -msgstr "" +msgstr "Grupper" #. module: base #: selection:base.language.install,lang:0 msgid "Spanish (CL) / Español (CL)" -msgstr "" +msgstr "Spanish (CL) / Español (CL)" #. module: base #: view:res.config.users:0 @@ -1559,17 +1598,17 @@ msgstr "" #. module: base #: model:res.country,name:base.bz msgid "Belize" -msgstr "" +msgstr "Belize" #. module: base #: model:res.country,name:base.ge msgid "Georgia" -msgstr "" +msgstr "Georgia" #. module: base #: model:res.country,name:base.pl msgid "Poland" -msgstr "" +msgstr "Polen" #. module: base #: help:ir.actions.act_window,view_mode:0 @@ -1593,12 +1632,12 @@ msgstr "" #: selection:ir.module.module,state:0 #: selection:ir.module.module.dependency,state:0 msgid "To be removed" -msgstr "" +msgstr "Å fjerne" #. module: base #: model:ir.model,name:base.model_ir_sequence msgid "ir.sequence" -msgstr "" +msgstr "ir.sequence" #. module: base #: help:ir.actions.server,expression:0 @@ -1607,13 +1646,16 @@ msgid "" "order in Object, and you can have loop on the sales order line. Expression = " "`object.order_line`." msgstr "" +"Skriv inn feltet/uttrykket som vil returnere listen. F.eks. velg salgsordren " +"i Objekt, og du kan iterere over salgsordrelinjen(e). Uttrykk = " +"'object.order_line'." #. module: base #: field:ir.property,fields_id:0 #: selection:ir.translation,type:0 #: field:multi_company.default,field_id:0 msgid "Field" -msgstr "" +msgstr "Felt" #. module: base #: view:ir.rule:0 @@ -1623,39 +1665,39 @@ msgstr "" #. module: base #: model:res.country,name:base.fo msgid "Faroe Islands" -msgstr "" +msgstr "Færøyene" #. module: base #: selection:res.config.users,view:0 #: selection:res.config.view,view:0 #: selection:res.users,view:0 msgid "Simplified" -msgstr "" +msgstr "Forenklet" #. module: base #: model:res.country,name:base.st msgid "Saint Tome (Sao Tome) and Principe" -msgstr "" +msgstr "Saint Tome (Sao Tome) and Principe" #. module: base #: selection:res.partner.address,type:0 msgid "Invoice" -msgstr "" +msgstr "Faktura" #. module: base #: selection:base.language.install,lang:0 msgid "Portugese (BR) / Português (BR)" -msgstr "" +msgstr "Portugese (BR) / Português (BR)" #. module: base #: model:res.country,name:base.bb msgid "Barbados" -msgstr "" +msgstr "Barbados" #. module: base #: model:res.country,name:base.mg msgid "Madagascar" -msgstr "" +msgstr "Madagaskar" #. module: base #: code:addons/base/ir/ir_model.py:96 @@ -1663,53 +1705,54 @@ msgstr "" msgid "" "The Object name must start with x_ and not contain any special character !" msgstr "" +"Objektnavnet må starte med x_ og kan ikke inneholde noen spesial karakterer !" #. module: base #: field:ir.actions.configuration.wizard,note:0 msgid "Next Wizard" -msgstr "" +msgstr "Neste veileder" #. module: base #: model:ir.actions.act_window,name:base.action_menu_admin #: view:ir.ui.menu:0 #: field:ir.ui.menu,name:0 msgid "Menu" -msgstr "" +msgstr "Meny" #. module: base #: field:res.currency,rate:0 msgid "Current Rate" -msgstr "" +msgstr "Gjeldene rate" #. module: base #: field:ir.ui.view.custom,ref_id:0 msgid "Original View" -msgstr "" +msgstr "Orginal visning" #. module: base #: view:ir.values:0 msgid "Action To Launch" -msgstr "" +msgstr "Handling som skal utføres" #. module: base #: field:ir.actions.url,target:0 msgid "Action Target" -msgstr "" +msgstr "Mål for handling" #. module: base #: model:res.country,name:base.ai msgid "Anguilla" -msgstr "" +msgstr "Anguilla" #. module: base #: field:ir.ui.view_sc,name:0 msgid "Shortcut Name" -msgstr "" +msgstr "Navn på snarvei" #. module: base #: help:ir.actions.act_window,limit:0 msgid "Default limit for the list view" -msgstr "" +msgstr "Standard grenseverdi for listevisningen" #. module: base #: help:ir.actions.server,write_id:0 @@ -1717,87 +1760,91 @@ msgid "" "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." msgstr "" +"Angi feltnavn som rad id'en refererer til for skrive operasjonen. Hvis den " +"er tom, så vil det refereres til den aktive id'en til objektet." #. module: base #: model:res.country,name:base.zw msgid "Zimbabwe" -msgstr "" +msgstr "Zimbabwe" #. module: base #: view:base.module.update:0 msgid "Please be patient, as this operation may take a few seconds..." -msgstr "" +msgstr "Vær tålmodig, denne operasjonen kan ta noen få sekunder..." #. module: base #: help:ir.values,action_id:0 msgid "This field is not used, it only helps you to select the right action." msgstr "" +"Dette feltet er ikke i bruk, det hjelper deg bare til å velge den riktige " +"handlingen." #. module: base #: field:ir.actions.server,email:0 msgid "Email Address" -msgstr "" +msgstr "Epostadresse" #. module: base #: selection:base.language.install,lang:0 msgid "French (BE) / Français (BE)" -msgstr "" +msgstr "Fransk / Français" #. module: base #: view:ir.actions.server:0 #: field:workflow.activity,action_id:0 msgid "Server Action" -msgstr "" +msgstr "Tjenerhandling" #. module: base #: model:res.country,name:base.tt msgid "Trinidad and Tobago" -msgstr "" +msgstr "Trinidad and Tobago" #. module: base #: model:res.country,name:base.lv msgid "Latvia" -msgstr "" +msgstr "Latvia" #. module: base #: view:ir.values:0 msgid "Values" -msgstr "" +msgstr "Verdier" #. module: base #: view:ir.actions.server:0 msgid "Field Mappings" -msgstr "" +msgstr "Feltoversikt" #. module: base #: view:base.language.export:0 msgid "Export Translations" -msgstr "" +msgstr "Eksporter oversettelser" #. module: base #: model:ir.ui.menu,name:base.menu_custom msgid "Customization" -msgstr "" +msgstr "Tilpasning" #. module: base #: model:res.country,name:base.py msgid "Paraguay" -msgstr "" +msgstr "Paraguay" #. module: base #: model:ir.model,name:base.model_ir_actions_act_window_close msgid "ir.actions.act_window_close" -msgstr "" +msgstr "ir.actions.act_window_close" #. module: base #: field:ir.server.object.lines,col1:0 msgid "Destination" -msgstr "" +msgstr "Destinasjon" #. module: base #: model:res.country,name:base.lt msgid "Lithuania" -msgstr "" +msgstr "Litauen" #. module: base #: model:ir.actions.act_window,name:base.action_view_partner_clear_ids @@ -1822,17 +1869,17 @@ msgstr "" #. module: base #: view:res.lang:0 msgid "%y - Year without century [00,99]." -msgstr "" +msgstr "%y - År uten århundre [00,99]." #. module: base #: model:res.country,name:base.si msgid "Slovenia" -msgstr "" +msgstr "Slovenia" #. module: base #: model:res.country,name:base.pk msgid "Pakistan" -msgstr "" +msgstr "Pakistan" #. module: base #: code:addons/orm.py:1350 @@ -1843,7 +1890,7 @@ msgstr "" #. module: base #: model:ir.ui.menu,name:base.menu_email_gateway_form msgid "Messages" -msgstr "" +msgstr "Meldinger" #. module: base #: code:addons/base/ir/ir_model.py:303 @@ -1855,17 +1902,17 @@ msgstr "" #: code:addons/base/module/wizard/base_update_translations.py:38 #, python-format msgid "Error!" -msgstr "" +msgstr "Feil!" #. module: base #: view:res.lang:0 msgid "%p - Equivalent of either AM or PM." -msgstr "" +msgstr "%p - Tilsvarende til enten AM eller PM." #. module: base #: view:ir.actions.server:0 msgid "Iteration Actions" -msgstr "" +msgstr "Iterasjonshandlinger" #. module: base #: help:multi_company.default,company_id:0 @@ -1875,12 +1922,12 @@ msgstr "" #. module: base #: field:publisher_warranty.contract,date_stop:0 msgid "Ending Date" -msgstr "" +msgstr "Slutter dato" #. module: base #: model:res.country,name:base.nz msgid "New Zealand" -msgstr "" +msgstr "New Zealand" #. module: base #: code:addons/orm.py:3366 @@ -1906,7 +1953,7 @@ msgstr "" #. module: base #: model:res.country,name:base.nf msgid "Norfolk Island" -msgstr "" +msgstr "Norfolk øyene" #. module: base #: selection:base.language.install,lang:0 @@ -1922,43 +1969,43 @@ msgstr "" #: field:ir.actions.server,action_id:0 #: selection:ir.actions.server,state:0 msgid "Client Action" -msgstr "" +msgstr "Klienthandling" #. module: base #: model:res.country,name:base.bd msgid "Bangladesh" -msgstr "" +msgstr "Bangladesh" #. module: base #: constraint:res.company:0 msgid "Error! You can not create recursive companies." -msgstr "" +msgstr "Feil ! Du kan ikke lage rekursive firmaer." #. module: base #: selection:publisher_warranty.contract,state:0 msgid "Valid" -msgstr "" +msgstr "Gyldig" #. module: base #: selection:ir.translation,type:0 msgid "XSL" -msgstr "" +msgstr "XSL" #. module: base #: code:addons/base/module/module.py:322 #, python-format msgid "Can not upgrade module '%s'. It is not installed." -msgstr "" +msgstr "Kan ikke oppgradere modulen '%s'. Den er ikke installert." #. module: base #: model:res.country,name:base.cu msgid "Cuba" -msgstr "" +msgstr "Cuba" #. module: base #: model:ir.model,name:base.model_res_partner_event msgid "res.partner.event" -msgstr "" +msgstr "res.partner.event" #. module: base #: model:res.widget,title:base.facebook_widget @@ -1968,41 +2015,41 @@ msgstr "" #. module: base #: model:res.country,name:base.am msgid "Armenia" -msgstr "" +msgstr "Armenia" #. module: base #: model:ir.actions.act_window,name:base.ir_property_form #: model:ir.ui.menu,name:base.menu_ir_property_form_all msgid "Configuration Parameters" -msgstr "" +msgstr "Konfigurasjonsparametere" #. module: base #: constraint:ir.cron:0 msgid "Invalid arguments" -msgstr "" +msgstr "Ugyldige argumenter" #. module: base #: model:res.country,name:base.se msgid "Sweden" -msgstr "" +msgstr "Sverige" #. module: base #: selection:ir.actions.act_window.view,view_mode:0 #: selection:ir.ui.view,type:0 #: selection:wizard.ir.model.menu.create.line,view_type:0 msgid "Gantt" -msgstr "" +msgstr "Gantt" #. module: base #: view:ir.property:0 msgid "Property" -msgstr "" +msgstr "Egenskap" #. module: base #: model:ir.model,name:base.model_res_partner_bank_type #: view:res.partner.bank.type:0 msgid "Bank Account Type" -msgstr "" +msgstr "Bankkontotype" #. module: base #: field:base.language.export,config_logo:0 @@ -2024,24 +2071,24 @@ msgstr "" #. module: base #: view:ir.actions.server:0 msgid "Iteration Action Configuration" -msgstr "" +msgstr "Iterasjonhandling instillinger" #. module: base #: selection:publisher_warranty.contract,state:0 msgid "Canceled" -msgstr "" +msgstr "Avbrutt" #. module: base #: model:res.country,name:base.at msgid "Austria" -msgstr "" +msgstr "Østerrike" #. module: base #: selection:base.language.install,state:0 #: selection:base.module.import,state:0 #: selection:base.module.update,state:0 msgid "done" -msgstr "" +msgstr "ferdig" #. module: base #: selection:ir.actions.act_window.view,view_mode:0 @@ -2049,7 +2096,7 @@ msgstr "" #: selection:ir.ui.view,type:0 #: selection:wizard.ir.model.menu.create.line,view_type:0 msgid "Calendar" -msgstr "" +msgstr "Kalender" #. module: base #: field:res.partner.address,partner_id:0 @@ -2059,12 +2106,12 @@ msgstr "" #. module: base #: field:workflow.activity,signal_send:0 msgid "Signal (subflow.*)" -msgstr "" +msgstr "Signal (subflow.*)" #. module: base #: model:res.partner.category,name:base.res_partner_category_17 msgid "HR sector" -msgstr "" +msgstr "HR sektor" #. module: base #: code:addons/orm.py:3817 @@ -2078,19 +2125,19 @@ msgstr "" #. module: base #: model:ir.model,name:base.model_ir_module_module_dependency msgid "Module dependency" -msgstr "" +msgstr "Modulavhengighet" #. module: base #: selection:publisher_warranty.contract.wizard,state:0 msgid "Draft" -msgstr "" +msgstr "Utkast" #. module: base #: selection:res.config.users,view:0 #: selection:res.config.view,view:0 #: selection:res.users,view:0 msgid "Extended" -msgstr "" +msgstr "Utvidet" #. module: base #: model:ir.actions.act_window,help:base.action_partner_title_contact @@ -2103,30 +2150,30 @@ msgstr "" #. module: base #: field:res.company,rml_footer1:0 msgid "Report Footer 1" -msgstr "" +msgstr "Rapport bunntekst 1" #. module: base #: field:res.company,rml_footer2:0 msgid "Report Footer 2" -msgstr "" +msgstr "Rapport bunntekst 2" #. module: base #: view:ir.model.access:0 #: view:res.groups:0 #: field:res.groups,model_access:0 msgid "Access Controls" -msgstr "" +msgstr "Tilgangskontroller" #. module: base #: view:ir.module.module:0 #: field:ir.module.module,dependencies_id:0 msgid "Dependencies" -msgstr "" +msgstr "Avhengigheter" #. module: base #: field:multi_company.default,company_id:0 msgid "Main Company" -msgstr "" +msgstr "Hovedfirma" #. module: base #: field:ir.ui.menu,web_icon_hover:0 @@ -2139,17 +2186,19 @@ msgid "" "If you use a formula type, use a python expression using the variable " "'object'." msgstr "" +"Hvis du benytter en formeltype, benytt et python uttrykk med variablen " +"'object'." #. module: base #: field:res.partner.address,birthdate:0 msgid "Birthdate" -msgstr "" +msgstr "Fødselsdag" #. module: base #: model:ir.actions.act_window,name:base.action_partner_title_contact #: model:ir.ui.menu,name:base.menu_partner_title_contact msgid "Contact Titles" -msgstr "" +msgstr "Kontakttitler" #. module: base #: view:base.language.import:0 @@ -2161,12 +2210,12 @@ msgstr "" #. module: base #: selection:base.language.install,lang:0 msgid "Spanish (DO) / Español (DO)" -msgstr "" +msgstr "Spanish (DO) / Español (DO)" #. module: base #: model:ir.model,name:base.model_workflow_activity msgid "workflow.activity" -msgstr "" +msgstr "workflow.activity" #. module: base #: help:ir.ui.view_sc,res_id:0 @@ -2178,17 +2227,17 @@ msgstr "" #. module: base #: field:ir.model.fields,select_level:0 msgid "Searchable" -msgstr "" +msgstr "Søkbar" #. module: base #: model:res.country,name:base.uy msgid "Uruguay" -msgstr "" +msgstr "Uruguay" #. module: base #: selection:base.language.install,lang:0 msgid "Finnish / Suomi" -msgstr "" +msgstr "Finland / Suomi" #. module: base #: field:ir.rule,perm_write:0 @@ -2198,32 +2247,32 @@ msgstr "" #. module: base #: field:ir.sequence,prefix:0 msgid "Prefix" -msgstr "" +msgstr "Prefix" #. module: base #: selection:base.language.install,lang:0 msgid "German / Deutsch" -msgstr "" +msgstr "Tysk / Deutsch" #. module: base #: help:ir.actions.server,trigger_name:0 msgid "Select the Signal name that is to be used as the trigger." -msgstr "" +msgstr "Velg signalnavnet som skal benyttes som utløser." #. module: base #: view:ir.actions.server:0 msgid "Fields Mapping" -msgstr "" +msgstr "Kobling av felter" #. module: base #: selection:base.language.install,lang:0 msgid "Portugese / Português" -msgstr "" +msgstr "Portugisisk / português" #. module: base #: model:res.partner.title,name:base.res_partner_title_sir msgid "Sir" -msgstr "" +msgstr "Hr" #. module: base #: code:addons/orm.py:1622 @@ -2234,23 +2283,23 @@ msgstr "" #. module: base #: field:ir.default,ref_id:0 msgid "ID Ref." -msgstr "" +msgstr "ID Ref." #. module: base #: model:ir.actions.server,name:base.action_start_configurator #: model:ir.ui.menu,name:base.menu_view_base_module_configuration msgid "Start Configuration" -msgstr "" +msgstr "Start konfigurasjon" #. module: base #: model:res.country,name:base.mt msgid "Malta" -msgstr "" +msgstr "Malta" #. module: base #: field:ir.actions.server,fields_lines:0 msgid "Field Mappings." -msgstr "" +msgstr "Mapping av felter." #. module: base #: model:ir.model,name:base.model_ir_module_module @@ -2261,7 +2310,7 @@ msgstr "" #: report:ir.module.reference.graph:0 #: field:ir.translation,module:0 msgid "Module" -msgstr "" +msgstr "Modul" #. module: base #: field:ir.attachment,description:0 @@ -2272,18 +2321,18 @@ msgstr "" #: field:res.partner.event,description:0 #: view:res.request:0 msgid "Description" -msgstr "" +msgstr "Beskrivelse" #. module: base #: model:ir.actions.act_window,name:base.action_workflow_instance_form #: model:ir.ui.menu,name:base.menu_workflow_instance msgid "Instances" -msgstr "" +msgstr "Instanser" #. module: base #: model:res.country,name:base.aq msgid "Antarctica" -msgstr "" +msgstr "Antarktis" #. module: base #: field:ir.actions.report.xml,auto:0 @@ -2293,55 +2342,55 @@ msgstr "" #. module: base #: view:base.language.import:0 msgid "_Import" -msgstr "" +msgstr "_Importer" #. module: base #: view:res.partner.canal:0 msgid "Channel" -msgstr "" +msgstr "Kanal" #. module: base #: field:res.lang,grouping:0 msgid "Separator Format" -msgstr "" +msgstr "Separatorformat" #. module: base #: selection:publisher_warranty.contract,state:0 msgid "Unvalidated" -msgstr "" +msgstr "Ikke validert" #. module: base #: model:ir.ui.menu,name:base.next_id_9 msgid "Database Structure" -msgstr "" +msgstr "Databasestruktur" #. module: base #: model:ir.actions.act_window,name:base.action_partner_mass_mail #: model:ir.model,name:base.model_partner_wizard_spam #: view:partner.wizard.spam:0 msgid "Mass Mailing" -msgstr "" +msgstr "Masse utsendelse av e-post" #. module: base #: model:res.country,name:base.yt msgid "Mayotte" -msgstr "" +msgstr "Mayotte" #. module: base #: code:addons/base/ir/ir_actions.py:597 #, python-format msgid "Please specify an action to launch !" -msgstr "" +msgstr "Vær vennlig å velg en handling å uføre !" #. module: base #: view:res.payterm:0 msgid "Payment Term" -msgstr "" +msgstr "Betalingsbetingelser" #. module: base #: selection:res.lang,direction:0 msgid "Right-to-Left" -msgstr "" +msgstr "Høyre-til-venstre" #. module: base #: view:ir.actions.act_window:0 @@ -2350,7 +2399,7 @@ msgstr "" #: model:ir.model,name:base.model_ir_filters #: model:ir.ui.menu,name:base.menu_ir_filters msgid "Filters" -msgstr "" +msgstr "Filter" #. module: base #: code:addons/orm.py:758 @@ -2363,14 +2412,14 @@ msgstr "" #: view:ir.cron:0 #: model:ir.ui.menu,name:base.menu_ir_cron_act msgid "Scheduled Actions" -msgstr "" +msgstr "Planlagte handlinger" #. module: base #: field:res.partner.address,title:0 #: field:res.partner.title,name:0 #: field:res.widget,title:0 msgid "Title" -msgstr "" +msgstr "Tittel" #. module: base #: help:ir.property,res_id:0 @@ -2387,7 +2436,7 @@ msgstr "" #: code:addons/base/module/module.py:262 #, python-format msgid "Recursion error in modules dependencies !" -msgstr "" +msgstr "Feil grunnet rekursjon i modulavhengigheter !" #. module: base #: view:base.language.install:0 @@ -2400,7 +2449,7 @@ msgstr "" #. module: base #: view:ir.model:0 msgid "Create a Menu" -msgstr "" +msgstr "Opprett en meny" #. module: base #: help:res.partner,vat:0 @@ -2408,16 +2457,18 @@ msgid "" "Value Added Tax number. Check the box if the partner is subjected to the " "VAT. Used by the VAT legal statement." msgstr "" +"MVA nummer. Kryss av boksen dersom partner er underlagt MVA. Benyttes fra " +"MVA legal statement!" #. module: base #: model:ir.model,name:base.model_maintenance_contract msgid "maintenance.contract" -msgstr "" +msgstr "maintenance.contract" #. module: base #: model:res.country,name:base.ru msgid "Russian Federation" -msgstr "" +msgstr "Russland" #. module: base #: selection:base.language.install,lang:0 @@ -2427,13 +2478,13 @@ msgstr "" #. module: base #: field:res.company,name:0 msgid "Company Name" -msgstr "" +msgstr "Firmanavn" #. module: base #: model:ir.actions.act_window,name:base.action_country #: model:ir.ui.menu,name:base.menu_country_partner msgid "Countries" -msgstr "" +msgstr "Land" #. module: base #: selection:ir.translation,type:0 @@ -2443,12 +2494,12 @@ msgstr "" #. module: base #: view:ir.rule:0 msgid "Record rules" -msgstr "" +msgstr "Opprett regler" #. module: base #: view:ir.property:0 msgid "Field Information" -msgstr "" +msgstr "Feltinformasjon" #. module: base #: view:ir.actions.todo:0 @@ -2464,37 +2515,37 @@ msgstr "" #. module: base #: field:res.partner,vat:0 msgid "VAT" -msgstr "" +msgstr "MVA" #. module: base #: view:res.lang:0 msgid "12. %w ==> 5 ( Friday is the 6th day)" -msgstr "" +msgstr "12. %w ==> 5 ( Fredag er den 6. dagen)" #. module: base #: constraint:res.partner.category:0 msgid "Error ! You can not create recursive categories." -msgstr "" +msgstr "Feil ! Du kan ikke lage rekursive kategorier." #. module: base #: view:res.lang:0 msgid "%x - Appropriate date representation." -msgstr "" +msgstr "%x - Passende datovisning." #. module: base #: view:res.lang:0 msgid "%d - Day of the month [01,31]." -msgstr "" +msgstr "%d - Dag i månedenl [01,31]." #. module: base #: model:res.country,name:base.tj msgid "Tajikistan" -msgstr "" +msgstr "Tajikistan" #. module: base #: selection:ir.module.module,license:0 msgid "GPL-2 or later version" -msgstr "" +msgstr "GPL-2 eller senere versjon" #. module: base #: model:res.partner.title,shortcut:base.res_partner_title_sir @@ -2508,6 +2559,8 @@ msgid "" "Can not create the module file:\n" " %s" msgstr "" +"Can not create the module file:\n" +" %s" #. module: base #: code:addons/orm.py:2973 @@ -2520,7 +2573,7 @@ msgstr "" #. module: base #: model:res.country,name:base.nr msgid "Nauru" -msgstr "" +msgstr "Nauru" #. module: base #: code:addons/base/module/module.py:200 @@ -2531,7 +2584,7 @@ msgstr "" #. module: base #: model:ir.model,name:base.model_ir_property msgid "ir.property" -msgstr "" +msgstr "Ukjent egenskap %s" #. module: base #: selection:ir.actions.act_window,view_type:0 @@ -2540,23 +2593,23 @@ msgstr "" #: selection:ir.ui.view,type:0 #: selection:wizard.ir.model.menu.create.line,view_type:0 msgid "Form" -msgstr "" +msgstr "Skjema" #. module: base #: model:res.country,name:base.me msgid "Montenegro" -msgstr "" +msgstr "Montenegro" #. module: base #: view:ir.cron:0 msgid "Technical Data" -msgstr "" +msgstr "Tekniske data" #. module: base #: view:res.partner:0 #: field:res.partner,category_id:0 msgid "Categories" -msgstr "" +msgstr "Kategorier" #. module: base #: view:base.language.import:0 @@ -2571,33 +2624,33 @@ msgstr "" #: selection:ir.module.module,state:0 #: selection:ir.module.module.dependency,state:0 msgid "To be upgraded" -msgstr "" +msgstr "Skal oppgraderes" #. module: base #: model:res.country,name:base.ly msgid "Libya" -msgstr "" +msgstr "Libya" #. module: base #: model:res.country,name:base.cf msgid "Central African Republic" -msgstr "" +msgstr "Den sentralafrikanske republikk" #. module: base #: model:res.country,name:base.li msgid "Liechtenstein" -msgstr "" +msgstr "Liechtenstein" #. module: base #: model:ir.model,name:base.model_partner_sms_send #: view:partner.sms.send:0 msgid "Send SMS" -msgstr "" +msgstr "Send SMS" #. module: base #: field:res.partner,ean13:0 msgid "EAN13" -msgstr "" +msgstr "EAN13" #. module: base #: code:addons/orm.py:1622 @@ -2608,7 +2661,7 @@ msgstr "" #. module: base #: model:res.country,name:base.pt msgid "Portugal" -msgstr "" +msgstr "Portugal" #. module: base #: sql_constraint:ir.model.data:0 @@ -2619,18 +2672,18 @@ msgstr "" #. module: base #: field:ir.module.module,certificate:0 msgid "Quality Certificate" -msgstr "" +msgstr "Kvalitestsertifikat" #. module: base #: view:res.lang:0 msgid "6. %d, %m ==> 05, 12" -msgstr "" +msgstr "6. %d, %m ==> 05, 12" #. module: base #: field:res.config.users,date:0 #: field:res.users,date:0 msgid "Last Connection" -msgstr "" +msgstr "Sist tilkoblet" #. module: base #: field:ir.actions.act_window,help:0 @@ -2640,7 +2693,7 @@ msgstr "" #. module: base #: help:res.partner,customer:0 msgid "Check this box if the partner is a customer." -msgstr "" +msgstr "Kryss av denne boksen dersom partneren er en kunde." #. module: base #: model:ir.actions.act_window,name:base.res_lang_act_window @@ -2648,18 +2701,18 @@ msgstr "" #: model:ir.ui.menu,name:base.menu_res_lang_act_window #: view:res.lang:0 msgid "Languages" -msgstr "" +msgstr "Språk" #. module: base #: selection:workflow.activity,join_mode:0 #: selection:workflow.activity,split_mode:0 msgid "Xor" -msgstr "" +msgstr "Xor" #. module: base #: model:res.country,name:base.ec msgid "Ecuador" -msgstr "" +msgstr "Equador" #. module: base #: code:addons/base/module/wizard/base_export_language.py:52 @@ -2669,6 +2722,9 @@ msgid "" "spreadsheet software. The file encoding is UTF-8. You have to translate the " "latest column before reimporting it." msgstr "" +"Lagre dette dokumentet til en .CSV fil og åpne den med programvare for " +"behandling av regneark. Enkodingen på denne filen er UTF-8. Du må oversette " +"den siste kolonnen før du re-importere den." #. module: base #: model:ir.actions.act_window,name:base.action_partner_customer_form @@ -2676,12 +2732,12 @@ msgstr "" #: model:ir.ui.menu,name:base.menu_partner_form #: view:res.partner:0 msgid "Customers" -msgstr "" +msgstr "Kunder" #. module: base #: model:res.country,name:base.au msgid "Australia" -msgstr "" +msgstr "Australia" #. module: base #: help:res.partner,lang:0 @@ -2689,16 +2745,19 @@ msgid "" "If the selected language is loaded in the system, all documents related to " "this partner will be printed in this language. If not, it will be english." msgstr "" +"Dersom the valgte språket er lastet i systemet, vil alle dokumenter relatert " +"til denne partneren bli skrevet ut med dette språket. Hvis ikke benyttes " +"engelsk som standard." #. module: base #: report:ir.module.reference.graph:0 msgid "Menu :" -msgstr "" +msgstr "Meny :" #. module: base #: selection:ir.model.fields,state:0 msgid "Base Field" -msgstr "" +msgstr "Basisfelt" #. module: base #: view:publisher_warranty.contract:0 @@ -2708,24 +2767,24 @@ msgstr "" #. module: base #: field:ir.actions.todo,restart:0 msgid "Restart" -msgstr "" +msgstr "Omstart" #. module: base #: field:ir.actions.report.xml,report_sxw_content:0 #: field:ir.actions.report.xml,report_sxw_content_data:0 msgid "SXW content" -msgstr "" +msgstr "SXW innhold" #. module: base #: view:ir.actions.wizard:0 #: field:wizard.ir.model.menu.create.line,wizard_id:0 msgid "Wizard" -msgstr "" +msgstr "Veiviser" #. module: base #: view:ir.cron:0 msgid "Action to Trigger" -msgstr "" +msgstr "Handling å trigge" #. module: base #: code:addons/base/res/res_user.py:136 @@ -2736,20 +2795,20 @@ msgstr "" #. module: base #: selection:ir.translation,type:0 msgid "Constraint" -msgstr "" +msgstr "Beskrankning" #. module: base #: selection:ir.values,key:0 #: selection:res.partner.address,type:0 msgid "Default" -msgstr "" +msgstr "Standard" #. module: base #: view:ir.model.fields:0 #: field:ir.model.fields,required:0 #: field:res.partner.bank.type.field,required:0 msgid "Required" -msgstr "" +msgstr "Obligatorisk" #. module: base #: view:res.users:0 @@ -2759,7 +2818,7 @@ msgstr "" #. module: base #: field:res.request.history,name:0 msgid "Summary" -msgstr "" +msgstr "Sammendrag" #. module: base #: field:multi_company.default,expression:0 @@ -2772,11 +2831,13 @@ msgid "" "Specify the subject. You can use fields from the object, e.g. `Hello [[ " "object.partner_id.name ]]`" msgstr "" +"Spesifiser emnet. Du kan bruke felter fra objektet. F.eks 'Hei [[ " +"object.partner_id.name ]]`" #. module: base #: view:res.company:0 msgid "Header/Footer" -msgstr "" +msgstr "Topptekst/Bunntekst" #. module: base #: help:ir.actions.act_window,help:0 @@ -2788,12 +2849,12 @@ msgstr "" #. module: base #: model:res.country,name:base.va msgid "Holy See (Vatican City State)" -msgstr "" +msgstr "Pavestolen (Vatikanstaten)" #. module: base #: field:base.module.import,module_file:0 msgid "Module .ZIP file" -msgstr "" +msgstr "Modul .ZIP fil" #. module: base #: field:ir.ui.view,xml_id:0 @@ -2808,7 +2869,7 @@ msgstr "" #. module: base #: field:workflow.transition,trigger_model:0 msgid "Trigger Object" -msgstr "" +msgstr "Utløserobjekt" #. module: base #: view:res.users:0 @@ -2819,12 +2880,12 @@ msgstr "" #: view:workflow.activity:0 #: field:workflow.activity,in_transitions:0 msgid "Incoming Transitions" -msgstr "" +msgstr "Innkommende overganger" #. module: base #: model:res.country,name:base.sr msgid "Suriname" -msgstr "" +msgstr "Surinam" #. module: base #: model:ir.ui.menu,name:base.marketing_menu @@ -2835,17 +2896,17 @@ msgstr "" #: view:res.partner.bank:0 #: model:res.partner.bank.type,name:base.bank_normal msgid "Bank account" -msgstr "" +msgstr "Bankkonto" #. module: base #: selection:base.language.install,lang:0 msgid "Spanish (HN) / Español (HN)" -msgstr "" +msgstr "Spanish (HN) / Español (HN)" #. module: base #: view:ir.sequence.type:0 msgid "Sequence Type" -msgstr "" +msgstr "Sekvenstype" #. module: base #: view:ir.ui.view.custom:0 @@ -2855,7 +2916,7 @@ msgstr "" #. module: base #: field:ir.module.module,license:0 msgid "License" -msgstr "" +msgstr "License" #. module: base #: field:ir.attachment,url:0 @@ -2865,18 +2926,18 @@ msgstr "" #. module: base #: selection:ir.actions.todo,restart:0 msgid "Always" -msgstr "" +msgstr "Alltid" #. module: base #: selection:ir.translation,type:0 msgid "SQL Constraint" -msgstr "" +msgstr "SQL beskrankning" #. module: base #: field:ir.actions.server,srcmodel_id:0 #: field:ir.model.fields,model_id:0 msgid "Model" -msgstr "" +msgstr "Modell" #. module: base #: view:base.language.install:0 @@ -2884,6 +2945,8 @@ msgid "" "The selected language has been successfully installed. You must change the " "preferences of the user and open a new menu to view the changes." msgstr "" +"The valgte språk har blitt installert. Du må endre preferansene til brukeren " +"og åpne en ny meny for å se endringene." #. module: base #: sql_constraint:ir.config_parameter:0 @@ -2893,31 +2956,31 @@ msgstr "" #. module: base #: view:ir.actions.act_window:0 msgid "Open a Window" -msgstr "" +msgstr "Åpne et vindu" #. module: base #: model:res.country,name:base.gq msgid "Equatorial Guinea" -msgstr "" +msgstr "Ekvatorial-Guinea" #. module: base #: view:base.module.import:0 #: model:ir.actions.act_window,name:base.action_view_base_module_import msgid "Module Import" -msgstr "" +msgstr "Importer modul" #. module: base #: field:res.bank,zip:0 #: field:res.partner.address,zip:0 #: field:res.partner.bank,zip:0 msgid "Zip" -msgstr "" +msgstr "Postnummer" #. module: base #: view:ir.module.module:0 #: field:ir.module.module,author:0 msgid "Author" -msgstr "" +msgstr "Forfatter" #. module: base #: model:res.country,name:base.mk @@ -2927,7 +2990,7 @@ msgstr "" #. module: base #: view:res.lang:0 msgid "%c - Appropriate date and time representation." -msgstr "" +msgstr "%c - Hensiktsmessig representasjon av tid og dato." #. module: base #: code:addons/base/res/res_config.py:422 @@ -2946,17 +3009,17 @@ msgstr "" #. module: base #: model:res.country,name:base.bo msgid "Bolivia" -msgstr "" +msgstr "Bolivia" #. module: base #: model:res.country,name:base.gh msgid "Ghana" -msgstr "" +msgstr "Ghana" #. module: base #: field:res.lang,direction:0 msgid "Direction" -msgstr "" +msgstr "Retning" #. module: base #: view:ir.actions.act_window:0 @@ -2967,34 +3030,35 @@ msgstr "" #: model:ir.ui.menu,name:base.menu_action_ui_view #: view:ir.ui.view:0 msgid "Views" -msgstr "" +msgstr "Visninger" #. module: base #: view:res.groups:0 #: field:res.groups,rule_groups:0 msgid "Rules" -msgstr "" +msgstr "Regler" #. module: base #: code:addons/base/module/module.py:216 #, python-format msgid "You try to remove a module that is installed or will be installed" msgstr "" +"Du prøver å fjerne en modul som er installert eller vil bli installert" #. module: base #: view:base.module.upgrade:0 msgid "The selected modules have been updated / installed !" -msgstr "" +msgstr "Modulene har blitt oppgradert / installert !" #. module: base #: selection:base.language.install,lang:0 msgid "Spanish (PR) / Español (PR)" -msgstr "" +msgstr "Spanish (PR) / Español (PR)" #. module: base #: model:res.country,name:base.gt msgid "Guatemala" -msgstr "" +msgstr "Guatemala" #. module: base #: model:ir.actions.act_window,name:base.action_workflow_form @@ -3002,27 +3066,27 @@ msgstr "" #: model:ir.ui.menu,name:base.menu_workflow #: model:ir.ui.menu,name:base.menu_workflow_root msgid "Workflows" -msgstr "" +msgstr "Arbeidsflyt" #. module: base #: field:ir.translation,xml_id:0 msgid "XML Id" -msgstr "" +msgstr "XML Identifikator" #. module: base #: model:ir.actions.act_window,name:base.action_config_user_form msgid "Create Users" -msgstr "" +msgstr "Opprett brukere" #. module: base #: model:ir.model,name:base.model_res_partner_title msgid "res.partner.title" -msgstr "" +msgstr "res.partner.title" #. module: base #: view:ir.values:0 msgid "tree_but_action, client_print_multi" -msgstr "" +msgstr "tree_but_action, client_print_multi" #. module: base #: model:res.partner.category,name:base.res_partner_category_retailers0 @@ -3035,28 +3099,30 @@ msgid "" "0=Very Urgent\n" "10=Not urgent" msgstr "" +"0=Haster veldig\n" +"10=Haster ikke" #. module: base #: view:res.config:0 #: view:res.config.installer:0 msgid "Skip" -msgstr "" +msgstr "Hopp over" #. module: base #: model:res.country,name:base.ls msgid "Lesotho" -msgstr "" +msgstr "Lesotho" #. module: base #: code:addons/base/ir/ir_model.py:114 #, python-format msgid "You can not remove the model '%s' !" -msgstr "" +msgstr "Du kan ikke fjerne modellen '%s'!" #. module: base #: model:res.country,name:base.ke msgid "Kenya" -msgstr "" +msgstr "Kenya" #. module: base #: view:res.partner.event:0 @@ -3066,7 +3132,7 @@ msgstr "" #. module: base #: model:ir.ui.menu,name:base.menu_custom_reports msgid "Custom Reports" -msgstr "" +msgstr "Tilpassede rapporter" #. module: base #: selection:base.language.install,lang:0 @@ -3087,32 +3153,32 @@ msgstr "" #. module: base #: view:ir.property:0 msgid "Generic" -msgstr "" +msgstr "Generell" #. module: base #: model:res.country,name:base.sm msgid "San Marino" -msgstr "" +msgstr "San Marino" #. module: base #: model:res.country,name:base.bm msgid "Bermuda" -msgstr "" +msgstr "Bermuda" #. module: base #: model:res.country,name:base.pe msgid "Peru" -msgstr "" +msgstr "Peru" #. module: base #: selection:ir.model.fields,on_delete:0 msgid "Set NULL" -msgstr "" +msgstr "Set NULL" #. module: base #: model:res.country,name:base.bj msgid "Benin" -msgstr "" +msgstr "Benin" #. module: base #: code:addons/base/publisher_warranty/publisher_warranty.py:281 @@ -3128,22 +3194,22 @@ msgstr "" #. module: base #: selection:base.language.install,lang:0 msgid "Spanish (PY) / Español (PY)" -msgstr "" +msgstr "Spanish (PY) / Español (PY)" #. module: base #: field:ir.config_parameter,key:0 msgid "Key" -msgstr "" +msgstr "Nøkkel" #. module: base #: field:res.company,rml_header:0 msgid "RML Header" -msgstr "" +msgstr "RML overskrift" #. module: base #: field:partner.sms.send,app_id:0 msgid "API ID" -msgstr "" +msgstr "API ID" #. module: base #: code:addons/base/ir/ir_model.py:486 @@ -3156,13 +3222,13 @@ msgstr "" #. module: base #: model:res.country,name:base.mu msgid "Mauritius" -msgstr "" +msgstr "Mauritius" #. module: base #: view:ir.model.access:0 #: view:ir.rule:0 msgid "Full Access" -msgstr "" +msgstr "Full tilgang" #. module: base #: view:ir.actions.act_window:0 @@ -3171,7 +3237,7 @@ msgstr "" #: view:ir.model.fields:0 #: model:ir.ui.menu,name:base.menu_security msgid "Security" -msgstr "" +msgstr "Sikkerhet" #. module: base #: model:res.widget,title:base.openerp_favorites_twitter_widget @@ -3181,14 +3247,14 @@ msgstr "" #. module: base #: model:res.country,name:base.za msgid "South Africa" -msgstr "" +msgstr "Sør-Afrika" #. module: base #: view:ir.module.module:0 #: selection:ir.module.module,state:0 #: selection:ir.module.module.dependency,state:0 msgid "Installed" -msgstr "" +msgstr "Installert" #. module: base #: selection:base.language.install,lang:0 @@ -3199,42 +3265,42 @@ msgstr "" #: model:ir.actions.act_window,name:base.action_translation #: model:ir.ui.menu,name:base.menu_action_translation msgid "Translation Terms" -msgstr "" +msgstr "Betegnelser i oversettelsen" #. module: base #: model:res.country,name:base.sn msgid "Senegal" -msgstr "" +msgstr "Senegal" #. module: base #: model:res.country,name:base.hu msgid "Hungary" -msgstr "" +msgstr "Ungarn" #. module: base #: model:ir.model,name:base.model_res_groups msgid "res.groups" -msgstr "" +msgstr "res.groups" #. module: base #: model:res.country,name:base.br msgid "Brazil" -msgstr "" +msgstr "Brasil" #. module: base #: view:res.lang:0 msgid "%M - Minute [00,59]." -msgstr "" +msgstr "%M - Minutt [00,59]." #. module: base #: selection:ir.module.module,license:0 msgid "Affero GPL-3" -msgstr "" +msgstr "Affero GPL-3" #. module: base #: field:ir.sequence,number_next:0 msgid "Next Number" -msgstr "" +msgstr "Neste nummer" #. module: base #: help:workflow.transition,condition:0 @@ -3244,23 +3310,23 @@ msgstr "" #. module: base #: selection:base.language.install,lang:0 msgid "Spanish (PA) / Español (PA)" -msgstr "" +msgstr "Spanish (PA) / Español (PA)" #. module: base #: view:res.currency:0 #: field:res.currency,rate_ids:0 msgid "Rates" -msgstr "" +msgstr "Rater" #. module: base #: model:res.country,name:base.sy msgid "Syria" -msgstr "" +msgstr "Syria" #. module: base #: view:res.lang:0 msgid "======================================================" -msgstr "" +msgstr "======================================================" #. module: base #: help:ir.actions.server,mobile:0 @@ -3269,16 +3335,19 @@ msgid "" "invoice, then `object.invoice_address_id.mobile` is the field which gives " "the correct mobile number" msgstr "" +"Tilgjengeliggjør felter som benyttes til å hente mobil nummeret, f.eks. når " +"du velger fakturaen så vil feltet `object.invoice_address_id.mobile` gi det " +"korrekte mobil nummeret" #. module: base #: view:base.module.upgrade:0 msgid "System update completed" -msgstr "" +msgstr "Systemoppgradering fullført" #. module: base #: selection:res.request,state:0 msgid "draft" -msgstr "" +msgstr "utkast" #. module: base #: selection:ir.property,type:0 @@ -3288,23 +3357,23 @@ msgstr "" #: field:res.partner.event,date:0 #: field:res.request,date_sent:0 msgid "Date" -msgstr "" +msgstr "Dato" #. module: base #: field:ir.actions.report.xml,report_sxw:0 msgid "SXW path" -msgstr "" +msgstr "SXW sti" #. module: base #: view:ir.attachment:0 msgid "Data" -msgstr "" +msgstr "Data" #. module: base #: field:ir.ui.menu,parent_id:0 #: field:wizard.ir.model.menu.create,menu_id:0 msgid "Parent Menu" -msgstr "" +msgstr "Overordnet meny" #. module: base #: field:ir.rule,perm_unlink:0 @@ -3320,12 +3389,12 @@ msgstr "" #. module: base #: view:ir.attachment:0 msgid "Attached To" -msgstr "" +msgstr "Knyttet til" #. module: base #: field:res.lang,decimal_point:0 msgid "Decimal Separator" -msgstr "" +msgstr "Desimal separator" #. module: base #: model:ir.actions.act_window,help:base.action_res_groups @@ -3343,12 +3412,12 @@ msgstr "" #: view:res.request:0 #: field:res.request,history:0 msgid "History" -msgstr "" +msgstr "Historikk" #. module: base #: field:ir.attachment,create_uid:0 msgid "Creator" -msgstr "" +msgstr "Forfatter" #. module: base #: model:res.company,overdue_msg:base.main_company @@ -3364,7 +3433,7 @@ msgstr "" #. module: base #: model:res.country,name:base.mx msgid "Mexico" -msgstr "" +msgstr "Mexico" #. module: base #: model:ir.ui.menu,name:base.menu_base_config_plugins @@ -3374,17 +3443,17 @@ msgstr "" #. module: base #: field:res.company,child_ids:0 msgid "Child Companies" -msgstr "" +msgstr "Datterselskap" #. module: base #: model:ir.model,name:base.model_res_users msgid "res.users" -msgstr "" +msgstr "res.users" #. module: base #: model:res.country,name:base.ni msgid "Nicaragua" -msgstr "" +msgstr "Nicaragua" #. module: base #: code:addons/orm.py:1046 @@ -3395,18 +3464,18 @@ msgstr "" #. module: base #: view:res.partner.event:0 msgid "General Description" -msgstr "" +msgstr "Generell beskrivelse" #. module: base #: model:ir.actions.act_window,name:base.action_config_simple_view_form #: view:res.config.view:0 msgid "Configure Your Interface" -msgstr "" +msgstr "Konfigurer grensesnittet ditt" #. module: base #: field:ir.values,meta:0 msgid "Meta Datas" -msgstr "" +msgstr "Metadata" #. module: base #: sql_constraint:ir.ui.view_sc:0 @@ -3416,17 +3485,17 @@ msgstr "" #. module: base #: model:res.country,name:base.ve msgid "Venezuela" -msgstr "" +msgstr "Venezuela" #. module: base #: view:res.lang:0 msgid "9. %j ==> 340" -msgstr "" +msgstr "9. %j ==> 340" #. module: base #: model:res.country,name:base.zm msgid "Zambia" -msgstr "" +msgstr "Zambia" #. module: base #: help:res.partner,user_id:0 @@ -3434,6 +3503,7 @@ msgid "" "The internal user that is in charge of communicating with this partner if " "any." msgstr "" +"Den interne brukeren som er ansvarlig for å kommunisere med partneren." #. module: base #: field:res.partner,parent_id:0 @@ -3443,22 +3513,22 @@ msgstr "" #. module: base #: view:ir.module.module:0 msgid "Cancel Upgrade" -msgstr "" +msgstr "Avbryt oppgradering" #. module: base #: model:res.country,name:base.ci msgid "Ivory Coast (Cote D'Ivoire)" -msgstr "" +msgstr "Elfenbenskysten" #. module: base #: model:res.country,name:base.kz msgid "Kazakhstan" -msgstr "" +msgstr "Kazakhstan" #. module: base #: view:res.lang:0 msgid "%w - Weekday number [0(Sunday),6]." -msgstr "" +msgstr "%w - Ukedag [0(Søndag),6]." #. module: base #: model:ir.actions.act_window,help:base.action_partner_form @@ -3498,7 +3568,7 @@ msgstr "" #: field:workflow,name:0 #: field:workflow.activity,name:0 msgid "Name" -msgstr "" +msgstr "Navn" #. module: base #: help:ir.actions.act_window,multi:0 @@ -3506,11 +3576,13 @@ msgid "" "If set to true, the action will not be displayed on the right toolbar of a " "form view" msgstr "" +"Hvis satt til sann, så vil ikke handlingen vises på den høyre verktøylinjen " +"i skjemavisning." #. module: base #: model:res.country,name:base.ms msgid "Montserrat" -msgstr "" +msgstr "Montserrat" #. module: base #: code:addons/base/ir/ir_model.py:205 @@ -3523,7 +3595,7 @@ msgstr "" #. module: base #: model:ir.ui.menu,name:base.menu_translation_app msgid "Application Terms" -msgstr "" +msgstr "Begrep i applikasjonen" #. module: base #: help:res.config.users,context_tz:0 @@ -3536,7 +3608,7 @@ msgstr "" #. module: base #: field:ir.module.module,demo:0 msgid "Demo data" -msgstr "" +msgstr "Demodata" #. module: base #: selection:base.language.install,lang:0 @@ -3570,12 +3642,12 @@ msgstr "" #. module: base #: model:ir.model,name:base.model_ir_actions_act_window_view msgid "ir.actions.act_window.view" -msgstr "" +msgstr "ir.actions.act_window_close" #. module: base #: report:ir.module.reference.graph:0 msgid "Web" -msgstr "" +msgstr "Web" #. module: base #: selection:base.language.install,lang:0 @@ -3590,23 +3662,23 @@ msgstr "" #. module: base #: model:res.country,name:base.et msgid "Ethiopia" -msgstr "" +msgstr "Etiopia" #. module: base #: help:res.country.state,code:0 msgid "The state code in three chars.\n" -msgstr "" +msgstr "Koden til staten med tre karakterer.\n" #. module: base #: model:res.country,name:base.sj msgid "Svalbard and Jan Mayen Islands" -msgstr "" +msgstr "Svalbard og Jan Mayen øyene" #. module: base #: model:ir.model,name:base.model_ir_actions_wizard #: selection:ir.ui.menu,action:0 msgid "ir.actions.wizard" -msgstr "" +msgstr "ir.actions.wizard" #. module: base #: view:ir.actions.act_window:0 @@ -3615,99 +3687,99 @@ msgstr "" #: view:ir.filters:0 #: view:res.request:0 msgid "Group By" -msgstr "" +msgstr "Grupper etter" #. module: base #: view:res.config:0 #: view:res.config.installer:0 msgid "title" -msgstr "" +msgstr "tittel" #. module: base #: model:ir.model,name:base.model_base_language_install msgid "Install Language" -msgstr "" +msgstr "Installer språk" #. module: base #: view:ir.translation:0 msgid "Translation" -msgstr "" +msgstr "Oversettelse" #. module: base #: selection:res.request,state:0 msgid "closed" -msgstr "" +msgstr "lukket" #. module: base #: selection:base.language.export,state:0 msgid "get" -msgstr "" +msgstr "hent" #. module: base #: help:ir.model.fields,on_delete:0 msgid "On delete property for many2one fields" -msgstr "" +msgstr "On delete property for many2one fields" #. module: base #: field:ir.actions.server,write_id:0 msgid "Write Id" -msgstr "" +msgstr "Write Id" #. module: base #: model:ir.ui.menu,name:base.menu_product msgid "Products" -msgstr "" +msgstr "Produkter" #. module: base #: field:ir.actions.act_window,domain:0 #: field:ir.filters,domain:0 msgid "Domain Value" -msgstr "" +msgstr "Domeneverdi" #. module: base #: view:ir.actions.server:0 msgid "SMS Configuration" -msgstr "" +msgstr "SMS konfigurasjon" #. module: base #: selection:base.language.install,lang:0 msgid "Spanish (BO) / Español (BO)" -msgstr "" +msgstr "Spanish (BO) / Español (BO)" #. module: base #: model:ir.actions.act_window,name:base.ir_access_act #: model:ir.ui.menu,name:base.menu_ir_access_act msgid "Access Controls List" -msgstr "" +msgstr "Liste over tilganger" #. module: base #: model:res.country,name:base.um msgid "USA Minor Outlying Islands" -msgstr "" +msgstr "USA Minor Outlying Islands" #. module: base #: field:res.partner.bank,state:0 #: field:res.partner.bank.type.field,bank_type_id:0 msgid "Bank Type" -msgstr "" +msgstr "Banktype" #. module: base #: code:addons/base/res/res_user.py:58 #: code:addons/base/res/res_user.py:67 #, python-format msgid "The name of the group can not start with \"-\"" -msgstr "" +msgstr "Navnet på gruppen kan ikke starte med \"-\"" #. module: base #: view:ir.ui.view_sc:0 #: field:res.partner.title,shortcut:0 msgid "Shortcut" -msgstr "" +msgstr "Snarvei" #. module: base #: field:ir.model.data,date_init:0 msgid "Init Date" -msgstr "" +msgstr "Initiell dato" #. module: base #: selection:base.language.install,lang:0 @@ -3730,7 +3802,7 @@ msgstr "" #: view:workflow.activity:0 #: field:workflow.activity,flow_start:0 msgid "Flow Start" -msgstr "" +msgstr "Flytstart" #. module: base #: code:addons/__init__.py:834 @@ -3741,28 +3813,28 @@ msgstr "" #. module: base #: view:res.partner.bank:0 msgid "Bank Account Owner" -msgstr "" +msgstr "Bankkontoeier" #. module: base #: model:ir.actions.act_window,name:base.act_values_form msgid "Client Actions Connections" -msgstr "" +msgstr "ir.actions.wizard" #. module: base #: field:ir.attachment,res_name:0 #: field:ir.ui.view_sc,resource:0 msgid "Resource Name" -msgstr "" +msgstr "Ressursnavn" #. module: base #: selection:ir.cron,interval_type:0 msgid "Hours" -msgstr "" +msgstr "Timer" #. module: base #: model:res.country,name:base.gp msgid "Guadeloupe (French)" -msgstr "" +msgstr "Guadeloupe (Fransk)" #. module: base #: code:addons/base/res/res_lang.py:157 @@ -3770,7 +3842,7 @@ msgstr "" #: code:addons/base/res/res_lang.py:161 #, python-format msgid "User Error" -msgstr "" +msgstr "Brukerfeil" #. module: base #: help:workflow.transition,signal:0 @@ -3788,12 +3860,12 @@ msgstr "" #. module: base #: report:ir.module.reference.graph:0 msgid "Directory" -msgstr "" +msgstr "Katalogområde" #. module: base #: field:wizard.ir.model.menu.create,name:0 msgid "Menu Name" -msgstr "" +msgstr "Menynavn" #. module: base #: view:ir.module.module:0 @@ -3803,34 +3875,34 @@ msgstr "" #. module: base #: view:ir.attachment:0 msgid "Month" -msgstr "" +msgstr "Måned" #. module: base #: model:res.country,name:base.my msgid "Malaysia" -msgstr "" +msgstr "Malaysia" #. module: base #: view:base.language.install:0 #: model:ir.actions.act_window,name:base.action_view_base_language_install msgid "Load Official Translation" -msgstr "" +msgstr "Last inn en offisiell oversettelse" #. module: base #: model:ir.model,name:base.model_res_request_history msgid "res.request.history" -msgstr "" +msgstr "res.request.history" #. module: base #: view:ir.actions.server:0 msgid "Client Action Configuration" -msgstr "" +msgstr "Innstillinger for Klienthandling" #. module: base #: model:ir.model,name:base.model_res_partner_address #: view:res.partner.address:0 msgid "Partner Addresses" -msgstr "" +msgstr "Partneradresser" #. module: base #: help:ir.model.fields,translate:0 @@ -3842,12 +3914,12 @@ msgstr "" #. module: base #: view:res.lang:0 msgid "%S - Seconds [00,61]." -msgstr "" +msgstr "%S - Sekunder [00,61]." #. module: base #: model:res.country,name:base.cv msgid "Cape Verde" -msgstr "" +msgstr "Cape Verde" #. module: base #: view:base.module.import:0 @@ -3860,13 +3932,13 @@ msgstr "" #: field:res.partner.event,name:0 #: model:res.widget,title:base.events_widget msgid "Events" -msgstr "" +msgstr "Hendelser" #. module: base #: model:ir.model,name:base.model_ir_actions_url #: selection:ir.ui.menu,action:0 msgid "ir.actions.url" -msgstr "" +msgstr "ir.actions.url" #. module: base #: model:res.widget,title:base.currency_converter_widget @@ -3883,12 +3955,12 @@ msgstr "" #: model:ir.actions.act_window,name:base.action_partner_addess_tree #: view:res.partner:0 msgid "Partner Contacts" -msgstr "" +msgstr "Partnerkontakter" #. module: base #: field:base.module.update,add:0 msgid "Number of modules added" -msgstr "" +msgstr "Antall moduler lagt til" #. module: base #: view:res.currency:0 @@ -3898,7 +3970,7 @@ msgstr "" #. module: base #: selection:base.language.install,lang:0 msgid "Latvian / latviešu valoda" -msgstr "" +msgstr "Latvisk / Latviešu valoda" #. module: base #: view:res.config:0 @@ -3909,7 +3981,7 @@ msgstr "" #. module: base #: selection:base.language.install,lang:0 msgid "French / Français" -msgstr "" +msgstr "Fransk / Français" #. module: base #: code:addons/orm.py:1049 @@ -3920,7 +3992,7 @@ msgstr "" #. module: base #: field:workflow.triggers,workitem_id:0 msgid "Workitem" -msgstr "" +msgstr "Arbeidselement" #. module: base #: view:ir.actions.todo:0 @@ -3936,17 +4008,17 @@ msgstr "" #: selection:ir.values,key:0 #: view:res.users:0 msgid "Action" -msgstr "" +msgstr "Handling" #. module: base #: view:ir.actions.server:0 msgid "Email Configuration" -msgstr "" +msgstr "E-post konfigurasjon" #. module: base #: model:ir.model,name:base.model_ir_cron msgid "ir.cron" -msgstr "" +msgstr "ir.actions.actions" #. module: base #: view:ir.rule:0 @@ -3961,7 +4033,7 @@ msgstr "" #. module: base #: field:ir.actions.server,trigger_obj_id:0 msgid "Trigger On" -msgstr "" +msgstr "Utløs ved" #. module: base #: sql_constraint:ir.rule:0 @@ -3971,34 +4043,34 @@ msgstr "" #. module: base #: model:res.country,name:base.fj msgid "Fiji" -msgstr "" +msgstr "Fiji" #. module: base #: field:ir.model.fields,size:0 msgid "Size" -msgstr "" +msgstr "Størrelse" #. module: base #: model:res.country,name:base.sd msgid "Sudan" -msgstr "" +msgstr "Sudan" #. module: base #: model:res.country,name:base.fm msgid "Micronesia" -msgstr "" +msgstr "Mikronesia" #. module: base #: view:res.request.history:0 msgid "Request History" -msgstr "" +msgstr "Forespørselshistorikk" #. module: base #: field:ir.actions.act_window,menus:0 #: field:ir.module.module,menus_by_module:0 #: view:res.groups:0 msgid "Menus" -msgstr "" +msgstr "Menyer" #. module: base #: selection:base.language.install,lang:0 @@ -4008,34 +4080,34 @@ msgstr "" #. module: base #: model:res.country,name:base.il msgid "Israel" -msgstr "" +msgstr "Israel" #. module: base #: model:ir.actions.wizard,name:base.wizard_server_action_create msgid "Create Action" -msgstr "" +msgstr "Opprett handling" #. module: base #: model:ir.actions.act_window,name:base.action_model_model #: model:ir.model,name:base.model_ir_model #: model:ir.ui.menu,name:base.ir_model_model_menu msgid "Objects" -msgstr "" +msgstr "Objekter" #. module: base #: field:res.lang,time_format:0 msgid "Time Format" -msgstr "" +msgstr "Tidsformat" #. module: base #: view:ir.module.module:0 msgid "Defined Reports" -msgstr "" +msgstr "Definerte rapporter" #. module: base #: view:ir.actions.report.xml:0 msgid "Report xml" -msgstr "" +msgstr "Rapport xml" #. module: base #: field:base.language.export,modules:0 @@ -4045,7 +4117,7 @@ msgstr "" #: model:ir.ui.menu,name:base.menu_management #: model:ir.ui.menu,name:base.menu_module_tree msgid "Modules" -msgstr "" +msgstr "Moduler" #. module: base #: view:workflow.activity:0 @@ -4053,17 +4125,17 @@ msgstr "" #: field:workflow.activity,subflow_id:0 #: field:workflow.workitem,subflow_id:0 msgid "Subflow" -msgstr "" +msgstr "Underordnet flyt" #. module: base #: model:ir.model,name:base.model_res_config msgid "res.config" -msgstr "" +msgstr "res.config" #. module: base #: field:workflow.transition,signal:0 msgid "Signal (button Name)" -msgstr "" +msgstr "Signal (navn på knapp)" #. module: base #: model:ir.actions.act_window,name:base.action_res_bank_form @@ -4071,38 +4143,38 @@ msgstr "" #: view:res.bank:0 #: field:res.partner,bank_ids:0 msgid "Banks" -msgstr "" +msgstr "Banker" #. module: base #: view:res.log:0 msgid "Unread" -msgstr "" +msgstr "Ulest" #. module: base #: field:ir.cron,doall:0 msgid "Repeat Missed" -msgstr "" +msgstr "Repeter uteblitte" #. module: base #: help:ir.actions.server,state:0 msgid "Type of the Action that is to be executed" -msgstr "" +msgstr "Type handling som skal utføres" #. module: base #: field:ir.server.object.lines,server_id:0 msgid "Object Mapping" -msgstr "" +msgstr "Objektkobling" #. module: base #: help:res.currency,rate:0 #: help:res.currency.rate,rate:0 msgid "The rate of the currency to the currency of rate 1" -msgstr "" +msgstr "The rate of the currency to the currency of rate 1" #. module: base #: model:res.country,name:base.uk msgid "United Kingdom" -msgstr "" +msgstr "United Kingdom" #. module: base #: view:res.config:0 @@ -4115,55 +4187,57 @@ msgstr "" #: help:res.partner.category,active:0 msgid "The active field allows you to hide the category without removing it." msgstr "" +"Det aktive feltet gir deg mulighet til å skjule denne kategorien uten å " +"fjerne det." #. module: base #: report:ir.module.reference.graph:0 msgid "Object:" -msgstr "" +msgstr "Objekt:" #. module: base #: model:res.country,name:base.bw msgid "Botswana" -msgstr "" +msgstr "Botswana" #. module: base #: model:ir.actions.act_window,name:base.action_partner_title_partner #: model:ir.ui.menu,name:base.menu_partner_title_partner #: view:res.partner.title:0 msgid "Partner Titles" -msgstr "" +msgstr "Partner titler" #. module: base #: help:ir.actions.act_window,auto_refresh:0 msgid "Add an auto-refresh on the view" -msgstr "" +msgstr "Legg til automatisk oppdatereing av denne visningen" #. module: base #: help:res.partner,employee:0 msgid "Check this box if the partner is an Employee." -msgstr "" +msgstr "Kryss av denne boksen dersom partneren er en ansatt." #. module: base #: field:ir.actions.report.xml,report_rml_content:0 #: field:ir.actions.report.xml,report_rml_content_data:0 msgid "RML content" -msgstr "" +msgstr "RML innhold" #. module: base #: model:ir.actions.act_window,name:base.action_workflow_workitem_form #: model:ir.ui.menu,name:base.menu_workflow_workitem msgid "Workitems" -msgstr "" +msgstr "Arbeidselementer" #. module: base #: field:base.language.export,advice:0 msgid "Advice" -msgstr "" +msgstr "Anbefaling" #. module: base #: model:ir.model,name:base.model_ir_attachment msgid "ir.attachment" -msgstr "" +msgstr "ir.attachment" #. module: base #: code:addons/orm.py:3533 @@ -4176,7 +4250,7 @@ msgstr "" #. module: base #: view:base.language.import:0 msgid "- module,type,name,res_id,src,value" -msgstr "" +msgstr "- module,type,name,res_id,src,value" #. module: base #: selection:base.language.install,lang:0 @@ -4189,6 +4263,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 "" +"Angi feltnavnet hvor nøkkel på nøkkelen på raden blir lagret etter " +"oppretting. Hvis den er tom kan du ikke spore den nye raden." #. module: base #: help:ir.model.fields,relation:0 @@ -4198,12 +4274,12 @@ msgstr "" #. module: base #: selection:base.language.install,lang:0 msgid "Indonesian / Bahasa Indonesia" -msgstr "" +msgstr "Indonesisk / Bahasa Indonesia" #. module: base #: field:ir.ui.view,inherit_id:0 msgid "Inherited View" -msgstr "" +msgstr "Inherited View" #. module: base #: view:ir.translation:0 @@ -4213,7 +4289,7 @@ msgstr "" #. module: base #: model:ir.ui.menu,name:base.menu_main_pm msgid "Project" -msgstr "" +msgstr "Prosjekt" #. module: base #: field:ir.ui.menu,web_icon_hover_data:0 @@ -4223,17 +4299,17 @@ msgstr "" #. module: base #: view:base.module.import:0 msgid "Module file successfully imported!" -msgstr "" +msgstr "Modul ble importert uten feil !" #. module: base #: selection:ir.actions.todo,state:0 msgid "Cancelled" -msgstr "" +msgstr "Avbrutt" #. module: base #: view:res.config.users:0 msgid "Create User" -msgstr "" +msgstr "Opprett bruker" #. module: base #: view:partner.clear.ids:0 @@ -4249,42 +4325,42 @@ msgstr "" #. module: base #: selection:res.request,priority:0 msgid "Low" -msgstr "" +msgstr "Lav" #. module: base #: model:ir.ui.menu,name:base.menu_audit msgid "Audit" -msgstr "" +msgstr "Audit" #. module: base #: model:res.country,name:base.lc msgid "Saint Lucia" -msgstr "" +msgstr "Saint Lucia" #. module: base #: view:publisher_warranty.contract:0 msgid "Maintenance Contract" -msgstr "" +msgstr "Vedlikeholdskontrakt" #. module: base #: help:ir.actions.server,trigger_obj_id:0 msgid "Select the object from the model on which the workflow will executed." -msgstr "" +msgstr "Velg objektet fra modellen som arbeidsflyten vil bli utført på." #. module: base #: field:res.partner,employee:0 msgid "Employee" -msgstr "" +msgstr "Ansatt" #. module: base #: field:ir.model.access,perm_create:0 msgid "Create Access" -msgstr "" +msgstr "Tilgang til å opprette" #. module: base #: field:res.partner.address,state_id:0 msgid "Fed. State" -msgstr "" +msgstr "Stat (USA)" #. module: base #: field:ir.actions.server,copy_object:0 @@ -4304,19 +4380,19 @@ msgstr "" #. module: base #: model:res.country,name:base.io msgid "British Indian Ocean Territory" -msgstr "" +msgstr "British Indian Ocean Territory" #. module: base #: field:res.config.users,view:0 #: field:res.config.view,view:0 #: field:res.users,view:0 msgid "Interface" -msgstr "" +msgstr "Grensesnitt" #. module: base #: view:ir.actions.server:0 msgid "Field Mapping" -msgstr "" +msgstr "Feltmapping" #. module: base #: view:publisher_warranty.contract:0 @@ -4327,40 +4403,40 @@ msgstr "" #: view:ir.model:0 #: field:ir.model.fields,ttype:0 msgid "Field Type" -msgstr "" +msgstr "Felttype" #. module: base #: field:res.country.state,code:0 msgid "State Code" -msgstr "" +msgstr "Statskode" #. module: base #: field:ir.model.fields,on_delete:0 msgid "On delete" -msgstr "" +msgstr "Ved sletting" #. module: base #: selection:res.lang,direction:0 msgid "Left-to-Right" -msgstr "" +msgstr "Venstre-til-høyre" #. module: base #: view:res.lang:0 #: field:res.lang,translatable:0 msgid "Translatable" -msgstr "" +msgstr "Oversettbar" #. module: base #: model:res.country,name:base.vn msgid "Vietnam" -msgstr "" +msgstr "Vietnam" #. module: base #: field:res.config.users,signature:0 #: view:res.users:0 #: field:res.users,signature:0 msgid "Signature" -msgstr "" +msgstr "Signatur" #. module: base #: code:addons/fields.py:456 @@ -4372,22 +4448,22 @@ msgstr "" #: code:addons/fields.py:664 #, python-format msgid "Not Implemented" -msgstr "" +msgstr "Ikke implementert" #. module: base #: model:ir.model,name:base.model_res_widget_user msgid "res.widget.user" -msgstr "" +msgstr "res.widget.user" #. module: base #: field:res.partner.category,complete_name:0 msgid "Full Name" -msgstr "" +msgstr "Fullt navn" #. module: base #: view:base.module.configuration:0 msgid "_Ok" -msgstr "" +msgstr "_Ok" #. module: base #: help:ir.filters,user_id:0 @@ -4403,7 +4479,7 @@ msgstr "" #. module: base #: model:res.country,name:base.mz msgid "Mozambique" -msgstr "" +msgstr "Mosambik" #. module: base #: model:ir.ui.menu,name:base.menu_project_long_term @@ -4416,24 +4492,24 @@ msgstr "" #: field:partner.wizard.spam,text:0 #: field:res.log,name:0 msgid "Message" -msgstr "" +msgstr "Melding" #. module: base #: field:ir.actions.act_window.view,multi:0 msgid "On Multiple Doc." -msgstr "" +msgstr "On Multiple Doc." #. module: base #: view:res.partner:0 #: field:res.partner,user_id:0 msgid "Salesman" -msgstr "" +msgstr "Selger" #. module: base #: field:res.partner,address:0 #: view:res.partner.address:0 msgid "Contacts" -msgstr "" +msgstr "Kontakter" #. module: base #: code:addons/orm.py:3199 @@ -4445,29 +4521,29 @@ msgstr "" #. module: base #: view:res.widget.wizard:0 msgid "Add" -msgstr "" +msgstr "Legg til" #. module: base #: view:base.module.upgrade:0 #: model:ir.actions.act_window,name:base.action_view_base_module_upgrade_window #: model:ir.ui.menu,name:base.menu_view_base_module_upgrade msgid "Apply Scheduled Upgrades" -msgstr "" +msgstr "Utfør planlagte oppgraderinger" #. module: base #: view:res.widget:0 msgid "Widgets" -msgstr "" +msgstr "Widgets" #. module: base #: model:res.country,name:base.cz msgid "Czech Republic" -msgstr "" +msgstr "Tsjekkia" #. module: base #: view:res.widget.wizard:0 msgid "Widget Wizard" -msgstr "" +msgstr "Widget Wizard" #. module: base #: model:ir.actions.act_window,help:base.act_ir_actions_todo_form @@ -4494,7 +4570,7 @@ msgstr "" #. module: base #: selection:ir.property,type:0 msgid "Integer" -msgstr "" +msgstr "Integer" #. module: base #: help:ir.actions.report.xml,report_rml:0 @@ -4512,42 +4588,42 @@ msgstr "" #. module: base #: model:ir.model,name:base.model_wizard_ir_model_menu_create msgid "wizard.ir.model.menu.create" -msgstr "" +msgstr "wizard.ir.model.menu.create" #. module: base #: view:workflow.transition:0 msgid "Transition" -msgstr "" +msgstr "Overgang" #. module: base #: field:res.groups,menu_access:0 msgid "Access Menu" -msgstr "" +msgstr "Tilgangsmeny" #. module: base #: model:res.country,name:base.na msgid "Namibia" -msgstr "" +msgstr "Namibia" #. module: base #: model:res.country,name:base.mn msgid "Mongolia" -msgstr "" +msgstr "Mongolia" #. module: base #: view:ir.module.module:0 msgid "Created Menus" -msgstr "" +msgstr "Opprettet menyer" #. module: base #: selection:ir.ui.view,type:0 msgid "mdx" -msgstr "" +msgstr "mdx" #. module: base #: model:res.country,name:base.bi msgid "Burundi" -msgstr "" +msgstr "Burundi" #. module: base #: view:base.language.install:0 @@ -4558,12 +4634,12 @@ msgstr "" #: wizard_button:server.action.create,init,end:0 #: wizard_button:server.action.create,step_1,end:0 msgid "Close" -msgstr "" +msgstr "Lukk" #. module: base #: selection:base.language.install,lang:0 msgid "Spanish (MX) / Español (MX)" -msgstr "" +msgstr "Spanish (MX) / Español (MX)" #. module: base #: view:res.log:0 @@ -4573,7 +4649,7 @@ msgstr "" #. module: base #: model:res.country,name:base.bt msgid "Bhutan" -msgstr "" +msgstr "Bhutan" #. module: base #: help:ir.sequence,number_next:0 @@ -4588,7 +4664,7 @@ msgstr "" #. module: base #: selection:ir.actions.url,target:0 msgid "This Window" -msgstr "" +msgstr "Dette vinduet" #. module: base #: view:publisher_warranty.contract:0 @@ -4603,28 +4679,28 @@ msgstr "" #. module: base #: field:base.language.export,format:0 msgid "File Format" -msgstr "" +msgstr "Filformat" #. module: base #: field:res.lang,iso_code:0 msgid "ISO code" -msgstr "" +msgstr "ISO code" #. module: base #: model:ir.model,name:base.model_res_config_view msgid "res.config.view" -msgstr "" +msgstr "res.config.view" #. module: base #: view:res.log:0 #: field:res.log,read:0 msgid "Read" -msgstr "" +msgstr "Les" #. module: base #: sql_constraint:res.country:0 msgid "The name of the country must be unique !" -msgstr "" +msgstr "Navnet på landet må være unikt !" #. module: base #: model:ir.actions.act_window,help:base.action_country_state @@ -4637,19 +4713,19 @@ msgstr "" #. module: base #: view:workflow.workitem:0 msgid "Workflow Workitems" -msgstr "" +msgstr "Arbeidsflyt arbeidselementer" #. module: base #: model:res.country,name:base.vc msgid "Saint Vincent & Grenadines" -msgstr "" +msgstr "Saint Vincent og Grenadinene" #. module: base #: field:partner.sms.send,password:0 #: field:res.config.users,password:0 #: field:res.users,password:0 msgid "Password" -msgstr "" +msgstr "Passord" #. module: base #: model:ir.actions.act_window,name:base.action_model_fields @@ -4659,12 +4735,12 @@ msgstr "" #: view:ir.model.fields:0 #: model:ir.ui.menu,name:base.ir_model_model_fields msgid "Fields" -msgstr "" +msgstr "Felter" #. module: base #: model:ir.actions.act_window,name:base.action_partner_employee_form msgid "Employees" -msgstr "" +msgstr "Ansatte" #. module: base #: help:res.log,read:0 @@ -4676,7 +4752,7 @@ msgstr "" #: field:res.company,rml_header2:0 #: field:res.company,rml_header3:0 msgid "RML Internal Header" -msgstr "" +msgstr "RML Internal Header" #. module: base #: field:ir.actions.act_window,search_view_id:0 @@ -4686,7 +4762,7 @@ msgstr "" #. module: base #: field:ir.module.module,installed_version:0 msgid "Latest version" -msgstr "" +msgstr "Siste versjon" #. module: base #: model:ir.actions.act_window,help:base.res_partner_canal-act @@ -4699,18 +4775,18 @@ msgstr "" #. module: base #: model:res.partner.bank.type.field,name:base.bank_normal_field msgid "acc_number" -msgstr "" +msgstr "acc_number" #. module: base #: model:ir.actions.act_window,name:base.action_partner_address_form #: model:ir.ui.menu,name:base.menu_partner_address_form msgid "Addresses" -msgstr "" +msgstr "Adresser" #. module: base #: model:res.country,name:base.mm msgid "Myanmar" -msgstr "" +msgstr "Myanmar" #. module: base #: selection:base.language.install,lang:0 @@ -4722,63 +4798,63 @@ msgstr "" #: field:res.partner.address,street:0 #: field:res.partner.bank,street:0 msgid "Street" -msgstr "" +msgstr "Gate" #. module: base #: model:res.country,name:base.yu msgid "Yugoslavia" -msgstr "" +msgstr "Jugoslavia" #. module: base #: field:ir.model.data,name:0 msgid "XML Identifier" -msgstr "" +msgstr "XML Identifikator" #. module: base #: model:res.country,name:base.ca msgid "Canada" -msgstr "" +msgstr "Canada" #. module: base #: selection:ir.module.module.dependency,state:0 msgid "Unknown" -msgstr "" +msgstr "Unknown" #. module: base #: model:ir.actions.act_window,name:base.action_res_users_my msgid "Change My Preferences" -msgstr "" +msgstr "Endre mine preferanser" #. module: base #: code:addons/base/ir/ir_actions.py:164 #, python-format msgid "Invalid model name in the action definition." -msgstr "" +msgstr "Ugyldig navn på modell i handlingsdefinisjonen." #. module: base #: field:partner.sms.send,text:0 msgid "SMS Message" -msgstr "" +msgstr "SMS melding" #. module: base #: model:res.country,name:base.cm msgid "Cameroon" -msgstr "" +msgstr "Kamerun" #. module: base #: model:res.country,name:base.bf msgid "Burkina Faso" -msgstr "" +msgstr "Burkina Faso" #. module: base #: selection:ir.actions.todo,state:0 msgid "Skipped" -msgstr "" +msgstr "Hoppet over" #. module: base #: selection:ir.model.fields,state:0 msgid "Custom Field" -msgstr "" +msgstr "Tilpasset felt" #. module: base #: field:ir.module.module,web:0 @@ -4788,7 +4864,7 @@ msgstr "" #. module: base #: model:res.country,name:base.cc msgid "Cocos (Keeling) Islands" -msgstr "" +msgstr "Cocos (Keeling) øyene" #. module: base #: selection:base.language.install,state:0 @@ -4800,17 +4876,17 @@ msgstr "" #. module: base #: view:res.lang:0 msgid "11. %U or %W ==> 48 (49th week)" -msgstr "" +msgstr "11. %U eler %W ==> 48 (49. uke)" #. module: base #: model:ir.model,name:base.model_res_partner_bank_type_field msgid "Bank type fields" -msgstr "" +msgstr "Banktypefelter" #. module: base #: selection:base.language.install,lang:0 msgid "Dutch / Nederlands" -msgstr "" +msgstr "Nederlandsk / Nederlands" #. module: base #: code:addons/base/res/res_config.py:384 @@ -4824,18 +4900,18 @@ msgstr "" #. module: base #: help:ir.cron,interval_number:0 msgid "Repeat every x." -msgstr "" +msgstr "Gjennta hvert x." #. module: base #: wizard_view:server.action.create,step_1:0 #: wizard_field:server.action.create,step_1,report:0 msgid "Select Report" -msgstr "" +msgstr "Velg rapport" #. module: base #: report:ir.module.reference.graph:0 msgid "1cm 28cm 20cm 28cm" -msgstr "" +msgstr "1cm 28cm 20cm 28cm" #. module: base #: field:ir.module.module,maintainer:0 @@ -4845,37 +4921,37 @@ msgstr "" #. module: base #: field:ir.sequence,suffix:0 msgid "Suffix" -msgstr "" +msgstr "Suffiks" #. module: base #: model:res.country,name:base.mo msgid "Macau" -msgstr "" +msgstr "Macau" #. module: base #: model:ir.actions.report.xml,name:base.res_partner_address_report msgid "Labels" -msgstr "" +msgstr "Etiketter" #. module: base #: field:partner.wizard.spam,email_from:0 msgid "Sender's email" -msgstr "" +msgstr "Senders e-post" #. module: base #: field:ir.default,field_name:0 msgid "Object Field" -msgstr "" +msgstr "Objektfelt" #. module: base #: selection:base.language.install,lang:0 msgid "Spanish (PE) / Español (PE)" -msgstr "" +msgstr "Spanish (PE) / Español (PE)" #. module: base #: selection:base.language.install,lang:0 msgid "French (CH) / Français (CH)" -msgstr "" +msgstr "French (CH) / Français (CH)" #. module: base #: help:res.config.users,action_id:0 @@ -4903,27 +4979,29 @@ msgid "" "You try to upgrade a module that depends on the module: %s.\n" "But this module is not available in your system." msgstr "" +"You try to upgrade a module that depends on the module: %s.\n" +"But this module is not available in your system." #. module: base #: field:workflow.transition,act_to:0 msgid "Destination Activity" -msgstr "" +msgstr "Aktivitetsblokker" #. module: base #: view:ir.values:0 msgid "Connect Events to Actions" -msgstr "" +msgstr "Koble arrangementr til handlinger" #. module: base #: model:ir.model,name:base.model_base_update_translations msgid "base.update.translations" -msgstr "" +msgstr "base.update.translations" #. module: base #: field:ir.module.category,parent_id:0 #: field:res.partner.category,parent_id:0 msgid "Parent Category" -msgstr "" +msgstr "Overordnet kategori" #. module: base #: selection:ir.property,type:0 @@ -4935,55 +5013,55 @@ msgstr "" #: selection:res.partner.title,domain:0 #: view:res.users:0 msgid "Contact" -msgstr "" +msgstr "Kontakt" #. module: base #: model:ir.model,name:base.model_ir_ui_menu msgid "ir.ui.menu" -msgstr "" +msgstr "ir.ui.menu" #. module: base #: model:res.country,name:base.us msgid "United States" -msgstr "" +msgstr "USA" #. module: base #: view:ir.module.module:0 msgid "Cancel Uninstall" -msgstr "" +msgstr "Avbryt installasjon" #. module: base #: view:res.bank:0 #: view:res.partner:0 #: view:res.partner.address:0 msgid "Communication" -msgstr "" +msgstr "Kommunikasjon" #. module: base #: view:ir.actions.report.xml:0 msgid "RML Report" -msgstr "" +msgstr "RML rapport" #. module: base #: model:ir.model,name:base.model_ir_server_object_lines msgid "ir.server.object.lines" -msgstr "" +msgstr "ir.server.object.lines" #. module: base #: code:addons/base/module/module.py:531 #, python-format msgid "Module %s: Invalid Quality Certificate" -msgstr "" +msgstr "Modul %s: Ugyldig kvalitetssertifikat" #. module: base #: model:res.country,name:base.kw msgid "Kuwait" -msgstr "" +msgstr "Kuwait" #. module: base #: field:workflow.workitem,inst_id:0 msgid "Instance" -msgstr "" +msgstr "Instans" #. module: base #: help:ir.actions.report.xml,attachment:0 @@ -4992,6 +5070,9 @@ msgid "" "Keep empty to not save the printed reports. You can use a python expression " "with the object and time variables." msgstr "" +"Dette er filnavnet til vedlegget som benyttes til å lagre resultatet av " +"utskriften. Behold blankt for ikke å lagre utskrevne rapporter. Du kan " +"benytte et python uttrykk på objektet og variabler for tid/dato." #. module: base #: selection:ir.property,type:0 @@ -5001,7 +5082,7 @@ msgstr "" #. module: base #: model:res.country,name:base.ng msgid "Nigeria" -msgstr "" +msgstr "Nigeria" #. module: base #: code:addons/base/ir/ir_model.py:250 @@ -5012,7 +5093,7 @@ msgstr "" #. module: base #: model:ir.actions.act_window,name:base.action_partner_sms_send msgid "SMS Send" -msgstr "" +msgstr "Send SMS" #. module: base #: field:res.company,user_ids:0 @@ -5027,22 +5108,22 @@ msgstr "" #. module: base #: view:ir.values:0 msgid "Values for Event Type" -msgstr "" +msgstr "Klarte ikke kopiere verdier av ikke-støttet type %d." #. module: base #: selection:ir.model.fields,select_level:0 msgid "Always Searchable" -msgstr "" +msgstr "Alltid søkbar" #. module: base #: model:res.country,name:base.hk msgid "Hong Kong" -msgstr "" +msgstr "Hong Kong" #. module: base #: help:ir.actions.server,name:0 msgid "Easy to Refer action by name e.g. One Sales Order -> Many Invoices" -msgstr "" +msgstr "Easy to Refer action by name e.g. One Sales Order -> Many Invoices" #. module: base #: model:ir.actions.act_window,help:base.action_partner_address_form @@ -5059,22 +5140,22 @@ msgstr "" #. module: base #: model:res.country,name:base.ph msgid "Philippines" -msgstr "" +msgstr "Filippinene" #. module: base #: model:res.country,name:base.ma msgid "Morocco" -msgstr "" +msgstr "Marokko" #. module: base #: view:res.lang:0 msgid "2. %a ,%A ==> Fri, Friday" -msgstr "" +msgstr "2. %a ,%A ==> Fri, Friday" #. module: base #: field:res.widget,content:0 msgid "Content" -msgstr "" +msgstr "Innhold" #. module: base #: help:ir.rule,global:0 @@ -5084,32 +5165,32 @@ msgstr "" #. module: base #: model:res.country,name:base.td msgid "Chad" -msgstr "" +msgstr "Tsjad / Republikken Tsjad" #. module: base #: model:ir.model,name:base.model_workflow_transition msgid "workflow.transition" -msgstr "" +msgstr "workflow.transition" #. module: base #: view:res.lang:0 msgid "%a - Abbreviated weekday name." -msgstr "" +msgstr "%a - Forkortet navn på ukedag." #. module: base #: report:ir.module.reference.graph:0 msgid "Introspection report on objects" -msgstr "" +msgstr "Introspektiv rapport på objekter" #. module: base #: model:res.country,name:base.pf msgid "Polynesia (French)" -msgstr "" +msgstr "Polynesia (Fransk)" #. module: base #: model:res.country,name:base.dm msgid "Dominica" -msgstr "" +msgstr "Dominica" #. module: base #: sql_constraint:publisher_warranty.contract:0 @@ -5131,7 +5212,7 @@ msgstr "" #. module: base #: model:res.country,name:base.np msgid "Nepal" -msgstr "" +msgstr "Nepal" #. module: base #: code:addons/orm.py:2307 @@ -5153,28 +5234,31 @@ msgid "" "groups. If this field is empty, OpenERP will compute visibility based on the " "related object's read access." msgstr "" +"Hvis du har grupper så vil synligheten av denne menyen baseres på disse. " +"Hvis dette feltet er tomt så vil OpenERP beregne synligheten basert på " +"lesetilganger til relaterte objekter." #. module: base #: model:ir.actions.act_window,name:base.action_ui_view_custom #: model:ir.ui.menu,name:base.menu_action_ui_view_custom #: view:ir.ui.view.custom:0 msgid "Customized Views" -msgstr "" +msgstr "Tilpassede visninger" #. module: base #: view:partner.sms.send:0 msgid "Bulk SMS send" -msgstr "" +msgstr "Masseutsendelse av SMS" #. module: base #: view:ir.sequence:0 msgid "Seconde: %(sec)s" -msgstr "" +msgstr "Sekund: %(sec)s" #. module: base #: model:ir.ui.menu,name:base.menu_view_base_module_update msgid "Update Modules List" -msgstr "" +msgstr "Oppdater liste over moduler" #. module: base #: code:addons/base/module/module.py:255 @@ -5196,7 +5280,7 @@ msgstr "" #. module: base #: view:ir.actions.configuration.wizard:0 msgid "Continue" -msgstr "" +msgstr "Fortsett" #. module: base #: selection:base.language.install,lang:0 @@ -5217,28 +5301,28 @@ msgstr "" #. module: base #: field:ir.actions.report.xml,attachment_use:0 msgid "Reload from Attachment" -msgstr "" +msgstr "Last på nytt fra vedlegg" #. module: base #: model:res.country,name:base.bv msgid "Bouvet Island" -msgstr "" +msgstr "Bouvet øyene" #. module: base #: field:ir.attachment,name:0 msgid "Attachment Name" -msgstr "" +msgstr "Navn på vedlegg" #. module: base #: field:base.language.export,data:0 #: field:base.language.import,data:0 msgid "File" -msgstr "" +msgstr "Fil" #. module: base #: view:res.config.users:0 msgid "Add User" -msgstr "" +msgstr "Legg til bruker" #. module: base #: model:ir.actions.act_window,name:base.action_view_base_module_upgrade_install @@ -5248,12 +5332,12 @@ msgstr "" #. module: base #: model:ir.model,name:base.model_ir_actions_configuration_wizard msgid "ir.actions.configuration.wizard" -msgstr "" +msgstr "ir.actions.configuration.wizard" #. module: base #: view:res.lang:0 msgid "%b - Abbreviated month name." -msgstr "" +msgstr "%b - Navn på måned (forkortet)." #. module: base #: field:res.partner,supplier:0 @@ -5261,30 +5345,30 @@ msgstr "" #: field:res.partner.address,is_supplier_add:0 #: model:res.partner.category,name:base.res_partner_category_8 msgid "Supplier" -msgstr "" +msgstr "Leverandør" #. module: base #: view:ir.actions.server:0 #: selection:ir.actions.server,state:0 msgid "Multi Actions" -msgstr "" +msgstr "Flerhandlinger" #. module: base #: view:base.language.export:0 #: view:base.language.import:0 #: view:wizard.ir.model.menu.create:0 msgid "_Close" -msgstr "" +msgstr "_Lukk" #. module: base #: field:multi_company.default,company_dest_id:0 msgid "Default Company" -msgstr "" +msgstr "Standard firma" #. module: base #: selection:base.language.install,lang:0 msgid "Spanish (EC) / Español (EC)" -msgstr "" +msgstr "Spanish (EC) / Español (EC)" #. module: base #: help:ir.ui.view,xml_id:0 @@ -5295,12 +5379,12 @@ msgstr "" #: model:ir.model,name:base.model_base_module_import #: model:ir.ui.menu,name:base.menu_view_base_module_import msgid "Import Module" -msgstr "" +msgstr "Importer modul" #. module: base #: model:res.country,name:base.as msgid "American Samoa" -msgstr "" +msgstr "Amerikansk Samoa" #. module: base #: help:ir.actions.act_window,res_model:0 @@ -5315,51 +5399,51 @@ msgstr "" #. module: base #: field:ir.model.fields,selectable:0 msgid "Selectable" -msgstr "" +msgstr "Valgbar" #. module: base #: view:res.request.link:0 msgid "Request Link" -msgstr "" +msgstr "res.request.link" #. module: base #: view:ir.attachment:0 #: selection:ir.attachment,type:0 #: field:ir.module.module,url:0 msgid "URL" -msgstr "" +msgstr "URL" #. module: base #: help:res.country,name:0 msgid "The full name of the country." -msgstr "" +msgstr "Fullt navn på land." #. module: base #: selection:ir.actions.server,state:0 msgid "Iteration" -msgstr "" +msgstr "Iterasjon" #. module: base #: code:addons/orm.py:3448 #: code:addons/orm.py:3532 #, python-format msgid "UserError" -msgstr "" +msgstr "BrukerFeil" #. module: base #: model:res.country,name:base.ae msgid "United Arab Emirates" -msgstr "" +msgstr "De forente arabiske emirater" #. module: base #: model:ir.ui.menu,name:base.menu_crm_case_job_req_main msgid "Recruitment" -msgstr "" +msgstr "Rekruttering" #. module: base #: model:res.country,name:base.re msgid "Reunion (French)" -msgstr "" +msgstr "Réunion (Frankrike)" #. module: base #: code:addons/base/ir/ir_model.py:321 @@ -5373,17 +5457,17 @@ msgstr "" #: view:ir.rule:0 #: field:ir.rule,global:0 msgid "Global" -msgstr "" +msgstr "Global" #. module: base #: model:res.country,name:base.mp msgid "Northern Mariana Islands" -msgstr "" +msgstr "Marianaøyene" #. module: base #: model:res.country,name:base.sb msgid "Solomon Islands" -msgstr "" +msgstr "Salomonøyene" #. module: base #: code:addons/base/ir/ir_model.py:490 @@ -5394,12 +5478,12 @@ msgstr "" #: code:addons/orm.py:3817 #, python-format msgid "AccessError" -msgstr "" +msgstr "Tilgangsfeil" #. module: base #: view:res.request:0 msgid "Waiting" -msgstr "" +msgstr "Venter" #. module: base #: code:addons/__init__.py:834 @@ -5410,7 +5494,7 @@ msgstr "" #. module: base #: view:res.lang:0 msgid "8. %I:%M:%S %p ==> 06:25:20 PM" -msgstr "" +msgstr "8. %I:%M:%S %p ==> 06:25:20 PM" #. module: base #: code:addons/orm.py:1803 @@ -5421,49 +5505,49 @@ msgstr "" #. module: base #: field:res.log,create_date:0 msgid "Creation Date" -msgstr "" +msgstr "Dato opprettet" #. module: base #: view:ir.translation:0 #: model:ir.ui.menu,name:base.menu_translation msgid "Translations" -msgstr "" +msgstr "Oversettelser" #. module: base #: field:ir.sequence,padding:0 msgid "Number padding" -msgstr "" +msgstr "Bunnfyll" #. module: base #: view:ir.actions.report.xml:0 msgid "Report" -msgstr "" +msgstr "Rapport" #. module: base #: model:res.country,name:base.ua msgid "Ukraine" -msgstr "" +msgstr "Ukraina" #. module: base #: model:res.country,name:base.to msgid "Tonga" -msgstr "" +msgstr "Tonga" #. module: base #: model:ir.model,name:base.model_ir_module_category #: view:ir.module.category:0 msgid "Module Category" -msgstr "" +msgstr "Modulkategori" #. module: base #: view:partner.wizard.ean.check:0 msgid "Ignore" -msgstr "" +msgstr "Ignorer" #. module: base #: report:ir.module.reference.graph:0 msgid "Reference Guide" -msgstr "" +msgstr "Veiledning" #. module: base #: view:ir.ui.view:0 @@ -5473,7 +5557,7 @@ msgstr "" #. module: base #: model:res.country,name:base.ml msgid "Mali" -msgstr "" +msgstr "Mali" #. module: base #: help:res.config.users,email:0 @@ -5493,22 +5577,22 @@ msgstr "" #. module: base #: field:ir.cron,interval_number:0 msgid "Interval Number" -msgstr "" +msgstr "Intervallnummer" #. module: base #: model:res.country,name:base.tk msgid "Tokelau" -msgstr "" +msgstr "Tokelau" #. module: base #: field:ir.actions.report.xml,report_xsl:0 msgid "XSL path" -msgstr "" +msgstr "Stil til XSL" #. module: base #: model:res.country,name:base.bn msgid "Brunei Darussalam" -msgstr "" +msgstr "Brunei Darussalam" #. module: base #: view:ir.actions.act_window:0 @@ -5517,22 +5601,22 @@ msgstr "" #: field:ir.ui.view,type:0 #: field:wizard.ir.model.menu.create.line,view_type:0 msgid "View Type" -msgstr "" +msgstr "Visningstype" #. module: base #: model:ir.ui.menu,name:base.next_id_2 msgid "User Interface" -msgstr "" +msgstr "Brukergrensesnitt" #. module: base #: field:ir.attachment,create_date:0 msgid "Date Created" -msgstr "" +msgstr "Dato opprettet" #. module: base #: model:ir.model,name:base.model_ir_actions_todo msgid "ir.actions.todo" -msgstr "" +msgstr "ir.actions.todo" #. module: base #: code:addons/base/res/res_config.py:94 @@ -5543,12 +5627,12 @@ msgstr "" #. module: base #: view:ir.actions.act_window:0 msgid "General Settings" -msgstr "" +msgstr "Generelle innstillinger" #. module: base #: model:ir.ui.menu,name:base.menu_administration_shortcut msgid "Custom Shortcuts" -msgstr "" +msgstr "Tilpassede snarveier" #. module: base #: selection:base.language.install,lang:0 @@ -5558,12 +5642,12 @@ msgstr "" #. module: base #: model:res.country,name:base.dz msgid "Algeria" -msgstr "" +msgstr "Algerie" #. module: base #: model:res.country,name:base.be msgid "Belgium" -msgstr "" +msgstr "Belgia" #. module: base #: model:ir.model,name:base.model_osv_memory_autovacuum @@ -5579,12 +5663,12 @@ msgstr "" #: field:res.partner,lang:0 #: field:res.users,context_lang:0 msgid "Language" -msgstr "" +msgstr "Språk" #. module: base #: model:res.country,name:base.gm msgid "Gambia" -msgstr "" +msgstr "Gambia" #. module: base #: model:ir.actions.act_window,name:base.action_res_company_form @@ -5596,12 +5680,12 @@ msgstr "" #: view:res.users:0 #: field:res.users,company_ids:0 msgid "Companies" -msgstr "" +msgstr "Firma" #. module: base #: view:res.lang:0 msgid "%H - Hour (24-hour clock) [00,23]." -msgstr "" +msgstr "%H - Time (24-times klokke) [00,23]." #. module: base #: model:ir.model,name:base.model_res_widget @@ -5631,18 +5715,18 @@ msgstr "" #: field:ir.actions.server,code:0 #: selection:ir.actions.server,state:0 msgid "Python Code" -msgstr "" +msgstr "Python kode" #. module: base #: code:addons/base/module/wizard/base_module_import.py:67 #, python-format msgid "Can not create the module file: %s !" -msgstr "" +msgstr "Kan ikke opprette modul filen: %s !" #. module: base #: model:ir.module.module,description:base.module_meta_information msgid "The kernel of OpenERP, needed for all installation." -msgstr "" +msgstr "Kjerne i OpenERP, nødvendig for all installasjoner" #. module: base #: view:base.language.install:0 @@ -5656,17 +5740,17 @@ msgstr "" #: view:publisher_warranty.contract.wizard:0 #: view:res.widget.wizard:0 msgid "Cancel" -msgstr "" +msgstr "Avbryt" #. module: base #: selection:base.language.export,format:0 msgid "PO File" -msgstr "" +msgstr "PO fil" #. module: base #: model:res.country,name:base.nt msgid "Neutral Zone" -msgstr "" +msgstr "Nøytral sone" #. module: base #: selection:base.language.install,lang:0 @@ -5676,7 +5760,7 @@ msgstr "" #. module: base #: view:ir.model:0 msgid "Custom" -msgstr "" +msgstr "Tilpasset" #. module: base #: view:res.request:0 @@ -5697,43 +5781,43 @@ msgstr "" #: field:res.groups,users:0 #: view:res.users:0 msgid "Users" -msgstr "" +msgstr "Brukere" #. module: base #: field:ir.module.module,published_version:0 msgid "Published Version" -msgstr "" +msgstr "Publisert versjon" #. module: base #: model:res.country,name:base.is msgid "Iceland" -msgstr "" +msgstr "Island" #. module: base #: model:ir.actions.act_window,name:base.ir_action_window #: model:ir.ui.menu,name:base.menu_ir_action_window msgid "Window Actions" -msgstr "" +msgstr "Vinduhandlinger" #. module: base #: view:res.lang:0 msgid "%I - Hour (12-hour clock) [01,12]." -msgstr "" +msgstr "%I - Time (12-times klokke) som et desimanummer [01,12]." #. module: base #: selection:publisher_warranty.contract.wizard,state:0 msgid "Finished" -msgstr "" +msgstr "Ferdig" #. module: base #: model:res.country,name:base.de msgid "Germany" -msgstr "" +msgstr "Tyskland" #. module: base #: view:ir.sequence:0 msgid "Week of the year: %(woy)s" -msgstr "" +msgstr "Uke i året: %(woy)s" #. module: base #: model:res.partner.category,name:base.res_partner_category_14 @@ -5743,12 +5827,12 @@ msgstr "" #. module: base #: report:ir.module.reference.graph:0 msgid "Reports :" -msgstr "" +msgstr "Rapporter :" #. module: base #: model:res.country,name:base.gy msgid "Guyana" -msgstr "" +msgstr "Guyana" #. module: base #: help:ir.actions.act_window,view_type:0 @@ -5766,12 +5850,12 @@ msgstr "" #. module: base #: field:ir.actions.server,record_id:0 msgid "Create Id" -msgstr "" +msgstr "Opprett ID" #. module: base #: model:res.country,name:base.hn msgid "Honduras" -msgstr "" +msgstr "Honduras" #. module: base #: help:res.config.users,menu_tips:0 @@ -5783,7 +5867,7 @@ msgstr "" #. module: base #: model:res.country,name:base.eg msgid "Egypt" -msgstr "" +msgstr "Egypt" #. module: base #: field:ir.rule,perm_read:0 @@ -5794,28 +5878,28 @@ msgstr "" #: help:ir.actions.server,model_id:0 msgid "" "Select the object on which the action will work (read, write, create)." -msgstr "" +msgstr "Velg objektet som handlingen vil utføres på (les, skriv, opprett)." #. module: base #: code:addons/base/ir/ir_actions.py:629 #, python-format msgid "Please specify server option --email-from !" -msgstr "" +msgstr "Vær vennlig å angi server parameteret --email-from !" #. module: base #: field:base.language.import,name:0 msgid "Language Name" -msgstr "" +msgstr "Navn på språk" #. module: base #: selection:ir.property,type:0 msgid "Boolean" -msgstr "" +msgstr "Bolsk" #. module: base #: view:ir.model:0 msgid "Fields Description" -msgstr "" +msgstr "Bekrivelse på felter" #. module: base #: view:ir.attachment:0 @@ -5831,14 +5915,14 @@ msgstr "" #: view:res.partner.address:0 #: view:workflow.activity:0 msgid "Group By..." -msgstr "" +msgstr "Grupper etter..." #. module: base #: view:ir.model.fields:0 #: field:ir.model.fields,readonly:0 #: field:res.partner.bank.type.field,readonly:0 msgid "Readonly" -msgstr "" +msgstr "Skrivebeskyttet" #. module: base #: field:ir.actions.act_window.view,view_id:0 @@ -5846,13 +5930,13 @@ msgstr "" #: selection:ir.translation,type:0 #: field:wizard.ir.model.menu.create.line,view_id:0 msgid "View" -msgstr "" +msgstr "Vis" #. module: base #: selection:ir.module.module,state:0 #: selection:ir.module.module.dependency,state:0 msgid "To be installed" -msgstr "" +msgstr "Å installere" #. module: base #: help:ir.actions.act_window,display_menu_tip:0 @@ -5866,7 +5950,7 @@ msgstr "" #: model:ir.module.module,shortdesc:base.module_meta_information #: field:res.currency,base:0 msgid "Base" -msgstr "" +msgstr "Basis" #. module: base #: selection:base.language.install,lang:0 @@ -5876,7 +5960,7 @@ msgstr "" #. module: base #: model:res.country,name:base.lr msgid "Liberia" -msgstr "" +msgstr "Liberia" #. module: base #: view:ir.attachment:0 @@ -5886,7 +5970,7 @@ msgstr "" #: field:res.partner,comment:0 #: model:res.widget,title:base.note_widget msgid "Notes" -msgstr "" +msgstr "Notater" #. module: base #: field:ir.config_parameter,value:0 @@ -5902,7 +5986,7 @@ msgstr "" #: field:ir.values,value:0 #: field:ir.values,value_unpickle:0 msgid "Value" -msgstr "" +msgstr "Verdi" #. module: base #: field:ir.sequence,code:0 @@ -5911,27 +5995,27 @@ msgstr "" #: field:res.bank,code:0 #: field:res.partner.bank.type,code:0 msgid "Code" -msgstr "" +msgstr "Kode" #. module: base #: model:ir.model,name:base.model_res_config_installer msgid "res.config.installer" -msgstr "" +msgstr "res.config.installer" #. module: base #: model:res.country,name:base.mc msgid "Monaco" -msgstr "" +msgstr "Monaco" #. module: base #: selection:ir.cron,interval_type:0 msgid "Minutes" -msgstr "" +msgstr "Minutter" #. module: base #: selection:ir.translation,type:0 msgid "Help" -msgstr "" +msgstr "Hjelp" #. module: base #: help:res.config.users,menu_id:0 @@ -5943,7 +6027,7 @@ msgstr "" #. module: base #: selection:ir.actions.server,state:0 msgid "Write Object" -msgstr "" +msgstr "Skriv objekt" #. module: base #: model:ir.ui.menu,name:base.menu_fundrising @@ -5954,12 +6038,12 @@ msgstr "" #: model:ir.actions.act_window,name:base.ir_sequence_type #: model:ir.ui.menu,name:base.menu_ir_sequence_type msgid "Sequence Codes" -msgstr "" +msgstr "Sekvenskoder" #. module: base #: selection:base.language.install,lang:0 msgid "Spanish (CO) / Español (CO)" -msgstr "" +msgstr "Spanish (CO) / Español (CO)" #. module: base #: view:base.module.configuration:0 @@ -5971,7 +6055,7 @@ msgstr "" #. module: base #: wizard_button:server.action.create,step_1,create:0 msgid "Create" -msgstr "" +msgstr "Opprett" #. module: base #: view:ir.sequence:0 @@ -5981,17 +6065,17 @@ msgstr "" #. module: base #: field:ir.exports,export_fields:0 msgid "Export ID" -msgstr "" +msgstr "Eksport ID" #. module: base #: model:res.country,name:base.fr msgid "France" -msgstr "" +msgstr "Frankrike" #. module: base #: model:ir.model,name:base.model_res_log msgid "res.log" -msgstr "" +msgstr "res.log" #. module: base #: help:ir.translation,module:0 @@ -6003,39 +6087,39 @@ msgstr "" #: view:workflow.activity:0 #: field:workflow.activity,flow_stop:0 msgid "Flow Stop" -msgstr "" +msgstr "_Stopp" #. module: base #: selection:ir.cron,interval_type:0 msgid "Weeks" -msgstr "" +msgstr "Uker" #. module: base #: model:res.country,name:base.af msgid "Afghanistan, Islamic State of" -msgstr "" +msgstr "Afghanistan" #. module: base #: code:addons/base/module/wizard/base_module_import.py:67 #, python-format msgid "Error !" -msgstr "" +msgstr "Feil!" #. module: base #: model:res.partner.bank.type.field,name:base.bank_normal_field_contry msgid "country_id" -msgstr "" +msgstr "country_id" #. module: base #: field:ir.cron,interval_type:0 msgid "Interval Unit" -msgstr "" +msgstr "Intervallenhet" #. module: base #: field:publisher_warranty.contract,kind:0 #: field:workflow.activity,kind:0 msgid "Kind" -msgstr "" +msgstr "Vennlig" #. module: base #: code:addons/orm.py:3775 @@ -6047,17 +6131,17 @@ msgstr "" #: field:res.bank,fax:0 #: field:res.partner.address,fax:0 msgid "Fax" -msgstr "" +msgstr "Fax" #. module: base #: field:res.lang,thousands_sep:0 msgid "Thousands Separator" -msgstr "" +msgstr "Tusenskilletegn" #. module: base #: field:res.request,create_date:0 msgid "Created Date" -msgstr "" +msgstr "Dato opprettet" #. module: base #: help:ir.actions.server,loop_action:0 @@ -6065,6 +6149,8 @@ msgid "" "Select the action that will be executed. Loop action will not be avaliable " "inside loop." msgstr "" +"Velg handlingen som skal utføres. Iterative handlinger vil ikke være " +"tilgjengelig i løkker." #. module: base #: selection:base.language.install,lang:0 @@ -6074,7 +6160,7 @@ msgstr "" #. module: base #: model:ir.model,name:base.model_res_request msgid "res.request" -msgstr "" +msgstr "res.request" #. module: base #: view:ir.model:0 @@ -6089,17 +6175,17 @@ msgstr "" #. module: base #: field:ir.attachment,datas:0 msgid "File Content" -msgstr "" +msgstr "Filinnhold" #. module: base #: model:res.country,name:base.pa msgid "Panama" -msgstr "" +msgstr "Panama" #. module: base #: model:res.partner.title,name:base.res_partner_title_ltd msgid "Ltd" -msgstr "" +msgstr "AS" #. module: base #: help:workflow.transition,group_id:0 @@ -6116,7 +6202,7 @@ msgstr "" #. module: base #: model:res.country,name:base.gi msgid "Gibraltar" -msgstr "" +msgstr "Gibraltar" #. module: base #: field:ir.actions.report.xml,report_name:0 @@ -6126,37 +6212,37 @@ msgstr "" #. module: base #: model:res.country,name:base.pn msgid "Pitcairn Island" -msgstr "" +msgstr "Pitcairnøyene" #. module: base #: view:base.module.upgrade:0 msgid "" "We suggest to reload the menu tab to see the new menus (Ctrl+T then Ctrl+R)." -msgstr "" +msgstr "Vi anbefaler at du laster menyene på nytt (Ctrl+T Ctrl+R)." #. module: base #: model:ir.actions.act_window,name:base.action_rule #: model:ir.ui.menu,name:base.menu_action_rule msgid "Record Rules" -msgstr "" +msgstr "Lagre regler" #. module: base #: field:res.config.users,name:0 #: field:res.users,name:0 msgid "User Name" -msgstr "" +msgstr "Brukernavn" #. module: base #: view:ir.sequence:0 msgid "Day of the year: %(doy)s" -msgstr "" +msgstr "Dag i året: %(day)s" #. module: base #: view:ir.model:0 #: view:ir.model.fields:0 #: view:workflow.activity:0 msgid "Properties" -msgstr "" +msgstr "Egenskaper" #. module: base #: help:ir.sequence,padding:0 @@ -6168,12 +6254,12 @@ msgstr "" #. module: base #: view:res.lang:0 msgid "%A - Full weekday name." -msgstr "" +msgstr "%A - Fullt navn på ukedag." #. module: base #: selection:ir.cron,interval_type:0 msgid "Months" -msgstr "" +msgstr "Måneder" #. module: base #: field:ir.actions.act_window,search_view:0 @@ -6191,42 +6277,42 @@ msgstr "" #: view:ir.attachment:0 #: model:ir.ui.menu,name:base.menu_action_attachment msgid "Attachments" -msgstr "" +msgstr "Vedlegg" #. module: base #: model:ir.ui.menu,name:base.menu_base_partner #: model:ir.ui.menu,name:base.menu_sale_config_sales #: model:ir.ui.menu,name:base.menu_sales msgid "Sales" -msgstr "" +msgstr "Salg" #. module: base #: field:ir.actions.server,child_ids:0 msgid "Other Actions" -msgstr "" +msgstr "Andre handlinger" #. module: base #: selection:ir.actions.todo,state:0 #: view:res.config.users:0 msgid "Done" -msgstr "" +msgstr "Fullført" #. module: base #: model:res.partner.title,name:base.res_partner_title_miss msgid "Miss" -msgstr "" +msgstr "Frøken" #. module: base #: view:ir.model.access:0 #: field:ir.model.access,perm_write:0 #: view:ir.rule:0 msgid "Write Access" -msgstr "" +msgstr "Skrivetilgang" #. module: base #: view:res.lang:0 msgid "%m - Month number [01,12]." -msgstr "" +msgstr "%m - Måned som et desimaltall [01,12]." #. module: base #: field:res.bank,city:0 @@ -6234,17 +6320,17 @@ msgstr "" #: field:res.partner.address,city:0 #: field:res.partner.bank,city:0 msgid "City" -msgstr "" +msgstr "By" #. module: base #: model:res.country,name:base.qa msgid "Qatar" -msgstr "" +msgstr "Qatar" #. module: base #: model:res.country,name:base.it msgid "Italy" -msgstr "" +msgstr "Italia" #. module: base #: view:ir.actions.todo:0 @@ -6255,24 +6341,24 @@ msgstr "" #. module: base #: selection:base.language.install,lang:0 msgid "Estonian / Eesti keel" -msgstr "" +msgstr "Estisk / Eesti keel" #. module: base #: field:res.config.users,email:0 #: field:res.partner,email:0 #: field:res.users,email:0 msgid "E-mail" -msgstr "" +msgstr "E-post" #. module: base #: selection:ir.module.module,license:0 msgid "GPL-3 or later version" -msgstr "" +msgstr "GPL-3 eller senere versjon" #. module: base #: field:workflow.activity,action:0 msgid "Python Action" -msgstr "" +msgstr "Python handlinger" #. module: base #: selection:base.language.install,lang:0 @@ -6297,6 +6383,7 @@ msgstr "" #: view:base.language.export:0 msgid "To browse official translations, you can start with these links:" msgstr "" +"For å se gjennom offisielle oversettelser kan du besøke følgende lenke:" #. module: base #: code:addons/base/ir/ir_model.py:484 @@ -6313,12 +6400,12 @@ msgstr "" #: view:res.users:0 #: field:res.users,address_id:0 msgid "Address" -msgstr "" +msgstr "Adresse" #. module: base #: field:ir.module.module,latest_version:0 msgid "Installed version" -msgstr "" +msgstr "Installert versjon" #. module: base #: selection:base.language.install,lang:0 @@ -6328,12 +6415,12 @@ msgstr "" #. module: base #: model:res.country,name:base.mr msgid "Mauritania" -msgstr "" +msgstr "Mauritania" #. module: base #: model:ir.model,name:base.model_ir_translation msgid "ir.translation" -msgstr "" +msgstr "ir.translation" #. module: base #: view:base.module.update:0 @@ -6344,7 +6431,7 @@ msgstr "" #: view:workflow.activity:0 #: field:workflow.workitem,act_id:0 msgid "Activity" -msgstr "" +msgstr "Aktivitet" #. module: base #: view:res.partner:0 @@ -6355,42 +6442,42 @@ msgstr "" #. module: base #: field:res.company,parent_id:0 msgid "Parent Company" -msgstr "" +msgstr "Morselskap" #. module: base #: selection:base.language.install,lang:0 msgid "Spanish (CR) / Español (CR)" -msgstr "" +msgstr "Spanish (CR) / Español (CR)" #. module: base #: field:res.currency.rate,rate:0 msgid "Rate" -msgstr "" +msgstr "Sats" #. module: base #: model:res.country,name:base.cg msgid "Congo" -msgstr "" +msgstr "Kongo" #. module: base #: view:res.lang:0 msgid "Examples" -msgstr "" +msgstr "Eksempler" #. module: base #: field:ir.default,value:0 msgid "Default Value" -msgstr "" +msgstr "Standardverdi" #. module: base #: model:ir.ui.menu,name:base.menu_tools msgid "Tools" -msgstr "" +msgstr "Verktøy" #. module: base #: model:res.country,name:base.kn msgid "Saint Kitts & Nevis Anguilla" -msgstr "" +msgstr "Saint Kitts og Nevis" #. module: base #: code:addons/base/res/res_currency.py:100 @@ -6413,7 +6500,7 @@ msgstr "" #: field:ir.model.fields,model:0 #: field:ir.values,model:0 msgid "Object Name" -msgstr "" +msgstr "Objektnavn" #. module: base #: help:ir.actions.server,srcmodel_id:0 @@ -6421,24 +6508,26 @@ msgid "" "Object in which you want to create / write the object. If it is empty then " "refer to the Object field." msgstr "" +"Objekt hvorpå du vil opprette / lagre objeket. Hvis det er blankt refererer " +"du til objektfeltet." #. module: base #: view:ir.module.module:0 #: selection:ir.module.module,state:0 #: selection:ir.module.module.dependency,state:0 msgid "Not Installed" -msgstr "" +msgstr "Ikke installert" #. module: base #: view:workflow.activity:0 #: field:workflow.activity,out_transitions:0 msgid "Outgoing Transitions" -msgstr "" +msgstr "Utgående overganger" #. module: base #: field:ir.ui.menu,icon:0 msgid "Icon" -msgstr "" +msgstr "Ikon" #. module: base #: help:ir.model.fields,model_id:0 @@ -6448,12 +6537,12 @@ msgstr "" #. module: base #: model:res.country,name:base.mq msgid "Martinique (French)" -msgstr "" +msgstr "Martinique (Fransk)" #. module: base #: view:ir.sequence.type:0 msgid "Sequences Type" -msgstr "" +msgstr "Sekvenstype" #. module: base #: model:ir.actions.act_window,name:base.res_request-act @@ -6461,17 +6550,17 @@ msgstr "" #: model:ir.ui.menu,name:base.menu_resquest_ref #: view:res.request:0 msgid "Requests" -msgstr "" +msgstr "Forespørsler" #. module: base #: model:res.country,name:base.ye msgid "Yemen" -msgstr "" +msgstr "Yemen" #. module: base #: selection:workflow.activity,split_mode:0 msgid "Or" -msgstr "" +msgstr "Eller" #. module: base #: model:ir.actions.act_window,name:base.res_log_act_window @@ -6482,12 +6571,12 @@ msgstr "" #. module: base #: model:res.country,name:base.al msgid "Albania" -msgstr "" +msgstr "Albania" #. module: base #: model:res.country,name:base.ws msgid "Samoa" -msgstr "" +msgstr "Samoa" #. module: base #: code:addons/base/res/res_lang.py:161 @@ -6508,14 +6597,14 @@ msgstr "" #. module: base #: field:ir.ui.menu,child_id:0 msgid "Child IDs" -msgstr "" +msgstr "Over barn" #. module: base #: code:addons/base/ir/ir_actions.py:713 #: code:addons/base/ir/ir_actions.py:716 #, python-format msgid "Problem in configuration `Record Id` in Server Action!" -msgstr "" +msgstr "Problem med konfigurasjon `Record Id` i Server Action!" #. module: base #: code:addons/orm.py:2306 @@ -6538,12 +6627,12 @@ msgstr "" #. module: base #: view:base.module.import:0 msgid "Import module" -msgstr "" +msgstr "Importer modul" #. module: base #: field:ir.actions.server,loop_action:0 msgid "Loop Action" -msgstr "" +msgstr "Løkkehandling" #. module: base #: help:ir.actions.report.xml,report_file:0 @@ -6555,20 +6644,20 @@ msgstr "" #. module: base #: model:res.country,name:base.la msgid "Laos" -msgstr "" +msgstr "Laos" #. module: base #: selection:ir.actions.server,state:0 #: field:res.config.users,user_email:0 #: field:res.users,user_email:0 msgid "Email" -msgstr "" +msgstr "E-post" #. module: base #: field:res.config.users,action_id:0 #: field:res.users,action_id:0 msgid "Home Action" -msgstr "" +msgstr "Handlingsgruppe" #. module: base #: code:addons/custom.py:558 @@ -6588,22 +6677,22 @@ msgstr "" #: model:ir.ui.menu,name:base.next_id_73 #: model:ir.ui.menu,name:base.reporting_menu msgid "Reporting" -msgstr "" +msgstr "Rapportering" #. module: base #: model:res.country,name:base.tg msgid "Togo" -msgstr "" +msgstr "Togo" #. module: base #: selection:ir.module.module,license:0 msgid "Other Proprietary" -msgstr "" +msgstr "Annen propertiær" #. module: base #: selection:workflow.activity,kind:0 msgid "Stop All" -msgstr "" +msgstr "Stop alle" #. module: base #: code:addons/orm.py:412 @@ -6614,17 +6703,17 @@ msgstr "" #. module: base #: view:ir.model.data:0 msgid "Updatable" -msgstr "" +msgstr "Oppdaterbar" #. module: base #: view:res.lang:0 msgid "3. %x ,%X ==> 12/05/08, 18:25:20" -msgstr "" +msgstr "3. %x ,%X ==> 12/05/08, 18:25:20" #. module: base #: selection:ir.model.fields,on_delete:0 msgid "Cascade" -msgstr "" +msgstr "Kaskade" #. module: base #: field:workflow.transition,group_id:0 @@ -6634,17 +6723,17 @@ msgstr "" #. module: base #: view:ir.actions.configuration.wizard:0 msgid "Next Configuration Step" -msgstr "" +msgstr "Neste steg i konfigurasjonen" #. module: base #: field:res.groups,comment:0 msgid "Comment" -msgstr "" +msgstr "Kommentar" #. module: base #: model:res.country,name:base.ro msgid "Romania" -msgstr "" +msgstr "Romania" #. module: base #: help:ir.cron,doall:0 @@ -6656,7 +6745,7 @@ msgstr "" #. module: base #: view:base.module.upgrade:0 msgid "Start update" -msgstr "" +msgstr "Start oppdatering" #. module: base #: code:addons/base/publisher_warranty/publisher_warranty.py:144 @@ -6667,24 +6756,24 @@ msgstr "" #. module: base #: field:res.country.state,name:0 msgid "State Name" -msgstr "" +msgstr "Navn på stat" #. module: base #: field:workflow.activity,join_mode:0 msgid "Join Mode" -msgstr "" +msgstr "Koblingstype" #. module: base #: field:res.config.users,context_tz:0 #: field:res.users,context_tz:0 msgid "Timezone" -msgstr "" +msgstr "Tidssone" #. module: base #: model:ir.model,name:base.model_ir_actions_report_xml #: selection:ir.ui.menu,action:0 msgid "ir.actions.report.xml" -msgstr "" +msgstr "ir.actions.report.xml" #. module: base #: model:res.partner.title,shortcut:base.res_partner_title_miss @@ -6694,7 +6783,7 @@ msgstr "" #. module: base #: model:ir.model,name:base.model_ir_ui_view msgid "ir.ui.view" -msgstr "" +msgstr "ir.ui.view" #. module: base #: constraint:res.partner:0 @@ -6709,7 +6798,7 @@ msgstr "" #. module: base #: model:res.partner.category,name:base.res_partner_category_2 msgid "OpenERP Partners" -msgstr "" +msgstr "OpenERP partnere" #. module: base #: model:ir.ui.menu,name:base.menu_hr_manager @@ -6731,7 +6820,7 @@ msgstr "" #. module: base #: model:res.country,name:base.by msgid "Belarus" -msgstr "" +msgstr "Hviterussland" #. module: base #: field:ir.actions.act_window,name:0 @@ -6741,7 +6830,7 @@ msgstr "" #: field:ir.actions.url,name:0 #: field:ir.filters,name:0 msgid "Action Name" -msgstr "" +msgstr "Handlingsnavn" #. module: base #: model:ir.actions.act_window,help:base.action_res_users @@ -6755,18 +6844,18 @@ msgstr "" #. module: base #: selection:res.request,priority:0 msgid "Normal" -msgstr "" +msgstr "Normal" #. module: base #: field:res.bank,street2:0 #: field:res.partner.address,street2:0 msgid "Street2" -msgstr "" +msgstr "Gate2" #. module: base #: model:ir.actions.act_window,name:base.action_view_base_module_update msgid "Module Update" -msgstr "" +msgstr "Moduloppdatering" #. module: base #: code:addons/base/module/wizard/base_module_upgrade.py:95 @@ -6786,17 +6875,17 @@ msgstr "" #: view:res.users:0 #: field:res.widget.user,user_id:0 msgid "User" -msgstr "" +msgstr "Bruker" #. module: base #: model:res.country,name:base.pr msgid "Puerto Rico" -msgstr "" +msgstr "Puerto Rico" #. module: base #: view:ir.actions.act_window:0 msgid "Open Window" -msgstr "" +msgstr "Åpne vindu" #. module: base #: field:ir.actions.act_window,auto_search:0 @@ -6806,7 +6895,7 @@ msgstr "" #. module: base #: field:ir.actions.act_window,filter:0 msgid "Filter" -msgstr "" +msgstr "Filter" #. module: base #: model:res.partner.title,shortcut:base.res_partner_title_madam @@ -6816,27 +6905,27 @@ msgstr "" #. module: base #: model:res.country,name:base.ch msgid "Switzerland" -msgstr "" +msgstr "Sveits" #. module: base #: model:res.country,name:base.gd msgid "Grenada" -msgstr "" +msgstr "Grenada" #. module: base #: model:res.country,name:base.wf msgid "Wallis and Futuna Islands" -msgstr "" +msgstr "Wallis og Futuna øyene" #. module: base #: selection:server.action.create,init,type:0 msgid "Open Report" -msgstr "" +msgstr "Åpne rapport" #. module: base #: field:res.currency,rounding:0 msgid "Rounding factor" -msgstr "" +msgstr "Avrundingsfaktor" #. module: base #: view:base.language.install:0 @@ -6859,7 +6948,7 @@ msgstr "" #. module: base #: model:ir.model,name:base.model_ir_wizard_screen msgid "ir.wizard.screen" -msgstr "" +msgstr "ir.wizard.screen" #. module: base #: code:addons/base/ir/ir_model.py:223 @@ -6870,7 +6959,7 @@ msgstr "" #. module: base #: model:res.country,name:base.so msgid "Somalia" -msgstr "" +msgstr "Somalia" #. module: base #: selection:publisher_warranty.contract,state:0 @@ -6880,25 +6969,25 @@ msgstr "" #. module: base #: model:res.partner.category,name:base.res_partner_category_13 msgid "Important customers" -msgstr "" +msgstr "Viktige kunder" #. module: base #: view:res.lang:0 msgid "Update Terms" -msgstr "" +msgstr "Oppdater betegnelser" #. module: base #: field:partner.sms.send,mobile_to:0 #: field:res.request,act_to:0 #: field:res.request.history,act_to:0 msgid "To" -msgstr "" +msgstr "Til" #. module: base #: view:ir.cron:0 #: field:ir.cron,args:0 msgid "Arguments" -msgstr "" +msgstr "Argumenter" #. module: base #: code:addons/orm.py:716 @@ -6909,12 +6998,12 @@ msgstr "" #. module: base #: selection:ir.module.module,license:0 msgid "GPL Version 2" -msgstr "" +msgstr "GPL versjon 2" #. module: base #: selection:ir.module.module,license:0 msgid "GPL Version 3" -msgstr "" +msgstr "GPL versjon 3" #. module: base #: code:addons/orm.py:836 @@ -6939,33 +7028,33 @@ msgstr "" #: field:res.partner.address,is_customer_add:0 #: model:res.partner.category,name:base.res_partner_category_0 msgid "Customer" -msgstr "" +msgstr "Kunde" #. module: base #: selection:base.language.install,lang:0 msgid "Spanish (NI) / Español (NI)" -msgstr "" +msgstr "Spanish (NI) / Español (NI)" #. module: base #: field:ir.module.module,shortdesc:0 msgid "Short Description" -msgstr "" +msgstr "Kort beskrivelse" #. module: base #: field:ir.actions.act_window,context:0 #: field:ir.filters,context:0 msgid "Context Value" -msgstr "" +msgstr "Kontekstverdi" #. module: base #: view:ir.sequence:0 msgid "Hour 00->24: %(h24)s" -msgstr "" +msgstr "Timer 00->24: %(h24)s" #. module: base #: field:ir.cron,nextcall:0 msgid "Next Execution Date" -msgstr "" +msgstr "Neste dato for eksekvering" #. module: base #: help:multi_company.default,field_id:0 @@ -6975,12 +7064,12 @@ msgstr "" #. module: base #: field:res.request.history,date_sent:0 msgid "Date sent" -msgstr "" +msgstr "Dato sendt" #. module: base #: view:ir.sequence:0 msgid "Month: %(month)s" -msgstr "" +msgstr "Måned: %(month)s" #. module: base #: field:ir.actions.act_window.view,sequence:0 @@ -6997,34 +7086,34 @@ msgstr "" #: field:res.widget.user,sequence:0 #: field:wizard.ir.model.menu.create.line,sequence:0 msgid "Sequence" -msgstr "" +msgstr "Sekvens" #. module: base #: model:res.country,name:base.tn msgid "Tunisia" -msgstr "" +msgstr "Tunisia" #. module: base #: model:ir.ui.menu,name:base.menu_mrp_root msgid "Manufacturing" -msgstr "" +msgstr "Produksjon" #. module: base #: model:res.country,name:base.km msgid "Comoros" -msgstr "" +msgstr "Komorene / Den islamske forbundsrepublikk Komorene" #. module: base #: model:ir.actions.act_window,name:base.action_server_action #: view:ir.actions.server:0 #: model:ir.ui.menu,name:base.menu_server_action msgid "Server Actions" -msgstr "" +msgstr "Handlinger på server" #. module: base #: view:ir.module.module:0 msgid "Cancel Install" -msgstr "" +msgstr "Avbryt installasjon" #. module: base #: field:ir.model.fields,selection:0 @@ -7039,12 +7128,12 @@ msgstr "" #. module: base #: view:res.lang:0 msgid "Legends for Date and Time Formats" -msgstr "" +msgstr "Tegnforklaring for dato- og tidsangivelse" #. module: base #: selection:ir.actions.server,state:0 msgid "Copy Object" -msgstr "" +msgstr "Kopier objekt" #. module: base #: code:addons/base/res/res_user.py:581 @@ -7063,12 +7152,12 @@ msgstr "" #: view:ir.model:0 #: view:res.groups:0 msgid "Access Rules" -msgstr "" +msgstr "Tilgangsregler" #. module: base #: field:ir.default,ref_table:0 msgid "Table Ref." -msgstr "" +msgstr "Tabell ref." #. module: base #: field:ir.actions.act_window,res_model:0 @@ -7096,7 +7185,7 @@ msgstr "" #: field:res.request.link,object:0 #: field:workflow.triggers,model:0 msgid "Object" -msgstr "" +msgstr "Objekt" #. module: base #: code:addons/osv.py:151 @@ -7110,24 +7199,24 @@ msgstr "" #. module: base #: model:ir.model,name:base.model_ir_default msgid "ir.default" -msgstr "" +msgstr "ir.default" #. module: base #: view:ir.sequence:0 msgid "Minute: %(min)s" -msgstr "" +msgstr "Minutt: %(min)s" #. module: base #: view:base.update.translations:0 #: model:ir.actions.act_window,name:base.action_wizard_update_translations #: model:ir.ui.menu,name:base.menu_wizard_update_translations msgid "Synchronize Translations" -msgstr "" +msgstr "Synkroniser oversettelser" #. module: base #: model:ir.ui.menu,name:base.next_id_10 msgid "Scheduler" -msgstr "" +msgstr "Planlegger" #. module: base #: help:ir.cron,numbercall:0 @@ -7135,6 +7224,8 @@ msgid "" "Number of time the function is called,\n" "a negative number indicates no limit" msgstr "" +"Antall ganger denne funksjonen blir kalt,\n" +"et negativt nummer indikerer at denne funksjonen alltid vil blir kalt" #. module: base #: code:addons/base/ir/ir_model.py:331 @@ -7147,13 +7238,13 @@ msgstr "" #. module: base #: field:ir.ui.view_sc,user_id:0 msgid "User Ref." -msgstr "" +msgstr "Bruker ref." #. module: base #: code:addons/base/res/res_user.py:580 #, python-format msgid "Warning !" -msgstr "" +msgstr "Advarsel !" #. module: base #: model:res.widget,title:base.google_maps_widget @@ -7169,27 +7260,27 @@ msgstr "" #: model:ir.ui.menu,name:base.menu_marketing_config_root #: view:res.company:0 msgid "Configuration" -msgstr "" +msgstr "Konfigurasjon" #. module: base #: model:ir.model,name:base.model_publisher_warranty_contract_wizard msgid "publisher_warranty.contract.wizard" -msgstr "" +msgstr "publisher_warranty.contract.wizard" #. module: base #: field:ir.actions.server,expression:0 msgid "Loop Expression" -msgstr "" +msgstr "Løkkeuttrykk" #. module: base #: field:publisher_warranty.contract,date_start:0 msgid "Starting Date" -msgstr "" +msgstr "Startdato" #. module: base #: help:res.partner,website:0 msgid "Website of Partner" -msgstr "" +msgstr "Partners webside" #. module: base #: model:res.partner.category,name:base.res_partner_category_5 @@ -7205,28 +7296,28 @@ msgstr "" #: selection:res.partner.title,domain:0 #: model:res.request.link,name:base.req_link_partner msgid "Partner" -msgstr "" +msgstr "Partner" #. module: base #: model:res.country,name:base.tr msgid "Turkey" -msgstr "" +msgstr "Tyrkia" #. module: base #: model:res.country,name:base.fk msgid "Falkland Islands" -msgstr "" +msgstr "Falklandsøyene" #. module: base #: model:res.country,name:base.lb msgid "Lebanon" -msgstr "" +msgstr "Libanon" #. module: base #: view:ir.actions.report.xml:0 #: field:ir.actions.report.xml,report_type:0 msgid "Report Type" -msgstr "" +msgstr "Rapporttype" #. module: base #: field:ir.actions.todo,state:0 @@ -7242,28 +7333,28 @@ msgstr "" #: field:workflow.instance,state:0 #: field:workflow.workitem,state:0 msgid "State" -msgstr "" +msgstr "Bekreft" #. module: base #: selection:base.language.install,lang:0 msgid "Galician / Galego" -msgstr "" +msgstr "Galicisk / Galego" #. module: base #: model:res.country,name:base.no msgid "Norway" -msgstr "" +msgstr "Norge" #. module: base #: view:res.lang:0 msgid "4. %b, %B ==> Dec, December" -msgstr "" +msgstr "4. %b, %B ==> Dec, December" #. module: base #: view:base.language.install:0 #: model:ir.ui.menu,name:base.menu_view_base_language_install msgid "Load an Official Translation" -msgstr "" +msgstr "Last inn en offisiell oversettelse" #. module: base #: view:res.currency:0 @@ -7278,12 +7369,12 @@ msgstr "" #. module: base #: model:res.country,name:base.kg msgid "Kyrgyz Republic (Kyrgyzstan)" -msgstr "" +msgstr "Kirgisistan, Republikken Kirgisistan" #. module: base #: selection:res.request,state:0 msgid "waiting" -msgstr "" +msgstr "venter" #. module: base #: field:ir.actions.report.xml,report_file:0 @@ -7293,7 +7384,7 @@ msgstr "" #. module: base #: model:ir.model,name:base.model_workflow_triggers msgid "workflow.triggers" -msgstr "" +msgstr "workflow.triggers" #. module: base #: code:addons/base/ir/ir_model.py:62 @@ -7304,7 +7395,7 @@ msgstr "" #. module: base #: view:ir.attachment:0 msgid "Created" -msgstr "" +msgstr "Opprettet" #. module: base #: help:ir.actions.wizard,multi:0 @@ -7312,31 +7403,33 @@ msgid "" "If set to true, the wizard will not be displayed on the right toolbar of a " "form view." msgstr "" +"Hvis satt til sann, så vil ikke veiviseren blir vist på den høyre " +"verktøylinjen i skjemavisning." #. module: base #: view:base.language.import:0 msgid "- type,name,res_id,src,value" -msgstr "" +msgstr "- type,name,res_id,src,value" #. module: base #: model:res.country,name:base.hm msgid "Heard and McDonald Islands" -msgstr "" +msgstr "Heard- og McDonaldøyene" #. module: base #: field:ir.actions.act_window,view_id:0 msgid "View Ref." -msgstr "" +msgstr "Visnings ref:" #. module: base #: selection:ir.translation,type:0 msgid "Selection" -msgstr "" +msgstr "Valg" #. module: base #: field:res.company,rml_header1:0 msgid "Report Header" -msgstr "" +msgstr "Topptekst i rapport" #. module: base #: field:ir.actions.act_window,type:0 @@ -7349,7 +7442,7 @@ msgstr "" #: field:ir.actions.url,type:0 #: field:ir.actions.wizard,type:0 msgid "Action Type" -msgstr "" +msgstr "Handlingstype" #. module: base #: code:addons/base/module/module.py:268 @@ -7364,68 +7457,68 @@ msgstr "" #: model:ir.actions.act_window,name:base.action_view_base_import_language #: model:ir.ui.menu,name:base.menu_view_base_import_language msgid "Import Translation" -msgstr "" +msgstr "Importer oversettelse" #. module: base #: field:res.partner.bank.type,field_ids:0 msgid "Type fields" -msgstr "" +msgstr "Felttyper" #. module: base #: view:ir.module.module:0 #: field:ir.module.module,category_id:0 msgid "Category" -msgstr "" +msgstr "Kategori" #. module: base #: view:ir.attachment:0 #: selection:ir.attachment,type:0 #: selection:ir.property,type:0 msgid "Binary" -msgstr "" +msgstr "Binær" #. module: base #: field:ir.actions.server,sms:0 #: selection:ir.actions.server,state:0 msgid "SMS" -msgstr "" +msgstr "SMS" #. module: base #: model:res.country,name:base.cr msgid "Costa Rica" -msgstr "" +msgstr "Costa Rica" #. module: base #: view:workflow.activity:0 msgid "Conditions" -msgstr "" +msgstr "Vilkår" #. module: base #: model:ir.actions.act_window,name:base.action_partner_other_form msgid "Other Partners" -msgstr "" +msgstr "Andre partnere" #. module: base #: model:ir.actions.act_window,name:base.action_currency_form #: model:ir.ui.menu,name:base.menu_action_currency_form #: view:res.currency:0 msgid "Currencies" -msgstr "" +msgstr "Valuta" #. module: base #: sql_constraint:res.groups:0 msgid "The name of the group must be unique !" -msgstr "" +msgstr "Navnet på gruppen må være unikt !" #. module: base #: view:ir.sequence:0 msgid "Hour 00->12: %(h12)s" -msgstr "" +msgstr "Time 00->12: %(h12)s" #. module: base #: help:res.partner.address,active:0 msgid "Uncheck the active field to hide the contact." -msgstr "" +msgstr "Fjern avkrysningen fra aktivt felt for å skjule kontakt." #. module: base #: model:ir.model,name:base.model_res_widget_wizard @@ -7435,17 +7528,17 @@ msgstr "" #. module: base #: model:res.country,name:base.dk msgid "Denmark" -msgstr "" +msgstr "Danmark" #. module: base #: field:res.country,code:0 msgid "Country Code" -msgstr "" +msgstr "Landekode" #. module: base #: model:ir.model,name:base.model_workflow_instance msgid "workflow.instance" -msgstr "" +msgstr "workflow.instance" #. module: base #: code:addons/orm.py:278 @@ -7456,7 +7549,7 @@ msgstr "" #. module: base #: view:res.lang:0 msgid "10. %S ==> 20" -msgstr "" +msgstr "10. %S ==> 20" #. module: base #: code:addons/fields.py:106 @@ -7480,12 +7573,12 @@ msgstr "" #. module: base #: model:res.partner.title,name:base.res_partner_title_madam msgid "Madam" -msgstr "" +msgstr "Fru" #. module: base #: model:res.country,name:base.ee msgid "Estonia" -msgstr "" +msgstr "Estland" #. module: base #: model:ir.ui.menu,name:base.dashboard @@ -7501,27 +7594,27 @@ msgstr "" #: field:res.config.users,new_password:0 #: field:res.users,new_password:0 msgid "Change password" -msgstr "" +msgstr "Endre passord" #. module: base #: model:res.country,name:base.nl msgid "Netherlands" -msgstr "" +msgstr "Nederland" #. module: base #: model:ir.ui.menu,name:base.next_id_4 msgid "Low Level Objects" -msgstr "" +msgstr "Lavnivå objekter" #. module: base #: view:res.company:0 msgid "Your Logo - Use a size of about 450x150 pixels." -msgstr "" +msgstr "Din egen logo - Bruk en logo med størrelse på ca 450x150 pixler" #. module: base #: model:ir.model,name:base.model_ir_values msgid "ir.values" -msgstr "" +msgstr "ir.values" #. module: base #: selection:base.language.install,lang:0 @@ -7546,7 +7639,7 @@ msgstr "" #. module: base #: model:res.country,name:base.cd msgid "Congo, The Democratic Republic of the" -msgstr "" +msgstr "Kongo" #. module: base #: selection:base.language.install,lang:0 @@ -7558,23 +7651,23 @@ msgstr "" #: field:res.request,body:0 #: field:res.request.history,req_id:0 msgid "Request" -msgstr "" +msgstr "Forespørsel" #. module: base #: model:res.country,name:base.jp msgid "Japan" -msgstr "" +msgstr "Japan" #. module: base #: field:ir.cron,numbercall:0 msgid "Number of Calls" -msgstr "" +msgstr "Antall samtaler" #. module: base #: view:base.module.upgrade:0 #: field:base.module.upgrade,module_info:0 msgid "Modules to update" -msgstr "" +msgstr "Moduler å oppdatere" #. module: base #: help:ir.actions.server,sequence:0 @@ -7582,26 +7675,28 @@ msgid "" "Important when you deal with multiple actions, the execution order will be " "decided based on this, low number is higher priority." msgstr "" +"Viktig ved flere handlinger. Rekkefølgen på avvikling baseres på dette. Lavt " +"nummer betyr høyere prioritet." #. module: base #: field:ir.actions.report.xml,header:0 msgid "Add RML header" -msgstr "" +msgstr "topptekst for kolonne i tabell" #. module: base #: model:res.country,name:base.gr msgid "Greece" -msgstr "" +msgstr "Hellas" #. module: base #: field:res.request,trigger_date:0 msgid "Trigger Date" -msgstr "" +msgstr "Trigger dato" #. module: base #: selection:base.language.install,lang:0 msgid "Croatian / hrvatski jezik" -msgstr "" +msgstr "Kroatisk / hrvatski jezik" #. module: base #: field:base.language.install,overwrite:0 @@ -7611,7 +7706,7 @@ msgstr "" #. module: base #: help:ir.actions.server,code:0 msgid "Python code to be executed" -msgstr "" +msgstr "Python kode som skal eksekveres" #. module: base #: sql_constraint:res.country:0 @@ -7621,45 +7716,45 @@ msgstr "" #. module: base #: selection:ir.module.module.dependency,state:0 msgid "Uninstallable" -msgstr "" +msgstr "ikke installerbar" #. module: base #: view:res.partner.category:0 msgid "Partner Category" -msgstr "" +msgstr "Gullpartner" #. module: base #: view:ir.actions.server:0 #: selection:ir.actions.server,state:0 msgid "Trigger" -msgstr "" +msgstr "Trigger" #. module: base #: model:ir.model,name:base.model_base_module_update msgid "Update Module" -msgstr "" +msgstr "Oppdater modul" #. module: base #: view:ir.model.fields:0 #: field:ir.model.fields,translate:0 msgid "Translate" -msgstr "" +msgstr "Oversett" #. module: base #: field:res.request.history,body:0 msgid "Body" -msgstr "" +msgstr "Innhold" #. module: base #: view:partner.wizard.spam:0 msgid "Send Email" -msgstr "" +msgstr "Send epost" #. module: base #: field:res.config.users,menu_id:0 #: field:res.users,menu_id:0 msgid "Menu Action" -msgstr "" +msgstr "Menyvalg" #. module: base #: help:ir.model.fields,selection:0 @@ -7672,7 +7767,7 @@ msgstr "" #. module: base #: selection:base.language.export,state:0 msgid "choose" -msgstr "" +msgstr "velg" #. module: base #: help:ir.model,osv_memory:0 @@ -7685,14 +7780,14 @@ msgstr "" #: field:res.partner,child_ids:0 #: field:res.request,ref_partner_id:0 msgid "Partner Ref." -msgstr "" +msgstr "Partner ref." #. module: base #: model:ir.actions.act_window,name:base.action_partner_supplier_form #: model:ir.ui.menu,name:base.menu_procurement_management_supplier_name #: view:res.partner:0 msgid "Suppliers" -msgstr "" +msgstr "Leverandører" #. module: base #: view:publisher_warranty.contract.wizard:0 @@ -7702,54 +7797,54 @@ msgstr "" #. module: base #: field:res.request,ref_doc2:0 msgid "Document Ref 2" -msgstr "" +msgstr "Dokumentref. 2" #. module: base #: field:res.request,ref_doc1:0 msgid "Document Ref 1" -msgstr "" +msgstr "Dokumentref. 1" #. module: base #: model:res.country,name:base.ga msgid "Gabon" -msgstr "" +msgstr "Gabon" #. module: base #: model:ir.model,name:base.model_ir_model_data msgid "ir.model.data" -msgstr "" +msgstr "ir.model.data" #. module: base #: view:ir.model:0 #: view:ir.rule:0 #: view:res.groups:0 msgid "Access Rights" -msgstr "" +msgstr "Tilgangsrettigheter" #. module: base #: model:res.country,name:base.gl msgid "Greenland" -msgstr "" +msgstr "Grønnland" #. module: base #: field:res.partner.bank,acc_number:0 msgid "Account Number" -msgstr "" +msgstr "Kontonummer" #. module: base #: view:res.lang:0 msgid "1. %c ==> Fri Dec 5 18:25:20 2008" -msgstr "" +msgstr "1. %c ==> Fri Dec 5 18:25:20 2008" #. module: base #: model:res.country,name:base.nc msgid "New Caledonia (French)" -msgstr "" +msgstr "Ny-Caledonia" #. module: base #: model:res.country,name:base.cy msgid "Cyprus" -msgstr "" +msgstr "Kypros" #. module: base #: view:base.module.import:0 @@ -7764,18 +7859,18 @@ msgstr "" #: field:partner.wizard.spam,subject:0 #: field:res.request,name:0 msgid "Subject" -msgstr "" +msgstr "Emne" #. module: base #: field:res.request,act_from:0 #: field:res.request.history,act_from:0 msgid "From" -msgstr "" +msgstr "Fra" #. module: base #: view:res.users:0 msgid "Preferences" -msgstr "" +msgstr "Oppsett" #. module: base #: model:res.partner.category,name:base.res_partner_category_consumers0 @@ -7786,7 +7881,7 @@ msgstr "" #: view:res.config:0 #: wizard_button:server.action.create,init,step_1:0 msgid "Next" -msgstr "" +msgstr "Neste" #. module: base #: help:ir.cron,function:0 @@ -7811,7 +7906,7 @@ msgstr "" #. module: base #: model:res.country,name:base.cn msgid "China" -msgstr "" +msgstr "Kina" #. module: base #: code:addons/base/res/res_user.py:516 @@ -7824,12 +7919,12 @@ msgstr "" #. module: base #: model:res.country,name:base.eh msgid "Western Sahara" -msgstr "" +msgstr "Vest-Sahara" #. module: base #: model:ir.model,name:base.model_workflow msgid "workflow" -msgstr "" +msgstr "arbeidsflyt" #. module: base #: model:ir.actions.act_window,help:base.action_res_company_form @@ -7841,7 +7936,7 @@ msgstr "" #. module: base #: model:res.country,name:base.id msgid "Indonesia" -msgstr "" +msgstr "Indonesia" #. module: base #: view:base.update.translations:0 @@ -7850,6 +7945,9 @@ msgid "" "you can then add translations manually or perform a complete export (as a " "template for a new language example)." msgstr "" +"Denne veiviseren vil oppdage nye betegnelser i applikasjonen slik at du kan " +"oppdatere dem manuelt eller foreta en komplett eksport (som en mal for et " +"nytt språk f.eks)." #. module: base #: help:multi_company.default,expression:0 @@ -7861,7 +7959,7 @@ msgstr "" #. module: base #: model:res.country,name:base.bg msgid "Bulgaria" -msgstr "" +msgstr "Bulgaria" #. module: base #: view:publisher_warranty.contract.wizard:0 @@ -7871,12 +7969,12 @@ msgstr "" #. module: base #: model:res.country,name:base.ao msgid "Angola" -msgstr "" +msgstr "Angola" #. module: base #: model:res.country,name:base.tf msgid "French Southern Territories" -msgstr "" +msgstr "Franske Sørlige Terrotorier" #. module: base #: model:ir.model,name:base.model_res_currency @@ -7886,38 +7984,38 @@ msgstr "" #: field:res.currency,name:0 #: field:res.currency.rate,currency_id:0 msgid "Currency" -msgstr "" +msgstr "Valuta" #. module: base #: field:res.partner.canal,name:0 msgid "Channel Name" -msgstr "" +msgstr "Kanalnavn" #. module: base #: view:res.lang:0 msgid "5. %y, %Y ==> 08, 2008" -msgstr "" +msgstr "5. %y, %Y ==> 08, 2008" #. module: base #: model:res.partner.title,shortcut:base.res_partner_title_ltd msgid "ltd" -msgstr "" +msgstr "AS" #. module: base #: field:ir.values,res_id:0 #: field:res.log,res_id:0 msgid "Object ID" -msgstr "" +msgstr "Objekt-ID" #. module: base #: view:res.company:0 msgid "Landscape" -msgstr "" +msgstr "Landskap/Liggende" #. module: base #: model:ir.ui.menu,name:base.menu_administration msgid "Administration" -msgstr "" +msgstr "Administrasjon" #. module: base #: view:base.module.update:0 @@ -7927,7 +8025,7 @@ msgstr "" #. module: base #: model:res.country,name:base.ir msgid "Iran" -msgstr "" +msgstr "Iran" #. module: base #: model:ir.actions.act_window,name:base.res_widget_user_act_window @@ -7945,7 +8043,7 @@ msgstr "" #: field:ir.ui.menu,icon_pict:0 #: field:publisher_warranty.contract.wizard,state:0 msgid "unknown" -msgstr "" +msgstr "ukjent" #. module: base #: field:res.currency,symbol:0 @@ -7966,17 +8064,17 @@ msgstr "" #. module: base #: field:ir.ui.view_sc,res_id:0 msgid "Resource Ref." -msgstr "" +msgstr "Ressures ref." #. module: base #: model:res.country,name:base.ki msgid "Kiribati" -msgstr "" +msgstr "Kiribati" #. module: base #: model:res.country,name:base.iq msgid "Iraq" -msgstr "" +msgstr "Irak" #. module: base #: model:ir.ui.menu,name:base.menu_association @@ -7986,7 +8084,7 @@ msgstr "" #. module: base #: model:res.country,name:base.cl msgid "Chile" -msgstr "" +msgstr "Chile" #. module: base #: model:ir.ui.menu,name:base.menu_address_book @@ -7998,17 +8096,17 @@ msgstr "" #. module: base #: model:ir.model,name:base.model_ir_sequence_type msgid "ir.sequence.type" -msgstr "" +msgstr "ir.sequence.type" #. module: base #: selection:base.language.export,format:0 msgid "CSV File" -msgstr "" +msgstr "CSV fil" #. module: base #: field:res.company,account_no:0 msgid "Account No." -msgstr "" +msgstr "Kontonummer" #. module: base #: code:addons/base/res/res_lang.py:157 @@ -8019,32 +8117,32 @@ msgstr "" #. module: base #: selection:ir.model,state:0 msgid "Base Object" -msgstr "" +msgstr "redundant objekt" #. module: base #: report:ir.module.reference.graph:0 msgid "Dependencies :" -msgstr "" +msgstr "Avhengigheter :" #. module: base #: field:ir.model.fields,field_description:0 msgid "Field Label" -msgstr "" +msgstr "Feltbetegnelse" #. module: base #: model:res.country,name:base.dj msgid "Djibouti" -msgstr "" +msgstr "Djibouti" #. module: base #: field:ir.translation,value:0 msgid "Translation Value" -msgstr "" +msgstr "Oversettelses verdi" #. module: base #: model:res.country,name:base.ag msgid "Antigua and Barbuda" -msgstr "" +msgstr "Antigua og Barbuda" #. module: base #: code:addons/orm.py:3166 @@ -8057,7 +8155,7 @@ msgstr "" #. module: base #: model:res.country,name:base.zr msgid "Zaire" -msgstr "" +msgstr "Zaire" #. module: base #: field:ir.model.data,res_id:0 @@ -8065,13 +8163,13 @@ msgstr "" #: field:workflow.instance,res_id:0 #: field:workflow.triggers,res_id:0 msgid "Resource ID" -msgstr "" +msgstr "Ressurs ID" #. module: base #: view:ir.cron:0 #: field:ir.model,info:0 msgid "Information" -msgstr "" +msgstr "Informasjon" #. module: base #: view:res.widget.user:0 @@ -8081,22 +8179,22 @@ msgstr "" #. module: base #: view:base.module.update:0 msgid "Update Module List" -msgstr "" +msgstr "Oppdater liste over moduler" #. module: base #: selection:res.partner.address,type:0 msgid "Other" -msgstr "" +msgstr "Andre" #. module: base #: view:res.request:0 msgid "Reply" -msgstr "" +msgstr "Svar" #. module: base #: selection:base.language.install,lang:0 msgid "Turkish / Türkçe" -msgstr "" +msgstr "Tyrkisk / Türkçe" #. module: base #: model:ir.actions.act_window,name:base.action_workflow_activity_form @@ -8104,12 +8202,12 @@ msgstr "" #: view:workflow:0 #: field:workflow,activities:0 msgid "Activities" -msgstr "" +msgstr "Aktiviteter" #. module: base #: field:ir.actions.act_window,auto_refresh:0 msgid "Auto-Refresh" -msgstr "" +msgstr "Oppdater automatisk" #. module: base #: code:addons/base/ir/ir_model.py:62 @@ -8151,32 +8249,32 @@ msgstr "" #: model:ir.ui.menu,name:base.next_id_6 #: view:workflow.activity:0 msgid "Actions" -msgstr "" +msgstr "Handinger" #. module: base #: selection:res.request,priority:0 msgid "High" -msgstr "" +msgstr "Høy" #. module: base #: field:ir.exports.line,export_id:0 msgid "Export" -msgstr "" +msgstr "Eksport" #. module: base #: model:res.country,name:base.hr msgid "Croatia" -msgstr "" +msgstr "Kroatia" #. module: base #: help:res.bank,bic:0 msgid "Bank Identifier Code" -msgstr "" +msgstr "Bank ID" #. module: base #: model:res.country,name:base.tm msgid "Turkmenistan" -msgstr "" +msgstr "Turkmenistan" #. module: base #: code:addons/base/ir/ir_actions.py:597 @@ -8208,17 +8306,17 @@ msgstr "" #: code:addons/orm.py:3199 #, python-format msgid "Error" -msgstr "" +msgstr "Feil" #. module: base #: model:res.country,name:base.pm msgid "Saint Pierre and Miquelon" -msgstr "" +msgstr "Saint Pierre og Miquelon" #. module: base #: help:ir.actions.report.xml,header:0 msgid "Add or not the coporate RML header" -msgstr "" +msgstr "Legg til, eller ikke RML toppteksten til selskapet" #. module: base #: help:workflow.transition,act_to:0 @@ -8229,42 +8327,42 @@ msgstr "" #: view:base.module.update:0 #: view:base.update.translations:0 msgid "Update" -msgstr "" +msgstr "Oppdater" #. module: base #: model:ir.actions.report.xml,name:base.ir_module_reference_print msgid "Technical guide" -msgstr "" +msgstr "Teknisk veiledning" #. module: base #: model:res.country,name:base.tz msgid "Tanzania" -msgstr "" +msgstr "Tanzania" #. module: base #: selection:base.language.install,lang:0 msgid "Danish / Dansk" -msgstr "" +msgstr "Dansk" #. module: base #: selection:ir.model.fields,select_level:0 msgid "Advanced Search (deprecated)" -msgstr "" +msgstr "Avansert søk" #. module: base #: model:res.country,name:base.cx msgid "Christmas Island" -msgstr "" +msgstr "Juleøyene" #. module: base #: view:ir.actions.server:0 msgid "Other Actions Configuration" -msgstr "" +msgstr "Annen handlingskonfigurasjon" #. module: base #: view:res.config.installer:0 msgid "Install Modules" -msgstr "" +msgstr "Installer moduler" #. module: base #: model:ir.actions.act_window,name:base.res_partner_canal-act @@ -8272,7 +8370,7 @@ msgstr "" #: model:ir.ui.menu,name:base.menu_res_partner_canal-act #: view:res.partner.canal:0 msgid "Channels" -msgstr "" +msgstr "Kanaler" #. module: base #: view:ir.ui.view:0 @@ -8288,7 +8386,7 @@ msgstr "" #. module: base #: view:ir.module.module:0 msgid "Schedule for Installation" -msgstr "" +msgstr "Planlegg installasjon" #. module: base #: model:ir.model,name:base.model_partner_wizard_ean_check @@ -8299,7 +8397,7 @@ msgstr "" #: sql_constraint:res.config.users:0 #: sql_constraint:res.users:0 msgid "You can not have two users with the same login !" -msgstr "" +msgstr "Du kan ikke ha to brukere med samme login !" #. module: base #: model:ir.model,name:base.model_multi_company_default @@ -8309,7 +8407,7 @@ msgstr "" #. module: base #: view:res.request:0 msgid "Send" -msgstr "" +msgstr "Send" #. module: base #: field:res.config.users,menu_tips:0 @@ -8320,22 +8418,22 @@ msgstr "" #. module: base #: field:ir.translation,src:0 msgid "Source" -msgstr "" +msgstr "Kilde" #. module: base #: help:res.partner.address,partner_id:0 msgid "Keep empty for a private address, not related to partner." -msgstr "" +msgstr "Behold blank for en private adresse ikke relatert til en partner" #. module: base #: model:res.country,name:base.vu msgid "Vanuatu" -msgstr "" +msgstr "Vanuatu" #. module: base #: view:res.company:0 msgid "Internal Header/Footer" -msgstr "" +msgstr "Intern topptekst/bunntekst" #. module: base #: code:addons/base/module/wizard/base_export_language.py:59 @@ -8344,33 +8442,35 @@ msgid "" "Save this document to a .tgz file. This archive containt UTF-8 %s files and " "may be uploaded to launchpad." msgstr "" +"Lagre dette dokumentet til en .tgz fil. Arkivet inneholder UTF-8 %s filer og " +"kan lastes opp til launchpad." #. module: base #: view:base.module.upgrade:0 msgid "Start configuration" -msgstr "" +msgstr "Start konfigurasjon" #. module: base #: view:base.language.export:0 msgid "_Export" -msgstr "" +msgstr "_Eksporter" #. module: base #: field:base.language.install,state:0 #: field:base.module.import,state:0 #: field:base.module.update,state:0 msgid "state" -msgstr "" +msgstr "status" #. module: base #: selection:base.language.install,lang:0 msgid "Catalan / Català" -msgstr "" +msgstr "Catalan / Català" #. module: base #: model:res.country,name:base.do msgid "Dominican Republic" -msgstr "" +msgstr "Den dominikanske republikk" #. module: base #: selection:base.language.install,lang:0 @@ -8388,7 +8488,7 @@ msgstr "" #. module: base #: model:res.country,name:base.sa msgid "Saudi Arabia" -msgstr "" +msgstr "Saudi Arabia" #. module: base #: help:res.partner,supplier:0 @@ -8396,11 +8496,14 @@ msgid "" "Check this box if the partner is a supplier. If it's not checked, purchase " "people will not see it when encoding a purchase order." msgstr "" +"Kryss av denne boksen dersom partneren er en leverandør. Hvis den ikke er " +"avkrysset så vil innkjøpsavdelingen ikke se den ved utarbeidelse av " +"innkjøpsordre." #. module: base #: field:ir.model.fields,relation_field:0 msgid "Relation Field" -msgstr "" +msgstr "Relasjonsfelt" #. module: base #: view:res.partner.event:0 @@ -8416,23 +8519,23 @@ msgstr "" #. module: base #: field:workflow.triggers,instance_id:0 msgid "Destination Instance" -msgstr "" +msgstr "workflow.instance" #. module: base #: field:ir.actions.act_window,multi:0 #: field:ir.actions.wizard,multi:0 msgid "Action on Multiple Doc." -msgstr "" +msgstr "Handling på flere dok." #. module: base #: view:base.language.export:0 msgid "https://translations.launchpad.net/openobject" -msgstr "" +msgstr "https://translations.launchpad.net/openobject" #. module: base #: field:ir.actions.report.xml,report_xml:0 msgid "XML path" -msgstr "" +msgstr "Sti til XML" #. module: base #: selection:ir.actions.todo,restart:0 @@ -8442,31 +8545,31 @@ msgstr "" #. module: base #: model:res.country,name:base.gn msgid "Guinea" -msgstr "" +msgstr "Guinea" #. module: base #: model:res.country,name:base.lu msgid "Luxembourg" -msgstr "" +msgstr "Luxembourg" #. module: base #: help:ir.values,key2:0 msgid "" "The kind of action or button in the client side that will trigger the action." -msgstr "" +msgstr "Type handling eller knapp på klientsiden som vil trigge handlingen." #. module: base #: code:addons/base/ir/ir_ui_menu.py:285 #, python-format msgid "Error ! You can not create recursive Menu." -msgstr "" +msgstr "Feil ! Du kan ikke lage rekursive menyer." #. module: base #: model:ir.actions.act_window,name:base.action_publisher_warranty_contract_add_wizard #: model:ir.ui.menu,name:base.menu_publisher_warranty_contract_add #: view:publisher_warranty.contract.wizard:0 msgid "Register a Contract" -msgstr "" +msgstr "Registrer en kontrakt" #. module: base #: view:ir.rule:0 @@ -8484,14 +8587,14 @@ msgstr "" #. module: base #: model:res.country,name:base.sv msgid "El Salvador" -msgstr "" +msgstr "El Salvador" #. module: base #: field:res.bank,phone:0 #: field:res.partner,phone:0 #: field:res.partner.address,phone:0 msgid "Phone" -msgstr "" +msgstr "Telefon" #. module: base #: field:ir.cron,active:0 @@ -8509,12 +8612,12 @@ msgstr "" #: view:workflow.instance:0 #: view:workflow.workitem:0 msgid "Active" -msgstr "" +msgstr "Aktiv" #. module: base #: model:res.country,name:base.th msgid "Thailand" -msgstr "" +msgstr "Thailand" #. module: base #: model:ir.ui.menu,name:base.menu_crm_config_lead @@ -8535,29 +8638,29 @@ msgstr "" #: selection:workflow.activity,join_mode:0 #: selection:workflow.activity,split_mode:0 msgid "And" -msgstr "" +msgstr "Og" #. module: base #: field:ir.model.fields,relation:0 msgid "Object Relation" -msgstr "" +msgstr "Objektrelasjon" #. module: base #: view:ir.rule:0 #: view:res.partner:0 msgid "General" -msgstr "" +msgstr "Generell" #. module: base #: model:res.country,name:base.uz msgid "Uzbekistan" -msgstr "" +msgstr "Uzbekistan" #. module: base #: model:ir.model,name:base.model_ir_actions_act_window #: selection:ir.ui.menu,action:0 msgid "ir.actions.act_window" -msgstr "" +msgstr "ir.actions.act_window" #. module: base #: field:ir.rule,perm_create:0 @@ -8567,17 +8670,17 @@ msgstr "" #. module: base #: model:res.country,name:base.vi msgid "Virgin Islands (USA)" -msgstr "" +msgstr "Jomfruøyene" #. module: base #: model:res.country,name:base.tw msgid "Taiwan" -msgstr "" +msgstr "Taiwan" #. module: base #: model:ir.model,name:base.model_res_currency_rate msgid "Currency Rate" -msgstr "" +msgstr "Valutakurs" #. module: base #: model:ir.actions.act_window,help:base.grant_menu_access @@ -8592,7 +8695,7 @@ msgstr "" #. module: base #: field:ir.ui.view,field_parent:0 msgid "Child Field" -msgstr "" +msgstr "Underordnet felt" #. module: base #: field:ir.actions.act_window,usage:0 @@ -8602,40 +8705,40 @@ msgstr "" #: field:ir.actions.server,usage:0 #: field:ir.actions.wizard,usage:0 msgid "Action Usage" -msgstr "" +msgstr "Anvendelse av handling" #. module: base #: model:ir.model,name:base.model_workflow_workitem msgid "workflow.workitem" -msgstr "" +msgstr "workflow.workitem" #. module: base #: selection:ir.module.module,state:0 msgid "Not Installable" -msgstr "" +msgstr "Ikke tilgjengelig for installasjon" #. module: base #: report:ir.module.reference.graph:0 msgid "View :" -msgstr "" +msgstr "Vis :" #. module: base #: field:ir.model.fields,view_load:0 msgid "View Auto-Load" -msgstr "" +msgstr "Modell for ikonvisning" #. module: base #: code:addons/base/ir/ir_model.py:232 #, python-format msgid "You cannot remove the field '%s' !" -msgstr "" +msgstr "Du kan ikke fjerne feltet '%s' !" #. module: base #: field:ir.exports,resource:0 #: view:ir.property:0 #: field:ir.property,res_id:0 msgid "Resource" -msgstr "" +msgstr "Ressurs" #. module: base #: field:ir.ui.menu,web_icon:0 @@ -8676,24 +8779,24 @@ msgstr "" #. module: base #: model:ir.model,name:base.model_base_module_configuration msgid "base.module.configuration" -msgstr "" +msgstr "base.module.configuration" #. module: base #: field:base.language.export,name:0 #: field:ir.attachment,datas_fname:0 msgid "Filename" -msgstr "" +msgstr "Filnavn" #. module: base #: field:ir.model,access_ids:0 #: view:ir.model.access:0 msgid "Access" -msgstr "" +msgstr "Tilgang" #. module: base #: model:res.country,name:base.sk msgid "Slovak Republic" -msgstr "" +msgstr "Slovakia" #. module: base #: model:ir.ui.menu,name:base.publisher_warranty @@ -8703,27 +8806,27 @@ msgstr "" #. module: base #: model:res.country,name:base.aw msgid "Aruba" -msgstr "" +msgstr "Aruba" #. module: base #: model:res.country,name:base.ar msgid "Argentina" -msgstr "" +msgstr "Argentina" #. module: base #: field:res.groups,name:0 msgid "Group Name" -msgstr "" +msgstr "Gruppenavn" #. module: base #: model:res.country,name:base.bh msgid "Bahrain" -msgstr "" +msgstr "Bahrain" #. module: base #: model:res.partner.category,name:base.res_partner_category_12 msgid "Segmentation" -msgstr "" +msgstr "Segmentering" #. module: base #: view:ir.attachment:0 @@ -8740,12 +8843,12 @@ msgstr "" #: view:res.users:0 #: field:res.users,company_id:0 msgid "Company" -msgstr "" +msgstr "Firma" #. module: base #: view:res.users:0 msgid "Email & Signature" -msgstr "" +msgstr "Epost & Signatur" #. module: base #: view:publisher_warranty.contract:0 @@ -8770,17 +8873,17 @@ msgstr "" #. module: base #: field:ir.actions.act_window,limit:0 msgid "Limit" -msgstr "" +msgstr "Grense" #. module: base #: help:ir.actions.server,wkf_model_id:0 msgid "Workflow to be executed on this model." -msgstr "" +msgstr "Arbeidsflyt som skal utføres på denne modellen." #. module: base #: model:res.country,name:base.jm msgid "Jamaica" -msgstr "" +msgstr "Jamaica" #. module: base #: model:ir.actions.act_window,help:base.action_partner_category_form @@ -8794,13 +8897,13 @@ msgstr "" #. module: base #: model:res.country,name:base.az msgid "Azerbaijan" -msgstr "" +msgstr "Aserbajdsjan" #. module: base #: code:addons/base/res/partner/partner.py:250 #, python-format msgid "Warning" -msgstr "" +msgstr "Advarsel" #. module: base #: selection:base.language.install,lang:0 @@ -8810,13 +8913,13 @@ msgstr "" #. module: base #: model:res.country,name:base.vg msgid "Virgin Islands (British)" -msgstr "" +msgstr "Jomfruøyene" #. module: base #: view:ir.property:0 #: model:ir.ui.menu,name:base.next_id_15 msgid "Parameters" -msgstr "" +msgstr "Parametere" #. module: base #: selection:base.language.install,lang:0 @@ -8826,7 +8929,7 @@ msgstr "" #. module: base #: view:ir.actions.server:0 msgid "Trigger Configuration" -msgstr "" +msgstr "Trigger konfigurasjon" #. module: base #: model:ir.actions.act_window,help:base.action_partner_supplier_form @@ -8840,22 +8943,22 @@ msgstr "" #. module: base #: model:res.country,name:base.rw msgid "Rwanda" -msgstr "" +msgstr "Rwanda" #. module: base #: view:ir.sequence:0 msgid "Day of the week (0:Monday): %(weekday)s" -msgstr "" +msgstr "Dag i uken (0:Mandag): %(weekday)s" #. module: base #: model:res.country,name:base.ck msgid "Cook Islands" -msgstr "" +msgstr "Cookøyene" #. module: base #: field:ir.model.data,noupdate:0 msgid "Non Updatable" -msgstr "" +msgstr "Ikke oppdaterbar" #. module: base #: selection:base.language.install,lang:0 @@ -8865,17 +8968,17 @@ msgstr "" #. module: base #: model:res.country,name:base.sg msgid "Singapore" -msgstr "" +msgstr "Singapore" #. module: base #: selection:ir.actions.act_window,target:0 msgid "Current Window" -msgstr "" +msgstr "Aktivt vindu" #. module: base #: view:ir.values:0 msgid "Action Source" -msgstr "" +msgstr "Handlingskilde" #. module: base #: view:res.config.view:0 @@ -8895,18 +8998,18 @@ msgstr "" #: field:res.partner.address,country_id:0 #: field:res.partner.bank,country_id:0 msgid "Country" -msgstr "" +msgstr "Land" #. module: base #: field:ir.model.fields,complete_name:0 #: field:ir.ui.menu,complete_name:0 msgid "Complete Name" -msgstr "" +msgstr "Fullt navn" #. module: base #: field:ir.values,object:0 msgid "Is Object" -msgstr "" +msgstr "Er objekt" #. module: base #: view:ir.rule:0 @@ -8918,7 +9021,7 @@ msgstr "" #. module: base #: field:res.partner.category,name:0 msgid "Category Name" -msgstr "" +msgstr "Kategorinavn" #. module: base #: model:res.partner.category,name:base.res_partner_category_15 @@ -8928,17 +9031,17 @@ msgstr "" #. module: base #: view:ir.actions.act_window:0 msgid "Select Groups" -msgstr "" +msgstr "Velg grupper" #. module: base #: view:res.lang:0 msgid "%X - Appropriate time representation." -msgstr "" +msgstr "%X - Hensiktsmessig tidsrepresentasjon" #. module: base #: selection:base.language.install,lang:0 msgid "Spanish (SV) / Español (SV)" -msgstr "" +msgstr "Spansk (AR) / Español (AR)" #. module: base #: help:res.lang,grouping:0 @@ -8948,11 +9051,15 @@ msgid "" "1,06,500;[1,2,-1] will represent it to be 106,50,0;[3] will represent it as " "106,500. Provided ',' as the thousand separator in each case." msgstr "" +"The Separator Format should be like [,n] where 0 < n :starting from Unit " +"digit.-1 will end the separation. e.g. [3,2,-1] will represent 106500 to be " +"1,06,500;[1,2,-1] will represent it to be 106,50,0;[3] will represent it as " +"106,500. Provided ',' as the thousand separator in each case." #. module: base #: view:res.company:0 msgid "Portrait" -msgstr "" +msgstr "Portrett/Stående" #. module: base #: code:addons/base/ir/ir_model.py:317 @@ -8963,7 +9070,7 @@ msgstr "" #. module: base #: selection:ir.translation,type:0 msgid "Wizard Button" -msgstr "" +msgstr "Veiviserknapp" #. module: base #: selection:ir.translation,type:0 @@ -8975,13 +9082,13 @@ msgstr "" #: selection:ir.ui.view,type:0 #: selection:wizard.ir.model.menu.create.line,view_type:0 msgid "Graph" -msgstr "" +msgstr "Diagram" #. module: base #: model:ir.model,name:base.model_ir_actions_server #: selection:ir.ui.menu,action:0 msgid "ir.actions.server" -msgstr "" +msgstr "ir.actions.server" #. module: base #: field:ir.actions.configuration.wizard,progress:0 @@ -8990,14 +9097,14 @@ msgstr "" #: field:res.config.users,progress:0 #: field:res.config.view,progress:0 msgid "Configuration Progress" -msgstr "" +msgstr "Konfigurasjonsprosess" #. module: base #: model:ir.actions.act_window,name:base.act_ir_actions_todo_form #: model:ir.ui.menu,name:base.menu_ir_actions_todo_form #: model:ir.ui.menu,name:base.next_id_11 msgid "Configuration Wizards" -msgstr "" +msgstr "Konfigurasjonsveileder" #. module: base #: field:res.lang,code:0 @@ -9007,22 +9114,22 @@ msgstr "" #. module: base #: field:workflow.activity,split_mode:0 msgid "Split Mode" -msgstr "" +msgstr "Split-metode" #. module: base #: view:base.module.upgrade:0 msgid "Note that this operation might take a few minutes." -msgstr "" +msgstr "Denne operasjonen kan ta noen minutter." #. module: base #: model:ir.ui.menu,name:base.menu_localisation msgid "Localisation" -msgstr "" +msgstr "Lokalisering" #. module: base #: view:ir.actions.server:0 msgid "Action to Launch" -msgstr "" +msgstr "Handling å utføre" #. module: base #: view:ir.cron:0 @@ -9033,27 +9140,28 @@ msgstr "" #: field:ir.actions.server,condition:0 #: field:workflow.transition,condition:0 msgid "Condition" -msgstr "" +msgstr "Betingelse" #. module: base #: help:ir.values,model_id:0 msgid "This field is not used, it only helps you to select a good model." msgstr "" +"Dette feltet benyttes ikke, det hjelper deg bare til å velge en god modell." #. module: base #: field:ir.ui.view,name:0 msgid "View Name" -msgstr "" +msgstr "Visningsnavn" #. module: base #: selection:base.language.install,lang:0 msgid "Italian / Italiano" -msgstr "" +msgstr "Italisensk / Italiano" #. module: base #: field:ir.actions.report.xml,attachment:0 msgid "Save As Attachment Prefix" -msgstr "" +msgstr "Save As Attachment Prefix" #. module: base #: view:ir.actions.server:0 @@ -9065,12 +9173,12 @@ msgstr "" #. module: base #: view:res.lang:0 msgid "%j - Day of the year [001,366]." -msgstr "" +msgstr "%j - Dag i året som et desimaltall [001,366]." #. module: base #: field:ir.actions.server,mobile:0 msgid "Mobile No" -msgstr "" +msgstr "Mobilnr" #. module: base #: model:ir.actions.act_window,name:base.action_partner_by_category @@ -9079,17 +9187,17 @@ msgstr "" #: model:ir.ui.menu,name:base.menu_partner_category_form #: view:res.partner.category:0 msgid "Partner Categories" -msgstr "" +msgstr "Partner kategorier" #. module: base #: view:base.module.upgrade:0 msgid "System Update" -msgstr "" +msgstr "Systemoppdatering" #. module: base #: selection:ir.translation,type:0 msgid "Wizard Field" -msgstr "" +msgstr "Veiviserfelt" #. module: base #: help:ir.sequence,prefix:0 @@ -9099,34 +9207,34 @@ msgstr "" #. module: base #: model:res.country,name:base.sc msgid "Seychelles" -msgstr "" +msgstr "Seychellene" #. module: base #: model:ir.model,name:base.model_res_partner_bank #: view:res.partner.bank:0 msgid "Bank Accounts" -msgstr "" +msgstr "Bankkonti" #. module: base #: model:res.country,name:base.sl msgid "Sierra Leone" -msgstr "" +msgstr "Sierra Leone" #. module: base #: view:res.company:0 #: view:res.partner:0 msgid "General Information" -msgstr "" +msgstr "Generell informasjon" #. module: base #: model:res.country,name:base.tc msgid "Turks and Caicos Islands" -msgstr "" +msgstr "Turks and Caicos Islands" #. module: base #: field:res.partner.bank,owner_name:0 msgid "Account Owner" -msgstr "" +msgstr "Kontoeier" #. module: base #: code:addons/base/res/res_user.py:256 @@ -9143,7 +9251,7 @@ msgstr "" #: field:workflow,osv:0 #: field:workflow.instance,res_type:0 msgid "Resource Object" -msgstr "" +msgstr "Ressursobjekt" #. module: base #: help:ir.sequence,number_increment:0 @@ -9155,54 +9263,54 @@ msgstr "" #: field:res.partner.address,function:0 #: selection:workflow.activity,kind:0 msgid "Function" -msgstr "" +msgstr "Funksjon" #. module: base #: view:res.widget:0 msgid "Search Widget" -msgstr "" +msgstr "Søke widget" #. module: base #: selection:ir.actions.todo,restart:0 msgid "Never" -msgstr "" +msgstr "Aldri" #. module: base #: selection:res.partner.address,type:0 msgid "Delivery" -msgstr "" +msgstr "Leveranse" #. module: base #: model:res.partner.title,name:base.res_partner_title_pvt_ltd #: model:res.partner.title,shortcut:base.res_partner_title_pvt_ltd msgid "Corp." -msgstr "" +msgstr "Selskap" #. module: base #: model:res.country,name:base.gw msgid "Guinea Bissau" -msgstr "" +msgstr "Guinea Bissau" #. module: base #: view:workflow.instance:0 msgid "Workflow Instances" -msgstr "" +msgstr "Arbeidsflytinstanser" #. module: base #: code:addons/base/res/partner/partner.py:261 #, python-format msgid "Partners: " -msgstr "" +msgstr "Partnere: " #. module: base #: model:res.country,name:base.kp msgid "North Korea" -msgstr "" +msgstr "Nord-Korea" #. module: base #: selection:ir.actions.server,state:0 msgid "Create Object" -msgstr "" +msgstr "Opprett Objekt" #. module: base #: view:ir.filters:0 @@ -9213,12 +9321,12 @@ msgstr "" #. module: base #: field:res.bank,bic:0 msgid "BIC/Swift code" -msgstr "" +msgstr "BIC/Swift kode" #. module: base #: model:res.partner.category,name:base.res_partner_category_1 msgid "Prospect" -msgstr "" +msgstr "Prospect" #. module: base #: selection:base.language.install,lang:0 @@ -9228,7 +9336,7 @@ msgstr "" #. module: base #: field:ir.exports,name:0 msgid "Export Name" -msgstr "" +msgstr "Eksportnavn" #. module: base #: help:res.partner.address,type:0 @@ -9236,11 +9344,13 @@ msgid "" "Used to select automatically the right address according to the context in " "sales and purchases documents." msgstr "" +"Brukes til å automatisk velge den rikitige adressen i kontekst av salgs- " +"eller innkjøpsdokumenter." #. module: base #: model:res.country,name:base.lk msgid "Sri Lanka" -msgstr "" +msgstr "Sri Lanka" #. module: base #: selection:base.language.install,lang:0 @@ -9249,3 +9359,1050 @@ msgstr "" #~ msgid "Yearly" #~ msgstr "Årlig" + +#, python-format +#~ msgid "You can not create this kind of document! (%s)" +#~ msgstr "Du kan ikke opprette denne type dokument! (%s)" + +#~ msgid "Outgoing transitions" +#~ msgstr "Utgående overganger" + +#~ msgid "" +#~ "Choose between the \"Simplified Interface\" or the extended one.\n" +#~ "If you are testing or using OpenERP for the first time, we suggest you to " +#~ "use\n" +#~ "the simplified interface, which has less options and fields but is easier " +#~ "to\n" +#~ "understand. You will be able to switch to the extended view later.\n" +#~ " " +#~ msgstr "" +#~ "Choose between the \"Simplified Interface\" or the extended one.\n" +#~ "If you are testing or using OpenERP for the first time, we suggest you to " +#~ "use\n" +#~ "the simplified interface, which has less options and fields but is easier " +#~ "to\n" +#~ "understand. You will be able to switch to the extended view later.\n" +#~ " " + +#~ msgid "Operand" +#~ msgstr "Operator" + +#~ msgid "ir.actions.report.custom" +#~ msgstr "ir.actions.report.custom" + +#~ msgid "STOCK_CANCEL" +#~ msgstr "STOCK_CANCEL" + +#~ msgid "Sorted By" +#~ msgstr "Sortert etter" + +#~ msgid "STOCK_NO" +#~ msgstr "STOCK_NO" + +#~ msgid "STOCK_GOTO_TOP" +#~ msgstr "STOCK_GOTO_TOP" + +#~ msgid "STOCK_DELETE" +#~ msgstr "STOCK_DELETE" + +#, python-format +#~ msgid "Password mismatch !" +#~ msgstr "Passord stemmer ikke!" + +#, python-format +#~ msgid "This url '%s' must provide an html file with links to zip modules" +#~ msgstr "" +#~ "Denne url '%s' må lenke til en html file med kobling videre til zip moduler" + +#~ msgid "STOCK_GOTO_FIRST" +#~ msgstr "STOCK_GOTO_FIRST" + +#~ msgid "The rule is satisfied if at least one test is True" +#~ msgstr "Denne regelen er oppfylt dersom minst en test er Sann" + +#~ msgid "Get Max" +#~ msgstr "Hent maks" + +#~ msgid "Uninstalled modules" +#~ msgstr "Ikke installerte moduler" + +#~ msgid "Configure" +#~ msgstr "Konfigurer" + +#~ msgid "STOCK_MEDIA_REWIND" +#~ msgstr "STOCK_MEDIA_REWIND" + +#~ msgid "Report Ref." +#~ msgstr "Rapportref." + +#~ msgid "STOCK_CUT" +#~ msgstr "STOCK_CUT" + +#~ msgid "Configure simple view" +#~ msgstr "Konfigurer simpel visning" + +#~ msgid "Bar Chart" +#~ msgstr "Stolpediagram" + +#~ msgid "STOCK_DIALOG_ERROR" +#~ msgstr "STOCK_DIALOG_ERROR" + +#~ msgid "STOCK_INDEX" +#~ msgstr "STOCK_INDEX" + +#~ msgid "STOCK_DIALOG_QUESTION" +#~ msgstr "STOCK_DIALOG_QUESTION" + +#~ msgid "You may have to reinstall some language pack." +#~ msgstr "Du må kanskje reinstallere enkelte språkpakker." + +#~ msgid "maintenance contract modules" +#~ msgstr "kontraktvedlikeholdsmoduler" + +#~ msgid "Factor" +#~ msgstr "Faktor" + +#~ msgid "STOCK_FILE" +#~ msgstr "STOCK_FILE" + +#~ msgid "Objects Security Grid" +#~ msgstr "Rutenett for objektsikkerhet" + +#~ msgid "STOCK_GO_DOWN" +#~ msgstr "STOCK_GO_DOWN" + +#~ msgid "STOCK_OK" +#~ msgstr "STOCK_OK" + +#~ msgid "Sequence Name" +#~ msgstr "Sekvensnavn" + +#~ msgid "Alignment" +#~ msgstr "Justering" + +#~ msgid ">=" +#~ msgstr ">=" + +#~ msgid "Planned Cost" +#~ msgstr "Planlagt kost" + +#~ msgid "ir.model.config" +#~ msgstr "ir.model.config" + +#~ msgid "Tests" +#~ msgstr "Tester" + +#~ msgid "Repository" +#~ msgstr "Oppbevaringssted" + +#~ msgid "STOCK_JUSTIFY_FILL" +#~ msgstr "STOCK_JUSTIFY_FILL" + +#~ msgid "RML" +#~ msgstr "RML" + +#~ msgid "Partners by Categories" +#~ msgstr "Partnere per kategori" + +#, python-format +#~ msgid "Pie charts need exactly two fields" +#~ msgstr "Kakediagram krever nøyaktig to felt" + +#~ msgid "Frequency" +#~ msgstr "Regelmessighet" + +#~ msgid "Relation" +#~ msgstr "Relasjon" + +#~ msgid "STOCK_MISSING_IMAGE" +#~ msgstr "STOCK_MISSING_IMAGE" + +#~ msgid "STOCK_REMOVE" +#~ msgstr "STOCK_REMOVE" + +#~ msgid "raw" +#~ msgstr "rå" + +#~ msgid "Please give your module .ZIP file to import." +#~ msgstr "Vennligst velg modul.ZIP filen å importere." + +#~ msgid "Covered Modules" +#~ msgstr "Offisielle moduler" + +#~ msgid "STOCK_COPY" +#~ msgstr "STOCK_COPY" + +#~ msgid "Check new modules" +#~ msgstr "Sjekk nye moduler" + +#~ msgid "Simple domain setup" +#~ msgstr "Simplelt domene oppsett" + +#, python-format +#~ msgid "You can not read this document! (%s)" +#~ msgstr "Du kan ikke lese dette dokumentet! (%s)" + +#~ msgid "STOCK_FIND_AND_REPLACE" +#~ msgstr "STOCK_FIND_AND_REPLACE" + +#~ msgid "Fixed Width" +#~ msgstr "Fast bredde" + +#~ msgid "terp-calendar" +#~ msgstr "terp-calendar" + +#~ msgid "STOCK_YES" +#~ msgstr "STOCK_YES" + +#~ msgid "Report Custom" +#~ msgstr "Tilpasset rapport" + +#~ msgid "STOCK_JUSTIFY_LEFT" +#~ msgstr "STOCK_JUSTIFY_LEFT" + +#~ msgid "End of Request" +#~ msgstr "Slutt på forespørsel" + +#~ msgid "Could you check your contract information ?" +#~ msgstr "Kan du sjekke kontrakt informasjonen ?" + +#~ msgid "STOCK_CLEAR" +#~ msgstr "STOCK_CLEAR" + +#~ msgid "STOCK_PROPERTIES" +#~ msgstr "STOCK_PROPERTIES" + +#~ msgid "Commercial Prospect" +#~ msgstr "Kommersiell mulighet" + +#~ msgid "STOCK_SELECT_COLOR" +#~ msgstr "STOCK_SELECT_COLOR" + +#~ msgid "ir.report.custom.fields" +#~ msgstr "ir.report.custom.fields" + +#~ msgid "STOCK_REDO" +#~ msgstr "STOCK_REDO" + +#~ msgid "Make the rule global, otherwise it needs to be put on a group" +#~ msgstr "Definer regel som global - i motsatt fall må den tilordnes en gruppe" + +#, python-format +#~ msgid "Make sure you have no users linked with the group(s)!" +#~ msgstr "Verifiser at gruppen(e) ikke inneholder noen brukere !" + +#~ msgid "Confirmation" +#~ msgstr "Bekreftelse" + +#, python-format +#~ msgid "Enter at least one field !" +#~ msgstr "Fyllt ut minimum et felt!" + +#, python-format +#~ msgid "You can not write in this document! (%s)" +#~ msgstr "Du kan ikke skrive i dette dokumentet! (%s)" + +#~ msgid "left" +#~ msgstr "venstre" + +#~ msgid "STOCK_PRINT_PREVIEW" +#~ msgstr "STOCK_PRINT_PREVIEW" + +#~ msgid "STOCK_MEDIA_PLAY" +#~ msgstr "STOCK_MEDIA_PLAY" + +#~ msgid "Operator" +#~ msgstr "Operatør" + +#~ msgid "Installation Done" +#~ msgstr "Installasjon fullført" + +#~ msgid "STOCK_OPEN" +#~ msgstr "STOCK_OPEN" + +#~ msgid "right" +#~ msgstr "høyre" + +#, python-format +#~ msgid "You can not delete this document! (%s)" +#~ msgstr "Du kan ikke slette dette dokumentet! (%s)" + +#~ msgid "Daily" +#~ msgstr "Daglig" + +#~ msgid "terp-project" +#~ msgstr "Slett prosjekt" + +#~ msgid "STOCK_JUSTIFY_CENTER" +#~ msgstr "STOCK_JUSTIFY_CENTER" + +#~ msgid "Choose Your Mode" +#~ msgstr "Velg modus" + +#~ msgid "Background Color" +#~ msgstr "Bakgrunnsfarge" + +#~ msgid "res.partner.som" +#~ msgstr "res.partner.som" + +#~ msgid "Document Link" +#~ msgstr "Dokumentlenke" + +#~ msgid "Start Upgrade" +#~ msgstr "Start oppgradering" + +#~ msgid "Export language" +#~ msgstr "Eksportér språk" + +#~ msgid "You can also import .po files." +#~ msgstr "Du kan også importere .po filer" + +#, python-format +#~ msgid "Unable to find a valid contract" +#~ msgstr "Kan ikke finne en gyldig kontrakt" + +#~ msgid "STOCK_JUSTIFY_RIGHT" +#~ msgstr "STOCK_JUSTIFY_RIGHT" + +#~ msgid "Function of the contact" +#~ msgstr "Kontaktens funksjon" + +#~ msgid "Modules to be installed, upgraded or removed" +#~ msgstr "Moduler som skal installeres, oppgraderes eller fjernes" + +#~ msgid "Report Footer" +#~ msgstr "Bunntekst på rapport" + +#~ msgid "Import language" +#~ msgstr "Importer språk" + +#~ msgid "STOCK_SAVE" +#~ msgstr "STOCK_SAVE" + +#~ msgid "terp-account" +#~ msgstr "Bankkonto" + +#~ msgid "Categories of Modules" +#~ msgstr "Modulkategorier" + +#~ msgid "Not Started" +#~ msgstr "Ikke påbegynt" + +#~ msgid "Roles" +#~ msgstr "Roller" + +#~ msgid "" +#~ "Regexp to search module on the repository webpage:\n" +#~ "- The first parenthesis must match the name of the module.\n" +#~ "- The second parenthesis must match the whole version number.\n" +#~ "- The last parenthesis must match the extension of the module." +#~ msgstr "" +#~ "Regulært uttrykk for å søke etter modulen i på websiden det sentrale " +#~ "lagringsstedet:\n" +#~ "- Den første parantesen må matche navnet på modulen.\n" +#~ "- Den andre parantesen må matche hele versjonsnummeret.\n" +#~ "- Den siste parantesen må matche filtypen til modulen," + +#~ msgid "Connect Actions To Client Events" +#~ msgstr "Koble handlinger til klient hendelser." + +#~ msgid "STOCK_QUIT" +#~ msgstr "STOCK_QUIT" + +#~ msgid "terp-purchase" +#~ msgstr "terp-purchase" + +#~ msgid "Repositories" +#~ msgstr "Oppbevaringssted" + +#~ msgid "Unvalid" +#~ msgstr "Ikke gyldig" + +#~ msgid "Children" +#~ msgstr "Underordnede" + +#~ msgid "Subscribed" +#~ msgstr "Abonnert" + +#~ msgid "Partner Address" +#~ msgstr "Adresse" + +#~ msgid "STOCK_SAVE_AS" +#~ msgstr "STOCK_SAVE_AS" + +#~ msgid "STOCK_UNDELETE" +#~ msgstr "STOCK_UNDELETE" + +#~ msgid "wizard.module.update_translations" +#~ msgstr "wizard.module.update_translations" + +#~ msgid "STOCK_PASTE" +#~ msgstr "STOCK_PASTE" + +#~ msgid "Configuration Wizard" +#~ msgstr "Konfigurasjonsveileder" + +#~ msgid "Accepted Links in Requests" +#~ msgstr "Aksepterte lenker i forespørsel" + +#~ msgid "Grant Access To Menus" +#~ msgstr "Gi tilgang til menyer" + +#~ msgid "" +#~ "Choose the simplified interface if you are testing OpenERP for the first " +#~ "time. Less used options or fields are automatically hidden. You will be able " +#~ "to change this, later, through the Administration menu." +#~ msgstr "" +#~ "Velg det forenklede grensesnittet dersom du tester OpenERP for første gang. " +#~ "Mindre brukte valg og felter blir automatisk skjult. Du kan forandre på " +#~ "dette senere gjennom Administrasjons menyen." + +#~ msgid "State of Mind" +#~ msgstr "Beslutningsfase" + +#~ msgid "The rule is satisfied if all test are True (AND)" +#~ msgstr "Regelen er oppfyllt hvis alle tester er True (AND)" + +#~ msgid "STOCK_CONNECT" +#~ msgstr "STOCK_CONNECT" + +#~ msgid "Next Call Date" +#~ msgstr "Dato for neste telefonsamtale" + +#~ msgid "Scan for new modules" +#~ msgstr "Søk etter nye moduler" + +#~ msgid "Module Repository" +#~ msgstr "Modulbrønn" + +#, python-format +#~ msgid "Using a relation field which uses an unknown object" +#~ msgstr "Benytter et relasjonsfelt som benytter et ukjent objekt" + +#~ msgid "Field child2" +#~ msgstr "Underordnet felt2" + +#~ msgid "Field child3" +#~ msgstr "Underordnet felt3" + +#~ msgid "Field child0" +#~ msgstr "Underordnet felt0" + +#~ msgid "Field child1" +#~ msgstr "Underordnet felt1" + +#~ msgid "Field Selection" +#~ msgstr "Feltutvalg" + +#~ msgid "Maintenance contract added !" +#~ msgstr "Vedlikeholdskontrakt opprettet!" + +#~ msgid "Report Xml" +#~ msgstr "XML Rapport" + +#~ msgid "Calculate Average" +#~ msgstr "Beregn gjennomsnitt" + +#~ msgid "Planned Revenue" +#~ msgstr "Planlagt omsetning" + +#~ msgid "Role" +#~ msgstr "Rolle" + +#~ msgid "Test" +#~ msgstr "Test" + +#~ msgid "STOCK_DIALOG_WARNING" +#~ msgstr "STOCK_DIALOG_WARNING" + +#~ msgid "STOCK_ZOOM_IN" +#~ msgstr "STOCK_ZOOM_IN" + +#~ msgid "STOCK_ITALIC" +#~ msgstr "STOCK_ITALIC" + +#~ msgid "Accumulate" +#~ msgstr "Akkumuler" + +#, python-format +#~ msgid "Tree can only be used in tabular reports" +#~ msgstr "Tre kan bare benyttes i tabellariske rapporter" + +#~ msgid "Font color" +#~ msgstr "Farge på skrifttype" + +#~ msgid "STOCK_SORT_DESCENDING" +#~ msgstr "STOCK_SORT_DESCENDING" + +#~ msgid "Roles Structure" +#~ msgstr "Rollestruktur" + +#~ msgid "STOCK_MEDIA_STOP" +#~ msgstr "STOCK_MEDIA_STOP" + +#~ msgid "STOCK_DND_MULTIPLE" +#~ msgstr "STOCK_DND_MULTIPLE" + +#~ msgid "STOCK_DIALOG_AUTHENTICATION" +#~ msgstr "STOCK_DIALOG_AUTHENTICATION" + +#~ msgid "STOCK_ZOOM_OUT" +#~ msgstr "STOCK_ZOOM_OUT" + +#~ msgid "terp-mrp" +#~ msgstr "terp-mrp" + +#~ msgid "Export Data" +#~ msgstr "Eksporter data" + +#~ msgid "html" +#~ msgstr "html-område" + +#~ msgid "terp-tools" +#~ msgstr "terp-tools" + +#~ msgid "STOCK_UNDO" +#~ msgstr "STOCK_UNDO" + +#~ msgid "terp-sale" +#~ msgstr "terp-sale" + +#~ msgid "STOCK_ADD" +#~ msgstr "STOCK_ADD" + +#~ msgid "Modules to download" +#~ msgstr "Moduler å laste ned" + +#~ msgid "ir.rule.group" +#~ msgstr "ir.rule.group" + +#~ msgid "Manually Created" +#~ msgstr "Manuelt opprettet" + +#~ msgid "Calculate Count" +#~ msgstr "Kalkuler telling" + +#~ msgid "Partner State of Mind" +#~ msgstr "Partner State of Mind" + +#~ msgid "STOCK_INDENT" +#~ msgstr "STOCK_INDENT" + +#~ msgid "Macedonia" +#~ msgstr "Makedonia" + +#~ msgid "a4" +#~ msgstr "a4" + +#~ msgid "Multiple rules on same objects are joined using operator OR" +#~ msgstr "Flere regler på samme objekt kobles med operatoren OR" + +#~ msgid "STOCK_MEDIA_NEXT" +#~ msgstr "STOCK_MEDIA_NEXT" + +#~ msgid "Internal Name" +#~ msgstr "Internt navn" + +#~ msgid "STOCK_EDIT" +#~ msgstr "STOCK_EDIT" + +#~ msgid "STOCK_MEDIA_FORWARD" +#~ msgstr "STOCK_MEDIA_FORWARD" + +#~ msgid "User ID" +#~ msgstr "Bruker ID" + +#~ msgid "condition" +#~ msgstr "betingelse" + +#~ msgid "STOCK_NEW" +#~ msgstr "STOCK_NEW" + +#~ msgid "Report Fields" +#~ msgstr "Rapportfelter" + +#~ msgid "STOCK_ABOUT" +#~ msgstr "STOCK_ABOUT" + +#~ msgid "STOCK_UNDERLINE" +#~ msgstr "STOCK_UNDERLINE" + +#~ msgid "STOCK_CLOSE" +#~ msgstr "STOCK_CLOSE" + +#~ msgid "STOCK_ZOOM_100" +#~ msgstr "STOCK_ZOOM_100" + +#~ msgid "STOCK_BOLD" +#~ msgstr "STOCK_BOLD" + +#~ msgid "terp-graph" +#~ msgstr "terp-graph" + +#~ msgid "Partner Events" +#~ msgstr "Hendelser" + +#~ msgid "iCal id" +#~ msgstr "iCal id" + +#~ msgid "Partner Functions" +#~ msgstr "Partner funksjoner" + +#~ msgid "Pie Chart" +#~ msgstr "Kakediagram" + +#~ msgid "Default Properties" +#~ msgstr "Standard egenskaper" + +#~ msgid "Print orientation" +#~ msgstr "Papirretning" + +#~ msgid "Full" +#~ msgstr "Full" + +#~ msgid "terp-stock" +#~ msgstr "Standard ID" + +#, python-format +#~ msgid "Please specify the Partner Email address !" +#~ msgstr "Vær vennlig å angi partnerens e-post adresse !" + +#~ msgid "STOCK_MEDIA_RECORD" +#~ msgstr "STOCK_MEDIA_RECORD" + +#~ msgid "STOCK_UNINDENT" +#~ msgstr "STOCK_UNINDENT" + +#~ msgid "Partial" +#~ msgstr "Delvis" + +#~ msgid "STOCK_DIALOG_INFO" +#~ msgstr "STOCK_DIALOG_INFO" + +#~ msgid "Get file" +#~ msgstr "Hent fil" + +#~ msgid "" +#~ "This function will check for new modules in the 'addons' path and on module " +#~ "repositories:" +#~ msgstr "" +#~ "Denne funksjonen vil lete etter nye modulen i stien 'addons' og i det " +#~ "sentrale lagringsstedet for modulene." + +#~ msgid "STOCK_GO_BACK" +#~ msgstr "STOCK_GO_BACK" + +#~ msgid "Customers Partners" +#~ msgstr "Kunder" + +#~ msgid "STOCK_SPELL_CHECK" +#~ msgstr "STOCK_SPELL_CHECK" + +#~ msgid "Roles are used to defined available actions, provided by workflows." +#~ msgstr "" +#~ "Roller blir benyttet til å tilordne tilgjengelige handlinger for " +#~ "arbeidsflyter." + +#~ msgid "STOCK_HARDDISK" +#~ msgstr "STOCK_HARDDISK" + +#~ msgid "STOCK_APPLY" +#~ msgstr "STOCK_APPLY" + +#~ msgid "Your Maintenance Contracts" +#~ msgstr "Dine vedlikeholdskontrakter" + +#~ msgid "" +#~ "Please note that you will have to logout and relog if you change your " +#~ "password." +#~ msgstr "Bemerk at du må logge ut og inn hvis du endrer passordet ditt." + +#~ msgid "STOCK_CDROM" +#~ msgstr "STOCK_CDROM" + +#~ msgid "Type of Event" +#~ msgstr "Type handling" + +#~ msgid "Set" +#~ msgstr "Justering satt" + +#~ msgid "Manual" +#~ msgstr "Manuell" + +#~ msgid "Line Plot" +#~ msgstr "Linjebryting" + +#~ msgid "STOCK_GO_UP" +#~ msgstr "STOCK_GO_UP" + +#~ msgid "pdf" +#~ msgstr "pdf" + +#~ msgid "Unsubscribed" +#~ msgstr "Avsluttede abbonement" + +#~ msgid "Preview" +#~ msgstr "Forhåndsvis" + +#~ msgid "Skip Step" +#~ msgstr "Hopp over" + +#~ msgid "Active Partner Events" +#~ msgstr "Aktive partnere hendelser" + +#~ msgid "Force Domain" +#~ msgstr "Fastsett område" + +#~ msgid "Validated" +#~ msgstr "Validert" + +#~ msgid "<>" +#~ msgstr "<>" + +#~ msgid "<=" +#~ msgstr "<=" + +#~ msgid "Probability (0.50)" +#~ msgstr "Sannsynlighet (0.50)" + +#~ msgid "Workflow Definitions" +#~ msgstr "Arbeidsflytdefinisjoner" + +#~ msgid "STOCK_MEDIA_PAUSE" +#~ msgstr "STOCK_MEDIA_PAUSE" + +#~ msgid "All Properties" +#~ msgstr "Alle egenskaper" + +#~ msgid "STOCK_HOME" +#~ msgstr "STOCK_HOME" + +#, python-format +#~ msgid "This error occurs on database %s" +#~ msgstr "Denne feilen inntreffer i database %s" + +#~ msgid "STOCK_DISCONNECT" +#~ msgstr "STOCK_DISCONNECT" + +#~ msgid "Resynchronise Terms" +#~ msgstr "Resynkroniser begrep" + +#, python-format +#~ msgid "Field %d should be a figure" +#~ msgstr "Felt %d skal være et tall" + +#~ msgid "STOCK_PREFERENCES" +#~ msgstr "STOCK_PREFERENCES" + +#~ msgid "STOCK_GOTO_LAST" +#~ msgstr "STOCK_GOTO_LAST" + +#~ msgid "Start installation" +#~ msgstr "Start installasjon" + +#~ msgid "res.company" +#~ msgstr "res.company" + +#~ msgid "Configure Simple View" +#~ msgstr "Konfigurer forenklet visning" + +#~ msgid "sxw" +#~ msgstr "sxw" + +#~ msgid "Automatic XSL:RML" +#~ msgstr "Automatisk XSL:RML" + +#~ msgid "Manual domain setup" +#~ msgstr "Manuelt oppsett av område" + +#~ msgid "Partner Relation" +#~ msgstr "Partnerrelasjon" + +#~ msgid "Monthly" +#~ msgstr "Månedlig" + +#~ msgid "States of mind" +#~ msgstr "Tilstander" + +#~ msgid "STOCK_SORT_ASCENDING" +#~ msgstr "STOCK_SORT_ASCENDING" + +#~ msgid "Parent" +#~ msgstr "Overordnet" + +#~ msgid "Export translation file" +#~ msgstr "Eksporter oversettelsesfil" + +#~ msgid "Tabular" +#~ msgstr "Tabellarisk" + +#~ msgid "Start On" +#~ msgstr "Start På" + +#~ msgid "odt" +#~ msgstr "odt" + +#~ msgid "terp-administration" +#~ msgstr "terp-administration" + +#~ msgid "All terms" +#~ msgstr "Alle begrep" + +#~ msgid "Link" +#~ msgstr "Link" + +#~ msgid "Report Ref" +#~ msgstr "Rapport ref." + +#~ msgid "terp-hr" +#~ msgstr "terp-hr" + +#~ msgid "STOCK_DND" +#~ msgstr "STOCK_DND" + +#~ msgid "Dutch (Belgium) / Nederlands (Belgïe)" +#~ msgstr "Nederlansk (Belgisk) / Nederlands (Belgïe)" + +#~ msgid "Repository list" +#~ msgstr "Liste over lagringssteder" + +#~ msgid "STOCK_FLOPPY" +#~ msgstr "STOCK_FLOPPY" + +#, python-format +#~ msgid "Your can't submit bug reports due to uncovered modules: %s" +#~ msgstr "Du kan ikke sende feilrapporter på grunn av uoffisielle moduler: %s" + +#~ msgid "Status" +#~ msgstr "Status" + +#~ msgid "ir.report.custom" +#~ msgstr "ir.report.custom" + +#~ msgid "STOCK_ZOOM_FIT" +#~ msgstr "STOCK_ZOOM_FIT" + +#~ msgid "Language file loaded." +#~ msgstr "Språkfil lastet." + +#~ msgid "Company Architecture" +#~ msgstr "Firmanavn" + +#~ msgid "STOCK_GOTO_BOTTOM" +#~ msgstr "STOCK_GOTO_BOTTOM" + +#~ msgid "STOCK_GO_FORWARD" +#~ msgstr "STOCK_GO_FORWARD" + +#~ msgid "" +#~ "Access all the fields related to the current object using expression in " +#~ "double brackets, i.e. [[ object.partner_id.name ]]" +#~ msgstr "" +#~ "Access all the fields related to the current object using expression in " +#~ "double brackets, i.e. [[ object.partner_id.name ]]" + +#~ msgid "STOCK_SELECT_FONT" +#~ msgstr "STOCK_SELECT_FONT" + +#~ msgid "<" +#~ msgstr "<" + +#~ msgid "Html from html" +#~ msgstr "Html fra html" + +#~ msgid "Workflow Items" +#~ msgstr "Arbeidsflytelementer" + +#~ msgid "Function Name" +#~ msgstr "Funksjonsnavn" + +#~ msgid "_Cancel" +#~ msgstr "_Avbryt" + +#~ msgid "terp-report" +#~ msgstr "terp-report" + +#~ msgid "" +#~ "Would your payment have been carried out after this mail was sent, please " +#~ "consider the present one as void. Do not hesitate to contact our accounting " +#~ "department" +#~ msgstr "" +#~ "Vi kan ikke se å ha mottatt innbetaling på forfalte fakturaer. Dersom dette " +#~ "ikke stemmer eller at betaling har skjedd de seneste dagne, ber vi dere " +#~ "selvsagt se bort fra denne henvendelsen." + +#~ msgid "Incoming transitions" +#~ msgstr "Inngående overganger" + +#, python-format +#~ msgid "Password empty !" +#~ msgstr "Blankt passord !" + +#~ msgid "At Once" +#~ msgstr "Med en gang" + +#~ msgid "STOCK_HELP" +#~ msgstr "STOCK_HELP" + +#~ msgid "child_of" +#~ msgstr "child_of" + +#~ msgid "Module import" +#~ msgstr "Modulimport" + +#~ msgid "Suppliers Partners" +#~ msgstr "Leverandører" + +#~ msgid "terp-crm" +#~ msgstr "terp-crm" + +#~ msgid "STOCK_STRIKETHROUGH" +#~ msgstr "STOCK_STRIKETHROUGH" + +#~ msgid "(year)=" +#~ msgstr "(year)=" + +#~ msgid "terp-partner" +#~ msgstr "terp-partner" + +#~ msgid "RML path" +#~ msgstr "Sti til RML" + +#~ msgid "Next Configuration Wizard" +#~ msgstr "Neste konfigurasjonsveileder" + +#~ msgid "Import New Language" +#~ msgstr "Importer nytt språk" + +#~ msgid "=" +#~ msgstr "=" + +#, python-format +#~ msgid "Second field should be figures" +#~ msgstr "Andre felt skal være numerisk" + +#~ msgid "Access Controls Grid" +#~ msgstr "Tilgangskontroll rutenett" + +#~ msgid "STOCK_REFRESH" +#~ msgstr "STOCK_REFRESH" + +#~ msgid "STOCK_STOP" +#~ msgstr "STOCK_STOP" + +#~ msgid "STOCK_CONVERT" +#~ msgstr "STOCK_CONVERT" + +#~ msgid "STOCK_EXECUTE" +#~ msgstr "STOCK_EXECUTE" + +#, python-format +#~ msgid "" +#~ "Model %s Does not Exist !\" % vals['relation']))\n" +#~ "\n" +#~ " if self.pool.get(vals['model']):\n" +#~ " self.pool.get(vals['model']).__init__(self.pool, cr)\n" +#~ " #Added context to _auto_init for special treatment to custom " +#~ "field for select_level\n" +#~ " ctx = context.copy()\n" +#~ " " +#~ "ctx.update({'field_name':vals['name'],'field_state':'manual','select':vals.ge" +#~ "t('select_level','0" +#~ msgstr "" +#~ "Model %s Does not Exist !\" % vals['relation']))\n" +#~ "\n" +#~ " if self.pool.get(vals['model']):\n" +#~ " self.pool.get(vals['model']).__init__(self.pool, cr)\n" +#~ " #Added context to _auto_init for special treatment to custom " +#~ "field for select_level\n" +#~ " ctx = context.copy()\n" +#~ " " +#~ "ctx.update({'field_name':vals['name'],'field_state':'manual','select':vals.ge" +#~ "t('select_level','0" + +#~ msgid "STOCK_COLOR_PICKER" +#~ msgstr "STOCK_COLOR_PICKER" + +#, python-format +#~ msgid "Bar charts need at least two fields" +#~ msgstr "Stolpediagram trenger minimum to felter" + +#~ msgid "Titles" +#~ msgstr "Titler" + +#~ msgid "" +#~ "Create your users.\n" +#~ "You will be able to assign groups to users. Groups define the access rights " +#~ "of each users on the different objects of the system.\n" +#~ " " +#~ msgstr "" +#~ "Opprett dine brukere.\n" +#~ "Du vil få mulighet til å tilordne\n" +#~ " " + +#~ msgid ">" +#~ msgstr ">" + +#~ msgid "Delete Permission" +#~ msgstr "Fjern tilgang" + +#~ msgid "STOCK_PRINT" +#~ msgstr "STOCK_PRINT" + +#~ msgid "If you don't force the domain, it will use the simple domain setup" +#~ msgstr "" +#~ "Hvis du ikke krever domenet, så vil det forenklet domeneoppsett benyttes" + +#~ msgid "Print format" +#~ msgstr "Utskriftsformat" + +#~ msgid "STOCK_JUMP_TO" +#~ msgstr "STOCK_JUMP_TO" + +#~ msgid "End Date" +#~ msgstr "Sluttdato" + +#~ msgid "Contract ID" +#~ msgstr "Kontrakt ID" + +#~ msgid "States" +#~ msgstr "Stater" + +#~ msgid "STOCK_FIND" +#~ msgstr "STOCK_FIND" + +#~ msgid "Add Maintenance Contract" +#~ msgstr "Legg til vedlikeholdskontrakt" + +#~ msgid "STOCK_MEDIA_PREVIOUS" +#~ msgstr "STOCK_MEDIA_PREVIOUS" + +#~ msgid "The VAT doesn't seem to be correct." +#~ msgstr "MVA ser ikke ut til å være riktig." + +#~ msgid "Calculate Sum" +#~ msgstr "Kalkuler sum" + +#~ msgid "STOCK_NETWORK" +#~ msgstr "STOCK_NETWORK" + +#~ msgid "Subscribe Report" +#~ msgstr "Abboner på rapport" + +#~ msgid "STOCK_DIRECTORY" +#~ msgstr "STOCK_DIRECTORY" + +#~ msgid "STOCK_REVERT_TO_SAVED" +#~ msgstr "STOCK_REVERT_TO_SAVED" + +#~ msgid "a5" +#~ msgstr "a5" + +#~ msgid "Image Preview" +#~ msgstr "Forhåndsvisning av bilde" + +#~ msgid "Unsubscribe Report" +#~ msgstr "Avslutt abbonement på rapport" + +#~ msgid "Choose a language to install:" +#~ msgstr "Velg et språk å installere" diff --git a/bin/addons/base/i18n/nl.po b/bin/addons/base/i18n/nl.po index e40c79706ce..00e24675f38 100644 --- a/bin/addons/base/i18n/nl.po +++ b/bin/addons/base/i18n/nl.po @@ -13,8 +13,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2011-02-16 04:51+0000\n" -"X-Generator: Launchpad (build 12351)\n" +"X-Launchpad-Export-Date: 2011-04-09 04:50+0000\n" +"X-Generator: Launchpad (build 12735)\n" #. module: base #: view:ir.filters:0 @@ -2905,7 +2905,7 @@ msgstr "Verplicht" #. module: base #: view:res.users:0 msgid "Default Filters" -msgstr "Stadaard filters" +msgstr "Standaard filters" #. module: base #: field:res.request.history,name:0 diff --git a/bin/addons/base/i18n/nl_BE.po b/bin/addons/base/i18n/nl_BE.po index d280272048e..6a43a00cb10 100644 --- a/bin/addons/base/i18n/nl_BE.po +++ b/bin/addons/base/i18n/nl_BE.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2011-02-16 04:58+0000\n" -"X-Generator: Launchpad (build 12351)\n" +"X-Launchpad-Export-Date: 2011-04-09 04:57+0000\n" +"X-Generator: Launchpad (build 12735)\n" #. module: base #: view:ir.filters:0 diff --git a/bin/addons/base/i18n/pl.po b/bin/addons/base/i18n/pl.po index 089aa4160ee..4ae7b3209e4 100644 --- a/bin/addons/base/i18n/pl.po +++ b/bin/addons/base/i18n/pl.po @@ -13,8 +13,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2011-02-16 04:55+0000\n" -"X-Generator: Launchpad (build 12351)\n" +"X-Launchpad-Export-Date: 2011-04-09 04:54+0000\n" +"X-Generator: Launchpad (build 12735)\n" #. module: base #: view:ir.filters:0 @@ -528,7 +528,7 @@ msgstr "Jordania" #. module: base #: view:ir.module.module:0 msgid "Certified" -msgstr "Certyfikowany" +msgstr "Certyfikowane" #. module: base #: model:res.country,name:base.er @@ -3305,7 +3305,7 @@ msgstr "Afryka Południowa" #: selection:ir.module.module,state:0 #: selection:ir.module.module.dependency,state:0 msgid "Installed" -msgstr "Zainstalowano" +msgstr "Zainstalowane" #. module: base #: selection:base.language.install,lang:0 diff --git a/bin/addons/base/i18n/pt.po b/bin/addons/base/i18n/pt.po index 8725cb11d64..516ea0a3a7b 100644 --- a/bin/addons/base/i18n/pt.po +++ b/bin/addons/base/i18n/pt.po @@ -13,8 +13,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2011-03-17 04:37+0000\n" -"X-Generator: Launchpad (build 12559)\n" +"X-Launchpad-Export-Date: 2011-04-09 04:54+0000\n" +"X-Generator: Launchpad (build 12735)\n" #. module: base #: view:ir.filters:0 diff --git a/bin/addons/base/i18n/pt_BR.po b/bin/addons/base/i18n/pt_BR.po index 59226b122be..a0e7a8e3d8c 100644 --- a/bin/addons/base/i18n/pt_BR.po +++ b/bin/addons/base/i18n/pt_BR.po @@ -13,8 +13,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2011-02-16 04:58+0000\n" -"X-Generator: Launchpad (build 12351)\n" +"X-Launchpad-Export-Date: 2011-04-09 04:57+0000\n" +"X-Generator: Launchpad (build 12735)\n" #. module: base #: view:ir.filters:0 @@ -153,6 +153,9 @@ msgid "" "Properties of base fields cannot be altered in this manner! Please modify " "them through Python code, preferably through a custom addon!" msgstr "" +"As propriedades dos campos base não podem ser alterados desta maneira! Por " +"favor, faça a modificação através de código Python e, preferencialmente, via " +"um addon customizado." #. module: base #: code:addons/osv.py:133 @@ -764,7 +767,7 @@ msgstr "Índia" #: model:ir.actions.act_window,name:base.res_request_link-act #: model:ir.ui.menu,name:base.menu_res_request_link_act msgid "Request Reference Types" -msgstr "Tipos de Solicitação de Referência" +msgstr "Tipos de Referência das Mensagens" #. module: base #: view:ir.values:0 @@ -837,7 +840,7 @@ msgstr "Painel de Recursos Humanps" #: code:addons/base/res/res_user.py:507 #, python-format msgid "Setting empty passwords is not allowed for security reasons!" -msgstr "" +msgstr "Senhas vazias não são permitidas por questões de segurança!" #. module: base #: selection:ir.actions.server,state:0 @@ -976,7 +979,7 @@ msgstr "Ilhas Marshall" #: code:addons/base/ir/ir_model.py:328 #, python-format msgid "Changing the model of a field is forbidden!" -msgstr "" +msgstr "Alteração de modelo de campo é proibido!" #. module: base #: model:res.country,name:base.ht @@ -1025,7 +1028,7 @@ msgstr "Para exportar um novo idioma, não selecione um idioma." #. module: base #: view:res.request:0 msgid "Request Date" -msgstr "Data de Requisição" +msgstr "Data da Mensagem" #. module: base #: model:ir.ui.menu,name:base.menu_hr_dasboard @@ -1349,7 +1352,7 @@ msgstr "Parceiros" #. module: base #: field:res.partner.category,parent_left:0 msgid "Left parent" -msgstr "" +msgstr "Parentese esquerdo" #. module: base #: model:ir.actions.act_window,name:base.res_widget_act_window @@ -2025,7 +2028,7 @@ msgstr "Coreâno (KR) / 한국어 (KR)" #. module: base #: help:ir.model.fields,model:0 msgid "The technical name of the model this field belongs to" -msgstr "" +msgstr "O nome técnico do modelo deste campo pertence a" #. module: base #: field:ir.actions.server,action_id:0 @@ -2183,6 +2186,9 @@ msgid "" "separated list of valid field names (optionally followed by asc/desc for the " "direction)" msgstr "" +"A ordem especificada é inválida. Uma ordem válida é uma lista de nomes de " +"campos separada por vírgula (opcionalmente seguida por ASC/DESC para " +"crescente ou descrescente)" #. module: base #: model:ir.model,name:base.model_ir_module_module_dependency @@ -2441,7 +2447,7 @@ msgstr "Email em Massa" #. module: base #: model:res.country,name:base.yt msgid "Mayotte" -msgstr "" +msgstr "Maiote" #. module: base #: code:addons/base/ir/ir_actions.py:597 @@ -2543,7 +2549,7 @@ msgstr "Rússia" #. module: base #: selection:base.language.install,lang:0 msgid "Urdu / اردو" -msgstr "" +msgstr "Urdu / اردو" #. module: base #: field:res.company,name:0 @@ -2759,7 +2765,7 @@ msgstr "6. %d, %m ==> 05, 12" #: field:res.config.users,date:0 #: field:res.users,date:0 msgid "Last Connection" -msgstr "Última conecção" +msgstr "Última Conexão" #. module: base #: field:ir.actions.act_window,help:0 @@ -3153,7 +3159,7 @@ msgstr "Workflows" #. module: base #: field:ir.translation,xml_id:0 msgid "XML Id" -msgstr "" +msgstr "Id XML" #. module: base #: model:ir.actions.act_window,name:base.action_config_user_form @@ -3384,7 +3390,7 @@ msgstr "Affero GPL-3" #. module: base #: field:ir.sequence,number_next:0 msgid "Next Number" -msgstr "Próximo numero" +msgstr "Próximo Número" #. module: base #: help:workflow.transition,condition:0 @@ -3519,6 +3525,12 @@ msgid "" "Would your payment have been carried out after this mail was sent, please " "consider the present one as void." msgstr "" +"Por favor, repare que as seguintes cobranças estão em aberto. Se o pagamento " +"já foi realizado, pedimos gentilmente que nos envie o comprovante. Se o " +"pagamento realmente estiver em aberto, entre em contato para conversarmos. " +" \n" +"Se o pagamento foi realizado após a postagem desta correspondência, favor " +"desconsiderar esta mensagem." #. module: base #: model:res.country,name:base.mx @@ -3690,6 +3702,8 @@ msgid "" "The Selection Options expression is not a valid Pythonic expression.Please " "provide an expression in the [('key','Label'), ...] format." msgstr "" +"A expressão em Opções de Seleção não é uma expressão Python válida. Favor " +"entrar com uma expressão no formato [('chave','Descrição'),...]" #. module: base #: model:ir.ui.menu,name:base.menu_translation_app @@ -3719,7 +3733,7 @@ msgstr "Inglês (GB)" #. module: base #: selection:base.language.install,lang:0 msgid "Japanese / 日本語" -msgstr "" +msgstr "Japanese / 日本語" #. module: base #: help:workflow.transition,act_from:0 @@ -3762,7 +3776,7 @@ msgstr "Inglês (CA)" #. module: base #: model:ir.model,name:base.model_publisher_warranty_contract msgid "publisher_warranty.contract" -msgstr "" +msgstr "publisher_warranty.contract" #. module: base #: model:res.country,name:base.et @@ -3849,7 +3863,7 @@ msgstr "Configuração SMS" #. module: base #: selection:base.language.install,lang:0 msgid "Spanish (BO) / Español (BO)" -msgstr "" +msgstr "Spanish (BO) / Español (BO)" #. module: base #: model:ir.actions.act_window,name:base.ir_access_act @@ -3889,7 +3903,7 @@ msgstr "Data Inicial" #. module: base #: selection:base.language.install,lang:0 msgid "Gujarati / ગુજરાતી" -msgstr "" +msgstr "Gujarati / ગુજરાતી" #. module: base #: code:addons/base/module/module.py:257 @@ -4084,7 +4098,7 @@ msgstr "Precisão do preço" #. module: base #: selection:base.language.install,lang:0 msgid "Latvian / latviešu valoda" -msgstr "" +msgstr "Latvian / latviešu valoda" #. module: base #: view:res.config:0 @@ -4189,7 +4203,7 @@ msgstr "Menus" #. module: base #: selection:base.language.install,lang:0 msgid "Serbian (Latin) / srpski" -msgstr "" +msgstr "Serbian (Latin) / srpski" #. module: base #: model:res.country,name:base.il @@ -4244,7 +4258,7 @@ msgstr "Subfluxo" #. module: base #: model:ir.model,name:base.model_res_config msgid "res.config" -msgstr "" +msgstr "res.config" #. module: base #: field:workflow.transition,signal:0 @@ -4295,7 +4309,7 @@ msgstr "Reino Unido" #: view:res.config.users:0 #: view:res.config.view:0 msgid "res_config_contents" -msgstr "" +msgstr "res_config_contents" #. module: base #: help:res.partner.category,active:0 @@ -4364,7 +4378,7 @@ msgstr "" #. module: base #: view:base.language.import:0 msgid "- module,type,name,res_id,src,value" -msgstr "" +msgstr "- módulo,tipo,nome,rec_id,src,valor" #. module: base #: selection:base.language.install,lang:0 @@ -4408,7 +4422,7 @@ msgstr "Projeto" #. module: base #: field:ir.ui.menu,web_icon_hover_data:0 msgid "Web Icon Image (hover)" -msgstr "" +msgstr "Imagem do Ícone Web (hover)" #. module: base #: view:base.module.import:0 @@ -4567,7 +4581,7 @@ msgstr "Não implementado" #. module: base #: model:ir.model,name:base.model_res_widget_user msgid "res.widget.user" -msgstr "" +msgstr "res.widget.user" #. module: base #: field:res.partner.category,complete_name:0 @@ -4975,7 +4989,7 @@ msgstr "Camarões" #. module: base #: model:res.country,name:base.bf msgid "Burkina Faso" -msgstr "" +msgstr "Burquina Fasso" #. module: base #: selection:ir.actions.todo,state:0 @@ -5080,7 +5094,7 @@ msgstr "Campo de objeto" #. module: base #: selection:base.language.install,lang:0 msgid "Spanish (PE) / Español (PE)" -msgstr "" +msgstr "Spanish (PE) / Español (PE)" #. module: base #: selection:base.language.install,lang:0 @@ -5131,7 +5145,7 @@ msgstr "Ligar eventos a ações" #. module: base #: model:ir.model,name:base.model_base_update_translations msgid "base.update.translations" -msgstr "" +msgstr "base.update.translations" #. module: base #: field:ir.module.category,parent_id:0 @@ -5442,7 +5456,7 @@ msgstr "Continuar" #. module: base #: selection:base.language.install,lang:0 msgid "Thai / ภาษาไทย" -msgstr "" +msgstr "Thai / ภาษาไทย" #. module: base #: code:addons/orm.py:158 @@ -5525,7 +5539,7 @@ msgstr "Empresa Padrão" #. module: base #: selection:base.language.install,lang:0 msgid "Spanish (EC) / Español (EC)" -msgstr "" +msgstr "Spanish (EC) / Español (EC)" #. module: base #: help:ir.ui.view,xml_id:0 @@ -5561,7 +5575,7 @@ msgstr "Selecionável" #. module: base #: view:res.request.link:0 msgid "Request Link" -msgstr "Link" +msgstr "Link da Mensagem" #. module: base #: view:ir.attachment:0 @@ -5674,7 +5688,7 @@ msgstr "Traduções" #. module: base #: field:ir.sequence,padding:0 msgid "Number padding" -msgstr "Preencher número" +msgstr "Preenchimento do número" #. module: base #: view:ir.actions.report.xml:0 @@ -5734,7 +5748,7 @@ msgstr "" #. module: base #: selection:base.language.install,lang:0 msgid "Flemish (BE) / Vlaams (BE)" -msgstr "" +msgstr "Flemish (BE) / Vlaams (BE)" #. module: base #: field:ir.cron,interval_number:0 @@ -5799,7 +5813,7 @@ msgstr "Atalhos Customizados" #. module: base #: selection:base.language.install,lang:0 msgid "Vietnamese / Tiếng Việt" -msgstr "" +msgstr "Vietnamese / Tiếng Việt" #. module: base #: model:res.country,name:base.dz @@ -5814,7 +5828,7 @@ msgstr "Bélgica" #. module: base #: model:ir.model,name:base.model_osv_memory_autovacuum msgid "osv_memory.autovacuum" -msgstr "" +msgstr "osv_memory.autovacuum" #. module: base #: field:base.language.export,lang:0 @@ -5852,7 +5866,7 @@ msgstr "%H - Hora (Relógio 24 horas) [00,23]." #. module: base #: model:ir.model,name:base.model_res_widget msgid "res.widget" -msgstr "" +msgstr "res.widget" #. module: base #: code:addons/base/ir/ir_model.py:258 @@ -5917,7 +5931,7 @@ msgstr "Zona Neutra" #. module: base #: selection:base.language.install,lang:0 msgid "Hindi / हिंदी" -msgstr "" +msgstr "Hindi / हिंदी" #. module: base #: view:ir.model:0 @@ -6122,7 +6136,7 @@ msgstr "Base" #. module: base #: selection:base.language.install,lang:0 msgid "Telugu / తెలుగు" -msgstr "" +msgstr "Telugu / తెలుగు" #. module: base #: model:res.country,name:base.lr @@ -6167,7 +6181,7 @@ msgstr "Código" #. module: base #: model:ir.model,name:base.model_res_config_installer msgid "res.config.installer" -msgstr "" +msgstr "res.config.installer" #. module: base #: model:res.country,name:base.mc @@ -6211,7 +6225,7 @@ msgstr "Códigos seqüenciais" #. module: base #: selection:base.language.install,lang:0 msgid "Spanish (CO) / Español (CO)" -msgstr "" +msgstr "Spanish (CO) / Español (CO)" #. module: base #: view:base.module.configuration:0 @@ -6231,7 +6245,7 @@ msgstr "Criar" #. module: base #: view:ir.sequence:0 msgid "Current Year with Century: %(year)s" -msgstr "" +msgstr "Ano atual (4 digitos): %(year)s" #. module: base #: field:ir.exports,export_fields:0 @@ -6392,6 +6406,8 @@ msgstr "Ilhas Pitcairn" msgid "" "We suggest to reload the menu tab to see the new menus (Ctrl+T then Ctrl+R)." msgstr "" +"Sugerimos a recarga do menu para a visualização dos novos menus (Ctrl+T, " +"depois Ctrl+R)." #. module: base #: model:ir.actions.act_window,name:base.action_rule @@ -6423,6 +6439,8 @@ msgid "" "OpenERP will automatically adds some '0' on the left of the 'Next Number' to " "get the required padding size." msgstr "" +"O OpenERP irá adicionar automaticamente alguns '0' à esquerda do 'Próximo " +"Número' para chegar ao preenchimento requerido." #. module: base #: view:res.lang:0 @@ -6442,7 +6460,7 @@ msgstr "Visão de Busca" #. module: base #: sql_constraint:res.lang:0 msgid "The code of the language must be unique !" -msgstr "" +msgstr "O código do idioma deve ser único!" #. module: base #: model:ir.actions.act_window,name:base.action_attachment @@ -6485,7 +6503,7 @@ msgstr "Acesso de gravação" #. module: base #: view:res.lang:0 msgid "%m - Month number [01,12]." -msgstr "" +msgstr "%m - Número do mês [01,12]." #. module: base #: field:res.bank,city:0 @@ -6521,7 +6539,7 @@ msgstr "Estonian / Eesti keel" #: field:res.partner,email:0 #: field:res.users,email:0 msgid "E-mail" -msgstr "" +msgstr "E-mail" #. module: base #: selection:ir.module.module,license:0 @@ -6543,7 +6561,7 @@ msgstr "Inglês (EUA)" #: view:ir.model.data:0 #: model:ir.ui.menu,name:base.ir_model_data_menu msgid "Object Identifiers" -msgstr "" +msgstr "Identificadores de Objeto" #. module: base #: model:ir.actions.act_window,help:base.action_partner_title_partner @@ -6551,11 +6569,15 @@ msgid "" "Manage the partner titles you want to have available in your system. The " "partner titles is the legal status of the company: Private Limited, SA, etc." msgstr "" +"Gerencia o nome de formação dos parceiros que você deseja que estejam " +"disponíveis no sistema. Um nome de formação é o tipo legal da empresa: " +"Limitada (Ltda), S.A., etc." #. module: base #: view:base.language.export:0 msgid "To browse official translations, you can start with these links:" msgstr "" +"Para consultar as traduções oficiais, você pode começar nestes links:" #. module: base #: code:addons/base/ir/ir_model.py:484 @@ -6564,6 +6586,8 @@ msgid "" "You can not read this document (%s) ! Be sure your user belongs to one of " "these groups: %s." msgstr "" +"Você não pode ler este documento (%s)! Certifique-se de que seu usuário " +"pertence a um destes grupos: %s." #. module: base #: view:res.bank:0 @@ -6582,7 +6606,7 @@ msgstr "Versão instalada" #. module: base #: selection:base.language.install,lang:0 msgid "Mongolian / монгол" -msgstr "" +msgstr "Mongolian / монгол" #. module: base #: model:res.country,name:base.mr @@ -6597,7 +6621,7 @@ msgstr "ir.translation" #. module: base #: view:base.module.update:0 msgid "Module update result" -msgstr "" +msgstr "Resultado da atualização de módulo" #. module: base #: view:workflow.activity:0 @@ -6619,7 +6643,7 @@ msgstr "Empresa Superior(Pai)" #. module: base #: selection:base.language.install,lang:0 msgid "Spanish (CR) / Español (CR)" -msgstr "" +msgstr "Spanish (CR) / Español (CR)" #. module: base #: field:res.currency.rate,rate:0 @@ -6644,7 +6668,7 @@ msgstr "Valor Padrão" #. module: base #: model:ir.ui.menu,name:base.menu_tools msgid "Tools" -msgstr "" +msgstr "Ferramentas" #. module: base #: model:res.country,name:base.kn @@ -6659,6 +6683,9 @@ msgid "" "for the currency: %s \n" "at the date: %s" msgstr "" +"Nenhuma taxa encontrada \n" +"para a moeda: %s \n" +"na data: %s" #. module: base #: model:ir.actions.act_window,help:base.action_ui_view_custom @@ -6666,6 +6693,8 @@ msgid "" "Customized views are used when users reorganize the content of their " "dashboard views (via web client)" msgstr "" +"Exibições personalizadas são usadas quando o usuário reorganiza o conteúdo " +"da exibição em painéis (via cliente web)" #. module: base #: field:ir.model,name:0 @@ -6703,7 +6732,7 @@ msgstr "Ícone" #. module: base #: help:ir.model.fields,model_id:0 msgid "The model this field belongs to" -msgstr "" +msgstr "O modelo pertence a este campo" #. module: base #: model:res.country,name:base.mq @@ -6713,7 +6742,7 @@ msgstr "Martinica(França)" #. module: base #: view:ir.sequence.type:0 msgid "Sequences Type" -msgstr "" +msgstr "Tipo de Sequências" #. module: base #: model:ir.actions.act_window,name:base.res_request-act @@ -6737,7 +6766,7 @@ msgstr "Ou" #: model:ir.actions.act_window,name:base.res_log_act_window #: model:ir.ui.menu,name:base.menu_res_log_act_window msgid "Client Logs" -msgstr "" +msgstr "Logs do Cliente" #. module: base #: model:res.country,name:base.al @@ -6756,6 +6785,8 @@ msgid "" "You cannot delete the language which is Active !\n" "Please de-activate the language first." msgstr "" +"Você não pode excluir um idioma que está Ativo!\n" +"Favor desativar o idioma primeiramente." #. module: base #: view:base.language.install:0 @@ -6764,6 +6795,8 @@ msgid "" "Please be patient, this operation may take a few minutes (depending on the " "number of modules currently installed)..." msgstr "" +"Por favor seja paciente. Esta operação pode demorar poucos minutos " +"(dependendo do número de módulos instalados atualmente)..." #. module: base #: field:ir.ui.menu,child_id:0 @@ -6788,12 +6821,14 @@ msgstr "ErroDeValidação" #: view:base.module.import:0 #: view:base.module.update:0 msgid "Open Modules" -msgstr "" +msgstr "Módulos Abertos" #. module: base #: model:ir.actions.act_window,help:base.action_res_bank_form msgid "Manage bank records you want to be used in the system." msgstr "" +"Gerencia os registros de bancos que você quiser que sejam usados pelo " +"sistema." #. module: base #: view:base.module.import:0 @@ -6811,6 +6846,8 @@ msgid "" "The path to the main report file (depending on Report Type) or NULL if the " "content is in another field" msgstr "" +"Caminho (diretório) para o arquivo de relatório principal (dependendo do " +"Tipo de Relatório) ou NULL se o conteúdo estiver em outro campo" #. module: base #: model:res.country,name:base.la @@ -6837,6 +6874,8 @@ msgid "" "The sum of the data (2nd field) is null.\n" "We can't draw a pie chart !" msgstr "" +"A soma dos dados (segundo campo) é nula.\n" +"Não posso montar o gráfico de pizza !" #. module: base #: model:ir.ui.menu,name:base.menu_lunch_reporting @@ -6858,7 +6897,7 @@ msgstr "Togo" #. module: base #: selection:ir.module.module,license:0 msgid "Other Proprietary" -msgstr "" +msgstr "Outro Proprietário" #. module: base #: selection:workflow.activity,kind:0 @@ -6869,12 +6908,12 @@ msgstr "Parar todos" #: code:addons/orm.py:412 #, python-format msgid "The read_group method is not implemented on this object !" -msgstr "" +msgstr "O método read_group não está implementado neste objeto!" #. module: base #: view:ir.model.data:0 msgid "Updatable" -msgstr "" +msgstr "Atualizável" #. module: base #: view:res.lang:0 @@ -6889,7 +6928,7 @@ msgstr "Cascata" #. module: base #: field:workflow.transition,group_id:0 msgid "Group Required" -msgstr "" +msgstr "O Grupo é Obrigatório" #. module: base #: view:ir.actions.configuration.wizard:0 @@ -6912,17 +6951,19 @@ msgid "" "Enable this if you want to execute missed occurences as soon as the server " "restarts." msgstr "" +"Ative isto se você quiser executar ocorrências faltantes assim que o " +"servidor reiniciar." #. module: base #: view:base.module.upgrade:0 msgid "Start update" -msgstr "" +msgstr "Iniciar atualização" #. module: base #: code:addons/base/publisher_warranty/publisher_warranty.py:144 #, python-format msgid "Contract validation error" -msgstr "" +msgstr "Erro de validação de Contrato" #. module: base #: field:res.country.state,name:0 @@ -6949,7 +6990,7 @@ msgstr "ir.actions.report.xml" #. module: base #: model:res.partner.title,shortcut:base.res_partner_title_miss msgid "Mss" -msgstr "" +msgstr "Sra" #. module: base #: model:ir.model,name:base.model_ir_ui_view @@ -6959,7 +7000,7 @@ msgstr "ir.ui.view" #. module: base #: constraint:res.partner:0 msgid "Error ! You can not create recursive associated members." -msgstr "" +msgstr "Erro ! Você não pode criar membros recursivos associados." #. module: base #: help:res.lang,code:0 @@ -6975,7 +7016,7 @@ msgstr "Parceiros OpenERP" #. module: base #: model:ir.ui.menu,name:base.menu_hr_manager msgid "HR Manager Dashboard" -msgstr "" +msgstr "Painel do Gerente de RH" #. module: base #: code:addons/base/module/module.py:253 @@ -6983,6 +7024,8 @@ msgstr "" msgid "" "Unable to install module \"%s\" because an external dependency is not met: %s" msgstr "" +"O módulo \"%s\" não pode ser instalado porque uma dependência externa não " +"foi encontrada: %s" #. module: base #: view:ir.module.module:0 @@ -7012,6 +7055,10 @@ msgid "" "not connect to the system. You can assign them groups in order to give them " "specific access to the applications they need to use in the system." msgstr "" +"Crie e gerencie os usuários que irão conectar no sistema. Usuários podem ser " +"desativados se não puderem/devessem se conectar no sistema por um período de " +"tempo. Você pode atribuir grupos para permitir acesso específico a " +"aplicações que eles precisam usar no sistema." #. module: base #: selection:res.request,priority:0 @@ -7027,13 +7074,13 @@ msgstr "Complemento" #. module: base #: model:ir.actions.act_window,name:base.action_view_base_module_update msgid "Module Update" -msgstr "" +msgstr "Atualização de Módulo" #. module: base #: code:addons/base/module/wizard/base_module_upgrade.py:95 #, python-format msgid "Following modules are not installed or unknown: %s" -msgstr "" +msgstr "Os seguintes módulos não estão instalados ou são desconhecidos: %s" #. module: base #: view:ir.cron:0 @@ -7062,7 +7109,7 @@ msgstr "Abrir Janela" #. module: base #: field:ir.actions.act_window,auto_search:0 msgid "Auto Search" -msgstr "" +msgstr "Persquisa Automática" #. module: base #: field:ir.actions.act_window,filter:0 @@ -7072,7 +7119,7 @@ msgstr "Filtro" #. module: base #: model:res.partner.title,shortcut:base.res_partner_title_madam msgid "Ms." -msgstr "" +msgstr "Sra." #. module: base #: model:res.country,name:base.ch @@ -7102,7 +7149,7 @@ msgstr "Arredondamento" #. module: base #: view:base.language.install:0 msgid "Load" -msgstr "" +msgstr "Carregar" #. module: base #: help:res.config.users,name:0 @@ -7115,18 +7162,18 @@ msgstr "" #: code:addons/osv.py:156 #, python-format msgid "Integrity Error" -msgstr "" +msgstr "Erro de Integridade" #. module: base #: model:ir.model,name:base.model_ir_wizard_screen msgid "ir.wizard.screen" -msgstr "" +msgstr "ir.wizard.screen" #. module: base #: code:addons/base/ir/ir_model.py:223 #, python-format msgid "Size of the field can never be less than 1 !" -msgstr "" +msgstr "Tamanho de campo nunca pode ser menor que 1!" #. module: base #: model:res.country,name:base.so @@ -7136,7 +7183,7 @@ msgstr "Somália" #. module: base #: selection:publisher_warranty.contract,state:0 msgid "Terminated" -msgstr "" +msgstr "Terminado" #. module: base #: model:res.partner.category,name:base.res_partner_category_13 @@ -7146,7 +7193,7 @@ msgstr "Clientes importantes" #. module: base #: view:res.lang:0 msgid "Update Terms" -msgstr "" +msgstr "Atualizar Termos" #. module: base #: field:partner.sms.send,mobile_to:0 @@ -7165,7 +7212,7 @@ msgstr "Argumentos" #: code:addons/orm.py:716 #, python-format msgid "Database ID doesn't exist: %s : %s" -msgstr "" +msgstr "ID do Banco de Dados não existe: %s : %s" #. module: base #: selection:ir.module.module,license:0 @@ -7181,18 +7228,18 @@ msgstr "GPL Versão 3" #: code:addons/orm.py:836 #, python-format msgid "key '%s' not found in selection field '%s'" -msgstr "" +msgstr "chave '%s' não encontrado no campo de seleção '%s'" #. module: base #: view:partner.wizard.ean.check:0 msgid "Correct EAN13" -msgstr "" +msgstr "EAN13 Correto" #. module: base #: code:addons/orm.py:2317 #, python-format msgid "The value \"%s\" for the field \"%s\" is not in the selection" -msgstr "" +msgstr "O valor \"%s\" para o campo \"%s\" não está na seleção" #. module: base #: field:res.partner,customer:0 @@ -7205,7 +7252,7 @@ msgstr "Cliente" #. module: base #: selection:base.language.install,lang:0 msgid "Spanish (NI) / Español (NI)" -msgstr "" +msgstr "Spanish (NI) / Español (NI)" #. module: base #: field:ir.module.module,shortdesc:0 @@ -7226,7 +7273,7 @@ msgstr "Hora 00->24: %(h24)s" #. module: base #: field:ir.cron,nextcall:0 msgid "Next Execution Date" -msgstr "" +msgstr "Próxima Data de Execução" #. module: base #: help:multi_company.default,field_id:0 @@ -7268,7 +7315,7 @@ msgstr "Tunísia" #. module: base #: model:ir.ui.menu,name:base.menu_mrp_root msgid "Manufacturing" -msgstr "" +msgstr "Manufatura" #. module: base #: model:res.country,name:base.km @@ -7290,7 +7337,7 @@ msgstr "Cancelar Instalação" #. module: base #: field:ir.model.fields,selection:0 msgid "Selection Options" -msgstr "" +msgstr "Opções de Seleção" #. module: base #: field:res.partner.category,parent_right:0 @@ -7313,6 +7360,8 @@ msgstr "Copiar Objeto" msgid "" "Group(s) cannot be deleted, because some user(s) still belong to them: %s !" msgstr "" +"O(s) grupo(s) não pode(m) ser excluído(s) porque algum usuário pertence a " +"ele(s): %s!" #. module: base #: model:ir.actions.act_window,name:base.action_country_state @@ -7367,6 +7416,9 @@ msgid "" "\n" "[object with reference: %s - %s]" msgstr "" +"\n" +"\n" +"[objeto com referência: %s - %s]" #. module: base #: model:ir.model,name:base.model_ir_default @@ -7396,6 +7448,8 @@ msgid "" "Number of time the function is called,\n" "a negative number indicates no limit" msgstr "" +"Número de vezes que a função é chamada,\n" +"um número negativo indica que não há limite" #. module: base #: code:addons/base/ir/ir_model.py:331 @@ -7404,6 +7458,8 @@ msgid "" "Changing the type of a column is not yet supported. Please drop it and " "create it again!" msgstr "" +"A alteração do tipo de uma coluna não é suportada ainda. Por favor, remova e " +"crie a coluna novamente!" #. module: base #: field:ir.ui.view_sc,user_id:0 @@ -7419,7 +7475,7 @@ msgstr "Aviso !" #. module: base #: model:res.widget,title:base.google_maps_widget msgid "Google Maps" -msgstr "" +msgstr "Google Maps" #. module: base #: model:ir.ui.menu,name:base.menu_base_config @@ -7435,7 +7491,7 @@ msgstr "Configuração" #. module: base #: model:ir.model,name:base.model_publisher_warranty_contract_wizard msgid "publisher_warranty.contract.wizard" -msgstr "" +msgstr "publisher_warranty.contract.wizard" #. module: base #: field:ir.actions.server,expression:0 @@ -7508,7 +7564,7 @@ msgstr "Estado" #. module: base #: selection:base.language.install,lang:0 msgid "Galician / Galego" -msgstr "" +msgstr "Galician / Galego" #. module: base #: model:res.country,name:base.no @@ -7529,7 +7585,7 @@ msgstr "Carregar uma tradução oficial" #. module: base #: view:res.currency:0 msgid "Miscelleanous" -msgstr "" +msgstr "Diversos" #. module: base #: model:res.partner.category,name:base.res_partner_category_10 @@ -7549,7 +7605,7 @@ msgstr "Aguardando" #. module: base #: field:ir.actions.report.xml,report_file:0 msgid "Report file" -msgstr "" +msgstr "Arquivo de relatório" #. module: base #: model:ir.model,name:base.model_workflow_triggers @@ -7560,7 +7616,7 @@ msgstr "workflow.triggers" #: code:addons/base/ir/ir_model.py:62 #, python-format msgid "Invalid search criterions" -msgstr "" +msgstr "Critério de pesquisa inválido" #. module: base #: view:ir.attachment:0 @@ -7620,13 +7676,15 @@ msgid "" "You try to install module '%s' that depends on module '%s'.\n" "But the latter module is not available in your system." msgstr "" +"Você está tentando instalar o módulo '%s' que depende do módulo '%s'.\n" +"Mas este último não está disponível no seu sistema." #. module: base #: view:base.language.import:0 #: model:ir.actions.act_window,name:base.action_view_base_import_language #: model:ir.ui.menu,name:base.menu_view_base_import_language msgid "Import Translation" -msgstr "" +msgstr "Importar Tradução" #. module: base #: field:res.partner.bank.type,field_ids:0 @@ -7644,7 +7702,7 @@ msgstr "Categoria" #: selection:ir.attachment,type:0 #: selection:ir.property,type:0 msgid "Binary" -msgstr "" +msgstr "Binário" #. module: base #: field:ir.actions.server,sms:0 @@ -7660,7 +7718,7 @@ msgstr "Costa Rica" #. module: base #: view:workflow.activity:0 msgid "Conditions" -msgstr "" +msgstr "Condições" #. module: base #: model:ir.actions.act_window,name:base.action_partner_other_form @@ -7677,7 +7735,7 @@ msgstr "Moedas" #. module: base #: sql_constraint:res.groups:0 msgid "The name of the group must be unique !" -msgstr "" +msgstr "O nome do grupo deve ser único!" #. module: base #: view:ir.sequence:0 @@ -7692,7 +7750,7 @@ msgstr "Desmarque o campo Ativo para esconder o contato." #. module: base #: model:ir.model,name:base.model_res_widget_wizard msgid "Add a widget for User" -msgstr "" +msgstr "Adiciona um widget para o Usuário" #. module: base #: model:res.country,name:base.dk @@ -7713,7 +7771,7 @@ msgstr "workflow.instance" #: code:addons/orm.py:278 #, python-format msgid "Unknown attribute %s in %s " -msgstr "" +msgstr "O atributo %s é desconhecido em %s " #. module: base #: view:res.lang:0 @@ -7724,12 +7782,12 @@ msgstr "10. %S ==> 20" #: code:addons/fields.py:106 #, python-format msgid "undefined get method !" -msgstr "" +msgstr "Método get não definido!" #. module: base #: selection:base.language.install,lang:0 msgid "Norwegian Bokmål / Norsk bokmål" -msgstr "" +msgstr "Norwegian Bokmål / Norsk bokmål" #. module: base #: help:res.config.users,new_password:0 @@ -7738,6 +7796,8 @@ msgid "" "Only specify a value if you want to change the user password. This user will " "have to logout and login again!" msgstr "" +"Especifique um conteúdo apenas se você quiser trocar a senha do usuário. " +"Este usuário precisará sair e entrar novamente!" #. module: base #: model:res.partner.title,name:base.res_partner_title_madam @@ -7752,18 +7812,18 @@ msgstr "Estônia" #. module: base #: model:ir.ui.menu,name:base.dashboard msgid "Dashboards" -msgstr "" +msgstr "Painéis" #. module: base #: help:ir.attachment,type:0 msgid "Binary File or external URL" -msgstr "" +msgstr "Arquivo Binário ou URL externa" #. module: base #: field:res.config.users,new_password:0 #: field:res.users,new_password:0 msgid "Change password" -msgstr "" +msgstr "Alterar senha" #. module: base #: model:res.country,name:base.nl @@ -7788,7 +7848,7 @@ msgstr "ir.values" #. module: base #: selection:base.language.install,lang:0 msgid "Occitan (FR, post 1500) / Occitan" -msgstr "" +msgstr "Occitan (FR, post 1500) / Occitan" #. module: base #: model:ir.actions.act_window,help:base.open_module_tree @@ -7798,12 +7858,17 @@ msgid "" "button \"Schedule for Installation\" from the form view, then click on " "\"Apply Scheduled Upgrades\" to migrate your system." msgstr "" +"Você pode instalar novos módulos para ativar novas funcionalidades, novos " +"menus, relatórios ou dados na sua instância do OpenERP. Para instalar algum " +"módulo, clique na opção \"Agendar para Instalação\" na visualização em " +"formulário, então clique em \"Aplicar Atualizações Agendadas\" para executar " +"a instalação." #. module: base #: model:ir.ui.menu,name:base.menu_emails #: model:ir.ui.menu,name:base.menu_mail_gateway msgid "Emails" -msgstr "" +msgstr "Emails" #. module: base #: model:res.country,name:base.cd @@ -7813,7 +7878,7 @@ msgstr "República Democrática do Congo" #. module: base #: selection:base.language.install,lang:0 msgid "Malayalam / മലയാളം" -msgstr "" +msgstr "Malayalam / മലയാളം" #. module: base #: view:res.request:0 @@ -7871,7 +7936,7 @@ msgstr "Croatian / hrvatski jezik" #. module: base #: field:base.language.install,overwrite:0 msgid "Overwrite Existing Terms" -msgstr "" +msgstr "Sobrescrever Termos Existentes" #. module: base #: help:ir.actions.server,code:0 @@ -7881,7 +7946,7 @@ msgstr "Código python a ser executado" #. module: base #: sql_constraint:res.country:0 msgid "The code of the country must be unique !" -msgstr "" +msgstr "O código do país deve ser único!" #. module: base #: selection:ir.module.module.dependency,state:0 @@ -7902,7 +7967,7 @@ msgstr "Gatilho" #. module: base #: model:ir.model,name:base.model_base_module_update msgid "Update Module" -msgstr "" +msgstr "Atualizar Módulo" #. module: base #: view:ir.model.fields:0 @@ -7933,6 +7998,9 @@ msgid "" "defining a list of (key, label) pairs. For example: " "[('blue','Blue'),('yellow','Yellow')]" msgstr "" +"Lista de opções para um campo de seleção, especificada em expressão Python " +"definindo uma lista de pares no formato (chave, descrição). Por exemplo: " +"[('azul','Azul'),('amarelo','Amarelo')]" #. module: base #: selection:base.language.export,state:0 @@ -7945,6 +8013,8 @@ msgid "" "Indicates whether this object model lives in memory only, i.e. is not " "persisted (osv.osv_memory)" msgstr "" +"Indica se este modelo de objeto reside apenas na memória, ou seja, não é " +"persistido (osv.osv_memory)" #. module: base #: field:res.partner,child_ids:0 @@ -7962,7 +8032,7 @@ msgstr "Fornecedores" #. module: base #: view:publisher_warranty.contract.wizard:0 msgid "Register" -msgstr "" +msgstr "Registrar" #. module: base #: field:res.request,ref_doc2:0 @@ -8023,6 +8093,9 @@ msgid "" "loading a new language it becomes available as default interface language " "for users and partners." msgstr "" +"Este assistente ajuda você a adicionar um novo idioma ao sistema OpenERP. " +"Após carregar o novo idioma, ele se torna disponível como idioma padrão da " +"interface para usuários e parceiros." #. module: base #: field:ir.actions.server,subject:0 @@ -8045,7 +8118,7 @@ msgstr "Preferências" #. module: base #: model:res.partner.category,name:base.res_partner_category_consumers0 msgid "Consumers" -msgstr "" +msgstr "Consumidores" #. module: base #: view:res.config:0 @@ -8059,6 +8132,7 @@ msgid "" "Name of the method to be called on the object when this scheduler is " "executed." msgstr "" +"Nome do método a ser chamado no objeto quando este agendamento for executado." #. module: base #: code:addons/base/ir/ir_model.py:219 @@ -8067,11 +8141,13 @@ msgid "" "The Selection Options expression is must be in the [('key','Label'), ...] " "format!" msgstr "" +"A expressão de Opções de Seleção deve estar no formato " +"[('chave','Descrição'),...]!" #. module: base #: view:ir.actions.report.xml:0 msgid "Miscellaneous" -msgstr "" +msgstr "Diversos" #. module: base #: model:res.country,name:base.cn @@ -8102,6 +8178,8 @@ msgid "" "Create and manage the companies that will be managed by OpenERP from here. " "Shops or subsidiaries can be created and maintained from here." msgstr "" +"Crie e gerencie as empresas que você quer controlar com o OpenERP aqui. " +"Lojas ou subsidiárias podem ser criadas e gerenciadas aqui também." #. module: base #: model:res.country,name:base.id @@ -8134,7 +8212,7 @@ msgstr "Bulgária" #. module: base #: view:publisher_warranty.contract.wizard:0 msgid "Publisher warranty contract successfully registered!" -msgstr "" +msgstr "O contrato de garantia do distribuidor foi registrado com sucesso!" #. module: base #: model:res.country,name:base.ao @@ -8169,7 +8247,7 @@ msgstr "5. %y, %Y ==> 08, 2008" #. module: base #: model:res.partner.title,shortcut:base.res_partner_title_ltd msgid "ltd" -msgstr "" +msgstr "ltda" #. module: base #: field:ir.values,res_id:0 @@ -8190,7 +8268,7 @@ msgstr "Administração" #. module: base #: view:base.module.update:0 msgid "Click on Update below to start the process..." -msgstr "" +msgstr "Clique no Atualizar abaixo para iniciar o processo..." #. module: base #: model:res.country,name:base.ir @@ -8201,12 +8279,12 @@ msgstr "Irã" #: model:ir.actions.act_window,name:base.res_widget_user_act_window #: model:ir.ui.menu,name:base.menu_res_widget_user_act_window msgid "Widgets per User" -msgstr "" +msgstr "Widgets por Usuário" #. module: base #: selection:base.language.install,lang:0 msgid "Slovak / Slovenský jazyk" -msgstr "" +msgstr "Slovak / Slovenský jazyk" #. module: base #: field:base.language.export,state:0 @@ -8218,18 +8296,18 @@ msgstr "desconhecido" #. module: base #: field:res.currency,symbol:0 msgid "Symbol" -msgstr "" +msgstr "Símbolo" #. module: base #: help:res.config.users,login:0 #: help:res.users,login:0 msgid "Used to log into the system" -msgstr "" +msgstr "Usado para entrar no sistema" #. module: base #: view:base.update.translations:0 msgid "Synchronize Translation" -msgstr "" +msgstr "Sincronizar Tradução" #. module: base #: field:ir.ui.view_sc,res_id:0 @@ -8249,7 +8327,7 @@ msgstr "Iraque" #. module: base #: model:ir.ui.menu,name:base.menu_association msgid "Association" -msgstr "" +msgstr "Associação" #. module: base #: model:res.country,name:base.cl @@ -8282,7 +8360,7 @@ msgstr "Conta No." #: code:addons/base/res/res_lang.py:157 #, python-format msgid "Base Language 'en_US' can not be deleted !" -msgstr "" +msgstr "O idioma base 'en_US' não pode ser excluído!" #. module: base #: selection:ir.model,state:0 @@ -8321,6 +8399,8 @@ msgid "" "Operation prohibited by access rules, or performed on an already deleted " "document (Operation: %s, Document type: %s)." msgstr "" +"Operação proibida por regras de acesso ou executada em um documento já " +"excluído (Operação: %s, Tipo de documento: %s)." #. module: base #: model:res.country,name:base.zr @@ -8344,12 +8424,12 @@ msgstr "Informação" #. module: base #: view:res.widget.user:0 msgid "User Widgets" -msgstr "" +msgstr "Widgets de Usuário" #. module: base #: view:base.module.update:0 msgid "Update Module List" -msgstr "" +msgstr "Atualizar Lista de Módulos" #. module: base #: selection:res.partner.address,type:0 @@ -8384,6 +8464,7 @@ msgstr "Auto-atualizar" #, python-format msgid "The osv_memory field can only be compared with = and != operator." msgstr "" +"O campo osv_memory pode ser comparado com os operadores = e != apenas." #. module: base #: selection:ir.ui.view,type:0 @@ -8393,24 +8474,24 @@ msgstr "Diagrama" #. module: base #: help:multi_company.default,name:0 msgid "Name it to easily find a record" -msgstr "" +msgstr "Coloque um nome para encontrar facilmente um registro" #. module: base #: model:ir.actions.act_window,name:base.grant_menu_access #: model:ir.ui.menu,name:base.menu_grant_menu_access msgid "Menu Items" -msgstr "" +msgstr "Ítens de Menu" #. module: base #: constraint:ir.rule:0 msgid "Rules are not supported for osv_memory objects !" -msgstr "" +msgstr "Regras não são suportadas em objetos osv_memory!" #. module: base #: model:ir.ui.menu,name:base.menu_event_association #: model:ir.ui.menu,name:base.menu_event_main msgid "Events Organisation" -msgstr "" +msgstr "Organização de Eventos" #. module: base #: model:ir.actions.act_window,name:base.ir_sequence_actions @@ -8512,12 +8593,12 @@ msgstr "Tanzânia" #. module: base #: selection:base.language.install,lang:0 msgid "Danish / Dansk" -msgstr "" +msgstr "Danish / Dansk" #. module: base #: selection:ir.model.fields,select_level:0 msgid "Advanced Search (deprecated)" -msgstr "" +msgstr "Pesquisa Avançada (obsoleta)" #. module: base #: model:res.country,name:base.cx @@ -8545,7 +8626,7 @@ msgstr "Canais" #. module: base #: view:ir.ui.view:0 msgid "Extra Info" -msgstr "" +msgstr "Info. Extra" #. module: base #: model:ir.actions.act_window,name:base.act_values_form_action @@ -8561,7 +8642,7 @@ msgstr "Agendar para instalação" #. module: base #: model:ir.model,name:base.model_partner_wizard_ean_check msgid "Ean Check" -msgstr "" +msgstr "Conferência de EAN" #. module: base #: sql_constraint:res.config.users:0 @@ -8583,7 +8664,7 @@ msgstr "Enviar" #: field:res.config.users,menu_tips:0 #: field:res.users,menu_tips:0 msgid "Menu Tips" -msgstr "" +msgstr "Dicas de Menu" #. module: base #: field:ir.translation,src:0 @@ -8624,14 +8705,14 @@ msgstr "Iniciar configuração" #. module: base #: view:base.language.export:0 msgid "_Export" -msgstr "" +msgstr "_Exportar" #. module: base #: field:base.language.install,state:0 #: field:base.module.import,state:0 #: field:base.module.update,state:0 msgid "state" -msgstr "" +msgstr "status" #. module: base #: selection:base.language.install,lang:0 @@ -8646,7 +8727,7 @@ msgstr "República Dominicana" #. module: base #: selection:base.language.install,lang:0 msgid "Serbian (Cyrillic) / српски" -msgstr "" +msgstr "Serbian (Cyrillic) / српски" #. module: base #: code:addons/orm.py:2161 @@ -8655,6 +8736,8 @@ msgid "" "Invalid group_by specification: \"%s\".\n" "A group_by specification must be a list of valid fields." msgstr "" +"Especificação de group_by inválida: \"%s\".\n" +"Uma definição de group_by precisa ser uma lista de campos válidos." #. module: base #: model:res.country,name:base.sa @@ -8684,7 +8767,7 @@ msgstr "Logs de Evento" #: code:addons/base/module/wizard/base_module_configuration.py:37 #, python-format msgid "System Configuration done" -msgstr "" +msgstr "Configuração do Sistema pronta" #. module: base #: field:workflow.triggers,instance_id:0 @@ -8739,7 +8822,7 @@ msgstr "Erro ! Você não pode criar menu recursivo." #: model:ir.ui.menu,name:base.menu_publisher_warranty_contract_add #: view:publisher_warranty.contract.wizard:0 msgid "Register a Contract" -msgstr "" +msgstr "Registrar um Contrato" #. module: base #: view:ir.rule:0 @@ -8755,6 +8838,8 @@ msgstr "" #, python-format msgid "Please check your publisher warranty contract name and validity." msgstr "" +"Por favor, confira o nome do seu contrato de garantia do distribuidor e a " +"validade." #. module: base #: model:res.country,name:base.sv @@ -8799,7 +8884,7 @@ msgstr "" #. module: base #: selection:base.language.install,lang:0 msgid "Romanian / română" -msgstr "" +msgstr "Romanian / română" #. module: base #: view:res.log:0 @@ -8837,7 +8922,7 @@ msgstr "ir.actions.act_window" #. module: base #: field:ir.rule,perm_create:0 msgid "Apply For Create" -msgstr "" +msgstr "Aplicar Para Criação" #. module: base #: model:res.country,name:base.vi @@ -8863,6 +8948,11 @@ msgid "" "be assigned to specific groups in order to make them accessible to some " "users within the system." msgstr "" +"Gerencie e personalize os itens disponíveis e mostrados no menu do seu " +"sistema OpenERP. Você pode excluir um item clicando no box que fica no " +"início de cada linha e depois clicar no botão que aparece. Itens podem ser " +"atribuídos a grupos específicos para que fiquem disponíveis apenas para " +"alguns usuários do sistema." #. module: base #: field:ir.ui.view,field_parent:0 @@ -8903,7 +8993,7 @@ msgstr "Auto-carregar Visão" #: code:addons/base/ir/ir_model.py:232 #, python-format msgid "You cannot remove the field '%s' !" -msgstr "" +msgstr "Você não pode remover o campo '%s'!" #. module: base #: field:ir.exports,resource:0 @@ -8915,23 +9005,23 @@ msgstr "Recurso" #. module: base #: field:ir.ui.menu,web_icon:0 msgid "Web Icon File" -msgstr "" +msgstr "Arquivo do Ícone Web" #. module: base #: selection:base.language.install,lang:0 msgid "Persian / فارس" -msgstr "" +msgstr "Persian / فارس" #. module: base #: view:ir.actions.act_window:0 msgid "View Ordering" -msgstr "" +msgstr "Ordenação da Exibição" #. module: base #: code:addons/base/module/wizard/base_module_upgrade.py:95 #, python-format msgid "Unmet dependency !" -msgstr "" +msgstr "Dependência não atendida!" #. module: base #: view:base.language.import:0 @@ -8939,6 +9029,8 @@ msgid "" "Supported file formats: *.csv (Comma-separated values) or *.po (GetText " "Portable Objects)" msgstr "" +"Formatos de arquivo suportado: *.csv (Separado por Vírgula) ou *.po (GetText " +"Portable Objects)" #. module: base #: code:addons/base/ir/ir_model.py:487 @@ -8947,11 +9039,13 @@ msgid "" "You can not delete this document (%s) ! Be sure your user belongs to one of " "these groups: %s." msgstr "" +"Você não pode excluir este documento (%s)! Certifique-se de que seu usuário " +"pertence a um destes grupos: %s." #. module: base #: model:ir.model,name:base.model_base_module_configuration msgid "base.module.configuration" -msgstr "" +msgstr "base.module.configuration" #. module: base #: field:base.language.export,name:0 @@ -8973,7 +9067,7 @@ msgstr "República da Eslováquia" #. module: base #: model:ir.ui.menu,name:base.publisher_warranty msgid "Publisher Warranty" -msgstr "" +msgstr "Garantia do Distribuidor" #. module: base #: model:res.country,name:base.aw @@ -9025,17 +9119,17 @@ msgstr "Email & Assinatura" #. module: base #: view:publisher_warranty.contract:0 msgid "Publisher Warranty Contract" -msgstr "" +msgstr "Contrato de Garantia do Distribuidor" #. module: base #: selection:base.language.install,lang:0 msgid "Bulgarian / български език" -msgstr "" +msgstr "Bulgarian / български език" #. module: base #: model:ir.ui.menu,name:base.menu_aftersale msgid "After-Sale Services" -msgstr "" +msgstr "Serviços pós-venda" #. module: base #: view:ir.actions.todo:0 @@ -9167,6 +9261,9 @@ msgid "" "simplified interface, which has less features but is easier. You can always " "switch later from the user preferences." msgstr "" +"Se você estiver usando o OpenERP pela primeira vez, recomendamos que " +"selecione a interface simplificada, que tem menos opções mas é mais fácil. " +"Você poderá sempre mudar isso nas preferências de usuário." #. module: base #: model:ir.model,name:base.model_res_country @@ -9208,7 +9305,7 @@ msgstr "Nome de Categoria" #. module: base #: model:res.partner.category,name:base.res_partner_category_15 msgid "IT sector" -msgstr "" +msgstr "Setor de TI" #. module: base #: view:ir.actions.act_window:0 @@ -9223,7 +9320,7 @@ msgstr "%X - Tempo de representação adequado." #. module: base #: selection:base.language.install,lang:0 msgid "Spanish (SV) / Español (SV)" -msgstr "" +msgstr "Spanish (SV) / Español (SV)" #. module: base #: help:res.lang,grouping:0 @@ -9248,7 +9345,7 @@ msgstr "Retrato" #: code:addons/base/ir/ir_model.py:317 #, python-format msgid "Can only rename one column at a time!" -msgstr "" +msgstr "Renomeie uma coluna de cada vez!" #. module: base #: selection:ir.translation,type:0 @@ -9258,7 +9355,7 @@ msgstr "Butão do assistente" #. module: base #: selection:ir.translation,type:0 msgid "Report/Template" -msgstr "" +msgstr "Relatório/Modelo" #. module: base #: selection:ir.actions.act_window.view,view_mode:0 @@ -9280,7 +9377,7 @@ msgstr "ir.actions.server" #: field:res.config.users,progress:0 #: field:res.config.view,progress:0 msgid "Configuration Progress" -msgstr "Progresso da configuração" +msgstr "Progresso da Configuração" #. module: base #: model:ir.actions.act_window,name:base.act_ir_actions_todo_form @@ -9302,7 +9399,7 @@ msgstr "Modo de separação" #. module: base #: view:base.module.upgrade:0 msgid "Note that this operation might take a few minutes." -msgstr "" +msgstr "Repare que esta operação pode durar alguns minutos." #. module: base #: model:ir.ui.menu,name:base.menu_localisation @@ -9317,7 +9414,7 @@ msgstr "Ação de Lançamento" #. module: base #: view:ir.cron:0 msgid "Execution" -msgstr "" +msgstr "Execução" #. module: base #: field:ir.actions.server,condition:0 @@ -9351,11 +9448,13 @@ msgid "" "Only one client action will be executed, last client action will be " "considered in case of multiple client actions." msgstr "" +"Apenas uma ação de cliente será executada. A última ação de cliente será " +"considerada em caso de múltiplas ações de cliente." #. module: base #: view:res.lang:0 msgid "%j - Day of the year [001,366]." -msgstr "" +msgstr "%j - Dia do ano [001-366]." #. module: base #: field:ir.actions.server,mobile:0 @@ -9374,7 +9473,7 @@ msgstr "Categorias de Parceiros" #. module: base #: view:base.module.upgrade:0 msgid "System Update" -msgstr "" +msgstr "Atualização do Sistema" #. module: base #: selection:ir.translation,type:0 @@ -9384,7 +9483,7 @@ msgstr "Campo do Assistente" #. module: base #: help:ir.sequence,prefix:0 msgid "Prefix value of the record for the sequence" -msgstr "" +msgstr "Prefixo de registro para a sequência" #. module: base #: model:res.country,name:base.sc @@ -9422,12 +9521,12 @@ msgstr "Titular da Conta" #: code:addons/base/res/res_user.py:256 #, python-format msgid "Company Switch Warning" -msgstr "" +msgstr "Aviso de Mudança de Empresa" #. module: base #: model:ir.actions.act_window,name:base.action_res_widget_wizard msgid "Homepage Widgets Management" -msgstr "" +msgstr "Homepage para Gerenciamento de Widgets" #. module: base #: field:workflow,osv:0 @@ -9438,7 +9537,7 @@ msgstr "Recurso do objeto" #. module: base #: help:ir.sequence,number_increment:0 msgid "The next number of the sequence will be incremented by this number" -msgstr "" +msgstr "O próximo número da sequência será incrementada com este número" #. module: base #: field:ir.cron,function:0 @@ -9450,7 +9549,7 @@ msgstr "Função" #. module: base #: view:res.widget:0 msgid "Search Widget" -msgstr "" +msgstr "Pesquisar Widget" #. module: base #: selection:ir.actions.todo,restart:0 diff --git a/bin/addons/base/i18n/ro.po b/bin/addons/base/i18n/ro.po index eaa521b990c..c4573a3822b 100644 --- a/bin/addons/base/i18n/ro.po +++ b/bin/addons/base/i18n/ro.po @@ -13,8 +13,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2011-03-25 04:39+0000\n" -"X-Generator: Launchpad (build 12559)\n" +"X-Launchpad-Export-Date: 2011-04-09 04:54+0000\n" +"X-Generator: Launchpad (build 12735)\n" #. module: base #: view:ir.filters:0 @@ -47,6 +47,8 @@ msgid "" "The second argument of the many2many field %s must be a SQL table !You used " "%s, which is not a valid SQL table name." msgstr "" +"Al doilea parametru a câmpului many2many %s trebuie să fie o tabelă SQL ! %s " +"utilizat nu este o tabelă SQL validă." #. module: base #: view:ir.values:0 @@ -117,6 +119,8 @@ msgid "" "You can not write in this document (%s) ! Be sure your user belongs to one " "of these groups: %s." msgstr "" +"Nu puteți scrie în acest document (%s) ! Asigurați-vă că utilizatorul " +"aparține grupului: %s." #. module: base #: help:ir.model.fields,domain:0 @@ -125,6 +129,8 @@ msgid "" "specified as a Python expression defining a list of triplets. For example: " "[('color','=','red')]" msgstr "" +"Domeniu opțional pentru a restricționa valorile pentru câmpul de relație, " +"specificat ca o listă Python. De exemplu: [('color','=','red')]" #. module: base #: field:res.partner,ref:0 @@ -437,7 +443,7 @@ msgstr "Planificare actualizare" #: code:addons/orm.py:838 #, python-format msgid "Key/value '%s' not found in selection field '%s'" -msgstr "" +msgstr "Cheia/valoarea '%s' nu este găsită în selecția câmpului '%s'" #. module: base #: help:res.country,code:0 @@ -784,7 +790,7 @@ msgstr "Categorii subordonate" #. module: base #: model:ir.model,name:base.model_ir_config_parameter msgid "ir.config_parameter" -msgstr "" +msgstr "ir.config_parameter" #. module: base #: selection:base.language.export,format:0 @@ -868,7 +874,7 @@ msgstr "Tranzitii" #: code:addons/orm.py:4020 #, python-format msgid "Record #%d of %s not found, cannot copy!" -msgstr "" +msgstr "Înregistrarea #%d a %s negăsită, nu se poate face copia!" #. module: base #: field:ir.module.module,contributors:0 @@ -2151,7 +2157,7 @@ msgstr "" #. module: base #: model:ir.model,name:base.model_ir_module_module_dependency msgid "Module dependency" -msgstr "Dependinţele modulului" +msgstr "Dependenţele modulului" #. module: base #: selection:publisher_warranty.contract.wizard,state:0 @@ -2194,7 +2200,7 @@ msgstr "Controale de acces" #: view:ir.module.module:0 #: field:ir.module.module,dependencies_id:0 msgid "Dependencies" -msgstr "Dependinţe" +msgstr "Dependențe" #. module: base #: field:multi_company.default,company_id:0 diff --git a/bin/addons/base/i18n/ru.po b/bin/addons/base/i18n/ru.po index b31a7c3ebb6..48d62b57ca6 100644 --- a/bin/addons/base/i18n/ru.po +++ b/bin/addons/base/i18n/ru.po @@ -13,8 +13,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2011-03-10 04:44+0000\n" -"X-Generator: Launchpad (build 12351)\n" +"X-Launchpad-Export-Date: 2011-04-09 04:55+0000\n" +"X-Generator: Launchpad (build 12735)\n" #. module: base #: view:ir.filters:0 @@ -1655,7 +1655,7 @@ msgstr "Для удаления" #. module: base #: model:ir.model,name:base.model_ir_sequence msgid "ir.sequence" -msgstr "Последовательность" +msgstr "ir.sequence" #. module: base #: help:ir.actions.server,expression:0 diff --git a/bin/addons/base/i18n/sk.po b/bin/addons/base/i18n/sk.po index b3a4fed2510..947f18ea4d3 100644 --- a/bin/addons/base/i18n/sk.po +++ b/bin/addons/base/i18n/sk.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2011-02-16 04:56+0000\n" -"X-Generator: Launchpad (build 12351)\n" +"X-Launchpad-Export-Date: 2011-04-09 04:55+0000\n" +"X-Generator: Launchpad (build 12735)\n" #. module: base #: view:ir.filters:0 diff --git a/bin/addons/base/i18n/sl.po b/bin/addons/base/i18n/sl.po index c47b6e51de7..b90532f954b 100644 --- a/bin/addons/base/i18n/sl.po +++ b/bin/addons/base/i18n/sl.po @@ -13,8 +13,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2011-02-16 04:56+0000\n" -"X-Generator: Launchpad (build 12351)\n" +"X-Launchpad-Export-Date: 2011-04-09 04:55+0000\n" +"X-Generator: Launchpad (build 12735)\n" #. module: base #: view:ir.filters:0 diff --git a/bin/addons/base/i18n/sq.po b/bin/addons/base/i18n/sq.po index 2204d6ec1c7..5163adbf424 100644 --- a/bin/addons/base/i18n/sq.po +++ b/bin/addons/base/i18n/sq.po @@ -13,8 +13,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2011-02-16 04:49+0000\n" -"X-Generator: Launchpad (build 12351)\n" +"X-Launchpad-Export-Date: 2011-04-09 04:49+0000\n" +"X-Generator: Launchpad (build 12735)\n" #. module: base #: view:ir.filters:0 diff --git a/bin/addons/base/i18n/sr.po b/bin/addons/base/i18n/sr.po index 363801d83d3..892fa6f8f8c 100644 --- a/bin/addons/base/i18n/sr.po +++ b/bin/addons/base/i18n/sr.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2011-02-16 04:55+0000\n" -"X-Generator: Launchpad (build 12351)\n" +"X-Launchpad-Export-Date: 2011-04-09 04:55+0000\n" +"X-Generator: Launchpad (build 12735)\n" #. module: base #: view:ir.filters:0 diff --git a/bin/addons/base/i18n/sr@latin.po b/bin/addons/base/i18n/sr@latin.po index 57fa91e9750..3b9f7fb9118 100644 --- a/bin/addons/base/i18n/sr@latin.po +++ b/bin/addons/base/i18n/sr@latin.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2011-02-16 04:59+0000\n" -"X-Generator: Launchpad (build 12351)\n" +"X-Launchpad-Export-Date: 2011-04-09 04:58+0000\n" +"X-Generator: Launchpad (build 12735)\n" #. module: base #: view:ir.filters:0 diff --git a/bin/addons/base/i18n/sv.po b/bin/addons/base/i18n/sv.po index e27ec11c80c..40170e9079d 100644 --- a/bin/addons/base/i18n/sv.po +++ b/bin/addons/base/i18n/sv.po @@ -13,8 +13,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2011-02-16 04:56+0000\n" -"X-Generator: Launchpad (build 12351)\n" +"X-Launchpad-Export-Date: 2011-04-09 04:56+0000\n" +"X-Generator: Launchpad (build 12735)\n" #. module: base #: view:ir.filters:0 diff --git a/bin/addons/base/i18n/th.po b/bin/addons/base/i18n/th.po index 81a8b413bb8..8a477dd3aff 100644 --- a/bin/addons/base/i18n/th.po +++ b/bin/addons/base/i18n/th.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2011-02-16 04:57+0000\n" -"X-Generator: Launchpad (build 12351)\n" +"X-Launchpad-Export-Date: 2011-04-09 04:56+0000\n" +"X-Generator: Launchpad (build 12735)\n" #. module: base #: view:ir.filters:0 diff --git a/bin/addons/base/i18n/tlh.po b/bin/addons/base/i18n/tlh.po index f980ef5c33c..94ce3d0d2a2 100644 --- a/bin/addons/base/i18n/tlh.po +++ b/bin/addons/base/i18n/tlh.po @@ -13,8 +13,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2011-02-16 04:57+0000\n" -"X-Generator: Launchpad (build 12351)\n" +"X-Launchpad-Export-Date: 2011-04-09 04:56+0000\n" +"X-Generator: Launchpad (build 12735)\n" #. module: base #: view:ir.filters:0 diff --git a/bin/addons/base/i18n/tr.po b/bin/addons/base/i18n/tr.po index 00f56cd972a..d2966e4cf56 100644 --- a/bin/addons/base/i18n/tr.po +++ b/bin/addons/base/i18n/tr.po @@ -13,8 +13,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2011-02-16 04:57+0000\n" -"X-Generator: Launchpad (build 12351)\n" +"X-Launchpad-Export-Date: 2011-04-09 04:56+0000\n" +"X-Generator: Launchpad (build 12735)\n" #. module: base #: view:ir.filters:0 diff --git a/bin/addons/base/i18n/uk.po b/bin/addons/base/i18n/uk.po index 21228faf03a..2c8dc3201e2 100644 --- a/bin/addons/base/i18n/uk.po +++ b/bin/addons/base/i18n/uk.po @@ -13,8 +13,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2011-02-16 04:57+0000\n" -"X-Generator: Launchpad (build 12351)\n" +"X-Launchpad-Export-Date: 2011-04-09 04:56+0000\n" +"X-Generator: Launchpad (build 12735)\n" #. module: base #: view:ir.filters:0 diff --git a/bin/addons/base/i18n/ur.po b/bin/addons/base/i18n/ur.po index e17e43cac57..265444a22c9 100644 --- a/bin/addons/base/i18n/ur.po +++ b/bin/addons/base/i18n/ur.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2011-02-16 04:57+0000\n" -"X-Generator: Launchpad (build 12351)\n" +"X-Launchpad-Export-Date: 2011-04-09 04:56+0000\n" +"X-Generator: Launchpad (build 12735)\n" #. module: base #: view:ir.filters:0 diff --git a/bin/addons/base/i18n/vi.po b/bin/addons/base/i18n/vi.po index 1f3f9a8fb85..a1a0f9c96c5 100644 --- a/bin/addons/base/i18n/vi.po +++ b/bin/addons/base/i18n/vi.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2011-02-16 04:57+0000\n" -"X-Generator: Launchpad (build 12351)\n" +"X-Launchpad-Export-Date: 2011-04-09 04:57+0000\n" +"X-Generator: Launchpad (build 12735)\n" #. module: base #: view:ir.filters:0 @@ -141,7 +141,7 @@ msgstr "Cửa sổ đích" #: code:addons/base/res/res_user.py:507 #, python-format msgid "Warning!" -msgstr "" +msgstr "Cảnh báo!" #. module: base #: code:addons/base/ir/ir_model.py:304 @@ -268,7 +268,7 @@ msgstr "có hiệu lực" #. module: base #: field:ir.actions.wizard,wiz_name:0 msgid "Wizard Name" -msgstr "" +msgstr "Tên Trình hướng dẫn" #. module: base #: code:addons/orm.py:2160 @@ -299,7 +299,7 @@ msgstr "Đối tượng Nguồn" #. module: base #: view:ir.actions.todo:0 msgid "Config Wizard Steps" -msgstr "" +msgstr "Các bước của Trình hướng dẫn Cấu hình" #. module: base #: model:ir.model,name:base.model_ir_ui_view_sc @@ -381,7 +381,7 @@ msgstr "Tiếng Hy Lạp" #. module: base #: selection:base.language.install,lang:0 msgid "Bosnian / bosanski jezik" -msgstr "" +msgstr "Tiếng Bosnia" #. module: base #: help:ir.actions.report.xml,attachment_use:0 @@ -494,7 +494,7 @@ msgstr "Người dùng mới" #. module: base #: view:base.language.export:0 msgid "Export done" -msgstr "" +msgstr "Trích xuất hoàn tất" #. module: base #: view:ir.model:0 @@ -615,7 +615,7 @@ msgstr "" #. module: base #: model:ir.ui.menu,name:base.menu_crm_config_opportunity msgid "Opportunities" -msgstr "" +msgstr "Các cơ hội" #. module: base #: model:ir.model,name:base.model_base_language_export diff --git a/bin/addons/base/i18n/zh_CN.po b/bin/addons/base/i18n/zh_CN.po index 4d14cf24207..e2a22c6c33b 100644 --- a/bin/addons/base/i18n/zh_CN.po +++ b/bin/addons/base/i18n/zh_CN.po @@ -13,8 +13,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2011-02-16 04:59+0000\n" -"X-Generator: Launchpad (build 12351)\n" +"X-Launchpad-Export-Date: 2011-04-09 04:58+0000\n" +"X-Generator: Launchpad (build 12735)\n" #. module: base #: view:ir.filters:0 diff --git a/bin/addons/base/i18n/zh_TW.po b/bin/addons/base/i18n/zh_TW.po index 5ad3c4f7145..c947f2027cb 100644 --- a/bin/addons/base/i18n/zh_TW.po +++ b/bin/addons/base/i18n/zh_TW.po @@ -13,8 +13,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2011-02-16 04:58+0000\n" -"X-Generator: Launchpad (build 12351)\n" +"X-Launchpad-Export-Date: 2011-04-09 04:58+0000\n" +"X-Generator: Launchpad (build 12735)\n" #. module: base #: view:ir.filters:0 diff --git a/debian/po/bg.po b/debian/po/bg.po index 31dca8470b1..4114098bf1f 100644 --- a/debian/po/bg.po +++ b/debian/po/bg.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2011-02-16 04:59+0000\n" -"X-Generator: Launchpad (build 12351)\n" +"X-Launchpad-Export-Date: 2011-04-09 04:58+0000\n" +"X-Generator: Launchpad (build 12735)\n" #. Type: string #. Description diff --git a/debian/po/ca.po b/debian/po/ca.po index 46b36a52944..d6620325be2 100644 --- a/debian/po/ca.po +++ b/debian/po/ca.po @@ -15,8 +15,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2011-02-16 04:59+0000\n" -"X-Generator: Launchpad (build 12351)\n" +"X-Launchpad-Export-Date: 2011-04-09 04:58+0000\n" +"X-Generator: Launchpad (build 12735)\n" #. Type: string #. Description diff --git a/debian/po/cs.po b/debian/po/cs.po index 05e61f1eec0..828da50ac8c 100644 --- a/debian/po/cs.po +++ b/debian/po/cs.po @@ -13,8 +13,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2011-02-16 04:59+0000\n" -"X-Generator: Launchpad (build 12351)\n" +"X-Launchpad-Export-Date: 2011-04-09 04:59+0000\n" +"X-Generator: Launchpad (build 12735)\n" #. Type: string #. Description diff --git a/debian/po/de.po b/debian/po/de.po index 8692ca59226..0913e1f9390 100644 --- a/debian/po/de.po +++ b/debian/po/de.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2011-02-16 04:59+0000\n" -"X-Generator: Launchpad (build 12351)\n" +"X-Launchpad-Export-Date: 2011-04-09 04:59+0000\n" +"X-Generator: Launchpad (build 12735)\n" #. Type: string #. Description diff --git a/debian/po/el.po b/debian/po/el.po index c49fc00b5d4..cf0a0ce7d49 100644 --- a/debian/po/el.po +++ b/debian/po/el.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2011-02-16 04:59+0000\n" -"X-Generator: Launchpad (build 12351)\n" +"X-Launchpad-Export-Date: 2011-04-09 04:59+0000\n" +"X-Generator: Launchpad (build 12735)\n" #. Type: string #. Description diff --git a/debian/po/en_GB.po b/debian/po/en_GB.po index da69df4666f..d18900928f6 100644 --- a/debian/po/en_GB.po +++ b/debian/po/en_GB.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2011-02-16 05:00+0000\n" -"X-Generator: Launchpad (build 12351)\n" +"X-Launchpad-Export-Date: 2011-04-09 04:59+0000\n" +"X-Generator: Launchpad (build 12735)\n" #. Type: string #. Description diff --git a/debian/po/es.po b/debian/po/es.po index 9c90f89530f..a2b756e0b56 100644 --- a/debian/po/es.po +++ b/debian/po/es.po @@ -15,8 +15,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2011-02-16 05:00+0000\n" -"X-Generator: Launchpad (build 12351)\n" +"X-Launchpad-Export-Date: 2011-04-09 04:59+0000\n" +"X-Generator: Launchpad (build 12735)\n" #. Type: string #. Description diff --git a/debian/po/es_CL.po b/debian/po/es_CL.po index 6f341a4db4d..534d217c24c 100644 --- a/debian/po/es_CL.po +++ b/debian/po/es_CL.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2011-02-16 05:00+0000\n" -"X-Generator: Launchpad (build 12351)\n" +"X-Launchpad-Export-Date: 2011-04-09 04:59+0000\n" +"X-Generator: Launchpad (build 12735)\n" #. Type: string #. Description diff --git a/debian/po/es_EC.po b/debian/po/es_EC.po index e3e5f08debc..56a5a0679e4 100644 --- a/debian/po/es_EC.po +++ b/debian/po/es_EC.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2011-02-16 05:00+0000\n" -"X-Generator: Launchpad (build 12351)\n" +"X-Launchpad-Export-Date: 2011-04-09 04:59+0000\n" +"X-Generator: Launchpad (build 12735)\n" #. Type: string #. Description diff --git a/debian/po/fa.po b/debian/po/fa.po index 586d23831c1..71e215d85a1 100644 --- a/debian/po/fa.po +++ b/debian/po/fa.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2011-02-16 04:59+0000\n" -"X-Generator: Launchpad (build 12351)\n" +"X-Launchpad-Export-Date: 2011-04-09 04:59+0000\n" +"X-Generator: Launchpad (build 12735)\n" #. Type: string #. Description diff --git a/debian/po/fi.po b/debian/po/fi.po index a7bb529de62..0b21344078d 100644 --- a/debian/po/fi.po +++ b/debian/po/fi.po @@ -13,8 +13,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=utf-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2011-02-16 04:59+0000\n" -"X-Generator: Launchpad (build 12351)\n" +"X-Launchpad-Export-Date: 2011-04-09 04:59+0000\n" +"X-Generator: Launchpad (build 12735)\n" #. Type: string #. Description diff --git a/debian/po/fr.po b/debian/po/fr.po index 5f3a9d3f534..d886baf38c0 100644 --- a/debian/po/fr.po +++ b/debian/po/fr.po @@ -13,8 +13,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=utf-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2011-02-16 04:59+0000\n" -"X-Generator: Launchpad (build 12351)\n" +"X-Launchpad-Export-Date: 2011-04-09 04:59+0000\n" +"X-Generator: Launchpad (build 12735)\n" #. Type: string #. Description diff --git a/debian/po/gl.po b/debian/po/gl.po index d9449cedb41..c77faee2a0d 100644 --- a/debian/po/gl.po +++ b/debian/po/gl.po @@ -13,8 +13,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2011-02-16 04:59+0000\n" -"X-Generator: Launchpad (build 12351)\n" +"X-Launchpad-Export-Date: 2011-04-09 04:59+0000\n" +"X-Generator: Launchpad (build 12735)\n" #. Type: string #. Description diff --git a/debian/po/he.po b/debian/po/he.po index d9e2a045591..0980a8f64a8 100644 --- a/debian/po/he.po +++ b/debian/po/he.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2011-02-23 06:17+0000\n" -"X-Generator: Launchpad (build 12351)\n" +"X-Launchpad-Export-Date: 2011-04-09 04:59+0000\n" +"X-Generator: Launchpad (build 12735)\n" #. Type: string #. Description diff --git a/debian/po/hr.po b/debian/po/hr.po index 588085b8566..97fccea596f 100644 --- a/debian/po/hr.po +++ b/debian/po/hr.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2011-02-16 05:00+0000\n" -"X-Generator: Launchpad (build 12351)\n" +"X-Launchpad-Export-Date: 2011-04-09 04:59+0000\n" +"X-Generator: Launchpad (build 12735)\n" #. Type: string #. Description diff --git a/debian/po/hu.po b/debian/po/hu.po index bc707ddeb1a..2749b521ed7 100644 --- a/debian/po/hu.po +++ b/debian/po/hu.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2011-02-16 04:59+0000\n" -"X-Generator: Launchpad (build 12351)\n" +"X-Launchpad-Export-Date: 2011-04-09 04:59+0000\n" +"X-Generator: Launchpad (build 12735)\n" #. Type: string #. Description diff --git a/debian/po/it.po b/debian/po/it.po index 02acddd4646..c8b7cddb483 100644 --- a/debian/po/it.po +++ b/debian/po/it.po @@ -13,8 +13,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2011-02-16 04:59+0000\n" -"X-Generator: Launchpad (build 12351)\n" +"X-Launchpad-Export-Date: 2011-04-09 04:59+0000\n" +"X-Generator: Launchpad (build 12735)\n" #. Type: string #. Description diff --git a/debian/po/ja.po b/debian/po/ja.po index e198f032b12..4cc67c42c40 100644 --- a/debian/po/ja.po +++ b/debian/po/ja.po @@ -13,8 +13,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2011-02-16 04:59+0000\n" -"X-Generator: Launchpad (build 12351)\n" +"X-Launchpad-Export-Date: 2011-04-09 04:59+0000\n" +"X-Generator: Launchpad (build 12735)\n" #. Type: string #. Description diff --git a/debian/po/ko.po b/debian/po/ko.po index 54f1823c68d..99b7c4820a6 100644 --- a/debian/po/ko.po +++ b/debian/po/ko.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2011-02-16 04:59+0000\n" -"X-Generator: Launchpad (build 12351)\n" +"X-Launchpad-Export-Date: 2011-04-09 04:59+0000\n" +"X-Generator: Launchpad (build 12735)\n" #. Type: string #. Description diff --git a/debian/po/lv.po b/debian/po/lv.po index b116aecddaa..f3be1623204 100644 --- a/debian/po/lv.po +++ b/debian/po/lv.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2011-02-16 04:59+0000\n" -"X-Generator: Launchpad (build 12351)\n" +"X-Launchpad-Export-Date: 2011-04-09 04:59+0000\n" +"X-Generator: Launchpad (build 12735)\n" #. Type: string #. Description diff --git a/debian/po/mn.po b/debian/po/mn.po index 957dd721bcc..15422904083 100644 --- a/debian/po/mn.po +++ b/debian/po/mn.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2011-02-16 04:59+0000\n" -"X-Generator: Launchpad (build 12351)\n" +"X-Launchpad-Export-Date: 2011-04-09 04:59+0000\n" +"X-Generator: Launchpad (build 12735)\n" #. Type: string #. Description diff --git a/debian/po/nb.po b/debian/po/nb.po index 499159ecf3a..2cd4488244c 100644 --- a/debian/po/nb.po +++ b/debian/po/nb.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2011-02-16 04:59+0000\n" -"X-Generator: Launchpad (build 12351)\n" +"X-Launchpad-Export-Date: 2011-04-09 04:59+0000\n" +"X-Generator: Launchpad (build 12735)\n" #. Type: string #. Description diff --git a/debian/po/nl.po b/debian/po/nl.po index 4964fc3d95c..bdc691b1ecc 100644 --- a/debian/po/nl.po +++ b/debian/po/nl.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2011-02-16 04:59+0000\n" -"X-Generator: Launchpad (build 12351)\n" +"X-Launchpad-Export-Date: 2011-04-09 04:59+0000\n" +"X-Generator: Launchpad (build 12735)\n" #. Type: string #. Description diff --git a/debian/po/pl.po b/debian/po/pl.po index ecf02080926..5276332e671 100644 --- a/debian/po/pl.po +++ b/debian/po/pl.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2011-02-16 04:59+0000\n" -"X-Generator: Launchpad (build 12351)\n" +"X-Launchpad-Export-Date: 2011-04-09 04:59+0000\n" +"X-Generator: Launchpad (build 12735)\n" #. Type: string #. Description diff --git a/debian/po/pt.po b/debian/po/pt.po index 5afe5a0006d..f0753a5dc23 100644 --- a/debian/po/pt.po +++ b/debian/po/pt.po @@ -13,8 +13,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2011-02-16 05:00+0000\n" -"X-Generator: Launchpad (build 12351)\n" +"X-Launchpad-Export-Date: 2011-04-09 04:59+0000\n" +"X-Generator: Launchpad (build 12735)\n" #. Type: string #. Description diff --git a/debian/po/pt_BR.po b/debian/po/pt_BR.po index d9dab2f9c2b..b57bfa26a26 100644 --- a/debian/po/pt_BR.po +++ b/debian/po/pt_BR.po @@ -8,14 +8,14 @@ msgstr "" "Project-Id-Version: openobject-server\n" "Report-Msgid-Bugs-To: FULL NAME \n" "POT-Creation-Date: 2009-08-24 22:41+0300\n" -"PO-Revision-Date: 2011-02-23 22:44+0000\n" -"Last-Translator: Emerson \n" +"PO-Revision-Date: 2010-11-07 07:06+0000\n" +"Last-Translator: OpenERP Administrators \n" "Language-Team: Brazilian Portuguese \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2011-03-01 06:00+0000\n" -"X-Generator: Launchpad (build 12351)\n" +"X-Launchpad-Export-Date: 2011-04-09 04:59+0000\n" +"X-Generator: Launchpad (build 12735)\n" #. Type: string #. Description diff --git a/debian/po/ro.po b/debian/po/ro.po index 02176b2b3ee..f0b3e852908 100644 --- a/debian/po/ro.po +++ b/debian/po/ro.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2011-02-16 05:00+0000\n" -"X-Generator: Launchpad (build 12351)\n" +"X-Launchpad-Export-Date: 2011-04-09 04:59+0000\n" +"X-Generator: Launchpad (build 12735)\n" #. Type: string #. Description diff --git a/debian/po/ru.po b/debian/po/ru.po index 317b73bf725..2206e7bcb5b 100644 --- a/debian/po/ru.po +++ b/debian/po/ru.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2011-02-16 05:00+0000\n" -"X-Generator: Launchpad (build 12351)\n" +"X-Launchpad-Export-Date: 2011-04-09 04:59+0000\n" +"X-Generator: Launchpad (build 12735)\n" #. Type: string #. Description diff --git a/debian/po/sk.po b/debian/po/sk.po index 7c7130a74d6..6d392a41dc5 100644 --- a/debian/po/sk.po +++ b/debian/po/sk.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2011-02-16 05:00+0000\n" -"X-Generator: Launchpad (build 12351)\n" +"X-Launchpad-Export-Date: 2011-04-09 04:59+0000\n" +"X-Generator: Launchpad (build 12735)\n" #. Type: string #. Description diff --git a/debian/po/sq.po b/debian/po/sq.po index 5383cb02030..a579e919dcb 100644 --- a/debian/po/sq.po +++ b/debian/po/sq.po @@ -14,14 +14,14 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2011-03-29 06:20+0000\n" -"X-Generator: Launchpad (build 12559)\n" +"X-Launchpad-Export-Date: 2011-04-09 04:58+0000\n" +"X-Generator: Launchpad (build 12735)\n" #. Type: string #. Description #: ../openerp-server.templates:1001 msgid "Dedicated system account for the Open ERP server:" -msgstr "" +msgstr "Llogari e dedikuar sistemi për serverin e Hapur ERP" #. Type: string #. Description @@ -31,9 +31,12 @@ msgid "" "the system's security is not compromised by running it with superuser " "privileges." msgstr "" +"Serveri i Hapur ERP duhet të përdorë llogarinë e dedikuar për veprimet e tij " +"në mënyrë që siguria e sistemit nuk është në rrezik nga përdorimi i " +"privilegjuar i super perdoruesve." #. Type: string #. Description #: ../openerp-server.templates:1001 msgid "Please choose that account's username." -msgstr "" +msgstr "Ju lutemi zgjidhni emrin e llogarisë tuaj." diff --git a/debian/po/sr.po b/debian/po/sr.po index da3deca9eb5..f8a410e4c8c 100644 --- a/debian/po/sr.po +++ b/debian/po/sr.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2011-02-16 05:00+0000\n" -"X-Generator: Launchpad (build 12351)\n" +"X-Launchpad-Export-Date: 2011-04-09 04:59+0000\n" +"X-Generator: Launchpad (build 12735)\n" #. Type: string #. Description diff --git a/debian/po/sv.po b/debian/po/sv.po index bfece85c5ef..9484bde189a 100644 --- a/debian/po/sv.po +++ b/debian/po/sv.po @@ -13,8 +13,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2011-02-16 05:00+0000\n" -"X-Generator: Launchpad (build 12351)\n" +"X-Launchpad-Export-Date: 2011-04-09 04:59+0000\n" +"X-Generator: Launchpad (build 12735)\n" "X-Poedit-Language: Swedish\n" #. Type: string diff --git a/debian/po/tr.po b/debian/po/tr.po index 638cf450f31..61c0d2ae9dd 100644 --- a/debian/po/tr.po +++ b/debian/po/tr.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2011-02-16 05:00+0000\n" -"X-Generator: Launchpad (build 12351)\n" +"X-Launchpad-Export-Date: 2011-04-09 04:59+0000\n" +"X-Generator: Launchpad (build 12735)\n" #. Type: string #. Description diff --git a/debian/po/uk.po b/debian/po/uk.po index 6bd5c022410..62c139cdbad 100644 --- a/debian/po/uk.po +++ b/debian/po/uk.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2011-02-16 05:00+0000\n" -"X-Generator: Launchpad (build 12351)\n" +"X-Launchpad-Export-Date: 2011-04-09 04:59+0000\n" +"X-Generator: Launchpad (build 12735)\n" #. Type: string #. Description diff --git a/debian/po/vi.po b/debian/po/vi.po index 800b6e227b1..7b05a26b1c2 100644 --- a/debian/po/vi.po +++ b/debian/po/vi.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2011-02-16 05:00+0000\n" -"X-Generator: Launchpad (build 12351)\n" +"X-Launchpad-Export-Date: 2011-04-09 04:59+0000\n" +"X-Generator: Launchpad (build 12735)\n" #. Type: string #. Description diff --git a/debian/po/zh_CN.po b/debian/po/zh_CN.po index 10f98e94af5..e9facd90e03 100644 --- a/debian/po/zh_CN.po +++ b/debian/po/zh_CN.po @@ -13,8 +13,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2011-02-16 05:00+0000\n" -"X-Generator: Launchpad (build 12351)\n" +"X-Launchpad-Export-Date: 2011-04-09 04:59+0000\n" +"X-Generator: Launchpad (build 12735)\n" #. Type: string #. Description diff --git a/debian/po/zh_TW.po b/debian/po/zh_TW.po index c5f769dcba6..b176cd4c2a7 100644 --- a/debian/po/zh_TW.po +++ b/debian/po/zh_TW.po @@ -12,8 +12,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2011-02-16 05:00+0000\n" -"X-Generator: Launchpad (build 12351)\n" +"X-Launchpad-Export-Date: 2011-04-09 04:59+0000\n" +"X-Generator: Launchpad (build 12735)\n" "X-Poedit-Country: TAIWAN\n" "X-Poedit-Language: Chinese\n" "X-Poedit-SourceCharset: utf-8\n" From b19baeb6a57811839be7afd56cf9621d9d73f560 Mon Sep 17 00:00:00 2001 From: "noz (OpenERP)" Date: Sat, 9 Apr 2011 23:20:50 +0530 Subject: [PATCH 119/259] [IMP] More implementation on poll, send etc... (Dont test anything, still need to modify more) bzr revid: noz@tinyerp.com-20110409175050-qf4hf3krdrxhzjdh --- addons/web_chat/controllers/main.py | 96 +++++++++++++++++----- addons/web_chat/static/lib/AjaxIM/js/im.js | 2 +- 2 files changed, 75 insertions(+), 23 deletions(-) diff --git a/addons/web_chat/controllers/main.py b/addons/web_chat/controllers/main.py index 24409ebce65..456fd0f5340 100644 --- a/addons/web_chat/controllers/main.py +++ b/addons/web_chat/controllers/main.py @@ -11,27 +11,32 @@ import openerpweb class PollServerMessageQueue(object): def __init__(self): # message queue - self.l = [] + self.messages = [] # online users self.users = {} # should contains: { # 'user1234' : { s:1, m:"status message", timestamp: last_contact_timestamp } # } def userlist(self, req): - userlist = [ - {"u": "Guest130205108745.47", "s": {"s": 1, "m": ""}, "g": "Users"}, - {"u": "Guest130209838956.76", "s": {"s": 1, "m": ""}, "g": "Users"}, - ] + userlist = [users for users in req.applicationsession['users']] + +# userlist = [ +# {"u": "Guest130205108745.47", "s": {"s": 1, "m": ""}, "g": "Users"}, +# {"u": "Guest130209838956.76", "s": {"s": 1, "m": ""}, "g": "Users"}, +# ] return userlist - def write(self, m_type, m_sender, m_recipent, m_message, m_group): - # appends messages to l + def write(self, m_type, m_from, m_to, m_message, m_group): + self.messages.append({'type': m_type, 'from': m_from, 'to': m_to, 'message': m_message, 'group': m_group}) # when status message update users pass - def read(self, recpient, timestamp): - # return matching message - pass + + def read(self, recipient, timestamp): + for msg in self.messages: + if msg['to'] == recipient: + return self.messages + def gc(): # remove message older than 300s from self.l # remove dead users from self.users @@ -63,7 +68,7 @@ class PollServer(openerpweb.Controller): """ mq = req.applicationsession.setdefault("web_chat", PollServerMessageQueue()) - #r = 'loggued in' + #r = 'logged in' #u = generate random.randint(0,2**32) #s = cherrypy cookie id #f = mq.userlist() @@ -74,11 +79,17 @@ class PollServer(openerpweb.Controller): # req.applicationsession['users'] = [{'u': username, 's':{'s':1, 'm':''}, 'g':'Users'}] # else: # req.applicationsession['users'].append({'u': username, 's':{'s':1, 'm':''}, 'g':'Users'}) + req.applicationsession['users'] = [{'u': 'Guest1', 's':{'s':1, 'm':'111'}, 'g':'Users'}, + {'u': 'Guest2', 's':{'s':1, 'm':'222'}, 'g':'Users'}, + {'u': 'Guest3', 's':{'s':1, 'm':'333'}, 'g':'Users'}] + + # Temporary Guest1 is my current user + req.applicationsession['current_user'] = 'Guest1' return """ { "r":"logged in", - "u":"Guest130213866190.85", + "u":'Guest1', "s":"f9e1811536f19ad5b9e00376f9ff1532", "f":""" + str(mq.userlist(req)) + """ } @@ -93,6 +104,11 @@ class PollServer(openerpweb.Controller): @openerpweb.httprequest def poll(self, req, **kw): + + mq = req.applicationsession.setdefault("web_chat", PollServerMessageQueue()) + print "================ poll ======= ", kw + # Long Polling + method = kw.get('method') """ --> GET http://im.ajaxim.com/poll?callback=jsonp1302138663582&_1302138663582= <-- 200 OK @@ -114,8 +130,16 @@ class PollServer(openerpweb.Controller): mag type s or m echo '' - """ + + for i in range(60): + received_msg = mq.read('Guest2', i); + if received_msg: + msg = self._pollParseMessages(received_msg) + print "============ msg...", msg + else: + time.sleep(2) + # for i in range(60): #r = mq.read(username,timestamp) # if messages @@ -125,13 +149,20 @@ class PollServer(openerpweb.Controller): # else # return emptylist - time.sleep(2) + # it's http://localhost:8002/web_chat/pollserver/poll?method=long?callback=jsonp1302147330483&_1302147330483= return '%s([{"t":"m","s":"Guest130214008855.5","r":"Guest130214013134.26","m":"xxxxxx"}]);'%kw.get('callback','') return None - - @openerpweb.jsonrequest + + @openerpweb.httprequest def send(self, req, **kw): + print "========= send ========", kw + + to = kw.get('to') + message = kw.get('message') + + mq = req.applicationsession.setdefault("web_chat", PollServerMessageQueue()) + """ --> GET http://im.ajaxim.com/send?callback=jsonp1302139980022&to=Guest130205108745.47&message=test&_1302139980022= callback: jsonp1302139980022 @@ -148,12 +179,22 @@ class PollServer(openerpweb.Controller): return array('r' => 'error', 'e' => 'send error'); """ - print "chat send",kw - # mq.write() - return {"action": actions} + + if not req.applicationsession['current_user']: + return dict(r='error', e='no session found') + + if not to: + return dict(r='error', e='no_recipient') + + if message: + mq.write(m_type="text", m_from=req.applicationsession['current_user'], m_to=to, m_message=message, m_group="Users") + + return {'r': 'sent'} - @openerpweb.jsonrequest + @openerpweb.httprequest def status(self, req, **kw): + mq = req.applicationsession.setdefault("web_chat", PollServerMessageQueue()) + """ --> GET status call const Offline = 0; @@ -168,8 +209,19 @@ class PollServer(openerpweb.Controller): return array('r' => 'error', 'e' => 'no session found'); return array('r' => 'error', 'e' => 'status error'); """ - print "chat status",kw + print "======== chat status ========",kw # mq.write() - return {"action": actions} + return {"action": ""} + + def _pollParseMessages(self, messages): + msg_arr = [] + print "=========== messages...", messages + for msg in messages: + print "=========== msg..", msg + msg_arr.append({'t': msg['type'], 's': msg['from'], 'r': msg['to'], 'm': msg['message']}) + return msg_arr + + def _sanitize(self, message): + return message.replace('>', '>').replace('<', '<').replace('&', '&'); diff --git a/addons/web_chat/static/lib/AjaxIM/js/im.js b/addons/web_chat/static/lib/AjaxIM/js/im.js index fbf6a1552f3..ef80481a246 100644 --- a/addons/web_chat/static/lib/AjaxIM/js/im.js +++ b/addons/web_chat/static/lib/AjaxIM/js/im.js @@ -1 +1 @@ -// = im.js = // // **Copyright © 2005 – 2010 Joshua Gross**\\ // //MIT Licensed// // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. // // This is the main library for Ajax IM. It encompasses the UI controls, // and connecting with the server. It does //not// handle registration or // account management. (function($, _instance) { AjaxIM = function(options, actions) { if(this instanceof AjaxIM) { var self = this; // === {{{ defaults }}} === // // These are the available settings for Ajax IM, and the associated // defaults: // // * {{{pollType}}} determines the way in which the client will talk to // the server. // ** {{{comet}}} will use http streaming, wherein a connection to the server will be held open indefinitely, and the server will push down new events (messages, status updates) as they occur. // ** {{{long}}} will hold open a connection with the server for as long as possible, or until a new event is received. Upon the server sending an event or closing the connection, the client will automatically—and immediately—reconnect. // ** {{{short}}} will open a connection, and the server (if this method is supported) will //immediately// provide a response as to whether or not there are any new events. Once a response is received, the client will wait 5 seconds, and then reconnect. // * {{{pollServer}}} is the default URL to which all actions refer. It is // possible to specify certain action URLs separately (as is used with the // NodeJS server). // * {{{cookieName}}} is the name of the session cookie used by the server. // If this is not set properly, the IM engine will not be able to automatically // reinitialize sessions. // * {{{theme}}} is the name of the theme folder that defines the HTML and // CSS of the IM bar and chat boxes. Usually, themes are deposited in the // provided "themes" folder and specified by that path, e.g. {{{themes/default}}}. // Theme files within the theme folder must be named {{{theme.html}}} and // {{{theme.css}}}. // * {{{storageMethod}}} defines the way in which data (chat sessions) are // temporarily stored client-side. By default, {{{"flash"}}} is used because // it is the most widely supported method. However, // [[http://eric.garside.name/docs.html?p=jstore#js-engines|other storage engines]] // are available, with their respective up- and down-sides // outlined, on the jStore website. // * {{{storeSession}}} (**not implemented**) sets the number of days to // retain stored chat session data before it should be deleted. // * {{{checkResume}}} is a flag that sets whether or not the client should // make a call to the server before resuming the session (such as on a page // reload). This will ensure that the session has not expired. If set to {{{false}}}, // a call to the server will not be made, and the session will be assumed to // be active. var defaults = { pollType: 'long', pollServer: './ajaxim.php', cookieName: 'ajaxim_session', theme: 'themes/default', storageMethod: 'auto', flashStorage: 'js/jStore.Flash.html', storeSession: 5, // number of days to store chat data (0 for current session only) checkResume: true }; // === {{{AjaxIM.}}}**{{{settings}}}** === // // These are the settings for the IM. If particular options are not specified, // the defaults (see above) will be used. //These options will be defined // upon calling the initialization function, and not set directly.// this.settings = $.extend(defaults, options); // === {{{AjaxIM.}}}**{{{actions}}}** === // // Each individual action that the IM engine can execute is predefined here. // By default, it merely appends the action onto the end of the {{{pollServer}}} url, // however, it is possible to define actions individually. //The alternative actions // will be defined upon calling the initialization function, and not set directly.// // // Should you define an action at a different URL, Ajax IM will determine whether // or not this URL is within the current domain. If it is within a subdomain of // the current domain, it will set the document.domain variable for you, // to match a broader hostname scope; the action will continue to use {{{$.post}}} // (the default AJAX method for Ajax IM). // // On the other hand, should you choose a URL outside the current domain // Ajax IM will switch to {{{$.getJSON}}} (a get request) to avoid // cross-domain scripting issues. This means that a server on a different // port or at a different address will need to be able to handle GET // requests rather than POST requests (such as how the Node.JS Ajax IM // server works). this.actions = $.extend({ login: this.settings.pollServer + '/login', logout: this.settings.pollServer + '/logout', register: this.settings.pollServer + '/register', poll: this.settings.pollServer + '/poll?method=' + this.settings.pollType, send: this.settings.pollServer + '/send', status: this.settings.pollServer + '/status', resume: this.settings.pollServer + '/resume' }, actions); var httpRx = new RegExp('^http://', 'i'), slashslashRx = new RegExp('^//', 'i'), queryStrRx = new RegExp('[?](.+)$'), subdomainRx = new RegExp('((http[s]?:)?//)?(.+?)[.]' + window.location.host, 'i'); $.each(this.actions, function(name, action) { if(name == 'poll') { if(self.settings.pollType != 'comet') action += (queryStrRx.test(action[1]) ? '&' : '?') + 'callback=?'; action = ['jsonp', action]; } else { action = ['ajax', action]; if(subdomainRx.test(action[1])) { document.domain = '.' + window.location.host; } else if((http = httpRx.test(action[1])) || slashslashRx.test(action[1])) { if(!(new RegExp('//' + window.location.host + '/', 'i')).test(action[1])) { action[1] += (queryStrRx.test(action[1]) ? '&' : '?') + 'callback=?'; action = ['jsonp', action[1]]; } } } self.actions[name] = action; }); // We load the theme dynamically based on the passed // settings. If the theme is set to false, we assume // that the user is going to load it himself. this.themeLoaded = false; if(this.settings.theme) { $('
    ').appendTo('body').load(this.settings.theme + '/theme.html #imjs-bar, .imjs-tooltip', function() { self.themeLoaded = true; setup.apply(self); } ); if(typeof document.createStyleSheet == 'function') document.createStyleSheet(this.settings.theme + '/theme.css'); else $('body').append(''); } else { this.themeLoaded = true; setup.apply(this); } // Client-side storage for keeping track of // conversation states, active tabs, etc. // The default is flash storage, however, other // options are available via the jStore library. if(this.settings.storageMethod) { this.storageBrowserKey = 'unknown'; this.storeKey = ''; $.each($.browser, function(k, v) { if(k == 'version') return true; else if(v == true) { self.storageBrowserKey = k; return false; } }); if(this.settings.storageMethod == 'auto') { $.each(['ie', 'html5', 'local', 'flash'], function() { if($.jStore.Availability[this]()) { self.settings.storageMethod = this; return false; } }); } $.extend($.jStore.defaults, { project: 'im.js', engine: this.settings.storageMethod, flash: this.settings.flashStorage }); this.storageReady = false; if(this.settings.storageMethod == 'flash') { $.jStore.ready(function(engine) { $.jStore.flashReady(function() { self.storageReady = true; setup.apply(self); }); }) } else { $.jStore.ready(function(engine) { self.storageReady = true; setup.apply(self); }); } $.jStore.load(); } else { this.storageReady = true; setup.apply(this); } // Allow a chatbox to me minimized $('.imjs-chatbox').live('click', function(e) { e.preventDefault(); return false; }); $('.imjs-chatbox .imjs-minimize').live('click', function() { $(this).parents('.imjs-chatbox').data('tab').click(); }); // Allow a chatbox to be closed $('.imjs-chatbox .imjs-close').live('click', function() { var chatbox = $(this).parents('.imjs-chatbox'); chatbox.data('tab') .data('state', 'closed').css('display', 'none'); if(self.settings.storageMethod && self.storageReady) { delete self.chatstore[chatbox.data('username')]; if(self.storageReady) { $.jStore.store( self.storageBrowserKey + '-' + self.username + '-chats', self.chatstore); } } }); // Setup message sending for all chatboxes $('.imjs-chatbox .imjs-input').live('keydown', function(event) { var obj = $(this); if(event.keyCode == 13 && !($.browser.msie && $.browser.version < 8)) { self.send(obj.parents('.imjs-chatbox').data('username'), obj.val()); } }).live('keyup', function(event) { if(event.keyCode == 13) { if($.browser.msie && $.browser.version < 8) { var obj = $(this); self.send(obj.parents('.imjs-chatbox').data('username'), obj.val()); } var obj = $(this); obj.val(''); obj.height(obj.data('height')); } }).live('keypress', function(e) { var obj = $(this); if(!($.browser.msie && $.browser.opera)) obj.height(0); if(this.scrollHeight > obj.height() || this.scrollHeight < obj.height()) { obj.height(this.scrollHeight); } }); $('.imjs-msglog').live('click', function() { var chatbox = $(this).parents('.imjs-chatbox'); chatbox.find('.imjs-input').focus(); }); // Create a chatbox when a buddylist item is clicked $('.imjs-friend').live('click', function() { var chatbox = self._createChatbox($(this).data('friend')); if(chatbox.data('tab').data('state') != 'active') chatbox.data('tab').click(); chatbox.find('.imjs-input').focus(); }); // Setup and hide the scrollers $('.imjs-scroll').css('display', 'none'); $('#imjs-scroll-left').live('click', function() { var hiddenTab = $('#imjs-bar li.imjs-tab:visible').slice(-1) .next('#imjs-bar li.imjs-tab:hidden') .filter(function() { return $(this).data('state') != 'closed' }) .not('.imjs-default').slice(-1).css('display', ''); if(hiddenTab.length) { $('#imjs-bar li.imjs-tab:visible').eq(0).css('display', 'none'); $(this).html(parseInt($(this).html()) - 1); $('#imjs-scroll-right').html(parseInt($('#imjs-scroll-right').html()) + 1); } return false; }); $('#imjs-scroll-right').live('click', function() { var hiddenTab = $('#imjs-bar li.imjs-tab:visible').eq(0) .prev('#imjs-bar li.imjs-tab:hidden') .filter(function() { return $(this).data('state') != 'closed' }) .not('.imjs-default').slice(-1).css('display', ''); if(hiddenTab.length) { $('#imjs-bar li.imjs-tab:visible').slice(-1).css('display', 'none'); $(this).html(parseInt($(this).html()) - 1); $('#imjs-scroll-left').html(parseInt($('#imjs-scroll-left').html()) + 1); } return false; }); // Initialize the chatbox hash this.chats = {}; // Try to resume any existing session this.resume(); $(window).resize(function() { self.bar._scrollers(); }); } else return AjaxIM.init(options); }; // We predefine all public functions here... // If they are called before everything (theme, storage engine) has loaded, // then they get put into a "prequeue" and run when everything *does* // finally load. // // This ensures that nothing loads without all of the principal components // being pre-loaded. If that were to occur (without this prequeue), things // would surely break. var prequeue = []; var empty = function() { var func = this; return function() { prequeue.push([func, arguments]) }; }; $.extend(AjaxIM.prototype, { settings: {}, friends: {}, chats: {}, storage: empty.apply('storage'), login: empty.apply('login'), logout: empty.apply('logout'), resume: empty.apply('resume'), form: empty.apply('form'), poll: empty.apply('poll'), incoming: empty.apply('incoming'), send: empty.apply('send'), status: empty.apply('status'), statuses: {}, bar: { initialize: empty.apply('bar.initialize'), activateTab: empty.apply('bar.activateTab'), closeTab: empty.apply('bar.closeTab'), addTab: empty.apply('bar.addTab'), notification: empty.apply('bar.notification'), _scrollers: empty.apply('bar._scrollers') } }); setup = (function() { var self = this; if(!this.storageReady || !this.themeLoaded) return; $(self).trigger('loadComplete'); $(window).resize(); $.extend(AjaxIM.prototype, { // == Cookies == // // The "cookies" functions can be used to set, get, and erase JSON-based cookies. // These functions are primarily used to manage and read the server-set cookie // that handles the user's chat session ID. cookies: { // === {{{AjaxIM.}}}**{{{cookies.set(name, value, days)}}}** === // // Sets a cookie, stringifying the JSON value upon storing it. // // ==== Parameters ==== // * {{{name}}} is the cookie name.\\ // * {{{value}}} is the cookie data that you would like to store.\\ // * {{{days}}} is the number of days that the cookie will be stored for. set: function(name, value, days) { if (days) { var date = new Date(); date.setTime(date.getTime() + (days * 24 * 60 * 60 * 1000)); var expires = "; expires=" + date.toGMTString(); } else var expires = ""; document.cookie = name + "=" + $.compactJSON(value) + expires + "; path=/"; }, // === {{{AjaxIM.}}}**{{{cookies.get(name)}}}** === // // Gets a cookie, decoding the JSON value before returning the data. // // ==== Parameters ==== // * {{{name}}} is the cookie name that you would like to retrieve. get: function(name) { var nameEQ = name + "="; var ca = document.cookie.split(';'); for(var i = 0; i < ca.length; i++) { var c = ca[i]; while (c.charAt(0) == ' ') c = c.substring(1, c.length); if (c.indexOf(nameEQ) == 0) { var cval = decodeURIComponent(c.substring(nameEQ.length, c.length)); return $.secureEvalJSON(cval); } } return null; }, // === {{{AjaxIM.}}}**{{{cookies.erase(name)}}}** === // // Deletes a cookie. // // {{{name}}} is the existing cookie that you would like to delete. erase: function(name) { self.cookies.set(name, '', -1); } }, // == Main == // === {{{AjaxIM.}}}**{{{storage()}}}** === // // Retrieves chat session data from whatever storage engine is enabled // (provided that one is enabled at all). If a page reloads, this function // is called to restore the user's chat state (existing conversations, active tab). // This function is called //automatically//, upon initialization of the IM engine. storage: function() { if(!self.storeKey.length) return; try { var chatstore = $.jStore.store(self.storeKey + 'chats') || {}; } catch(e) { $.jStore.remove(self.storeKey + 'chats'); var chatstore = {}; } if(this.chatstore) { $.each(this.chatstore, function(username, convo) { if(username in chatstore) chatstore[username] = $.merge(chatstore[username], self.chatstore[username]); else chatstore[username] = self.chatstore[username]; }); this.chatstore = chatstore; $.jStore.store(self.storeKey + 'chats', chatstore); } else { this.chatstore = chatstore; } $.each(this.chatstore, function(username, convo) { if(!convo.length) return; var chatbox = self._createChatbox(username, true); chatbox.data('lastDateStamp', null).css('display', 'none'); // Remove the automatic date stamp chatbox.find('.imjs-msglog').empty(); // Restore all messages, date stamps, and errors $.each(convo, function() { switch(this[0]) { case 'error': self._addError(chatbox, decodeURIComponent(this[2]), this[3]); break; case 'datestamp': self._addDateStamp(chatbox, this[3]); break; case 'a': case 'b': self._addMessage(this[0], chatbox, this[1], decodeURIComponent(this[2]), this[3]); break; } }); $(self).trigger('chatRestored', [username, chatbox]); }); var activeTab = $.jStore.store(self.storeKey + 'activeTab') || []; if(activeTab.length && (activeTab = activeTab[0]) && activeTab in this.chats) { this.chats[activeTab].data('tab').click(); var msglog = this.chats[activeTab].find('.imjs-msglog'); msglog[0].scrollTop = msglog[0].scrollHeight; } }, // === {{{AjaxIM.}}}**{{{login(username, password)}}}** === // // Authenticates a user and initializes the IM engine. If the user is // already logged in, [s]he is logged out, the session is cleared, and // the new user is logged in. // // Returns the user's properly formatted username, session ID, and online // friends in JSON, if successful; e.g.:\\ // {{{ {u: 'username', s: 'longsessionid', f: [{u: 'friend', s: 1, g: 'group'}]} }}} // // If unsuccessful, {{{false}}} is returned. // // ==== Parameters ==== // * {{{username}}} is the user's username.\\ // * {{{password}}} is the user's password. This password will be MD5 hashed // before it is sent to the server. login: function(username, password) { if(!username) username = ''; if(!password) password = ''; if(this.username) return true; // Already logged in! // hash password before sending it to the server password = $.md5(password); // authenticate AjaxIM.request( this.actions.login, {'username': username, 'password': password}, function(auth) { if(auth.r == 'logged in') { self.username = ('u' in auth ? auth.u : username); if(self.settings.storageMethod) self.storeKey = [self.storageBrowserKey, self.username, ''].join('-'); var existing = self.cookies.get(self.settings.cookieName); self.storage(); // Begin the session $.each(auth.f, function() { self.friends[this.u] = {status: [this.s, ''], group: this.g}; }); self._session(self.friends); self._storeFriends(); $(self).trigger('loginSuccessful', [auth]); return auth; } else { $(self).trigger('loginError', [auth]); } return false; } ); }, // === {{{AjaxIM.}}}**{{{logout()}}}** === // // Logs the user out and removes his/her session cookie. As well, it // will close all existing chat windows, clear the storage engine, and // remove the IM bar. logout: function() { AjaxIM.request( this.actions.logout, {}, function(done) { if(done) { self.cookies.erase(self.settings.cookieName); self._clearSession(); $(self).trigger('logoutSuccessful'); return true; } else { $(self).trigger('logoutError'); return false; } } ); }, // === {{{AjaxIM.}}}**{{{resume()}}}** === // // Resumes an existing session based on a session ID stored in the // server-set cookie. This function is called //automatically// upon IM // engine (re-)initialization, so the user does not need to re-login // should a session already exist. resume: function() { var session = this.cookies.get(this.settings.cookieName); if(session && session.sid) { this.username = session.user; this.storeKey = [this.storageBrowserKey, this.username, ''].join('-'); var friends = $.jStore.store(this.storeKey + 'friends') || []; if(self.settings.checkResume) { AjaxIM.request( this.actions.resume, {}, function(response) { if(response.r == 'connected') { self._session(friends); self.storage(); } else { var username = this.username; self._clearSession(); $(self).trigger('sessionNotResumed', [username]); } } ); } else { self._session(friends); self.storage(); } } else { $(self).trigger('noSession'); } }, // === //private// {{{AjaxIM.}}}**{{{_session(friends)}}}** === // // Restores session data (username, friends) and begins polling the server. // Called only by {{{AjaxIM.resume()}}}. // // ==== Parameters ==== // * {{{friends}}} is a list of "friend" objects, e.g.:\\ // {{{[{u: 'friend', s: 1, g: 'group'}, ...]}}} // ** {{{u}}} being the friend's username. // ** {{{s}}} being one of the available status codes (see {{{AjaxIM.statuses}}}), depending on the friend's current status. // ** {{{g}}} being the group that the friend is in. _session: function(friends) { $('#imjs-friends-panel .imjs-header span').html(this.username); $('#imjs-friends').removeClass('imjs-not-connected'); $.each(friends, function(friend, info) { self.addFriend.apply(self, [friend, info.status, info.group]); }); self._storeFriends(); $(self).trigger('sessionResumed', [this.username]); setTimeout(function() { self.poll(); }, 0); }, // === //private// {{{AjaxIM.}}}**{{{_clearSession()}}}** === // // Clears all session data from the last known user. _clearSession: function() { if(self.settings.storageMethod && self.storageReady) { $.jStore.remove(self.storeKey + 'chats'); $.jStore.remove(self.storeKey + 'friends'); $.jStore.remove(self.storeKey + 'activeTab'); } self.chats = {}; $('.imjs-tab').not('.imjs-tab.imjs-default').remove(); self.cookies.erase('ajaxim_session'); delete self.username; }, // === {{{AjaxIM.}}}**{{{form(element)}}}** === // // Loads a login and registration form into the specified element // or, if no element is supplied, to the location on the page from // which this function was called. form: function(element) { $(element).load(this.settings.theme + '/theme.html #imjs-lr', function() { $('#imjs-lr .error').hide(); if(self.username) { $('#imjs-register, #imjs-login fieldset').hide(); $('#imjs-logged-in') .show() .html($('#imjs-logged-in').html().replace('{username}', self.username)); } else { $('#imjs-logged-in').hide(); } // Handle logout success $(self).bind('logoutSuccessful', function() { $('#imjs-login fieldset').slideDown(); $('#imjs-register').slideDown(); $('#imjs-logged-in') .html($('#imjs-logged-in strong').html('{username}')) .slideUp(); }); $('#imjs-logged-in a').click(function() { self.logout(); return false; }); // Handle login error or success $(self).bind('loginError', function() { $('#imjs-login .error').html(AjaxIM.i18n.authInvalid).slideDown('fast'); $('#imjs-login input') .addClass('imjs-lr-error') .blur(function() { $(this).removeClass('imjs-lr-error'); }); }).bind('loginSuccessful', function() { $('#imjs-login fieldset').slideUp(); $('#imjs-register').slideUp(); $('#imjs-logged-in') .html($('#imjs-logged-in').html().replace('{username}', self.username)) .slideDown(); }); var login = function() { self.login($('#imjs-login-username').val(), $('#imjs-login-password').val()); return false; }; $('#imjs-login').submit(login); $('#imjs-login-submit').click(login); var regIssues = false; var regError = function(error, fields) { $('#imjs-register .error') .append(AjaxIM.i18n['register' + error] + ' ') .slideDown(); $(fields) .addClass('imjs-lr-error') .blur(function() { $(this).removeClass('imjs-lr-error'); }); regIssues = true; }; var register = function() { $('#imjs-register .error').empty(); regIssues = false; var username = $('#imjs-register-username').val(); var password = $('#imjs-register-password').val(); if(password.length < 4) regError('PasswordLength', '#imjs-register-password'); if(password != $('#imjs-register-cpassword').val()) regError('PasswordMatch', '#imjs-register-password, #imjs-register-cpassword'); if(username.length <= 2 || !$('#imjs-register-username').val().match(/^[A-Za-z0-9_.]+$/)) regError('UsernameLength', '#imjs-register-username'); if(!regIssues) { AjaxIM.request( self.actions.register, {username: username, password: password}, function(response) { if(response.r == 'registered') { self.login(username, password); } else if(response.r == 'error') { switch(response.e) { case 'unknown': regError('Unknown', ''); break; case 'invalid password': regError('PasswordLength', '#imjs-register-password'); break; case 'invalid username': regError('UsernameLength', '#imjs-register-username'); break; case 'username taken': regError('UsernameTaken', '#imjs-register-username'); break; } } }, function(error) { regError('Unknown', ''); } ); } return false; }; $('#imjs-register').submit(register); $('#imjs-register-submit').click(register); }); }, // === {{{AjaxIM.}}}**{{{poll()}}}** === // // Queries the server for new messages. If a 'long' or 'short' poll // type is used, jQuery's {{{$.post}}} or {{{$.getJSON}}} will be // used. If 'comet' is used, the server connection will be deferred // to the comet set of functions. poll: function() { if(/^(short|long)$/.test(this.settings.pollType)) { AjaxIM.request( this.actions.poll, {}, function(response) { if(!response['e']) { if(response.length) self._parseMessages(response); setTimeout(function() { self.poll(); }, 0); } else { switch(response.e) { case 'no session found': self._notConnected(); break; } $(self).trigger('pollFailed', [response.e]); } }, function(error) { self._notConnected(); $(self).trigger('pollFailed', ['not connected']); // try reconnecting? } ); } else if(this.settings.pollType == 'comet') { this.comet.connect(); } }, // === //private// {{{AjaxIM.}}}**{{{_parseMessages(messages)}}}** === // // Handles an incoming message array:\\ // {{{[{t: 'type', s: 'sender', r: 'recipient', m: 'message'}, ...]}}} // // * {{{t}}} (message type) is one of: // ** {{{m}}} — a standard message // ** {{{s}}} — a user's status update // ** {{{b}}} — a broadcasted message (sent to many users simultaneously) // * {{{s}}} is the sender of the message. // * {{{r}}} is the intended recipient of the message. Most of the time, this will // simply be the logged in user, however, a broadcasted message may not specify // a recipient or may specify a different recipient. Also provides future // compatability for chatrooms. // * {{{m}}} is the actual message. For something such as a status update, this can // be a JSON object or parsable string; e.g. {{{"2:I'm away."}}} // // ==== Parameters ==== // * {{{messages}}} is the message array _parseMessages: function(messages) { if($.isArray(messages)) { $.each(messages, function() { $(self).trigger('parseMessage', [this]); switch(this.t) { case 'm': self.incoming(this.s, this.m); break; case 's': var status = this.m.split(':'); if(this['g']) self.addFriend(this.s, status, this.g); self._friendUpdate(this.s, status[0], status.slice(1).join(':')); self._storeFriends(); break; case 'b': break; default: break; } }); } }, // === {{{AjaxIM.}}}**{{{incoming(from, message)}}}** === // // Handles a new message from another user. If a chatbox for that // user does not yet exist, one is created. If it does exist, but // is minimized, the user is notified but the chatbox is not brought // to the front. This function also stores the message, if a storage // method is set. // // ==== Parameters ==== // * {{{from}}} is the username of the sender. // * {{{message}}} is the body. incoming: function(from, message) { // check if IM exists, otherwise create new window // TODO: If friend is not on the buddylist, // should add them to a temp list? var chatbox = this._createChatbox(from); if(!$('#imjs-bar .imjs-selected').length) { chatbox.data('tab').click(); } else if(chatbox.data('tab').data('state') != 'active') { this.bar.notification(chatbox.data('tab')); } var time = this._addMessage('b', chatbox, from, message); this._storeMessage('b', chatbox, from, message, time); }, // === {{{AjaxIM.}}}**{{{addFriend(username, group)}}}** === // // Inserts a new friend into the friends list. If the group specified // doesn't exist, it is created. If the friend is already in this group, // they aren't added again, however, the friend item is returned. // // ==== Parameters ==== // * {{{username}}} is the username of the new friend. // * {{{status}}} is the current status of the friend. // * {{{group}}} is the user group to which the friend should be added. addFriend: function(username, status, group) { var status_name = 'available'; $.each(this.statuses, function(key, val) { if(status[0] == val) { status_name = key; return false; } }); var group_id = 'imjs-group-' + $.md5(group); if(!(group_item = $('#' + group_id)).length) { var group_item = $('.imjs-friend-group.imjs-default').clone() .removeClass('imjs-default') .attr('id', group_id) .data('group', group) .appendTo('#imjs-friends-list'); var group_header = group_item.find('.imjs-friend-group-header'); group_header.html(group_header.html().replace('{group}', group)); } var user_id = 'imjs-friend-' + $.md5(username + group); if(!$('#' + user_id).length) { var user_item = group_item.find('ul li.imjs-default').clone() .removeClass('imjs-default') .addClass('imjs-' + status_name) .attr('id', user_id) .data('friend', username) .appendTo(group_item.find('ul')); if(status[0] == 0) user_item.hide(); user_item.html(user_item.html().replace('{username}', username)); } this.friends[username] = {'status': status, group: group}; this._updateFriendCount(); return this.friends[username]; }, // === //private// {{{AjaxIM.}}}**{{{_updateFriendCount()}}}** === // // Counts the number of online friends and updates the friends count // in the friend tab. _updateFriendCount: function() { var friendsLength = 0; for(var f in this.friends) { if(this.friends[f].status[0] != 0) friendsLength++; } $('#imjs-friends .imjs-tab-text span span').html(friendsLength); }, // === //private// {{{AjaxIM.}}}**{{{_storeFriends()}}}** === // // If a storage method is enabled, the current state of the // user's friends list is stored. _storeFriends: function() { if(this.settings.storageMethod && this.storageReady) $.jStore.store(this.storeKey + 'friends', this.friends); }, // === //private// {{{AjaxIM.}}}**{{{_createChatbox(username)}}}** === // // Builds a chatbox based on the default chatbox HTML and CSS defined // in the current theme. Should a chatbox for this user already exist, // a new one is not created. Instead, it is either given focus (should // no other windows already have focus), or a notification is issued. // // As well, if the chatbox does not exist, an associated tab will be // created. // // ==== Parameters ==== // * {{{username}}} is the name of the user for whom the chatbox is intended // for. // * {{{no_stamp}}} sets whther or not to add a date stamp to the chatbox // upon creation. // // //Note:// New chatboxes are given an automatically generated ID in the // format of {{{#imjs-[md5 of username]}}}. _createChatbox: function(username, no_stamp) { var chatbox_id = 'imjs-' + $.md5(username); if(!(chatbox = $('#' + chatbox_id)).size()) { // add a tab var tab = this.bar.addTab(username, '#' + chatbox_id); var chatbox = tab.find('.imjs-chatbox'); chatbox.attr('id', chatbox_id); chatbox.data('tab', tab); // remove default items from the message log var message_log = chatbox.find('.imjs-msglog').empty(); // setup the chatbox header var cb_header = chatbox.find('.imjs-header'); cb_header.html(cb_header.html().replace('{username}', username)); if(!no_stamp) { // add a date stamp var time = this._addDateStamp(chatbox); this._storeNonMessage('datestamp', username, null, time); } // associate the username with the object and vice-versa this.chats[username] = chatbox; chatbox.data('username', username); // did this chatbox fall down? this.bar._scrollers(); if(username in this.friends) { status = this.friends[username].status; var status_name = 'available'; $.each(this.statuses, function(key, val) { if(status[0] == val) { status_name = key; return false; } }); tab.addClass('imjs-' + status_name); } // store inputbox height //var input = chatbox.find('.imjs-input'); //input.data('height', input.height()); } else if(chatbox.data('tab').data('state') == 'closed') { chatbox.find('.imjs-msglog > *').addClass('imjs-msg-old'); var tab = chatbox.data('tab'); if(tab.css('display') == 'none') tab.css('display', '').removeClass('imjs-selected') .appendTo('#imjs-bar'); if(!no_stamp) { // possibly add a date stamp var time = this._addDateStamp(chatbox); this._storeNonMessage('datestamp', username, null, time); } if(!$('#imjs-bar .imjs-selected').length) { tab.click(); } else { this.bar.notification(tab); } } return chatbox; }, // === //private// {{{AjaxIM.}}}**{{{_addDateStamp(chatbox)}}}** // // // Adds a date/time notifier to a chatbox. These are generally // inserted upon creation of a chatbox, or upon the date changing // since the last time a date stamp was added. If a date stamp for // the current date already exists, a new one will not be added. // // ==== Parameters ==== // * {{{chatbox}}} refers to the jQuery-selected chatbox DOM element. // * {{{time}}} is the date/time the date stamp will show. It is specified // in milliseconds since the Unix Epoch. This is //only// defined when // date stamps are being restored from storage; if not specified, the // current computer time will be used. _addDateStamp: function(chatbox, time) { var message_log = $(chatbox).find('.imjs-msglog'); if(!time) time = (new Date()).getTime(); var date_stamp = $('.imjs-tab.imjs-default .imjs-chatbox .imjs-msglog .imjs-date').clone(); var date_stamp_time = date_stamp.find('.imjs-msg-time'); if(date_stamp_time.length) date_stamp_time.html(AjaxIM.dateFormat(time, date_stamp_time.html())); var date_stamp_date = date_stamp.find('.imjs-date-date'); var formatted_date = AjaxIM.dateFormat(time, date_stamp_date.html()); if(chatbox.data('lastDateStamp') != formatted_date) { if(date_stamp_date.length) date_stamp_date.html(AjaxIM.dateFormat(time, date_stamp_date.html())); chatbox.data('lastDateStamp', formatted_date); date_stamp.appendTo(message_log); } else { //$('
    ').appendTo(message_log); } return time; }, // === //private// {{{AjaxIM.}}}**{{{_addError(chatbox, error)}}}** // // // Adds an error to a chatbox. These are generally inserted after // a user sends a message unsuccessfully. If an error message // was already added, another one will be added anyway. // // ==== Parameters ==== // * {{{chatbox}}} refers to the jQuery-selected chatbox DOM element. // * {{{error}}} is the error message string. // * {{{time}}} is the date/time the error occurred. It is specified in // milliseconds since the Unix Epoch. This is //only// defined when // errors are being restored from storage; if not specified, the current // computer time will be used. _addError: function(chatbox, error, time) { var message_log = $(chatbox).find('.imjs-msglog'); var error_item = $('.imjs-tab.imjs-default .imjs-chatbox .imjs-msglog .imjs-error').clone(); var error_item_time = error_item.find('.imjs-msg-time'); if(error_item_time.length) { if(!time) time = (new Date()).getTime(); error_item_time.html(AjaxIM.dateFormat(time, error_item_time.html())); } error_item.find('.imjs-error-error').html(error); error_item.appendTo(message_log); message_log[0].scrollTop = message_log[0].scrollHeight; }, // === //private// {{{AjaxIM.}}}**{{{_addMessage(ab, chatbox, username, message, time)}}}** // // // Adds a message to a chatbox. Depending on the {{{ab}}} value, // the color of the username may change as a way of visually // identifying users (however, this depends on the theme's CSS). // A timestamp is added to the message, and the chatbox is scrolled // to the bottom, such that the new message is visible. // // Messages will be automatically tag-escaped, so as to prevent // any potential cross-site scripting problems. Additionally, // URLs will be automatically linked. // // ==== Parameters ==== // * {{{ab}}} refers to whether the user is "a" or "b" in a conversation. // For the general case, "you" are "a" and "they" are "b". // * {{{chatbox}}} refers to the jQuery-selected chatbox DOM element. // * {{{username}}} is the username of the user who sent the message. // * {{{time}}} is the time the message was sent in milliseconds since // the Unix Epoch. This is //only// defined when messages are being // restored from storage. For new messages, the current computer // time is automatically used. _addMessage: function(ab, chatbox, username, message, time) { var last_message = chatbox.find('.imjs-msglog > *:last-child'); if(last_message.hasClass('imjs-msg-' + ab)) { // Last message was from the same person, so let's just add another imjs-msg-*-msg var message_container = (last_message.hasClass('imjs-msg-' + ab + '-container') ? last_message : last_message.find('.imjs-msg-' + ab + '-container')); var single_message = $('.imjs-tab.imjs-default .imjs-chatbox .imjs-msglog .imjs-msg-' + ab + '-msg') .clone().appendTo(message_container); single_message.html(single_message.html().replace('{username}', username)); } else if(!last_message.length || !last_message.hasClass('imjs-msg-' + ab)) { var message_group = $('.imjs-tab.imjs-default .imjs-chatbox .imjs-msg-' + ab) .clone().appendTo(chatbox.find('.imjs-msglog')); message_group.html(message_group.html().replace('{username}', username)); var single_message = message_group.find('.imjs-msg-' + ab + '-msg'); } // clean up the message message = message.replace(//g, '>') .replace(/(^|.*)\*([^*]+)\*(.*|$)/, '$1$2$3'); // autolink URLs message = message.replace( new RegExp('([A-Za-z][A-Za-z0-9+.-]{1,120}:[A-Za-z0-9/]' + '(([A-Za-z0-9$_.+!*,;/?:@&~=-])|%[A-Fa-f0-9]{2}){1,333}' + '(#([a-zA-Z0-9][a-zA-Z0-9$_.+!*,;/?:@&~=%-]{0,1000}))?)', 'g'), '$1'); // insert the message single_message.html(single_message.html().replace('{message}', message)); // set the message time var msgtime = single_message.find('.imjs-msg-time'); if(!time) time = new Date(); if(typeof time != 'string') time = AjaxIM.dateFormat(time, msgtime.html()); msgtime.html(time); var msglog = chatbox.find('.imjs-msglog'); msglog[0].scrollTop = msglog[0].scrollHeight; return time; }, // === //private// {{{AjaxIM.}}}**{{{_storeNonMessage(type, username, data, time)}}}** === // // **Redundant?**\\ // Similar to {{{AjaxIM._storeMessage}}}, but stores items that aren't messages, // such as datestamps and errors. // // ==== Parameters ==== // * {{{type}}} is the type of non-message (error, datestamp). // * {{{username}}} is the username of the user being chatted with. // * {{{data}}} is the (optional) data of the non-message to be stored. // * {{{time}}} is the time of the message. _storeNonMessage: function(type, username, data, time) { // If storage is on & ready, store the non-message if(this.settings.storageMethod) { if(!this.chatstore) this.chatstore = {}; if(!(username in this.chatstore)) this.chatstore[username] = []; // If the chat store gets too long, it becomes slow to load. if(this.chatstore[username].length > 300) this.chatstore[username].shift(); // For some reason, if we don't encode and decode the message, it *will* break // (at least) the Flash storage engine's retrieval. Gah! this.chatstore[username].push( [type, username, encodeURIComponent(data), time]); if(this.storageReady) $.jStore.store(self.storeKey + 'chats', this.chatstore); } }, // === //private// {{{AjaxIM.}}}**{{{_storeMessage(ab, chatbox, username, message, time)}}}** === // // Taking the same arguments as {{{AjaxIM._addMessage}}}, {{{_storeMessage}}} pushes a message // into the storage hash, if storage is enabled. // // Messages are added to a message array, by username. The entire chat hash is stored as // a {{{'chats'}}} object in whatever storage engine is enabled. _storeMessage: function(ab, chatbox, username, message, time) { // If storage is on & ready, store the message if(this.settings.storageMethod) { if(!this.chatstore) this.chatstore = {}; message = message.replace(//g, '>'); if(!(username in this.chatstore)) { this.chatstore[username] = []; } else if(this.chatstore[username].length > 300) { // If the chat store gets too long, it becomes slow to load. this.chatstore[username].shift(); } // For some reason, if we don't encode and decode the message, it *will* break // (at least) the Flash storage engine's retrieval. Gah! this.chatstore[chatbox.data('username')].push( [ab, username, encodeURIComponent(message), time]); if(this.storageReady) $.jStore.store(this.storeKey + 'chats', this.chatstore); } }, // === //private// {{{AjaxIM.}}}**{{{_friendUpdate(friend, status, statusMessage)}}}** === // // Called when a friend's status is updated. This function will update all locations // where a status icon is displayed (chat tab, friends list), as well as insert // a notification, should a chatbox be open. // // ==== Parameters ==== // * {{{friend}}} is the username of the friend. // * {{{status}}} is the new status code. See {{{AjaxIM.statuses}}} for a list of available // codes. //Note: If an invalid status is specified, no action will be taken.// // * {{{statusMessage}}} is a message that was, optionally, specified by the user. It will be // used should "you" send the user an IM while they are away, or if their status is viewed // in another way (such as via the friends list [**not yet implemented**]). _friendUpdate: function(friend, status, statusMessage) { // add friend to buddylist, update their status, etc. var status_name = 'available'; $.each(this.statuses, function(key, val) { if(status == val) { status_name = key; return false; } }); if(this.chats[friend]) { var tab = this.chats[friend].data('tab'); var tab_class = 'imjs-tab'; if(tab.data('state') == 'active') tab_class += ' imjs-selected'; tab_class += ' imjs-' + status_name; tab.attr('class', tab_class); // display the status in the chatbox var date_stamp = $('.imjs-tab.imjs-default .imjs-chatbox .imjs-msglog .imjs-date').clone(); var date_stamp_time = date_stamp.find('.imjs-msg-time'); if(date_stamp_time.length) date_stamp_time.html(AjaxIM.dateFormat(date_stamp_time.html())); var date_stamp_date = date_stamp.find('.imjs-date-date').html( AjaxIM.i18n[ 'chat' + status_name[0].toUpperCase() + status_name.slice(1) ].replace(/%s/g, friend)); var msglog = this.chats[friend].find('.imjs-msglog'); date_stamp.appendTo(msglog); msglog[0].scrollTop = msglog[0].scrollHeight; } if(this.friends[friend]) { var friend_id = 'imjs-friend-' + $.md5(friend + this.friends[friend].group); $('#' + friend_id).attr('class', 'imjs-friend imjs-' + status_name); if(status == 0) { $('#' + friend_id + ':visible').slideUp(); $('#' + friend_id + ':hidden').hide(); } else if(!$('#' + friend_id + ':visible').length) { $('#' + friend_id).slideDown(); } this.friends[friend].status = [status, statusMessage]; this._updateFriendCount(); } }, // === //private// {{{AjaxIM.}}}**{{{_notConnected()}}}** === // // Puts the user into a visible state of disconnection. Sets the // friends list to "not connected" and empties it; disallows new messages // to be sent. _notConnected: function() { $('#imjs-friends').addClass('imjs-not-connected').unbind('click', this.activateTab); }, // === {{{AjaxIM.}}}**{{{send(to, message)}}}** === // // Sends a message to another user. The message will be added // to the chatbox before it is actually sent, however, if an // error occurs during sending, that will be indicated immediately // afterward. // // After sending the message, one of three status codes should be // returned as a JSON object, e.g. {{{{r: 'code'}}}}: // * {{{ok}}} — Message was sent successfully. // * {{{offline}}} — The user is offline or unavailable to // receive messages. // * {{{error}}} — a problem occurred, unrelated to the user // being unavailable. // // ==== Parameters ==== // * {{{to}}} is the username of the recipient. // * {{{message}}} is the content to be sent. send: function(to, message) { if(!message) return; if(this.chats[to]) { // REMOVE ME? // possibly add a datestamp var time = self._addDateStamp(this.chats[to]); this._storeNonMessage('datestamp', to, null, time); time = this._addMessage('a', this.chats[to], this.username, message); this._storeMessage('a', this.chats[to], this.username, message, time); } $(self).trigger('sendingMessage', [to, message]); AjaxIM.request( this.actions.send, {'to': to, 'message': message}, function(result) { switch(result.r) { case 'ok': $(self).trigger('sendMessageSuccessful', [to, message]); break; case 'offline': $(self).trigger('sendMessageFailed', ['offline', to, message]); break; case 'error': default: if(result.e == 'no session found') { self._notConnected(); self._addError(self.chats[to], AjaxIM.i18n.notConnected); self._storeNonMessage('error', to, AjaxIM.i18n.notConnected, (new Date()).getTime()); } $(self).trigger('sendMessageFailed', [result.e, to, message]); break; } }, function(error) { self._notConnected(); self._addError(self.chats[to], AjaxIM.i18n.notConnected); self._storeNonMessage('error', to, AjaxIM.i18n.notConnected, (new Date()).getTime()); $(self).trigger('sendMessageFailed', ['not connected', to, message]); } ); }, // === {{{AjaxIM.}}}**{{{status(s, message)}}}** === // // Sets the user's status and status message. It is possible to not // set a status message by setting it to an empty string. The status // will be sent to the server, where upon the server will broadcast // the update to all individuals with "you" on their friends list. // // ==== Parameters ==== // * {{{s}}} is the status code, as defined by {{{AjaxIM.statuses}}}. // * {{{message}}} is the custom status message. status: function(s, message) { // update status icon(s) if(!this.statuses[s]) return; $('#imjs-friends').attr('class', 'imjs-' + s); $(self).trigger('changingStatus', [s, message]); AjaxIM.request( this.actions.status, {'status': this.statuses[s], 'message': message}, function(result) { switch(result.r) { case 'ok': $(self).trigger('changeStatusSuccessful', [s, message]); break; case 'error': default: $(self).trigger('changeStatusFailed', [result.e, s, message]); break; } }, function(error) { $(self).trigger('changeStatusFailed', ['not connected', s, message]); } ); }, // === {{{AjaxIM.}}}**{{{statuses}}}** === // // These are the available status codes and their associated identities: // * {{{offline}}} (0) — Only used when signing out/when another // user has signed out, as once this status is set, the user is removed // from the server and friends will be unable to contact the user. // * {{{available}}} (1) — The user is online and ready to be messaged. // * {{{away}}} (2) — The user is online but is not available. Others // may still contact this user, however, the user may not respond. Anyone // contacting an away user will receive a notice stating that the user is away, // and (if one is set) their custom status message. // * {{{invisible}}} (3; **not yet implemented**) — The user is online, // but other users are made unaware, and the user will be represented // as being offline. It is still possible to contact this user, and for this // user to contact others; no status message or notice will be sent to others // messaging this user. statuses: {offline: 0, available: 1, away: 2, invisible: 3}, // == Footer bar == // // The footer bar is the bar that sits at the bottom of the page, in a fixed // position. It contains a tab for the friends list, and tabs for any open // chat boxes. It is also possible to add custom tabs for other functionality. bar: { // === {{{AjaxIM.}}}**{{{bar.initialize()}}}** === // // Setup the footer bar and enable tab actions. This function // uses {{{jQuery.live}}} to set hooks on any bar tabs created // in the future. initialize: function() { // Set up your standard tab actions $('.imjs-tab') .live('click', this.activateTab); $('.imjs-tab .imjs-close') .live('click', this.closeTab); // Set up the friends list actions var self = this; $(document).click(function(e) { if(e.target.id == 'imjs-friends' || $(e.target).parents('#imjs-friends').length) { return; } if($('#imjs-friends').data('state') == 'active') self.activateTab.call($('#imjs-friends')); }); $('#imjs-friends') .data('state', 'minimized') .click(function(e) { if(!$(this).hasClass('imjs-not-connected') && e.target.id != 'imjs-friends-panel' && !$(e.target).parents('#imjs-friends-panel').length) self.activateTab.call(this); }) .mouseenter(function() { if($(this).hasClass('imjs-not-connected')) { $('.imjs-tooltip').css('display', 'block'); $('.imjs-tooltip p').html(AjaxIM.i18n.notConnectedTip); var tip_left = $(this).offset().left - $('.imjs-tooltip').outerWidth() + ($(this).outerWidth() / 2); var tip_top = $(this).offset().top - $('.imjs-tooltip').outerHeight(true); $('.imjs-tooltip').css({ left: tip_left, top: tip_top }); } }) .mouseleave(function() { if($(this).hasClass('imjs-not-connected')) { $('.imjs-tooltip').css('display', ''); } }); $('#imjs-friends-panel') .data('tab', $('#imjs-friends')) .css('display', 'none'); }, // === {{{AjaxIM.}}}**{{{bar.activateTab()}}}** === // // Activate a tab by setting it to the 'active' state and // showing any related chatbox. If a chatbox is available // for this tab, also focus the input box. // // //Note:// {{{this}}}, here, refers to the tab DOM element. activateTab: function() { var chatbox = $(this).find('.imjs-chatbox') || false; if($(this).data('state') != 'active') { if($(this).attr('id') != 'imjs-friends') { $('#imjs-bar > li') .not($(this)) .not('#imjs-friends') .removeClass('imjs-selected') .each(function() { if($(this).data('state') != 'closed') { $(this).data('state', 'minimized'); var chatbox = $(this).find('.imjs-chatbox'); if(chatbox.length) chatbox.css('display', 'none'); } }); } if(chatbox && chatbox.css('display') == 'none') chatbox.css('display', ''); // set the tab to active... var tab = $(this).addClass('imjs-selected').data('state', 'active'); // ...and hide and reset the notification icon tab.find('.imjs-notification').css('display', 'none') .data('count', 0); if(self.settings.storageMethod && self.storageReady && chatbox && (username = chatbox.data('username'))) { $.jStore.store(self.storeKey + 'activeTab', [username]); } $(self).trigger('tabToggled', ['activated', tab]); } else { var tab = $(this).removeClass('imjs-selected').data('state', 'minimized'); if(chatbox && chatbox.css('display') != 'none') chatbox.css('display', 'none'); if(self.settings.storageMethod && self.storageReady) { $.jStore.store(self.storeKey + 'activeTab', ['*']); } $(self).trigger('tabToggled', ['minimized', tab]); } if(chatbox) { if(!(input = chatbox.find('.imjs-input')).data('height')) { // store the height for resizing later input.data('height', input.height()); } try { var msglog = chatbox.find('.imjs-msglog'); msglog[0].scrollTop = msglog[0].scrollHeight; } catch(e) {} try { chatbox.find('.imjs-input').focus(); } catch(e) {} } }, // === {{{AjaxIM.}}}**{{{bar.closeTab()}}}** === // // Close a tab and hide any related chatbox, such that // the chatbox can not be reopened without reinitializing // the tab. // // //Note:// {{{this}}}, here, refers to the tab DOM element. closeTab: function() { var tab = $(this).parents('.imjs-tab'); tab.css('display', 'none').data('state', 'closed'); if(self.settings.storageMethod && self.storageReady) { delete self.chatstore[tab.find('.imjs-chatbox').data('username')]; if(self.storageReady) $.jStore.store(self.storeKey + 'chats', self.chatstore); } $(self).trigger('tabToggled', ['closed', tab]); self.bar._scrollers(); return false; }, // === {{{AjaxIM.}}}**{{{bar.addTab(label, action, closable)}}}** === // // Adds a tab to the tab bar, with the label {{{label}}}. When // clicked, it will call a callback function, {{{action}}}. If // {{{action}}} is a string, it is assumed that the string is // referring to a chatbox ID. // // ==== Parameters ==== // * {{{label}}} is the text that will be displayed on the tab.\\ // * {{{action}}} is the callback function, if it is a non-chatbox // tab, or a string if it //is// a chatbox tab.\\ // * {{{closable}}} is a boolean value that determines whether or not // it is possible for a user to close this tab. // // //Note:// New tabs are given an automatically generated ID // in the format of {{{#imjs-tab-[md5 of label]}}}. addTab: function(label, action, closable) { var tab = $('.imjs-tab.imjs-default').clone().insertAfter('#imjs-scroll-right'); tab.removeClass('imjs-default') .attr('id', 'imjs-tab-' + $.md5(label)) .html(tab.html().replace('{label}', label)) .data('state', 'minimized'); var notification = tab.find('.imjs-notification'); notification.css('display', 'none') .data('count', 0) .data('default-text', notification.html()) .html(notification.html().replace('{count}', '0')); if(closable === false) tab.find('.imjs-close').eq(0).remove(); if(typeof action == 'string') { //tab.data('chatbox', action); } else { tab.find('.imjs-chatbox').remove(); tab.click(action); } return tab; }, // === {{{AjaxIM.}}}**{{{bar.notification(tab)}}}** === // // Displays a notification on a tab. Generally, this is called when // a tab is minimized to let the user know that there is an update // for them. The way the notification is displayed depends on the // theme CSS. // // ==== Parameters ==== // * {{{tab}}} is the jQuery-selected tab DOM element. notification: function(tab) { var notify = tab.find('.imjs-notification'); var notify_count = notify.data('count') + 1; notify.data('count', notify_count) .html(notify.data('default-text').replace('{count}', notify_count)) .css('display', ''); }, // === //private// {{{AjaxIM.}}}**{{{bar._scrollers()}}}** === // // Document me! _scrollers: function() { var needScrollers = false; $('.imjs-tab').filter(function() { return $(this).data('state') != 'closed' }).css('display', ''); $.each(self.chats, function(username, chatbox) { var tab = chatbox.data('tab'); if(tab.data('state') == 'closed') return true; if(tab.position().top > $('#imjs-bar').height()) { $('.imjs-scroll').css('display', ''); tab.css('display', 'none'); needScrollers = true; } else { tab.css('display', ''); } }); if(!needScrollers) { $('.imjs-scroll').css('display', 'none'); } if($('#imjs-scroll-left').css('display') != 'none' && $('#imjs-scroll-left').position().top > $('#imjs-bar').height()) { $('#imjs-bar li.imjs-tab:visible').slice(-1).css('display', 'none'); } var hiddenLeft = $('#imjs-bar li.imjs-tab:visible').slice(-1) .nextAll('#imjs-bar li.imjs-tab:hidden') .not('.imjs-default') .filter(function() { return $(this).data('state') != 'closed' }).length; var hiddenRight = $('#imjs-bar li.imjs-tab:visible').eq(0) .prevAll('#imjs-bar li.imjs-tab:hidden') .not('.imjs-default') .filter(function() { return $(this).data('state') != 'closed' }).length; $('#imjs-scroll-left').html(hiddenLeft); $('#imjs-scroll-right').html(hiddenRight); } }, // == Comet == // // Comet, or HTTP streaming, holds open a connection between the client and // the server indefinitely. As the server receives new messages or events, // they are passed down to the client in a {{{<script>}}} // tag which calls the {{{AjaxIM.incoming()}}} function. The connection is // opened using either an {{{iframe}}} (in Opera or Internet Explorer) or // an {{{XMLHTTPRequest}}} object. Due to the extra flexibility necessary // with the {{{XMLHTTPRequest}}} object, jQuery's {{{$.ajax}}} is not used. comet: { type: '', obj: null, onbeforeunload: null, onreadystatechange: null, iframe: function() { if(/loaded|complete/i.test(this.obj.readyState)) throw new Error("IM server not available!"); }, // === {{{AjaxIM.}}}**{{{comet.connect()}}}** === // // Creates and initializes the object and connection between the server // and the client. For Internet Explorer and Opera, we use an // {{{<iframe>}}} element; for all other browsers, we create an // {{{XMLHTTPRequest}}} object. The server connects to the URI defined // as the "poll" action. This function is called automatically, when // the IM engine is initialized and the {{{AjaxIM.poll()}}} function // is called. connect: function() { var self = _instance; if($.browser.opera || $.browser.msie) { var iframe = $(''); with(iframe) { css({ position: 'absolute', visibility: 'visible', display: 'block', left: '-10000px', top: '-10000px', width: '1px', height: '1px' }); attr('src', self.actions.poll[1]); appendTo('body'); bind('readystatechange', self.comet.onreadystatechange = function() { self.comet.iframe() }); bind('beforeunload', self.comet.onbeforeunload = function() { self.comet.disconnect() }); } self.comet.type = 'iframe'; self.comet.obj = iframe; } else { var xhr = new XMLHttpRequest; var length = 1029; var code = /^\s*]*>parent\.(.+);<\/script>$/; xhr.open('get', self.actions.poll[1], true); xhr.onreadystatechange = function(){ if(xhr.readyState > 2) { if(xhr.status == 200) { responseText = xhr.responseText.substring(length); length = xhr.responseText.length; if(responseText != ' ') eval(responseText.replace(code, "$1")); } // We need an "else" here. If the state changes to // "loaded", the user needs to know they're // disconnected. } }; self.comet.type = 'xhr'; self.comet.obj = xhr; addEventListener('beforeunload', self.comet.beforeunload = function() { self.comet.disconnect(); }, false); setTimeout(function() { xhr.send(null) }, 10); } }, // === {{{AjaxIM.}}}**{{{comet.disconnect()}}}** === // // Disconnect from the server and destroy the connection object. This // function is called before the page unloads, so that we plug up and // potential leaks and free memory. disconnect: function() { var self = _instance.comet; if(!this.type || !this.obj) return; if(this.type == 'iframe') { detachEvent('onreadystatechange', this.onreadystatechange); detachEvent('onbeforeunload', this.onbeforeunload); this.obj.src = '.'; $(this.obj).remove(); } else { removeEventListener('beforeunload', this.onbeforeunload, false); this.obj.onreadystatechange = function(){}; this.obj.abort(); } delete this.obj; } } }) self.bar.initialize(); if(prequeue.length) { $.each(prequeue, function() { var func = this[0].split('.'); if(func.length > 1) self[func[0]][func[1]].apply(self, this[1]); else self[func[0]].apply(self, this[1]); }); } }); // == Static functions and variables == // // The following functions and variables are available outside of an initialized // {{{AjaxIM}}} object. // === {{{AjaxIM.}}}**{{{client}}}** === // // Once {{{AjaxIM.init()}}} is called, this will be set to the active AjaxIM // object. Only one AjaxIM object instance can exist at a time. This variable // can and should be accessed directly. AjaxIM.client = null; // === {{{AjaxIM.}}}**{{{init(options, actions)}}}** === // // Initialize the AjaxIM client object and engine. Here, you can define your // options and actions as outlined at the top of this documentation. // // ==== Parameters ==== // * {{{options}}} is the hash of custom settings to initialize Ajax IM with. // * {{{actions}}} is the hash of any custom action URLs. AjaxIM.init = function(options, actions) { if(!_instance) { _instance = new AjaxIM(options, actions); AjaxIM.client = _instance; } return _instance; } // === {{{AjaxIM.}}}**{{{request(url, data, successFunc, failureFunc)}}}** === // // Wrapper around {{{$.jsonp}}}, the JSON-P library for jQuery, and {{{$.ajax}}}, // jQuery's ajax library. Allows either function to be called, automatically, // depending on the request's URL array (see {{{AjaxIM.actions}}}). // // ==== Parameters ==== // {{{url}}} is the URL of the request. // {{{data}}} are any arguments that go along with the request. // {{{success}}} is a callback function called when a request has completed // without issue. // {{{_ignore_}}} is simply to provide compatability with {{{$.post}}}. // {{{failure}}} is a callback function called when a request hasn't not // completed successfully. AjaxIM.request = function(url, data, successFunc, failureFunc) { if(typeof failureFunc != 'function'); failureFunc = function(){}; $[url[0]]({ 'url': url[1], 'data': data, dataType: (url[0] == 'ajax' ? 'json' : 'jsonp'), type: 'POST', cache: false, timeout: 60000, callback: 'jsonp' + (new Date()).getTime(), success: function(json, textStatus) { successFunc(json); }, error: function(xOptions, error) { failureFunc(error); } }); // This prevents Firefox from spinning indefinitely // while it waits for a response. Why? Fuck if I know. if(url[0] == 'jsonp' && $.browser.mozilla) { $.jsonp({ 'url': 'about:', timeout: 0 }); } }; // === {{{AjaxIM.}}}**{{{incoming(data)}}}** === // // Never call this directly. It is used as a connecting function between // client and server for Comet. // // //Note:// There are two {{{AjaxIM.incoming()}}} functions. This one is a // static function called outside of the initialized AjaxIM object; the other // is only called within the initalized AjaxIM object. AjaxIM.incoming = function(data) { if(!_instance) return false; if(data.length) _instance._parseMessages(data); } // === {{{AjaxIM.}}}**{{{loaded}}}** === // // If Ajax IM has been loaded with the im.load.js file, this function will be // called when the library is finally loaded and ready for use. Similar to // jQuery's $(document).ready(), but for Ajax IM. AjaxIM.loaded = function() { if(typeof AjaxIMLoadedFunction == 'function') { AjaxIMLoadedFunction(); delete AjaxIMLoadedFunction; // clean up the global namespace } }; // === {{{AjaxIM.}}}**{{{dateFormat([date,] [mask,] utc)}}}** === // // Date Format 1.2.3\\ // © 2007-2009 Steven Levithan ([[http://blog.stevenlevithan.com/archives/date-time-format|stevenlevithan.com]])\\ // MIT license // // Includes enhancements by Scott Trenda // and Kris Kowal ([[http://cixar.com/~kris.kowal/|cixar.com/~kris.kowal/]]) // // Accepts a date, a mask, or a date and a mask and returns a formatted version // of the given date. // // ==== Parameters ==== // * {{{date}}} is a {{{Date()}}} object. If not specified, the date defaults to the // current date/time. // * {{{mask}}} is a string that defines the formatting of the date. Formatting // options can be found in the // [[http://blog.stevenlevithan.com/archives/date-time-format|Date Format]] // documentation. If not specified, the mask defaults to {{{dateFormat.masks.default}}}. AjaxIM.dateFormat = function () { var token = /d{1,4}|m{1,4}|yy(?:yy)?|([HhMsTt])\1?|[LloSZ]|"[^"]*"|'[^']*'/g, timezone = new RegExp('\b(?:[PMCEA][SDP]T|(?:Pacific|Mountain|Central|Eastern|Atlantic) ' + '(?:Standard|Daylight|Prevailing) Time|(?:GMT|UTC)(?:[-+]\d{4})?)\b', 'g'), timezoneClip = /[^-+\dA-Z]/g, pad = function (val, len) { val = String(val); len = len || 2; while (val.length < len) val = "0" + val; return val; }; // Regexes and supporting functions are cached through closure return function (date, mask, utc) { var dF = AjaxIM.dateFormat; // You can't provide utc if you skip other args (use the "UTC:" mask prefix) if (arguments.length == 1 && Object.prototype.toString.call(date) == "[object String]" && !/\d/.test(date)) { mask = date; date = undefined; } // Passing date through Date applies Date.parse, if necessary date = date ? new Date(date) : new Date; if (isNaN(date)) throw SyntaxError("invalid date"); mask = String(dF.masks[mask] || mask || dF.masks["default"]); // Allow setting the utc argument via the mask if (mask.slice(0, 4) == "UTC:") { mask = mask.slice(4); utc = true; } var _ = utc ? "getUTC" : "get", d = date[_ + "Date"](), D = date[_ + "Day"](), m = date[_ + "Month"](), y = date[_ + "FullYear"](), H = date[_ + "Hours"](), M = date[_ + "Minutes"](), s = date[_ + "Seconds"](), L = date[_ + "Milliseconds"](), o = utc ? 0 : date.getTimezoneOffset(), flags = { d: d, dd: pad(d), ddd: AjaxIM.i18n.dayNames[D], dddd: AjaxIM.i18n.dayNames[D + 7], m: m + 1, mm: pad(m + 1), mmm: AjaxIM.i18n.monthNames[m], mmmm: AjaxIM.i18n.monthNames[m + 12], yy: String(y).slice(2), yyyy: y, h: H % 12 || 12, hh: pad(H % 12 || 12), H: H, HH: pad(H), M: M, MM: pad(M), s: s, ss: pad(s), l: pad(L, 3), L: pad(L > 99 ? Math.round(L / 10) : L), t: H < 12 ? "a" : "p", tt: H < 12 ? "am" : "pm", T: H < 12 ? "A" : "P", TT: H < 12 ? "AM" : "PM", Z: utc ? "UTC" : (String(date).match(timezone) || [""]) .pop().replace(timezoneClip, ""), o: (o > 0 ? "-" : "+") + pad(Math.floor(Math.abs(o) / 60) * 100 + Math.abs(o) % 60, 4), S: ["th", "st", "nd", "rd"][d % 10 > 3 ? 0 : (d % 100 - d % 10 != 10) * d % 10] }; return mask.replace(token, function ($0) { return $0 in flags ? flags[$0] : $0.slice(1, $0.length - 1); }); }; }(); // Some common format strings AjaxIM.dateFormat.masks = { "default": "ddd mmm dd yyyy HH:MM:ss", shortDate: "m/d/yy", mediumDate: "mmm d, yyyy", longDate: "mmmm d, yyyy", fullDate: "dddd, mmmm d, yyyy", shortTime: "h:MM TT", mediumTime: "h:MM:ss TT", longTime: "h:MM:ss TT Z", isoDate: "yyyy-mm-dd", isoTime: "HH:MM:ss", isoDateTime: "yyyy-mm-dd'T'HH:MM:ss", isoUtcDateTime: "UTC:yyyy-mm-dd'T'HH:MM:ss'Z'" }; // === {{{AjaxIM.}}}**{{{i18n}}}** === // // Text strings used by Ajax IM. Should you want to translate Ajax IM into // another language, merely change these strings. // // {{{%s}}} denotes text that will be automatically replaced when the string is // used. AjaxIM.i18n = { dayNames: [ "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday" ], monthNames: [ "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December" ], chatOffline: '%s signed off.', chatAvailable: '%s became available.', chatAway: '%s went away.', notConnected: 'You are currently not connected or the server is not available. ' + 'Please ensure that you are signed in and try again.', notConnectedTip: 'You are currently not connected.', authInvalid: 'Invalid username or password.', registerPasswordLength: 'Passwords must be more than 4 characters in length.', registerUsernameLength: 'Usernames must be more than 2 characters in length and ' + ' contain only A-Z, a-z, 0-9, underscores (_) and periods (.).', registerPasswordMatch: 'Entered passwords do not match.', registerUsernameTaken: 'The chosen username is already in use; please choose another.', registerUnknown: 'An unknown error occurred. Please try again.' } })(jQuery, false); \ No newline at end of file +// = im.js = // // **Copyright © 2005 – 2010 Joshua Gross**\\ // //MIT Licensed// // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. // // This is the main library for Ajax IM. It encompasses the UI controls, // and connecting with the server. It does //not// handle registration or // account management. (function($, _instance) { AjaxIM = function(options, actions) { if(this instanceof AjaxIM) { var self = this; // === {{{ defaults }}} === // // These are the available settings for Ajax IM, and the associated // defaults: // // * {{{pollType}}} determines the way in which the client will talk to // the server. // ** {{{comet}}} will use http streaming, wherein a connection to the server will be held open indefinitely, and the server will push down new events (messages, status updates) as they occur. // ** {{{long}}} will hold open a connection with the server for as long as possible, or until a new event is received. Upon the server sending an event or closing the connection, the client will automatically—and immediately—reconnect. // ** {{{short}}} will open a connection, and the server (if this method is supported) will //immediately// provide a response as to whether or not there are any new events. Once a response is received, the client will wait 5 seconds, and then reconnect. // * {{{pollServer}}} is the default URL to which all actions refer. It is // possible to specify certain action URLs separately (as is used with the // NodeJS server). // * {{{cookieName}}} is the name of the session cookie used by the server. // If this is not set properly, the IM engine will not be able to automatically // reinitialize sessions. // * {{{theme}}} is the name of the theme folder that defines the HTML and // CSS of the IM bar and chat boxes. Usually, themes are deposited in the // provided "themes" folder and specified by that path, e.g. {{{themes/default}}}. // Theme files within the theme folder must be named {{{theme.html}}} and // {{{theme.css}}}. // * {{{storageMethod}}} defines the way in which data (chat sessions) are // temporarily stored client-side. By default, {{{"flash"}}} is used because // it is the most widely supported method. However, // [[http://eric.garside.name/docs.html?p=jstore#js-engines|other storage engines]] // are available, with their respective up- and down-sides // outlined, on the jStore website. // * {{{storeSession}}} (**not implemented**) sets the number of days to // retain stored chat session data before it should be deleted. // * {{{checkResume}}} is a flag that sets whether or not the client should // make a call to the server before resuming the session (such as on a page // reload). This will ensure that the session has not expired. If set to {{{false}}}, // a call to the server will not be made, and the session will be assumed to // be active. var defaults = { pollType: 'long', pollServer: './ajaxim.php', cookieName: 'ajaxim_session', theme: 'themes/default', storageMethod: 'auto', flashStorage: 'js/jStore.Flash.html', storeSession: 5, // number of days to store chat data (0 for current session only) checkResume: true }; // === {{{AjaxIM.}}}**{{{settings}}}** === // // These are the settings for the IM. If particular options are not specified, // the defaults (see above) will be used. //These options will be defined // upon calling the initialization function, and not set directly.// this.settings = $.extend(defaults, options); // === {{{AjaxIM.}}}**{{{actions}}}** === // // Each individual action that the IM engine can execute is predefined here. // By default, it merely appends the action onto the end of the {{{pollServer}}} url, // however, it is possible to define actions individually. //The alternative actions // will be defined upon calling the initialization function, and not set directly.// // // Should you define an action at a different URL, Ajax IM will determine whether // or not this URL is within the current domain. If it is within a subdomain of // the current domain, it will set the document.domain variable for you, // to match a broader hostname scope; the action will continue to use {{{$.post}}} // (the default AJAX method for Ajax IM). // // On the other hand, should you choose a URL outside the current domain // Ajax IM will switch to {{{$.getJSON}}} (a get request) to avoid // cross-domain scripting issues. This means that a server on a different // port or at a different address will need to be able to handle GET // requests rather than POST requests (such as how the Node.JS Ajax IM // server works). this.actions = $.extend({ login: this.settings.pollServer + '/login', logout: this.settings.pollServer + '/logout', register: this.settings.pollServer + '/register', poll: this.settings.pollServer + '/poll?method=' + this.settings.pollType, send: this.settings.pollServer + '/send', status: this.settings.pollServer + '/status', resume: this.settings.pollServer + '/resume' }, actions); var httpRx = new RegExp('^http://', 'i'), slashslashRx = new RegExp('^//', 'i'), queryStrRx = new RegExp('[?](.+)$'), subdomainRx = new RegExp('((http[s]?:)?//)?(.+?)[.]' + window.location.host, 'i'); $.each(this.actions, function(name, action) { if(name == 'poll' || name == 'send') { if(self.settings.pollType != 'comet') action += (queryStrRx.test(action[1]) ? '&' : '?') + 'callback=?'; action = ['jsonp', action]; } else { action = ['ajax', action]; if(subdomainRx.test(action[1])) { document.domain = '.' + window.location.host; } else if((http = httpRx.test(action[1])) || slashslashRx.test(action[1])) { if(!(new RegExp('//' + window.location.host + '/', 'i')).test(action[1])) { action[1] += (queryStrRx.test(action[1]) ? '&' : '?') + 'callback=?'; action = ['jsonp', action[1]]; } } } self.actions[name] = action; }); // We load the theme dynamically based on the passed // settings. If the theme is set to false, we assume // that the user is going to load it himself. this.themeLoaded = false; if(this.settings.theme) { $('
    ').appendTo('body').load(this.settings.theme + '/theme.html #imjs-bar, .imjs-tooltip', function() { self.themeLoaded = true; setup.apply(self); } ); if(typeof document.createStyleSheet == 'function') document.createStyleSheet(this.settings.theme + '/theme.css'); else $('body').append(''); } else { this.themeLoaded = true; setup.apply(this); } // Client-side storage for keeping track of // conversation states, active tabs, etc. // The default is flash storage, however, other // options are available via the jStore library. if(this.settings.storageMethod) { this.storageBrowserKey = 'unknown'; this.storeKey = ''; $.each($.browser, function(k, v) { if(k == 'version') return true; else if(v == true) { self.storageBrowserKey = k; return false; } }); if(this.settings.storageMethod == 'auto') { $.each(['ie', 'html5', 'local', 'flash'], function() { if($.jStore.Availability[this]()) { self.settings.storageMethod = this; return false; } }); } $.extend($.jStore.defaults, { project: 'im.js', engine: this.settings.storageMethod, flash: this.settings.flashStorage }); this.storageReady = false; if(this.settings.storageMethod == 'flash') { $.jStore.ready(function(engine) { $.jStore.flashReady(function() { self.storageReady = true; setup.apply(self); }); }) } else { $.jStore.ready(function(engine) { self.storageReady = true; setup.apply(self); }); } $.jStore.load(); } else { this.storageReady = true; setup.apply(this); } // Allow a chatbox to me minimized $('.imjs-chatbox').live('click', function(e) { e.preventDefault(); return false; }); $('.imjs-chatbox .imjs-minimize').live('click', function() { $(this).parents('.imjs-chatbox').data('tab').click(); }); // Allow a chatbox to be closed $('.imjs-chatbox .imjs-close').live('click', function() { var chatbox = $(this).parents('.imjs-chatbox'); chatbox.data('tab') .data('state', 'closed').css('display', 'none'); if(self.settings.storageMethod && self.storageReady) { delete self.chatstore[chatbox.data('username')]; if(self.storageReady) { $.jStore.store( self.storageBrowserKey + '-' + self.username + '-chats', self.chatstore); } } }); // Setup message sending for all chatboxes $('.imjs-chatbox .imjs-input').live('keydown', function(event) { var obj = $(this); if(event.keyCode == 13 && !($.browser.msie && $.browser.version < 8)) { self.send(obj.parents('.imjs-chatbox').data('username'), obj.val()); } }).live('keyup', function(event) { if(event.keyCode == 13) { if($.browser.msie && $.browser.version < 8) { var obj = $(this); self.send(obj.parents('.imjs-chatbox').data('username'), obj.val()); } var obj = $(this); obj.val(''); obj.height(obj.data('height')); } }).live('keypress', function(e) { var obj = $(this); if(!($.browser.msie && $.browser.opera)) obj.height(0); if(this.scrollHeight > obj.height() || this.scrollHeight < obj.height()) { obj.height(this.scrollHeight); } }); $('.imjs-msglog').live('click', function() { var chatbox = $(this).parents('.imjs-chatbox'); chatbox.find('.imjs-input').focus(); }); // Create a chatbox when a buddylist item is clicked $('.imjs-friend').live('click', function() { var chatbox = self._createChatbox($(this).data('friend')); if(chatbox.data('tab').data('state') != 'active') chatbox.data('tab').click(); chatbox.find('.imjs-input').focus(); }); // Setup and hide the scrollers $('.imjs-scroll').css('display', 'none'); $('#imjs-scroll-left').live('click', function() { var hiddenTab = $('#imjs-bar li.imjs-tab:visible').slice(-1) .next('#imjs-bar li.imjs-tab:hidden') .filter(function() { return $(this).data('state') != 'closed' }) .not('.imjs-default').slice(-1).css('display', ''); if(hiddenTab.length) { $('#imjs-bar li.imjs-tab:visible').eq(0).css('display', 'none'); $(this).html(parseInt($(this).html()) - 1); $('#imjs-scroll-right').html(parseInt($('#imjs-scroll-right').html()) + 1); } return false; }); $('#imjs-scroll-right').live('click', function() { var hiddenTab = $('#imjs-bar li.imjs-tab:visible').eq(0) .prev('#imjs-bar li.imjs-tab:hidden') .filter(function() { return $(this).data('state') != 'closed' }) .not('.imjs-default').slice(-1).css('display', ''); if(hiddenTab.length) { $('#imjs-bar li.imjs-tab:visible').slice(-1).css('display', 'none'); $(this).html(parseInt($(this).html()) - 1); $('#imjs-scroll-left').html(parseInt($('#imjs-scroll-left').html()) + 1); } return false; }); // Initialize the chatbox hash this.chats = {}; // Try to resume any existing session this.resume(); $(window).resize(function() { self.bar._scrollers(); }); } else return AjaxIM.init(options); }; // We predefine all public functions here... // If they are called before everything (theme, storage engine) has loaded, // then they get put into a "prequeue" and run when everything *does* // finally load. // // This ensures that nothing loads without all of the principal components // being pre-loaded. If that were to occur (without this prequeue), things // would surely break. var prequeue = []; var empty = function() { var func = this; return function() { prequeue.push([func, arguments]) }; }; $.extend(AjaxIM.prototype, { settings: {}, friends: {}, chats: {}, storage: empty.apply('storage'), login: empty.apply('login'), logout: empty.apply('logout'), resume: empty.apply('resume'), form: empty.apply('form'), poll: empty.apply('poll'), incoming: empty.apply('incoming'), send: empty.apply('send'), status: empty.apply('status'), statuses: {}, bar: { initialize: empty.apply('bar.initialize'), activateTab: empty.apply('bar.activateTab'), closeTab: empty.apply('bar.closeTab'), addTab: empty.apply('bar.addTab'), notification: empty.apply('bar.notification'), _scrollers: empty.apply('bar._scrollers') } }); setup = (function() { var self = this; if(!this.storageReady || !this.themeLoaded) return; $(self).trigger('loadComplete'); $(window).resize(); $.extend(AjaxIM.prototype, { // == Cookies == // // The "cookies" functions can be used to set, get, and erase JSON-based cookies. // These functions are primarily used to manage and read the server-set cookie // that handles the user's chat session ID. cookies: { // === {{{AjaxIM.}}}**{{{cookies.set(name, value, days)}}}** === // // Sets a cookie, stringifying the JSON value upon storing it. // // ==== Parameters ==== // * {{{name}}} is the cookie name.\\ // * {{{value}}} is the cookie data that you would like to store.\\ // * {{{days}}} is the number of days that the cookie will be stored for. set: function(name, value, days) { if (days) { var date = new Date(); date.setTime(date.getTime() + (days * 24 * 60 * 60 * 1000)); var expires = "; expires=" + date.toGMTString(); } else var expires = ""; document.cookie = name + "=" + $.compactJSON(value) + expires + "; path=/"; }, // === {{{AjaxIM.}}}**{{{cookies.get(name)}}}** === // // Gets a cookie, decoding the JSON value before returning the data. // // ==== Parameters ==== // * {{{name}}} is the cookie name that you would like to retrieve. get: function(name) { var nameEQ = name + "="; var ca = document.cookie.split(';'); for(var i = 0; i < ca.length; i++) { var c = ca[i]; while (c.charAt(0) == ' ') c = c.substring(1, c.length); if (c.indexOf(nameEQ) == 0) { var cval = decodeURIComponent(c.substring(nameEQ.length, c.length)); return $.secureEvalJSON(cval); } } return null; }, // === {{{AjaxIM.}}}**{{{cookies.erase(name)}}}** === // // Deletes a cookie. // // {{{name}}} is the existing cookie that you would like to delete. erase: function(name) { self.cookies.set(name, '', -1); } }, // == Main == // === {{{AjaxIM.}}}**{{{storage()}}}** === // // Retrieves chat session data from whatever storage engine is enabled // (provided that one is enabled at all). If a page reloads, this function // is called to restore the user's chat state (existing conversations, active tab). // This function is called //automatically//, upon initialization of the IM engine. storage: function() { if(!self.storeKey.length) return; try { var chatstore = $.jStore.store(self.storeKey + 'chats') || {}; } catch(e) { $.jStore.remove(self.storeKey + 'chats'); var chatstore = {}; } if(this.chatstore) { $.each(this.chatstore, function(username, convo) { if(username in chatstore) chatstore[username] = $.merge(chatstore[username], self.chatstore[username]); else chatstore[username] = self.chatstore[username]; }); this.chatstore = chatstore; $.jStore.store(self.storeKey + 'chats', chatstore); } else { this.chatstore = chatstore; } $.each(this.chatstore, function(username, convo) { if(!convo.length) return; var chatbox = self._createChatbox(username, true); chatbox.data('lastDateStamp', null).css('display', 'none'); // Remove the automatic date stamp chatbox.find('.imjs-msglog').empty(); // Restore all messages, date stamps, and errors $.each(convo, function() { switch(this[0]) { case 'error': self._addError(chatbox, decodeURIComponent(this[2]), this[3]); break; case 'datestamp': self._addDateStamp(chatbox, this[3]); break; case 'a': case 'b': self._addMessage(this[0], chatbox, this[1], decodeURIComponent(this[2]), this[3]); break; } }); $(self).trigger('chatRestored', [username, chatbox]); }); var activeTab = $.jStore.store(self.storeKey + 'activeTab') || []; if(activeTab.length && (activeTab = activeTab[0]) && activeTab in this.chats) { this.chats[activeTab].data('tab').click(); var msglog = this.chats[activeTab].find('.imjs-msglog'); msglog[0].scrollTop = msglog[0].scrollHeight; } }, // === {{{AjaxIM.}}}**{{{login(username, password)}}}** === // // Authenticates a user and initializes the IM engine. If the user is // already logged in, [s]he is logged out, the session is cleared, and // the new user is logged in. // // Returns the user's properly formatted username, session ID, and online // friends in JSON, if successful; e.g.:\\ // {{{ {u: 'username', s: 'longsessionid', f: [{u: 'friend', s: 1, g: 'group'}]} }}} // // If unsuccessful, {{{false}}} is returned. // // ==== Parameters ==== // * {{{username}}} is the user's username.\\ // * {{{password}}} is the user's password. This password will be MD5 hashed // before it is sent to the server. login: function(username, password) { if(!username) username = ''; if(!password) password = ''; if(this.username) return true; // Already logged in! // hash password before sending it to the server password = $.md5(password); // authenticate AjaxIM.request( this.actions.login, {'username': username, 'password': password}, function(auth) { if(auth.r == 'logged in') { self.username = ('u' in auth ? auth.u : username); if(self.settings.storageMethod) self.storeKey = [self.storageBrowserKey, self.username, ''].join('-'); var existing = self.cookies.get(self.settings.cookieName); self.storage(); // Begin the session $.each(auth.f, function() { self.friends[this.u] = {status: [this.s, ''], group: this.g}; }); self._session(self.friends); self._storeFriends(); $(self).trigger('loginSuccessful', [auth]); return auth; } else { $(self).trigger('loginError', [auth]); } return false; } ); }, // === {{{AjaxIM.}}}**{{{logout()}}}** === // // Logs the user out and removes his/her session cookie. As well, it // will close all existing chat windows, clear the storage engine, and // remove the IM bar. logout: function() { AjaxIM.request( this.actions.logout, {}, function(done) { if(done) { self.cookies.erase(self.settings.cookieName); self._clearSession(); $(self).trigger('logoutSuccessful'); return true; } else { $(self).trigger('logoutError'); return false; } } ); }, // === {{{AjaxIM.}}}**{{{resume()}}}** === // // Resumes an existing session based on a session ID stored in the // server-set cookie. This function is called //automatically// upon IM // engine (re-)initialization, so the user does not need to re-login // should a session already exist. resume: function() { var session = this.cookies.get(this.settings.cookieName); if(session && session.sid) { this.username = session.user; this.storeKey = [this.storageBrowserKey, this.username, ''].join('-'); var friends = $.jStore.store(this.storeKey + 'friends') || []; if(self.settings.checkResume) { AjaxIM.request( this.actions.resume, {}, function(response) { if(response.r == 'connected') { self._session(friends); self.storage(); } else { var username = this.username; self._clearSession(); $(self).trigger('sessionNotResumed', [username]); } } ); } else { self._session(friends); self.storage(); } } else { $(self).trigger('noSession'); } }, // === //private// {{{AjaxIM.}}}**{{{_session(friends)}}}** === // // Restores session data (username, friends) and begins polling the server. // Called only by {{{AjaxIM.resume()}}}. // // ==== Parameters ==== // * {{{friends}}} is a list of "friend" objects, e.g.:\\ // {{{[{u: 'friend', s: 1, g: 'group'}, ...]}}} // ** {{{u}}} being the friend's username. // ** {{{s}}} being one of the available status codes (see {{{AjaxIM.statuses}}}), depending on the friend's current status. // ** {{{g}}} being the group that the friend is in. _session: function(friends) { $('#imjs-friends-panel .imjs-header span').html(this.username); $('#imjs-friends').removeClass('imjs-not-connected'); $.each(friends, function(friend, info) { self.addFriend.apply(self, [friend, info.status, info.group]); }); self._storeFriends(); $(self).trigger('sessionResumed', [this.username]); setTimeout(function() { self.poll(); }, 0); }, // === //private// {{{AjaxIM.}}}**{{{_clearSession()}}}** === // // Clears all session data from the last known user. _clearSession: function() { if(self.settings.storageMethod && self.storageReady) { $.jStore.remove(self.storeKey + 'chats'); $.jStore.remove(self.storeKey + 'friends'); $.jStore.remove(self.storeKey + 'activeTab'); } self.chats = {}; $('.imjs-tab').not('.imjs-tab.imjs-default').remove(); self.cookies.erase('ajaxim_session'); delete self.username; }, // === {{{AjaxIM.}}}**{{{form(element)}}}** === // // Loads a login and registration form into the specified element // or, if no element is supplied, to the location on the page from // which this function was called. form: function(element) { $(element).load(this.settings.theme + '/theme.html #imjs-lr', function() { $('#imjs-lr .error').hide(); if(self.username) { $('#imjs-register, #imjs-login fieldset').hide(); $('#imjs-logged-in') .show() .html($('#imjs-logged-in').html().replace('{username}', self.username)); } else { $('#imjs-logged-in').hide(); } // Handle logout success $(self).bind('logoutSuccessful', function() { $('#imjs-login fieldset').slideDown(); $('#imjs-register').slideDown(); $('#imjs-logged-in') .html($('#imjs-logged-in strong').html('{username}')) .slideUp(); }); $('#imjs-logged-in a').click(function() { self.logout(); return false; }); // Handle login error or success $(self).bind('loginError', function() { $('#imjs-login .error').html(AjaxIM.i18n.authInvalid).slideDown('fast'); $('#imjs-login input') .addClass('imjs-lr-error') .blur(function() { $(this).removeClass('imjs-lr-error'); }); }).bind('loginSuccessful', function() { $('#imjs-login fieldset').slideUp(); $('#imjs-register').slideUp(); $('#imjs-logged-in') .html($('#imjs-logged-in').html().replace('{username}', self.username)) .slideDown(); }); var login = function() { self.login($('#imjs-login-username').val(), $('#imjs-login-password').val()); return false; }; $('#imjs-login').submit(login); $('#imjs-login-submit').click(login); var regIssues = false; var regError = function(error, fields) { $('#imjs-register .error') .append(AjaxIM.i18n['register' + error] + ' ') .slideDown(); $(fields) .addClass('imjs-lr-error') .blur(function() { $(this).removeClass('imjs-lr-error'); }); regIssues = true; }; var register = function() { $('#imjs-register .error').empty(); regIssues = false; var username = $('#imjs-register-username').val(); var password = $('#imjs-register-password').val(); if(password.length < 4) regError('PasswordLength', '#imjs-register-password'); if(password != $('#imjs-register-cpassword').val()) regError('PasswordMatch', '#imjs-register-password, #imjs-register-cpassword'); if(username.length <= 2 || !$('#imjs-register-username').val().match(/^[A-Za-z0-9_.]+$/)) regError('UsernameLength', '#imjs-register-username'); if(!regIssues) { AjaxIM.request( self.actions.register, {username: username, password: password}, function(response) { if(response.r == 'registered') { self.login(username, password); } else if(response.r == 'error') { switch(response.e) { case 'unknown': regError('Unknown', ''); break; case 'invalid password': regError('PasswordLength', '#imjs-register-password'); break; case 'invalid username': regError('UsernameLength', '#imjs-register-username'); break; case 'username taken': regError('UsernameTaken', '#imjs-register-username'); break; } } }, function(error) { regError('Unknown', ''); } ); } return false; }; $('#imjs-register').submit(register); $('#imjs-register-submit').click(register); }); }, // === {{{AjaxIM.}}}**{{{poll()}}}** === // // Queries the server for new messages. If a 'long' or 'short' poll // type is used, jQuery's {{{$.post}}} or {{{$.getJSON}}} will be // used. If 'comet' is used, the server connection will be deferred // to the comet set of functions. poll: function() { if(/^(short|long)$/.test(this.settings.pollType)) { AjaxIM.request( this.actions.poll, {}, function(response) { if(!response['e']) { if(response.length) self._parseMessages(response); setTimeout(function() { self.poll(); }, 0); } else { switch(response.e) { case 'no session found': self._notConnected(); break; } $(self).trigger('pollFailed', [response.e]); } }, function(error) { self._notConnected(); $(self).trigger('pollFailed', ['not connected']); // try reconnecting? } ); } else if(this.settings.pollType == 'comet') { this.comet.connect(); } }, // === //private// {{{AjaxIM.}}}**{{{_parseMessages(messages)}}}** === // // Handles an incoming message array:\\ // {{{[{t: 'type', s: 'sender', r: 'recipient', m: 'message'}, ...]}}} // // * {{{t}}} (message type) is one of: // ** {{{m}}} — a standard message // ** {{{s}}} — a user's status update // ** {{{b}}} — a broadcasted message (sent to many users simultaneously) // * {{{s}}} is the sender of the message. // * {{{r}}} is the intended recipient of the message. Most of the time, this will // simply be the logged in user, however, a broadcasted message may not specify // a recipient or may specify a different recipient. Also provides future // compatability for chatrooms. // * {{{m}}} is the actual message. For something such as a status update, this can // be a JSON object or parsable string; e.g. {{{"2:I'm away."}}} // // ==== Parameters ==== // * {{{messages}}} is the message array _parseMessages: function(messages) { if($.isArray(messages)) { $.each(messages, function() { $(self).trigger('parseMessage', [this]); switch(this.t) { case 'm': self.incoming(this.s, this.m); break; case 's': var status = this.m.split(':'); if(this['g']) self.addFriend(this.s, status, this.g); self._friendUpdate(this.s, status[0], status.slice(1).join(':')); self._storeFriends(); break; case 'b': break; default: break; } }); } }, // === {{{AjaxIM.}}}**{{{incoming(from, message)}}}** === // // Handles a new message from another user. If a chatbox for that // user does not yet exist, one is created. If it does exist, but // is minimized, the user is notified but the chatbox is not brought // to the front. This function also stores the message, if a storage // method is set. // // ==== Parameters ==== // * {{{from}}} is the username of the sender. // * {{{message}}} is the body. incoming: function(from, message) { // check if IM exists, otherwise create new window // TODO: If friend is not on the buddylist, // should add them to a temp list? var chatbox = this._createChatbox(from); if(!$('#imjs-bar .imjs-selected').length) { chatbox.data('tab').click(); } else if(chatbox.data('tab').data('state') != 'active') { this.bar.notification(chatbox.data('tab')); } var time = this._addMessage('b', chatbox, from, message); this._storeMessage('b', chatbox, from, message, time); }, // === {{{AjaxIM.}}}**{{{addFriend(username, group)}}}** === // // Inserts a new friend into the friends list. If the group specified // doesn't exist, it is created. If the friend is already in this group, // they aren't added again, however, the friend item is returned. // // ==== Parameters ==== // * {{{username}}} is the username of the new friend. // * {{{status}}} is the current status of the friend. // * {{{group}}} is the user group to which the friend should be added. addFriend: function(username, status, group) { var status_name = 'available'; $.each(this.statuses, function(key, val) { if(status[0] == val) { status_name = key; return false; } }); var group_id = 'imjs-group-' + $.md5(group); if(!(group_item = $('#' + group_id)).length) { var group_item = $('.imjs-friend-group.imjs-default').clone() .removeClass('imjs-default') .attr('id', group_id) .data('group', group) .appendTo('#imjs-friends-list'); var group_header = group_item.find('.imjs-friend-group-header'); group_header.html(group_header.html().replace('{group}', group)); } var user_id = 'imjs-friend-' + $.md5(username + group); if(!$('#' + user_id).length) { var user_item = group_item.find('ul li.imjs-default').clone() .removeClass('imjs-default') .addClass('imjs-' + status_name) .attr('id', user_id) .data('friend', username) .appendTo(group_item.find('ul')); if(status[0] == 0) user_item.hide(); user_item.html(user_item.html().replace('{username}', username)); } this.friends[username] = {'status': status, group: group}; this._updateFriendCount(); return this.friends[username]; }, // === //private// {{{AjaxIM.}}}**{{{_updateFriendCount()}}}** === // // Counts the number of online friends and updates the friends count // in the friend tab. _updateFriendCount: function() { var friendsLength = 0; for(var f in this.friends) { if(this.friends[f].status[0] != 0) friendsLength++; } $('#imjs-friends .imjs-tab-text span span').html(friendsLength); }, // === //private// {{{AjaxIM.}}}**{{{_storeFriends()}}}** === // // If a storage method is enabled, the current state of the // user's friends list is stored. _storeFriends: function() { if(this.settings.storageMethod && this.storageReady) $.jStore.store(this.storeKey + 'friends', this.friends); }, // === //private// {{{AjaxIM.}}}**{{{_createChatbox(username)}}}** === // // Builds a chatbox based on the default chatbox HTML and CSS defined // in the current theme. Should a chatbox for this user already exist, // a new one is not created. Instead, it is either given focus (should // no other windows already have focus), or a notification is issued. // // As well, if the chatbox does not exist, an associated tab will be // created. // // ==== Parameters ==== // * {{{username}}} is the name of the user for whom the chatbox is intended // for. // * {{{no_stamp}}} sets whther or not to add a date stamp to the chatbox // upon creation. // // //Note:// New chatboxes are given an automatically generated ID in the // format of {{{#imjs-[md5 of username]}}}. _createChatbox: function(username, no_stamp) { var chatbox_id = 'imjs-' + $.md5(username); if(!(chatbox = $('#' + chatbox_id)).size()) { // add a tab var tab = this.bar.addTab(username, '#' + chatbox_id); var chatbox = tab.find('.imjs-chatbox'); chatbox.attr('id', chatbox_id); chatbox.data('tab', tab); // remove default items from the message log var message_log = chatbox.find('.imjs-msglog').empty(); // setup the chatbox header var cb_header = chatbox.find('.imjs-header'); cb_header.html(cb_header.html().replace('{username}', username)); if(!no_stamp) { // add a date stamp var time = this._addDateStamp(chatbox); this._storeNonMessage('datestamp', username, null, time); } // associate the username with the object and vice-versa this.chats[username] = chatbox; chatbox.data('username', username); // did this chatbox fall down? this.bar._scrollers(); if(username in this.friends) { status = this.friends[username].status; var status_name = 'available'; $.each(this.statuses, function(key, val) { if(status[0] == val) { status_name = key; return false; } }); tab.addClass('imjs-' + status_name); } // store inputbox height //var input = chatbox.find('.imjs-input'); //input.data('height', input.height()); } else if(chatbox.data('tab').data('state') == 'closed') { chatbox.find('.imjs-msglog > *').addClass('imjs-msg-old'); var tab = chatbox.data('tab'); if(tab.css('display') == 'none') tab.css('display', '').removeClass('imjs-selected') .appendTo('#imjs-bar'); if(!no_stamp) { // possibly add a date stamp var time = this._addDateStamp(chatbox); this._storeNonMessage('datestamp', username, null, time); } if(!$('#imjs-bar .imjs-selected').length) { tab.click(); } else { this.bar.notification(tab); } } return chatbox; }, // === //private// {{{AjaxIM.}}}**{{{_addDateStamp(chatbox)}}}** // // // Adds a date/time notifier to a chatbox. These are generally // inserted upon creation of a chatbox, or upon the date changing // since the last time a date stamp was added. If a date stamp for // the current date already exists, a new one will not be added. // // ==== Parameters ==== // * {{{chatbox}}} refers to the jQuery-selected chatbox DOM element. // * {{{time}}} is the date/time the date stamp will show. It is specified // in milliseconds since the Unix Epoch. This is //only// defined when // date stamps are being restored from storage; if not specified, the // current computer time will be used. _addDateStamp: function(chatbox, time) { var message_log = $(chatbox).find('.imjs-msglog'); if(!time) time = (new Date()).getTime(); var date_stamp = $('.imjs-tab.imjs-default .imjs-chatbox .imjs-msglog .imjs-date').clone(); var date_stamp_time = date_stamp.find('.imjs-msg-time'); if(date_stamp_time.length) date_stamp_time.html(AjaxIM.dateFormat(time, date_stamp_time.html())); var date_stamp_date = date_stamp.find('.imjs-date-date'); var formatted_date = AjaxIM.dateFormat(time, date_stamp_date.html()); if(chatbox.data('lastDateStamp') != formatted_date) { if(date_stamp_date.length) date_stamp_date.html(AjaxIM.dateFormat(time, date_stamp_date.html())); chatbox.data('lastDateStamp', formatted_date); date_stamp.appendTo(message_log); } else { //$('
    ').appendTo(message_log); } return time; }, // === //private// {{{AjaxIM.}}}**{{{_addError(chatbox, error)}}}** // // // Adds an error to a chatbox. These are generally inserted after // a user sends a message unsuccessfully. If an error message // was already added, another one will be added anyway. // // ==== Parameters ==== // * {{{chatbox}}} refers to the jQuery-selected chatbox DOM element. // * {{{error}}} is the error message string. // * {{{time}}} is the date/time the error occurred. It is specified in // milliseconds since the Unix Epoch. This is //only// defined when // errors are being restored from storage; if not specified, the current // computer time will be used. _addError: function(chatbox, error, time) { var message_log = $(chatbox).find('.imjs-msglog'); var error_item = $('.imjs-tab.imjs-default .imjs-chatbox .imjs-msglog .imjs-error').clone(); var error_item_time = error_item.find('.imjs-msg-time'); if(error_item_time.length) { if(!time) time = (new Date()).getTime(); error_item_time.html(AjaxIM.dateFormat(time, error_item_time.html())); } error_item.find('.imjs-error-error').html(error); error_item.appendTo(message_log); message_log[0].scrollTop = message_log[0].scrollHeight; }, // === //private// {{{AjaxIM.}}}**{{{_addMessage(ab, chatbox, username, message, time)}}}** // // // Adds a message to a chatbox. Depending on the {{{ab}}} value, // the color of the username may change as a way of visually // identifying users (however, this depends on the theme's CSS). // A timestamp is added to the message, and the chatbox is scrolled // to the bottom, such that the new message is visible. // // Messages will be automatically tag-escaped, so as to prevent // any potential cross-site scripting problems. Additionally, // URLs will be automatically linked. // // ==== Parameters ==== // * {{{ab}}} refers to whether the user is "a" or "b" in a conversation. // For the general case, "you" are "a" and "they" are "b". // * {{{chatbox}}} refers to the jQuery-selected chatbox DOM element. // * {{{username}}} is the username of the user who sent the message. // * {{{time}}} is the time the message was sent in milliseconds since // the Unix Epoch. This is //only// defined when messages are being // restored from storage. For new messages, the current computer // time is automatically used. _addMessage: function(ab, chatbox, username, message, time) { var last_message = chatbox.find('.imjs-msglog > *:last-child'); if(last_message.hasClass('imjs-msg-' + ab)) { // Last message was from the same person, so let's just add another imjs-msg-*-msg var message_container = (last_message.hasClass('imjs-msg-' + ab + '-container') ? last_message : last_message.find('.imjs-msg-' + ab + '-container')); var single_message = $('.imjs-tab.imjs-default .imjs-chatbox .imjs-msglog .imjs-msg-' + ab + '-msg') .clone().appendTo(message_container); single_message.html(single_message.html().replace('{username}', username)); } else if(!last_message.length || !last_message.hasClass('imjs-msg-' + ab)) { var message_group = $('.imjs-tab.imjs-default .imjs-chatbox .imjs-msg-' + ab) .clone().appendTo(chatbox.find('.imjs-msglog')); message_group.html(message_group.html().replace('{username}', username)); var single_message = message_group.find('.imjs-msg-' + ab + '-msg'); } // clean up the message message = message.replace(//g, '>') .replace(/(^|.*)\*([^*]+)\*(.*|$)/, '$1$2$3'); // autolink URLs message = message.replace( new RegExp('([A-Za-z][A-Za-z0-9+.-]{1,120}:[A-Za-z0-9/]' + '(([A-Za-z0-9$_.+!*,;/?:@&~=-])|%[A-Fa-f0-9]{2}){1,333}' + '(#([a-zA-Z0-9][a-zA-Z0-9$_.+!*,;/?:@&~=%-]{0,1000}))?)', 'g'), '$1'); // insert the message single_message.html(single_message.html().replace('{message}', message)); // set the message time var msgtime = single_message.find('.imjs-msg-time'); if(!time) time = new Date(); if(typeof time != 'string') time = AjaxIM.dateFormat(time, msgtime.html()); msgtime.html(time); var msglog = chatbox.find('.imjs-msglog'); msglog[0].scrollTop = msglog[0].scrollHeight; return time; }, // === //private// {{{AjaxIM.}}}**{{{_storeNonMessage(type, username, data, time)}}}** === // // **Redundant?**\\ // Similar to {{{AjaxIM._storeMessage}}}, but stores items that aren't messages, // such as datestamps and errors. // // ==== Parameters ==== // * {{{type}}} is the type of non-message (error, datestamp). // * {{{username}}} is the username of the user being chatted with. // * {{{data}}} is the (optional) data of the non-message to be stored. // * {{{time}}} is the time of the message. _storeNonMessage: function(type, username, data, time) { // If storage is on & ready, store the non-message if(this.settings.storageMethod) { if(!this.chatstore) this.chatstore = {}; if(!(username in this.chatstore)) this.chatstore[username] = []; // If the chat store gets too long, it becomes slow to load. if(this.chatstore[username].length > 300) this.chatstore[username].shift(); // For some reason, if we don't encode and decode the message, it *will* break // (at least) the Flash storage engine's retrieval. Gah! this.chatstore[username].push( [type, username, encodeURIComponent(data), time]); if(this.storageReady) $.jStore.store(self.storeKey + 'chats', this.chatstore); } }, // === //private// {{{AjaxIM.}}}**{{{_storeMessage(ab, chatbox, username, message, time)}}}** === // // Taking the same arguments as {{{AjaxIM._addMessage}}}, {{{_storeMessage}}} pushes a message // into the storage hash, if storage is enabled. // // Messages are added to a message array, by username. The entire chat hash is stored as // a {{{'chats'}}} object in whatever storage engine is enabled. _storeMessage: function(ab, chatbox, username, message, time) { // If storage is on & ready, store the message if(this.settings.storageMethod) { if(!this.chatstore) this.chatstore = {}; message = message.replace(//g, '>'); if(!(username in this.chatstore)) { this.chatstore[username] = []; } else if(this.chatstore[username].length > 300) { // If the chat store gets too long, it becomes slow to load. this.chatstore[username].shift(); } // For some reason, if we don't encode and decode the message, it *will* break // (at least) the Flash storage engine's retrieval. Gah! this.chatstore[chatbox.data('username')].push( [ab, username, encodeURIComponent(message), time]); if(this.storageReady) $.jStore.store(this.storeKey + 'chats', this.chatstore); } }, // === //private// {{{AjaxIM.}}}**{{{_friendUpdate(friend, status, statusMessage)}}}** === // // Called when a friend's status is updated. This function will update all locations // where a status icon is displayed (chat tab, friends list), as well as insert // a notification, should a chatbox be open. // // ==== Parameters ==== // * {{{friend}}} is the username of the friend. // * {{{status}}} is the new status code. See {{{AjaxIM.statuses}}} for a list of available // codes. //Note: If an invalid status is specified, no action will be taken.// // * {{{statusMessage}}} is a message that was, optionally, specified by the user. It will be // used should "you" send the user an IM while they are away, or if their status is viewed // in another way (such as via the friends list [**not yet implemented**]). _friendUpdate: function(friend, status, statusMessage) { // add friend to buddylist, update their status, etc. var status_name = 'available'; $.each(this.statuses, function(key, val) { if(status == val) { status_name = key; return false; } }); if(this.chats[friend]) { var tab = this.chats[friend].data('tab'); var tab_class = 'imjs-tab'; if(tab.data('state') == 'active') tab_class += ' imjs-selected'; tab_class += ' imjs-' + status_name; tab.attr('class', tab_class); // display the status in the chatbox var date_stamp = $('.imjs-tab.imjs-default .imjs-chatbox .imjs-msglog .imjs-date').clone(); var date_stamp_time = date_stamp.find('.imjs-msg-time'); if(date_stamp_time.length) date_stamp_time.html(AjaxIM.dateFormat(date_stamp_time.html())); var date_stamp_date = date_stamp.find('.imjs-date-date').html( AjaxIM.i18n[ 'chat' + status_name[0].toUpperCase() + status_name.slice(1) ].replace(/%s/g, friend)); var msglog = this.chats[friend].find('.imjs-msglog'); date_stamp.appendTo(msglog); msglog[0].scrollTop = msglog[0].scrollHeight; } if(this.friends[friend]) { var friend_id = 'imjs-friend-' + $.md5(friend + this.friends[friend].group); $('#' + friend_id).attr('class', 'imjs-friend imjs-' + status_name); if(status == 0) { $('#' + friend_id + ':visible').slideUp(); $('#' + friend_id + ':hidden').hide(); } else if(!$('#' + friend_id + ':visible').length) { $('#' + friend_id).slideDown(); } this.friends[friend].status = [status, statusMessage]; this._updateFriendCount(); } }, // === //private// {{{AjaxIM.}}}**{{{_notConnected()}}}** === // // Puts the user into a visible state of disconnection. Sets the // friends list to "not connected" and empties it; disallows new messages // to be sent. _notConnected: function() { $('#imjs-friends').addClass('imjs-not-connected').unbind('click', this.activateTab); }, // === {{{AjaxIM.}}}**{{{send(to, message)}}}** === // // Sends a message to another user. The message will be added // to the chatbox before it is actually sent, however, if an // error occurs during sending, that will be indicated immediately // afterward. // // After sending the message, one of three status codes should be // returned as a JSON object, e.g. {{{{r: 'code'}}}}: // * {{{ok}}} — Message was sent successfully. // * {{{offline}}} — The user is offline or unavailable to // receive messages. // * {{{error}}} — a problem occurred, unrelated to the user // being unavailable. // // ==== Parameters ==== // * {{{to}}} is the username of the recipient. // * {{{message}}} is the content to be sent. send: function(to, message) { if(!message) return; if(this.chats[to]) { // REMOVE ME? // possibly add a datestamp var time = self._addDateStamp(this.chats[to]); this._storeNonMessage('datestamp', to, null, time); time = this._addMessage('a', this.chats[to], this.username, message); this._storeMessage('a', this.chats[to], this.username, message, time); } $(self).trigger('sendingMessage', [to, message]); AjaxIM.request( this.actions.send, {'to': to, 'message': message}, function(result) { switch(result.r) { case 'ok': $(self).trigger('sendMessageSuccessful', [to, message]); break; case 'offline': $(self).trigger('sendMessageFailed', ['offline', to, message]); break; case 'error': default: if(result.e == 'no session found') { self._notConnected(); self._addError(self.chats[to], AjaxIM.i18n.notConnected); self._storeNonMessage('error', to, AjaxIM.i18n.notConnected, (new Date()).getTime()); } $(self).trigger('sendMessageFailed', [result.e, to, message]); break; } }, function(error) { self._notConnected(); self._addError(self.chats[to], AjaxIM.i18n.notConnected); self._storeNonMessage('error', to, AjaxIM.i18n.notConnected, (new Date()).getTime()); $(self).trigger('sendMessageFailed', ['not connected', to, message]); } ); }, // === {{{AjaxIM.}}}**{{{status(s, message)}}}** === // // Sets the user's status and status message. It is possible to not // set a status message by setting it to an empty string. The status // will be sent to the server, where upon the server will broadcast // the update to all individuals with "you" on their friends list. // // ==== Parameters ==== // * {{{s}}} is the status code, as defined by {{{AjaxIM.statuses}}}. // * {{{message}}} is the custom status message. status: function(s, message) { // update status icon(s) if(!this.statuses[s]) return; $('#imjs-friends').attr('class', 'imjs-' + s); $(self).trigger('changingStatus', [s, message]); AjaxIM.request( this.actions.status, {'status': this.statuses[s], 'message': message}, function(result) { switch(result.r) { case 'ok': $(self).trigger('changeStatusSuccessful', [s, message]); break; case 'error': default: $(self).trigger('changeStatusFailed', [result.e, s, message]); break; } }, function(error) { $(self).trigger('changeStatusFailed', ['not connected', s, message]); } ); }, // === {{{AjaxIM.}}}**{{{statuses}}}** === // // These are the available status codes and their associated identities: // * {{{offline}}} (0) — Only used when signing out/when another // user has signed out, as once this status is set, the user is removed // from the server and friends will be unable to contact the user. // * {{{available}}} (1) — The user is online and ready to be messaged. // * {{{away}}} (2) — The user is online but is not available. Others // may still contact this user, however, the user may not respond. Anyone // contacting an away user will receive a notice stating that the user is away, // and (if one is set) their custom status message. // * {{{invisible}}} (3; **not yet implemented**) — The user is online, // but other users are made unaware, and the user will be represented // as being offline. It is still possible to contact this user, and for this // user to contact others; no status message or notice will be sent to others // messaging this user. statuses: {offline: 0, available: 1, away: 2, invisible: 3}, // == Footer bar == // // The footer bar is the bar that sits at the bottom of the page, in a fixed // position. It contains a tab for the friends list, and tabs for any open // chat boxes. It is also possible to add custom tabs for other functionality. bar: { // === {{{AjaxIM.}}}**{{{bar.initialize()}}}** === // // Setup the footer bar and enable tab actions. This function // uses {{{jQuery.live}}} to set hooks on any bar tabs created // in the future. initialize: function() { // Set up your standard tab actions $('.imjs-tab') .live('click', this.activateTab); $('.imjs-tab .imjs-close') .live('click', this.closeTab); // Set up the friends list actions var self = this; $(document).click(function(e) { if(e.target.id == 'imjs-friends' || $(e.target).parents('#imjs-friends').length) { return; } if($('#imjs-friends').data('state') == 'active') self.activateTab.call($('#imjs-friends')); }); $('#imjs-friends') .data('state', 'minimized') .click(function(e) { if(!$(this).hasClass('imjs-not-connected') && e.target.id != 'imjs-friends-panel' && !$(e.target).parents('#imjs-friends-panel').length) self.activateTab.call(this); }) .mouseenter(function() { if($(this).hasClass('imjs-not-connected')) { $('.imjs-tooltip').css('display', 'block'); $('.imjs-tooltip p').html(AjaxIM.i18n.notConnectedTip); var tip_left = $(this).offset().left - $('.imjs-tooltip').outerWidth() + ($(this).outerWidth() / 2); var tip_top = $(this).offset().top - $('.imjs-tooltip').outerHeight(true); $('.imjs-tooltip').css({ left: tip_left, top: tip_top }); } }) .mouseleave(function() { if($(this).hasClass('imjs-not-connected')) { $('.imjs-tooltip').css('display', ''); } }); $('#imjs-friends-panel') .data('tab', $('#imjs-friends')) .css('display', 'none'); }, // === {{{AjaxIM.}}}**{{{bar.activateTab()}}}** === // // Activate a tab by setting it to the 'active' state and // showing any related chatbox. If a chatbox is available // for this tab, also focus the input box. // // //Note:// {{{this}}}, here, refers to the tab DOM element. activateTab: function() { var chatbox = $(this).find('.imjs-chatbox') || false; if($(this).data('state') != 'active') { if($(this).attr('id') != 'imjs-friends') { $('#imjs-bar > li') .not($(this)) .not('#imjs-friends') .removeClass('imjs-selected') .each(function() { if($(this).data('state') != 'closed') { $(this).data('state', 'minimized'); var chatbox = $(this).find('.imjs-chatbox'); if(chatbox.length) chatbox.css('display', 'none'); } }); } if(chatbox && chatbox.css('display') == 'none') chatbox.css('display', ''); // set the tab to active... var tab = $(this).addClass('imjs-selected').data('state', 'active'); // ...and hide and reset the notification icon tab.find('.imjs-notification').css('display', 'none') .data('count', 0); if(self.settings.storageMethod && self.storageReady && chatbox && (username = chatbox.data('username'))) { $.jStore.store(self.storeKey + 'activeTab', [username]); } $(self).trigger('tabToggled', ['activated', tab]); } else { var tab = $(this).removeClass('imjs-selected').data('state', 'minimized'); if(chatbox && chatbox.css('display') != 'none') chatbox.css('display', 'none'); if(self.settings.storageMethod && self.storageReady) { $.jStore.store(self.storeKey + 'activeTab', ['*']); } $(self).trigger('tabToggled', ['minimized', tab]); } if(chatbox) { if(!(input = chatbox.find('.imjs-input')).data('height')) { // store the height for resizing later input.data('height', input.height()); } try { var msglog = chatbox.find('.imjs-msglog'); msglog[0].scrollTop = msglog[0].scrollHeight; } catch(e) {} try { chatbox.find('.imjs-input').focus(); } catch(e) {} } }, // === {{{AjaxIM.}}}**{{{bar.closeTab()}}}** === // // Close a tab and hide any related chatbox, such that // the chatbox can not be reopened without reinitializing // the tab. // // //Note:// {{{this}}}, here, refers to the tab DOM element. closeTab: function() { var tab = $(this).parents('.imjs-tab'); tab.css('display', 'none').data('state', 'closed'); if(self.settings.storageMethod && self.storageReady) { delete self.chatstore[tab.find('.imjs-chatbox').data('username')]; if(self.storageReady) $.jStore.store(self.storeKey + 'chats', self.chatstore); } $(self).trigger('tabToggled', ['closed', tab]); self.bar._scrollers(); return false; }, // === {{{AjaxIM.}}}**{{{bar.addTab(label, action, closable)}}}** === // // Adds a tab to the tab bar, with the label {{{label}}}. When // clicked, it will call a callback function, {{{action}}}. If // {{{action}}} is a string, it is assumed that the string is // referring to a chatbox ID. // // ==== Parameters ==== // * {{{label}}} is the text that will be displayed on the tab.\\ // * {{{action}}} is the callback function, if it is a non-chatbox // tab, or a string if it //is// a chatbox tab.\\ // * {{{closable}}} is a boolean value that determines whether or not // it is possible for a user to close this tab. // // //Note:// New tabs are given an automatically generated ID // in the format of {{{#imjs-tab-[md5 of label]}}}. addTab: function(label, action, closable) { var tab = $('.imjs-tab.imjs-default').clone().insertAfter('#imjs-scroll-right'); tab.removeClass('imjs-default') .attr('id', 'imjs-tab-' + $.md5(label)) .html(tab.html().replace('{label}', label)) .data('state', 'minimized'); var notification = tab.find('.imjs-notification'); notification.css('display', 'none') .data('count', 0) .data('default-text', notification.html()) .html(notification.html().replace('{count}', '0')); if(closable === false) tab.find('.imjs-close').eq(0).remove(); if(typeof action == 'string') { //tab.data('chatbox', action); } else { tab.find('.imjs-chatbox').remove(); tab.click(action); } return tab; }, // === {{{AjaxIM.}}}**{{{bar.notification(tab)}}}** === // // Displays a notification on a tab. Generally, this is called when // a tab is minimized to let the user know that there is an update // for them. The way the notification is displayed depends on the // theme CSS. // // ==== Parameters ==== // * {{{tab}}} is the jQuery-selected tab DOM element. notification: function(tab) { var notify = tab.find('.imjs-notification'); var notify_count = notify.data('count') + 1; notify.data('count', notify_count) .html(notify.data('default-text').replace('{count}', notify_count)) .css('display', ''); }, // === //private// {{{AjaxIM.}}}**{{{bar._scrollers()}}}** === // // Document me! _scrollers: function() { var needScrollers = false; $('.imjs-tab').filter(function() { return $(this).data('state') != 'closed' }).css('display', ''); $.each(self.chats, function(username, chatbox) { var tab = chatbox.data('tab'); if(tab.data('state') == 'closed') return true; if(tab.position().top > $('#imjs-bar').height()) { $('.imjs-scroll').css('display', ''); tab.css('display', 'none'); needScrollers = true; } else { tab.css('display', ''); } }); if(!needScrollers) { $('.imjs-scroll').css('display', 'none'); } if($('#imjs-scroll-left').css('display') != 'none' && $('#imjs-scroll-left').position().top > $('#imjs-bar').height()) { $('#imjs-bar li.imjs-tab:visible').slice(-1).css('display', 'none'); } var hiddenLeft = $('#imjs-bar li.imjs-tab:visible').slice(-1) .nextAll('#imjs-bar li.imjs-tab:hidden') .not('.imjs-default') .filter(function() { return $(this).data('state') != 'closed' }).length; var hiddenRight = $('#imjs-bar li.imjs-tab:visible').eq(0) .prevAll('#imjs-bar li.imjs-tab:hidden') .not('.imjs-default') .filter(function() { return $(this).data('state') != 'closed' }).length; $('#imjs-scroll-left').html(hiddenLeft); $('#imjs-scroll-right').html(hiddenRight); } }, // == Comet == // // Comet, or HTTP streaming, holds open a connection between the client and // the server indefinitely. As the server receives new messages or events, // they are passed down to the client in a {{{<script>}}} // tag which calls the {{{AjaxIM.incoming()}}} function. The connection is // opened using either an {{{iframe}}} (in Opera or Internet Explorer) or // an {{{XMLHTTPRequest}}} object. Due to the extra flexibility necessary // with the {{{XMLHTTPRequest}}} object, jQuery's {{{$.ajax}}} is not used. comet: { type: '', obj: null, onbeforeunload: null, onreadystatechange: null, iframe: function() { if(/loaded|complete/i.test(this.obj.readyState)) throw new Error("IM server not available!"); }, // === {{{AjaxIM.}}}**{{{comet.connect()}}}** === // // Creates and initializes the object and connection between the server // and the client. For Internet Explorer and Opera, we use an // {{{<iframe>}}} element; for all other browsers, we create an // {{{XMLHTTPRequest}}} object. The server connects to the URI defined // as the "poll" action. This function is called automatically, when // the IM engine is initialized and the {{{AjaxIM.poll()}}} function // is called. connect: function() { var self = _instance; if($.browser.opera || $.browser.msie) { var iframe = $(''); with(iframe) { css({ position: 'absolute', visibility: 'visible', display: 'block', left: '-10000px', top: '-10000px', width: '1px', height: '1px' }); attr('src', self.actions.poll[1]); appendTo('body'); bind('readystatechange', self.comet.onreadystatechange = function() { self.comet.iframe() }); bind('beforeunload', self.comet.onbeforeunload = function() { self.comet.disconnect() }); } self.comet.type = 'iframe'; self.comet.obj = iframe; } else { var xhr = new XMLHttpRequest; var length = 1029; var code = /^\s*]*>parent\.(.+);<\/script>$/; xhr.open('get', self.actions.poll[1], true); xhr.onreadystatechange = function(){ if(xhr.readyState > 2) { if(xhr.status == 200) { responseText = xhr.responseText.substring(length); length = xhr.responseText.length; if(responseText != ' ') eval(responseText.replace(code, "$1")); } // We need an "else" here. If the state changes to // "loaded", the user needs to know they're // disconnected. } }; self.comet.type = 'xhr'; self.comet.obj = xhr; addEventListener('beforeunload', self.comet.beforeunload = function() { self.comet.disconnect(); }, false); setTimeout(function() { xhr.send(null) }, 10); } }, // === {{{AjaxIM.}}}**{{{comet.disconnect()}}}** === // // Disconnect from the server and destroy the connection object. This // function is called before the page unloads, so that we plug up and // potential leaks and free memory. disconnect: function() { var self = _instance.comet; if(!this.type || !this.obj) return; if(this.type == 'iframe') { detachEvent('onreadystatechange', this.onreadystatechange); detachEvent('onbeforeunload', this.onbeforeunload); this.obj.src = '.'; $(this.obj).remove(); } else { removeEventListener('beforeunload', this.onbeforeunload, false); this.obj.onreadystatechange = function(){}; this.obj.abort(); } delete this.obj; } } }) self.bar.initialize(); if(prequeue.length) { $.each(prequeue, function() { var func = this[0].split('.'); if(func.length > 1) self[func[0]][func[1]].apply(self, this[1]); else self[func[0]].apply(self, this[1]); }); } }); // == Static functions and variables == // // The following functions and variables are available outside of an initialized // {{{AjaxIM}}} object. // === {{{AjaxIM.}}}**{{{client}}}** === // // Once {{{AjaxIM.init()}}} is called, this will be set to the active AjaxIM // object. Only one AjaxIM object instance can exist at a time. This variable // can and should be accessed directly. AjaxIM.client = null; // === {{{AjaxIM.}}}**{{{init(options, actions)}}}** === // // Initialize the AjaxIM client object and engine. Here, you can define your // options and actions as outlined at the top of this documentation. // // ==== Parameters ==== // * {{{options}}} is the hash of custom settings to initialize Ajax IM with. // * {{{actions}}} is the hash of any custom action URLs. AjaxIM.init = function(options, actions) { if(!_instance) { _instance = new AjaxIM(options, actions); AjaxIM.client = _instance; } return _instance; } // === {{{AjaxIM.}}}**{{{request(url, data, successFunc, failureFunc)}}}** === // // Wrapper around {{{$.jsonp}}}, the JSON-P library for jQuery, and {{{$.ajax}}}, // jQuery's ajax library. Allows either function to be called, automatically, // depending on the request's URL array (see {{{AjaxIM.actions}}}). // // ==== Parameters ==== // {{{url}}} is the URL of the request. // {{{data}}} are any arguments that go along with the request. // {{{success}}} is a callback function called when a request has completed // without issue. // {{{_ignore_}}} is simply to provide compatability with {{{$.post}}}. // {{{failure}}} is a callback function called when a request hasn't not // completed successfully. AjaxIM.request = function(url, data, successFunc, failureFunc) { if(typeof failureFunc != 'function'); failureFunc = function(){}; $[url[0]]({ 'url': url[1], 'data': data, dataType: (url[0] == 'ajax' ? 'json' : 'jsonp'), type: 'POST', cache: false, timeout: 60000, callback: 'jsonp' + (new Date()).getTime(), success: function(json, textStatus) { successFunc(json); }, error: function(xOptions, error) { failureFunc(error); } }); // This prevents Firefox from spinning indefinitely // while it waits for a response. Why? Fuck if I know. if(url[0] == 'jsonp' && $.browser.mozilla) { $.jsonp({ 'url': 'about:', timeout: 0 }); } }; // === {{{AjaxIM.}}}**{{{incoming(data)}}}** === // // Never call this directly. It is used as a connecting function between // client and server for Comet. // // //Note:// There are two {{{AjaxIM.incoming()}}} functions. This one is a // static function called outside of the initialized AjaxIM object; the other // is only called within the initalized AjaxIM object. AjaxIM.incoming = function(data) { if(!_instance) return false; if(data.length) _instance._parseMessages(data); } // === {{{AjaxIM.}}}**{{{loaded}}}** === // // If Ajax IM has been loaded with the im.load.js file, this function will be // called when the library is finally loaded and ready for use. Similar to // jQuery's $(document).ready(), but for Ajax IM. AjaxIM.loaded = function() { if(typeof AjaxIMLoadedFunction == 'function') { AjaxIMLoadedFunction(); delete AjaxIMLoadedFunction; // clean up the global namespace } }; // === {{{AjaxIM.}}}**{{{dateFormat([date,] [mask,] utc)}}}** === // // Date Format 1.2.3\\ // © 2007-2009 Steven Levithan ([[http://blog.stevenlevithan.com/archives/date-time-format|stevenlevithan.com]])\\ // MIT license // // Includes enhancements by Scott Trenda // and Kris Kowal ([[http://cixar.com/~kris.kowal/|cixar.com/~kris.kowal/]]) // // Accepts a date, a mask, or a date and a mask and returns a formatted version // of the given date. // // ==== Parameters ==== // * {{{date}}} is a {{{Date()}}} object. If not specified, the date defaults to the // current date/time. // * {{{mask}}} is a string that defines the formatting of the date. Formatting // options can be found in the // [[http://blog.stevenlevithan.com/archives/date-time-format|Date Format]] // documentation. If not specified, the mask defaults to {{{dateFormat.masks.default}}}. AjaxIM.dateFormat = function () { var token = /d{1,4}|m{1,4}|yy(?:yy)?|([HhMsTt])\1?|[LloSZ]|"[^"]*"|'[^']*'/g, timezone = new RegExp('\b(?:[PMCEA][SDP]T|(?:Pacific|Mountain|Central|Eastern|Atlantic) ' + '(?:Standard|Daylight|Prevailing) Time|(?:GMT|UTC)(?:[-+]\d{4})?)\b', 'g'), timezoneClip = /[^-+\dA-Z]/g, pad = function (val, len) { val = String(val); len = len || 2; while (val.length < len) val = "0" + val; return val; }; // Regexes and supporting functions are cached through closure return function (date, mask, utc) { var dF = AjaxIM.dateFormat; // You can't provide utc if you skip other args (use the "UTC:" mask prefix) if (arguments.length == 1 && Object.prototype.toString.call(date) == "[object String]" && !/\d/.test(date)) { mask = date; date = undefined; } // Passing date through Date applies Date.parse, if necessary date = date ? new Date(date) : new Date; if (isNaN(date)) throw SyntaxError("invalid date"); mask = String(dF.masks[mask] || mask || dF.masks["default"]); // Allow setting the utc argument via the mask if (mask.slice(0, 4) == "UTC:") { mask = mask.slice(4); utc = true; } var _ = utc ? "getUTC" : "get", d = date[_ + "Date"](), D = date[_ + "Day"](), m = date[_ + "Month"](), y = date[_ + "FullYear"](), H = date[_ + "Hours"](), M = date[_ + "Minutes"](), s = date[_ + "Seconds"](), L = date[_ + "Milliseconds"](), o = utc ? 0 : date.getTimezoneOffset(), flags = { d: d, dd: pad(d), ddd: AjaxIM.i18n.dayNames[D], dddd: AjaxIM.i18n.dayNames[D + 7], m: m + 1, mm: pad(m + 1), mmm: AjaxIM.i18n.monthNames[m], mmmm: AjaxIM.i18n.monthNames[m + 12], yy: String(y).slice(2), yyyy: y, h: H % 12 || 12, hh: pad(H % 12 || 12), H: H, HH: pad(H), M: M, MM: pad(M), s: s, ss: pad(s), l: pad(L, 3), L: pad(L > 99 ? Math.round(L / 10) : L), t: H < 12 ? "a" : "p", tt: H < 12 ? "am" : "pm", T: H < 12 ? "A" : "P", TT: H < 12 ? "AM" : "PM", Z: utc ? "UTC" : (String(date).match(timezone) || [""]) .pop().replace(timezoneClip, ""), o: (o > 0 ? "-" : "+") + pad(Math.floor(Math.abs(o) / 60) * 100 + Math.abs(o) % 60, 4), S: ["th", "st", "nd", "rd"][d % 10 > 3 ? 0 : (d % 100 - d % 10 != 10) * d % 10] }; return mask.replace(token, function ($0) { return $0 in flags ? flags[$0] : $0.slice(1, $0.length - 1); }); }; }(); // Some common format strings AjaxIM.dateFormat.masks = { "default": "ddd mmm dd yyyy HH:MM:ss", shortDate: "m/d/yy", mediumDate: "mmm d, yyyy", longDate: "mmmm d, yyyy", fullDate: "dddd, mmmm d, yyyy", shortTime: "h:MM TT", mediumTime: "h:MM:ss TT", longTime: "h:MM:ss TT Z", isoDate: "yyyy-mm-dd", isoTime: "HH:MM:ss", isoDateTime: "yyyy-mm-dd'T'HH:MM:ss", isoUtcDateTime: "UTC:yyyy-mm-dd'T'HH:MM:ss'Z'" }; // === {{{AjaxIM.}}}**{{{i18n}}}** === // // Text strings used by Ajax IM. Should you want to translate Ajax IM into // another language, merely change these strings. // // {{{%s}}} denotes text that will be automatically replaced when the string is // used. AjaxIM.i18n = { dayNames: [ "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday" ], monthNames: [ "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December" ], chatOffline: '%s signed off.', chatAvailable: '%s became available.', chatAway: '%s went away.', notConnected: 'You are currently not connected or the server is not available. ' + 'Please ensure that you are signed in and try again.', notConnectedTip: 'You are currently not connected.', authInvalid: 'Invalid username or password.', registerPasswordLength: 'Passwords must be more than 4 characters in length.', registerUsernameLength: 'Usernames must be more than 2 characters in length and ' + ' contain only A-Z, a-z, 0-9, underscores (_) and periods (.).', registerPasswordMatch: 'Entered passwords do not match.', registerUsernameTaken: 'The chosen username is already in use; please choose another.', registerUnknown: 'An unknown error occurred. Please try again.' } })(jQuery, false); \ No newline at end of file From 24a68e40614ba23728e33864991bcb759e75d53d Mon Sep 17 00:00:00 2001 From: Antony Lesuisse Date: Sun, 10 Apr 2011 01:07:27 +0200 Subject: [PATCH 120/259] minor logging improvement bzr revid: al@openerp.com-20110409230727-dl78pjg6wvoo7g3e --- addons/base/static/src/js/base.js | 4 + addons/base/static/src/js/chrome.js | 114 ++++++++++++++++++---------- 2 files changed, 80 insertions(+), 38 deletions(-) diff --git a/addons/base/static/src/js/base.js b/addons/base/static/src/js/base.js index 8f9921ceeae..675476879cf 100644 --- a/addons/base/static/src/js/base.js +++ b/addons/base/static/src/js/base.js @@ -76,6 +76,10 @@ /** @lends openerp */ var openerp = this.openerp = { + /** + * Debug flag turns on logging + */ + debug: true, // element_ids registry linked to all controllers on the page // TODO rename to elements, or keep gtk naming? screen: {}, diff --git a/addons/base/static/src/js/chrome.js b/addons/base/static/src/js/chrome.js index cdfa1f4d192..67d829c2e54 100644 --- a/addons/base/static/src/js/chrome.js +++ b/addons/base/static/src/js/chrome.js @@ -193,8 +193,6 @@ openerp.base.BasicController = Class.extend( /** @lends openerp.base.BasicContro // try to call deferred methods on this return value. return $.Deferred().done().promise(); }, - on_ready: function() { - }, stop: function() { }, log: function() { @@ -206,20 +204,60 @@ openerp.base.BasicController = Class.extend( /** @lends openerp.base.BasicContro this.on_log.apply(this,args); }, on_log: function() { - if(true || window.openerp.debug || (window.location.search.indexOf('?debug') !== -1)) { + if(window.openerp.debug || (window.location.search.indexOf('?debug') !== -1)) { + var notify = false; + var body = false; if(window.console) { console.log(arguments); } else { - $.each(arguments, function(i,v) { - v = v==null ? "null" : v; - $('
    ').text(v.toString()).appendTo($('body'));
    -                });
    +                body = true;
    +            }
    +            var a = Array.prototype.slice.call(arguments, 0);
    +            for(var i = 0; i < a.length; i++) {
    +                var v = a[i]==null ? "null" : a[i].toString();
    +                if(i==0) {
    +                    notify = v.match(/^not/);
    +                    body = v.match(/^bod/);
    +                }
    +                if(body) {
    +                    $('
    ').text(v).appendTo($('body'));
    +                }
    +                if(notify && this.notification) {
    +                    this.notification.notify("Logging:",v);
    +                }
                 }
             }
     
         }
     });
     
    +openerp.base.Notification =  openerp.base.BasicController.extend({
    +    init: function(element_id) {
    +        this._super(element_id);
    +        this.$element.notify({
    +            speed: 500,
    +            expires: 1500
    +        });
    +    },
    +    notify: function(title, text) {
    +        this.$element.notify('create', {
    +            title: title,
    +            text: text
    +        });
    +    },
    +    // TODO remove to avoid default as attribute
    +    'default': function(title, text) {
    +        this.notify(title,text);
    +    },
    +    // TODO change into warn to avoid alert
    +    alert: function(title, text) {
    +        this.$element.notify('create', 'oe_notification_alert', {
    +            title: title,
    +            text: text
    +        });
    +    }
    +});
    +
     openerp.base.Session = openerp.base.BasicController.extend( /** @lends openerp.base.Session# */{
         /**
          * @constructs
    @@ -447,17 +485,40 @@ openerp.base.Session = openerp.base.BasicController.extend( /** @lends openerp.b
     });
     
     openerp.base.Controller = openerp.base.BasicController.extend( /** @lends openerp.base.Controller# */{
    +    /**
    +     * Controller manifest used to declare standard controller attributes
    +     */
    +    controller_manifest: {
    +        register: [ "FormView.widget.char" ],
    +        template: "",
    +        elementpost: false,
    +    },
         /**
          * @constructs
          * @extends openerp.base.BasicController
          */
    -    init: function(session, element_id) {
    +    init: function(parent_or_session, element_id) {
             this._super(element_id);
    -        this.session = session;
    +        // TODO migrate for backward compat
    +        if(parent_or_session) {
    +            if(parent_or_session.session) {
    +                this.parent = parent_or_session;
    +            } else {
    +                this.session = parent_or_session;
    +            }
    +
    +        }
         },
    -    on_log: function() {
    -        if(this.session)
    -            this.session.log.apply(this.session,arguments);
    +    /**
    +     * Controller registry, 
    +     */
    +    controller_registry: {
    +    },
    +    /**
    +     * Add a new child controller
    +     */
    +    controller_add: function(key,element_id) {
    +        var obj = "";
         },
         /**
          * Performs a JSON-RPC call
    @@ -495,10 +556,6 @@ openerp.base.CrashManager = openerp.base.Controller.extend({
         }
     });
     
    -openerp.base.Database = openerp.base.Controller.extend({
    -// Non Session Controller to manage databases
    -});
    -
     openerp.base.Loading =  openerp.base.Controller.extend({
         init: function(session, element_id) {
             this._super(session, element_id);
    @@ -518,26 +575,7 @@ openerp.base.Loading =  openerp.base.Controller.extend({
         }
     });
     
    -openerp.base.Notification =  openerp.base.Controller.extend({
    -    init: function(session, element_id) {
    -        this._super(session, element_id);
    -        this.$element.notify({
    -            speed: 500,
    -            expires: 1500
    -        });
    -    },
    -    'default': function(title, text) {
    -        this.$element.notify('create', {
    -            title: title,
    -            text: text
    -        });
    -    },
    -    alert: function(title, text) {
    -        this.$element.notify('create', 'oe_notification_alert', {
    -            title: title,
    -            text: text
    -        });
    -    }
    +openerp.base.Database = openerp.base.Controller.extend({
     });
     
     openerp.base.Login =  openerp.base.Controller.extend({
    @@ -630,7 +668,6 @@ openerp.base.Menu =  openerp.base.Controller.extend({
             });
     
             this.$element.add(this.$secondary_menu).find("a").click(this.on_menu_click);
    -        this.on_ready();
         },
         on_menu_click: function(ev, id) {
             id = id || 0;
    @@ -703,7 +740,7 @@ openerp.base.WebClient = openerp.base.Controller.extend({
             this.crashmanager =  new openerp.base.CrashManager(this.session);
     
             // Do you autorize this ?
    -        openerp.base.Controller.prototype.notification = new openerp.base.Notification(this.session, "oe_notification");
    +        openerp.base.Controller.prototype.notification = new openerp.base.Notification("oe_notification");
     
             this.header = new openerp.base.Header(this.session, "oe_header");
             this.login = new openerp.base.Login(this.session, "oe_login");
    @@ -739,6 +776,7 @@ openerp.base.webclient = function(element_id) {
         client.start();
         return client;
     };
    +
     };
     
     // vim:et fdc=0 fdl=0 foldnestmax=3 fdm=syntax:
    
    From a2c60d598c1faa09edaa0d53f362e21732fab6ab Mon Sep 17 00:00:00 2001
    From: Antony Lesuisse 
    Date: Sun, 10 Apr 2011 02:12:22 +0200
    Subject: [PATCH 121/259] controller rework based on niv widget and xmo
     registry part1
    
    bzr revid: al@openerp.com-20110410001222-pxar6n4szuy1zvzv
    ---
     addons/base/static/src/js/chrome.js | 190 +++++++++++++++++++++++++---
     addons/base/static/src/js/views.js  |  92 --------------
     2 files changed, 170 insertions(+), 112 deletions(-)
    
    diff --git a/addons/base/static/src/js/chrome.js b/addons/base/static/src/js/chrome.js
    index 67d829c2e54..b26dccffb2e 100644
    --- a/addons/base/static/src/js/chrome.js
    +++ b/addons/base/static/src/js/chrome.js
    @@ -484,30 +484,17 @@ openerp.base.Session = openerp.base.BasicController.extend( /** @lends openerp.b
         }
     });
     
    +// A controller takes an already existing element
    +// new()
    +// start()
     openerp.base.Controller = openerp.base.BasicController.extend( /** @lends openerp.base.Controller# */{
         /**
          * Controller manifest used to declare standard controller attributes
          */
         controller_manifest: {
    -        register: [ "FormView.widget.char" ],
    +        register: null,
             template: "",
    -        elementpost: false,
    -    },
    -    /**
    -     * @constructs
    -     * @extends openerp.base.BasicController
    -     */
    -    init: function(parent_or_session, element_id) {
    -        this._super(element_id);
    -        // TODO migrate for backward compat
    -        if(parent_or_session) {
    -            if(parent_or_session.session) {
    -                this.parent = parent_or_session;
    -            } else {
    -                this.session = parent_or_session;
    -            }
    -
    -        }
    +        element_post_prefix: false,
         },
         /**
          * Controller registry, 
    @@ -517,8 +504,69 @@ openerp.base.Controller = openerp.base.BasicController.extend( /** @lends opener
         /**
          * Add a new child controller
          */
    -    controller_add: function(key,element_id) {
    -        var obj = "";
    +    controller_get: function(key) {
    +        return this.controller_registry[key];
    +        // OR should contrustct it ? setting parent correctly ?
    +        // function construct(constructor, args) {
    +        //     function F() {
    +        //         return constructor.apply(this, args);
    +        //     }
    +        //     F.prototype = constructor.prototype;
    +        //     return new F();
    +        // }
    +        // var obj = this.controller_registry[key];
    +        // if(obj) {
    +        //     return construct(obj, Array.prototype.slice.call(arguments, 1));
    +        // }
    +    },
    +    controller_new: function(key) {
    +        var self;
    +        // OR should contrustct it ? setting parent correctly ?
    +        function construct(constructor, args) {
    +            function F() {
    +                return constructor.apply(this, args);
    +            }
    +            F.prototype = constructor.prototype;
    +            return new F();
    +        }
    +        var obj = this.controller_registry[key];
    +        if(obj) {
    +            // TODO Prepend parent
    +            return construct(obj, Array.prototype.slice.call(arguments, 1));
    +        }
    +    },
    +    /**
    +     * @constructs
    +     * @extends openerp.base.BasicController
    +     */
    +    init: function(parent_or_session, element_id) {
    +        this._super(element_id);
    +        this.controller_parent = null;
    +        this.controller_children = [];
    +        if(parent_or_session) {
    +            if(parent_or_session.session) {
    +                this.parent = parent_or_session;
    +                this.session = this.parent.session;
    +                if(this.parent.children) {
    +                    this.parent.children.push(this);
    +                }
    +            } else {
    +                // TODO remove Backward compatilbility
    +                this.session = parent_or_session;
    +            }
    +        }
    +        // Apply manifest options
    +        if(this.controller_manifest) {
    +            var register = this.controller_manifest.register;
    +            // TODO accept a simple string
    +            if(register) {
    +                for(var i=0; i
    Date: Mon, 11 Apr 2011 04:54:09 +0000
    Subject: [PATCH 122/259] Launchpad automatic translations update.
    
    bzr revid: launchpad_translations_on_behalf_of_openerp-20110408044528-x2b0tjohjf1dqbic
    bzr revid: launchpad_translations_on_behalf_of_openerp-20110409050011-j1zonbxqthg6cnbv
    bzr revid: launchpad_translations_on_behalf_of_openerp-20110410044959-wu9z8ma8je0netjq
    bzr revid: launchpad_translations_on_behalf_of_openerp-20110411045409-41dld74ls1lcxfwl
    ---
     addons/analytic/i18n/nb.po         |  257 +++++
     addons/anonymization/i18n/ca.po    |  226 ++++
     addons/base_synchro/i18n/ca.po     |  289 ++++++
     addons/crm/i18n/zh_CN.po           |  912 +++++++++--------
     addons/crm_caldav/i18n/zh_CN.po    |   49 +
     addons/crm_claim/i18n/gl.po        |  778 ++++++++++++++
     addons/crm_claim/i18n/zh_CN.po     |  749 ++++++++++++++
     addons/crm_helpdesk/i18n/zh_CN.po  |  697 +++++++++++++
     addons/crm_profiling/i18n/zh_CN.po |   55 +-
     addons/document_webdav/i18n/ca.po  |  206 ++++
     addons/fetchmail/i18n/ca.po        |  317 ++++++
     addons/hr_payroll/i18n/vi.po       | 1538 ++++++++++++++++++++++++++++
     addons/hr_timesheet/i18n/nb.po     |  702 +++++++++++++
     addons/product/i18n/ro.po          |    2 +-
     addons/product_margin/i18n/gl.po   |  305 ++++++
     addons/project/i18n/nb.po          |    8 +-
     addons/warning/i18n/nb.po          |  235 +++++
     addons/web_livechat/i18n/zh_CN.po  |   39 +
     addons/web_uservoice/i18n/zh_CN.po |   29 +
     19 files changed, 6928 insertions(+), 465 deletions(-)
     create mode 100644 addons/analytic/i18n/nb.po
     create mode 100644 addons/anonymization/i18n/ca.po
     create mode 100644 addons/base_synchro/i18n/ca.po
     create mode 100644 addons/crm_caldav/i18n/zh_CN.po
     create mode 100644 addons/crm_claim/i18n/gl.po
     create mode 100644 addons/crm_claim/i18n/zh_CN.po
     create mode 100644 addons/crm_helpdesk/i18n/zh_CN.po
     create mode 100644 addons/document_webdav/i18n/ca.po
     create mode 100644 addons/fetchmail/i18n/ca.po
     create mode 100644 addons/hr_payroll/i18n/vi.po
     create mode 100644 addons/hr_timesheet/i18n/nb.po
     create mode 100644 addons/product_margin/i18n/gl.po
     create mode 100644 addons/warning/i18n/nb.po
     create mode 100644 addons/web_livechat/i18n/zh_CN.po
     create mode 100644 addons/web_uservoice/i18n/zh_CN.po
    
    diff --git a/addons/analytic/i18n/nb.po b/addons/analytic/i18n/nb.po
    new file mode 100644
    index 00000000000..c8dc9e5efa9
    --- /dev/null
    +++ b/addons/analytic/i18n/nb.po
    @@ -0,0 +1,257 @@
    +# Norwegian Bokmal translation for openobject-addons
    +# Copyright (c) 2011 Rosetta Contributors and Canonical Ltd 2011
    +# This file is distributed under the same license as the openobject-addons package.
    +# FIRST AUTHOR , 2011.
    +#
    +msgid ""
    +msgstr ""
    +"Project-Id-Version: openobject-addons\n"
    +"Report-Msgid-Bugs-To: FULL NAME \n"
    +"POT-Creation-Date: 2011-01-11 11:14+0000\n"
    +"PO-Revision-Date: 2011-04-07 06:36+0000\n"
    +"Last-Translator: FULL NAME \n"
    +"Language-Team: Norwegian Bokmal \n"
    +"MIME-Version: 1.0\n"
    +"Content-Type: text/plain; charset=UTF-8\n"
    +"Content-Transfer-Encoding: 8bit\n"
    +"X-Launchpad-Export-Date: 2011-04-08 04:45+0000\n"
    +"X-Generator: Launchpad (build 12735)\n"
    +
    +#. module: analytic
    +#: field:account.analytic.account,child_ids:0
    +msgid "Child Accounts"
    +msgstr ""
    +
    +#. module: analytic
    +#: field:account.analytic.account,name:0
    +msgid "Account Name"
    +msgstr "Kontonavn"
    +
    +#. module: analytic
    +#: help:account.analytic.line,unit_amount:0
    +msgid "Specifies the amount of quantity to count."
    +msgstr ""
    +
    +#. module: analytic
    +#: model:ir.module.module,description:analytic.module_meta_information
    +msgid ""
    +"Module for defining analytic accounting object.\n"
    +"    "
    +msgstr ""
    +
    +#. module: analytic
    +#: field:account.analytic.account,state:0
    +msgid "State"
    +msgstr "Status"
    +
    +#. module: analytic
    +#: field:account.analytic.account,user_id:0
    +msgid "Account Manager"
    +msgstr ""
    +
    +#. module: analytic
    +#: selection:account.analytic.account,state:0
    +msgid "Draft"
    +msgstr "Utkast"
    +
    +#. module: analytic
    +#: selection:account.analytic.account,state:0
    +msgid "Closed"
    +msgstr "Lukket"
    +
    +#. module: analytic
    +#: field:account.analytic.account,debit:0
    +msgid "Debit"
    +msgstr "Debet"
    +
    +#. module: analytic
    +#: help:account.analytic.account,state:0
    +msgid ""
    +"* When an account is created its in 'Draft' state.                           "
    +"       \n"
    +"* If any associated partner is there, it can be in 'Open' state.             "
    +"                     \n"
    +"* If any pending balance is there it can be in 'Pending'.                    "
    +"               \n"
    +"* And finally when all the transactions are over, it can be in 'Close' "
    +"state.                                   \n"
    +"* The project can be in either if the states 'Template' and 'Running'.\n"
    +" If it is template then we can make projects based on the template projects. "
    +"If its in 'Running' state it is a normal project.                            "
    +"     \n"
    +" If it is to be reviewed then the state is 'Pending'.\n"
    +" When the project is completed the state is set to 'Done'."
    +msgstr ""
    +
    +#. module: analytic
    +#: field:account.analytic.account,type:0
    +msgid "Account Type"
    +msgstr "Kontotype"
    +
    +#. module: analytic
    +#: selection:account.analytic.account,state:0
    +msgid "Template"
    +msgstr "Mal"
    +
    +#. module: analytic
    +#: selection:account.analytic.account,state:0
    +msgid "Pending"
    +msgstr ""
    +
    +#. module: analytic
    +#: model:ir.model,name:analytic.model_account_analytic_line
    +msgid "Analytic Line"
    +msgstr ""
    +
    +#. module: analytic
    +#: field:account.analytic.account,description:0
    +#: field:account.analytic.line,name:0
    +msgid "Description"
    +msgstr "Beskrivelse"
    +
    +#. module: analytic
    +#: selection:account.analytic.account,type:0
    +msgid "Normal"
    +msgstr "Normal"
    +
    +#. module: analytic
    +#: field:account.analytic.account,company_id:0
    +#: field:account.analytic.line,company_id:0
    +msgid "Company"
    +msgstr "Firma"
    +
    +#. module: analytic
    +#: field:account.analytic.account,quantity_max:0
    +msgid "Maximum Quantity"
    +msgstr "Maksimum antall"
    +
    +#. module: analytic
    +#: field:account.analytic.line,user_id:0
    +msgid "User"
    +msgstr "Bruker"
    +
    +#. module: analytic
    +#: field:account.analytic.account,parent_id:0
    +msgid "Parent Analytic Account"
    +msgstr "Overordnet analytisk konto"
    +
    +#. module: analytic
    +#: field:account.analytic.line,date:0
    +msgid "Date"
    +msgstr "Dato"
    +
    +#. module: analytic
    +#: field:account.analytic.account,currency_id:0
    +msgid "Account currency"
    +msgstr "Konto valuta"
    +
    +#. module: analytic
    +#: field:account.analytic.account,quantity:0
    +#: field:account.analytic.line,unit_amount:0
    +msgid "Quantity"
    +msgstr "Antall"
    +
    +#. module: analytic
    +#: help:account.analytic.line,amount:0
    +msgid ""
    +"Calculated by multiplying the quantity and the price given in the Product's "
    +"cost price. Always expressed in the company main currency."
    +msgstr ""
    +"Beregnet ved å multiplisere antall og pris gitt av produktets kostpris. "
    +"Alltid uttrykt i firmaets hovedvaluta."
    +
    +#. module: analytic
    +#: help:account.analytic.account,quantity_max:0
    +msgid "Sets the higher limit of quantity of hours."
    +msgstr ""
    +
    +#. module: analytic
    +#: field:account.analytic.account,credit:0
    +msgid "Credit"
    +msgstr "Kredit"
    +
    +#. module: analytic
    +#: field:account.analytic.line,amount:0
    +msgid "Amount"
    +msgstr "Beløp"
    +
    +#. module: analytic
    +#: field:account.analytic.account,contact_id:0
    +msgid "Contact"
    +msgstr "Kontakt"
    +
    +#. module: analytic
    +#: constraint:account.analytic.account:0
    +msgid ""
    +"Error! The currency has to be the same as the currency of the selected "
    +"company"
    +msgstr "Feil! Valutaen må være lik valuaten til det valgte firmaet"
    +
    +#. module: analytic
    +#: selection:account.analytic.account,state:0
    +msgid "Cancelled"
    +msgstr "Annulert"
    +
    +#. module: analytic
    +#: field:account.analytic.account,balance:0
    +msgid "Balance"
    +msgstr "Saldo"
    +
    +#. module: analytic
    +#: constraint:account.analytic.account:0
    +msgid "Error! You can not create recursive analytic accounts."
    +msgstr ""
    +
    +#. module: analytic
    +#: help:account.analytic.account,type:0
    +msgid ""
    +"If you select the View Type, it means you won't allow to create journal "
    +"entries using that account."
    +msgstr ""
    +
    +#. module: analytic
    +#: field:account.analytic.account,date:0
    +msgid "Date End"
    +msgstr ""
    +
    +#. module: analytic
    +#: field:account.analytic.account,code:0
    +msgid "Account Code"
    +msgstr "Kontokode"
    +
    +#. module: analytic
    +#: field:account.analytic.account,complete_name:0
    +msgid "Full Account Name"
    +msgstr ""
    +
    +#. module: analytic
    +#: field:account.analytic.line,account_id:0
    +#: model:ir.model,name:analytic.model_account_analytic_account
    +#: model:ir.module.module,shortdesc:analytic.module_meta_information
    +msgid "Analytic Account"
    +msgstr "Analytisk konto"
    +
    +#. module: analytic
    +#: selection:account.analytic.account,type:0
    +msgid "View"
    +msgstr ""
    +
    +#. module: analytic
    +#: field:account.analytic.account,partner_id:0
    +msgid "Partner"
    +msgstr "Partner"
    +
    +#. module: analytic
    +#: field:account.analytic.account,date_start:0
    +msgid "Date Start"
    +msgstr "Startdato"
    +
    +#. module: analytic
    +#: selection:account.analytic.account,state:0
    +msgid "Open"
    +msgstr "Åpen"
    +
    +#. module: analytic
    +#: field:account.analytic.account,line_ids:0
    +msgid "Analytic Entries"
    +msgstr ""
    diff --git a/addons/anonymization/i18n/ca.po b/addons/anonymization/i18n/ca.po
    new file mode 100644
    index 00000000000..5ea0c6cc031
    --- /dev/null
    +++ b/addons/anonymization/i18n/ca.po
    @@ -0,0 +1,226 @@
    +# Catalan translation for openobject-addons
    +# Copyright (c) 2011 Rosetta Contributors and Canonical Ltd 2011
    +# This file is distributed under the same license as the openobject-addons package.
    +# FIRST AUTHOR , 2011.
    +#
    +msgid ""
    +msgstr ""
    +"Project-Id-Version: openobject-addons\n"
    +"Report-Msgid-Bugs-To: FULL NAME \n"
    +"POT-Creation-Date: 2011-01-11 11:14+0000\n"
    +"PO-Revision-Date: 2011-04-09 18:26+0000\n"
    +"Last-Translator: FULL NAME \n"
    +"Language-Team: Catalan \n"
    +"MIME-Version: 1.0\n"
    +"Content-Type: text/plain; charset=UTF-8\n"
    +"Content-Transfer-Encoding: 8bit\n"
    +"X-Launchpad-Export-Date: 2011-04-10 04:49+0000\n"
    +"X-Generator: Launchpad (build 12735)\n"
    +
    +#. module: anonymization
    +#: model:ir.model,name:anonymization.model_ir_model_fields_anonymize_wizard
    +msgid "ir.model.fields.anonymize.wizard"
    +msgstr ""
    +
    +#. module: anonymization
    +#: field:ir.model.fields.anonymization,field_name:0
    +msgid "Field Name"
    +msgstr ""
    +
    +#. module: anonymization
    +#: field:ir.model.fields.anonymization,field_id:0
    +msgid "Field"
    +msgstr ""
    +
    +#. module: anonymization
    +#: field:ir.model.fields.anonymization.history,state:0
    +#: field:ir.model.fields.anonymize.wizard,state:0
    +msgid "State"
    +msgstr ""
    +
    +#. module: anonymization
    +#: field:ir.model.fields.anonymize.wizard,file_import:0
    +msgid "Import"
    +msgstr ""
    +
    +#. module: anonymization
    +#: model:ir.model,name:anonymization.model_ir_model_fields_anonymization
    +msgid "ir.model.fields.anonymization"
    +msgstr ""
    +
    +#. module: anonymization
    +#: model:ir.module.module,shortdesc:anonymization.module_meta_information
    +msgid "Database anonymization module"
    +msgstr ""
    +
    +#. module: anonymization
    +#: field:ir.model.fields.anonymization.history,direction:0
    +msgid "Direction"
    +msgstr ""
    +
    +#. module: anonymization
    +#: model:ir.actions.act_window,name:anonymization.action_ir_model_fields_anonymization_tree
    +#: view:ir.model.fields.anonymization:0
    +#: model:ir.ui.menu,name:anonymization.menu_administration_anonymization_fields
    +msgid "Anonymized Fields"
    +msgstr ""
    +
    +#. module: anonymization
    +#: model:ir.ui.menu,name:anonymization.menu_administration_anonymization
    +msgid "Database anonymization"
    +msgstr ""
    +
    +#. module: anonymization
    +#: code:addons/anonymization/anonymization.py:55
    +#: sql_constraint:ir.model.fields.anonymization:0
    +#, python-format
    +msgid "You cannot have two records having the same model and the same field"
    +msgstr ""
    +
    +#. module: anonymization
    +#: selection:ir.model.fields.anonymization,state:0
    +#: selection:ir.model.fields.anonymize.wizard,state:0
    +msgid "Anonymized"
    +msgstr ""
    +
    +#. module: anonymization
    +#: field:ir.model.fields.anonymization,state:0
    +msgid "unknown"
    +msgstr ""
    +
    +#. module: anonymization
    +#: field:ir.model.fields.anonymization,model_id:0
    +msgid "Object"
    +msgstr ""
    +
    +#. module: anonymization
    +#: field:ir.model.fields.anonymization.history,filepath:0
    +msgid "File path"
    +msgstr ""
    +
    +#. module: anonymization
    +#: field:ir.model.fields.anonymization.history,date:0
    +msgid "Date"
    +msgstr ""
    +
    +#. module: anonymization
    +#: field:ir.model.fields.anonymize.wizard,file_export:0
    +msgid "Export"
    +msgstr ""
    +
    +#. module: anonymization
    +#: view:ir.model.fields.anonymize.wizard:0
    +msgid "Reverse the Database Anonymization"
    +msgstr ""
    +
    +#. module: anonymization
    +#: view:ir.model.fields.anonymize.wizard:0
    +msgid "Database Anonymization"
    +msgstr ""
    +
    +#. module: anonymization
    +#: model:ir.ui.menu,name:anonymization.menu_administration_anonymization_wizard
    +msgid "Anonymize database"
    +msgstr ""
    +
    +#. module: anonymization
    +#: view:ir.model.fields.anonymization.history:0
    +#: field:ir.model.fields.anonymization.history,field_ids:0
    +msgid "Fields"
    +msgstr ""
    +
    +#. module: anonymization
    +#: selection:ir.model.fields.anonymization,state:0
    +#: selection:ir.model.fields.anonymize.wizard,state:0
    +msgid "Clear"
    +msgstr ""
    +
    +#. module: anonymization
    +#: selection:ir.model.fields.anonymization.history,direction:0
    +msgid "clear -> anonymized"
    +msgstr ""
    +
    +#. module: anonymization
    +#: view:ir.model.fields.anonymize.wizard:0
    +#: field:ir.model.fields.anonymize.wizard,summary:0
    +msgid "Summary"
    +msgstr ""
    +
    +#. module: anonymization
    +#: view:ir.model.fields.anonymization:0
    +msgid "Anonymized Field"
    +msgstr ""
    +
    +#. module: anonymization
    +#: model:ir.module.module,description:anonymization.module_meta_information
    +msgid ""
    +"\n"
    +"This module allows you to anonymize a database.\n"
    +"    "
    +msgstr ""
    +
    +#. module: anonymization
    +#: selection:ir.model.fields.anonymize.wizard,state:0
    +msgid "Unstable"
    +msgstr ""
    +
    +#. module: anonymization
    +#: selection:ir.model.fields.anonymization.history,state:0
    +msgid "Exception occured"
    +msgstr ""
    +
    +#. module: anonymization
    +#: selection:ir.model.fields.anonymization,state:0
    +#: selection:ir.model.fields.anonymize.wizard,state:0
    +msgid "Not Existing"
    +msgstr ""
    +
    +#. module: anonymization
    +#: field:ir.model.fields.anonymization,model_name:0
    +msgid "Object Name"
    +msgstr ""
    +
    +#. module: anonymization
    +#: model:ir.actions.act_window,name:anonymization.action_ir_model_fields_anonymization_history_tree
    +#: view:ir.model.fields.anonymization.history:0
    +#: model:ir.ui.menu,name:anonymization.menu_administration_anonymization_history
    +msgid "Anonymization History"
    +msgstr ""
    +
    +#. module: anonymization
    +#: model:ir.model,name:anonymization.model_ir_model_fields_anonymization_history
    +msgid "ir.model.fields.anonymization.history"
    +msgstr ""
    +
    +#. module: anonymization
    +#: model:ir.actions.act_window,name:anonymization.action_ir_model_fields_anonymize_wizard
    +#: view:ir.model.fields.anonymize.wizard:0
    +msgid "Anonymize Database"
    +msgstr ""
    +
    +#. module: anonymization
    +#: field:ir.model.fields.anonymize.wizard,name:0
    +msgid "File Name"
    +msgstr ""
    +
    +#. module: anonymization
    +#: selection:ir.model.fields.anonymization.history,direction:0
    +msgid "anonymized -> clear"
    +msgstr ""
    +
    +#. module: anonymization
    +#: selection:ir.model.fields.anonymization.history,state:0
    +msgid "Started"
    +msgstr ""
    +
    +#. module: anonymization
    +#: selection:ir.model.fields.anonymization.history,state:0
    +msgid "Done"
    +msgstr ""
    +
    +#. module: anonymization
    +#: view:ir.model.fields.anonymization.history:0
    +#: field:ir.model.fields.anonymization.history,msg:0
    +#: field:ir.model.fields.anonymize.wizard,msg:0
    +msgid "Message"
    +msgstr ""
    diff --git a/addons/base_synchro/i18n/ca.po b/addons/base_synchro/i18n/ca.po
    new file mode 100644
    index 00000000000..63b8bd5664e
    --- /dev/null
    +++ b/addons/base_synchro/i18n/ca.po
    @@ -0,0 +1,289 @@
    +# Catalan translation for openobject-addons
    +# Copyright (c) 2011 Rosetta Contributors and Canonical Ltd 2011
    +# This file is distributed under the same license as the openobject-addons package.
    +# FIRST AUTHOR , 2011.
    +#
    +msgid ""
    +msgstr ""
    +"Project-Id-Version: openobject-addons\n"
    +"Report-Msgid-Bugs-To: FULL NAME \n"
    +"POT-Creation-Date: 2011-01-11 11:14+0000\n"
    +"PO-Revision-Date: 2011-04-10 21:15+0000\n"
    +"Last-Translator: FULL NAME \n"
    +"Language-Team: Catalan \n"
    +"MIME-Version: 1.0\n"
    +"Content-Type: text/plain; charset=UTF-8\n"
    +"Content-Transfer-Encoding: 8bit\n"
    +"X-Launchpad-Export-Date: 2011-04-11 04:54+0000\n"
    +"X-Generator: Launchpad (build 12735)\n"
    +
    +#. module: base_synchro
    +#: model:ir.actions.act_window,name:base_synchro.action_view_base_synchro
    +msgid "Base Synchronization"
    +msgstr ""
    +
    +#. module: base_synchro
    +#: field:base.synchro.server,server_db:0
    +msgid "Server Database"
    +msgstr ""
    +
    +#. module: base_synchro
    +#: view:base.synchro.server:0
    +#: model:ir.model,name:base_synchro.model_base_synchro_server
    +msgid "Synchronized server"
    +msgstr ""
    +
    +#. module: base_synchro
    +#: field:base.synchro.obj.avoid,name:0
    +msgid "Field Name"
    +msgstr ""
    +
    +#. module: base_synchro
    +#: field:base.synchro.obj,synchronize_date:0
    +msgid "Latest Synchronization"
    +msgstr ""
    +
    +#. module: base_synchro
    +#: field:base.synchro,user_id:0
    +msgid "Send Result To"
    +msgstr ""
    +
    +#. module: base_synchro
    +#: model:ir.model,name:base_synchro.model_base_synchro_obj_avoid
    +msgid "Fields to not synchronize"
    +msgstr ""
    +
    +#. module: base_synchro
    +#: view:base.synchro:0
    +msgid "_Close"
    +msgstr ""
    +
    +#. module: base_synchro
    +#: view:base.synchro:0
    +msgid "Transfer Data To Server"
    +msgstr ""
    +
    +#. module: base_synchro
    +#: model:ir.model,name:base_synchro.model_base_synchro_obj
    +msgid "Register Class"
    +msgstr ""
    +
    +#. module: base_synchro
    +#: view:base.synchro.obj:0
    +#: model:ir.actions.act_window,name:base_synchro.action_transfer_tree
    +#: model:ir.ui.menu,name:base_synchro.transfer_menu_id
    +msgid "Synchronized objects"
    +msgstr ""
    +
    +#. module: base_synchro
    +#: field:base.synchro.server,obj_ids:0
    +msgid "Models"
    +msgstr ""
    +
    +#. module: base_synchro
    +#: field:base.synchro.obj.avoid,obj_id:0
    +#: view:base.synchro.obj.line:0
    +#: field:base.synchro.obj.line,obj_id:0
    +msgid "Object"
    +msgstr ""
    +
    +#. module: base_synchro
    +#: field:base.synchro.server,login:0
    +msgid "User Name"
    +msgstr ""
    +
    +#. module: base_synchro
    +#: view:base.synchro.obj:0
    +#: view:base.synchro.obj.line:0
    +msgid "Group By"
    +msgstr ""
    +
    +#. module: base_synchro
    +#: selection:base.synchro.obj,action:0
    +msgid "Upload"
    +msgstr ""
    +
    +#. module: base_synchro
    +#: view:base.synchro.obj:0
    +msgid "Latest synchronization"
    +msgstr ""
    +
    +#. module: base_synchro
    +#: model:ir.module.module,description:base_synchro.module_meta_information
    +msgid "Synchronization with all objects."
    +msgstr ""
    +
    +#. module: base_synchro
    +#: view:base.synchro.obj.line:0
    +#: field:base.synchro.obj.line,name:0
    +msgid "Date"
    +msgstr ""
    +
    +#. module: base_synchro
    +#: field:base.synchro.server,password:0
    +msgid "Password"
    +msgstr ""
    +
    +#. module: base_synchro
    +#: field:base.synchro.obj,avoid_ids:0
    +msgid "Fields Not Sync."
    +msgstr ""
    +
    +#. module: base_synchro
    +#: selection:base.synchro.obj,action:0
    +msgid "Both"
    +msgstr ""
    +
    +#. module: base_synchro
    +#: field:base.synchro.obj,name:0
    +msgid "Name"
    +msgstr ""
    +
    +#. module: base_synchro
    +#: view:base.synchro.obj:0
    +msgid "Fields"
    +msgstr ""
    +
    +#. module: base_synchro
    +#: view:base.synchro.obj.line:0
    +msgid "Transfered Ids Details"
    +msgstr ""
    +
    +#. module: base_synchro
    +#: field:base.synchro.obj,action:0
    +msgid "Synchronisation direction"
    +msgstr ""
    +
    +#. module: base_synchro
    +#: field:base.synchro.obj,server_id:0
    +msgid "Server"
    +msgstr ""
    +
    +#. module: base_synchro
    +#: model:ir.actions.act_window,name:base_synchro.action_base_synchro_obj_line_tree
    +#: model:ir.model,name:base_synchro.model_base_synchro_obj_line
    +#: model:ir.ui.menu,name:base_synchro.menu_action_base_synchro_obj_line_tree
    +msgid "Synchronized instances"
    +msgstr ""
    +
    +#. module: base_synchro
    +#: field:base.synchro.obj,active:0
    +msgid "Active"
    +msgstr ""
    +
    +#. module: base_synchro
    +#: view:base.synchro.obj:0
    +#: field:base.synchro.obj,model_id:0
    +msgid "Object to synchronize"
    +msgstr ""
    +
    +#. module: base_synchro
    +#: model:ir.module.module,shortdesc:base_synchro.module_meta_information
    +msgid "Base Synchro"
    +msgstr ""
    +
    +#. module: base_synchro
    +#: model:ir.actions.act_window,name:base_synchro.action_base_synchro_server_tree
    +#: model:ir.ui.menu,name:base_synchro.synchro_server_tree_menu_id
    +msgid "Servers to be synchronized"
    +msgstr ""
    +
    +#. module: base_synchro
    +#: view:base.synchro.obj:0
    +msgid "Transfer Details"
    +msgstr ""
    +
    +#. module: base_synchro
    +#: field:base.synchro.obj.line,remote_id:0
    +msgid "Remote Id"
    +msgstr ""
    +
    +#. module: base_synchro
    +#: field:base.synchro.obj,line_id:0
    +msgid "Ids Affected"
    +msgstr ""
    +
    +#. module: base_synchro
    +#: model:ir.ui.menu,name:base_synchro.next_id_63
    +msgid "History"
    +msgstr ""
    +
    +#. module: base_synchro
    +#: model:ir.ui.menu,name:base_synchro.next_id_62
    +#: model:ir.ui.menu,name:base_synchro.synch_config
    +msgid "Synchronization"
    +msgstr ""
    +
    +#. module: base_synchro
    +#: field:base.synchro.obj,domain:0
    +msgid "Domain"
    +msgstr ""
    +
    +#. module: base_synchro
    +#: view:base.synchro:0
    +msgid "_Synchronize"
    +msgstr ""
    +
    +#. module: base_synchro
    +#: view:base.synchro:0
    +msgid "OK"
    +msgstr ""
    +
    +#. module: base_synchro
    +#: field:base.synchro.server,name:0
    +msgid "Server name"
    +msgstr ""
    +
    +#. module: base_synchro
    +#: field:base.synchro.obj,sequence:0
    +msgid "Sequence"
    +msgstr ""
    +
    +#. module: base_synchro
    +#: view:base.synchro:0
    +msgid ""
    +"The synchronisation has been started.You will receive a request when it's "
    +"done."
    +msgstr ""
    +
    +#. module: base_synchro
    +#: field:base.synchro.server,server_port:0
    +msgid "Server Port"
    +msgstr ""
    +
    +#. module: base_synchro
    +#: model:ir.ui.menu,name:base_synchro.menu_action_view_base_synchro
    +msgid "Synchronize objects"
    +msgstr ""
    +
    +#. module: base_synchro
    +#: view:base.synchro:0
    +msgid "Synchronization Complited!"
    +msgstr ""
    +
    +#. module: base_synchro
    +#: model:ir.model,name:base_synchro.model_base_synchro
    +msgid "base.synchro"
    +msgstr ""
    +
    +#. module: base_synchro
    +#: field:base.synchro.obj.line,local_id:0
    +msgid "Local Id"
    +msgstr ""
    +
    +#. module: base_synchro
    +#: model:ir.actions.act_window,name:base_synchro.actions_regclass_tree
    +#: model:ir.actions.act_window,name:base_synchro.actions_transfer_line_form
    +msgid "Filters"
    +msgstr ""
    +
    +#. module: base_synchro
    +#: selection:base.synchro.obj,action:0
    +msgid "Download"
    +msgstr ""
    +
    +#. module: base_synchro
    +#: field:base.synchro,server_url:0
    +#: field:base.synchro.server,server_url:0
    +msgid "Server URL"
    +msgstr ""
    diff --git a/addons/crm/i18n/zh_CN.po b/addons/crm/i18n/zh_CN.po
    index 5ad7b92e95f..2659bb040b9 100644
    --- a/addons/crm/i18n/zh_CN.po
    +++ b/addons/crm/i18n/zh_CN.po
    @@ -7,31 +7,31 @@ msgstr ""
     "Project-Id-Version: OpenERP Server 6.0dev\n"
     "Report-Msgid-Bugs-To: support@openerp.com\n"
     "POT-Creation-Date: 2011-01-11 11:15+0000\n"
    -"PO-Revision-Date: 2011-01-13 14:37+0000\n"
    -"Last-Translator: Wei \"oldrev\" Li \n"
    +"PO-Revision-Date: 2011-04-10 15:13+0000\n"
    +"Last-Translator: Black Jack \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: 2011-03-18 04:45+0000\n"
    -"X-Generator: Launchpad (build 12559)\n"
    +"X-Launchpad-Export-Date: 2011-04-11 04:53+0000\n"
    +"X-Generator: Launchpad (build 12735)\n"
     
     #. module: crm
     #: view:crm.lead.report:0
     msgid "# Leads"
    -msgstr ""
    +msgstr "线索"
     
     #. module: crm
     #: view:crm.lead:0
     #: selection:crm.lead,type:0
     #: selection:crm.lead.report,type:0
     msgid "Lead"
    -msgstr ""
    +msgstr "线索"
     
     #. module: crm
     #: model:crm.case.categ,name:crm.categ_oppor3
     msgid "Need Services"
    -msgstr ""
    +msgstr "需要的服务"
     
     #. module: crm
     #: selection:crm.meeting,rrule_type:0
    @@ -46,12 +46,12 @@ msgstr "安排一个电话访问"
     #. module: crm
     #: model:ir.model,name:crm.model_crm_case_stage
     msgid "Stage of case"
    -msgstr "业务个案阶段"
    +msgstr "业务阶段"
     
     #. module: crm
     #: view:crm.meeting:0
     msgid "Visibility"
    -msgstr "可见性"
    +msgstr "可见等级"
     
     #. module: crm
     #: field:crm.lead,title:0
    @@ -61,13 +61,13 @@ msgstr "标题"
     #. module: crm
     #: field:crm.meeting,show_as:0
     msgid "Show as"
    -msgstr ""
    +msgstr "显示为"
     
     #. module: crm
     #: field:crm.meeting,day:0
     #: selection:crm.meeting,select1:0
     msgid "Date of month"
    -msgstr "月中的天数"
    +msgstr "月的天数"
     
     #. module: crm
     #: view:crm.lead:0
    @@ -78,7 +78,7 @@ msgstr "今日"
     #. module: crm
     #: view:crm.merge.opportunity:0
     msgid "Select Opportunities"
    -msgstr ""
    +msgstr "选择商机"
     
     #. module: crm
     #: view:crm.meeting:0
    @@ -86,7 +86,7 @@ msgstr ""
     #: view:crm.phonecall2phonecall:0
     #: view:crm.send.mail:0
     msgid " "
    -msgstr ""
    +msgstr " "
     
     #. module: crm
     #: view:crm.lead.report:0
    @@ -97,13 +97,13 @@ msgstr "延迟关闭"
     #. module: crm
     #: view:crm.lead:0
     msgid "Previous Stage"
    -msgstr ""
    +msgstr "前一阶段"
     
     #. module: crm
     #: code:addons/crm/wizard/crm_add_note.py:26
     #, python-format
     msgid "Can not add note!"
    -msgstr ""
    +msgstr "添加备注不成功!"
     
     #. module: crm
     #: field:crm.case.stage,name:0
    @@ -121,24 +121,24 @@ msgstr "日"
     #. module: crm
     #: sql_constraint:crm.case.section:0
     msgid "The code of the sales team must be unique !"
    -msgstr "销售团队代码必须唯一!"
    +msgstr "销售团队编码必须唯一!"
     
     #. module: crm
     #: code:addons/crm/wizard/crm_lead_to_opportunity.py:93
     #, python-format
     msgid "Lead '%s' has been converted to an opportunity."
    -msgstr ""
    +msgstr "线索'%s'已转化商机"
     
     #. module: crm
     #: code:addons/crm/crm_lead.py:228
     #, python-format
     msgid "The lead '%s' has been closed."
    -msgstr ""
    +msgstr "线索 '%s' 已关闭."
     
     #. module: crm
     #: selection:crm.meeting,freq:0
     msgid "No Repeat"
    -msgstr ""
    +msgstr "不重复"
     
     #. module: crm
     #: code:addons/crm/wizard/crm_lead_to_opportunity.py:133
    @@ -152,7 +152,7 @@ msgstr "警告!"
     #. module: crm
     #: selection:crm.meeting,rrule_type:0
     msgid "Yearly"
    -msgstr ""
    +msgstr "按年"
     
     #. module: crm
     #: field:crm.segmentation.line,name:0
    @@ -172,7 +172,7 @@ msgstr "营销活动"
     #. module: crm
     #: selection:crm.lead2opportunity.partner,action:0
     msgid "Do not create a partner"
    -msgstr ""
    +msgstr "不能创建这业务伙伴"
     
     #. module: crm
     #: view:crm.lead:0
    @@ -184,7 +184,7 @@ msgstr "搜索商机"
     #, python-format
     msgid ""
     "Opportunity must have Partner assigned before merging with other Opportunity."
    -msgstr ""
    +msgstr "必须要为商机选择一个业务伙伴才能进行商机合并."
     
     #. module: crm
     #: code:addons/crm/wizard/crm_merge_opportunities.py:46
    @@ -198,7 +198,7 @@ msgstr "警告!"
     #: model:ir.actions.act_window,name:crm.action_report_crm_opportunity
     #: model:ir.ui.menu,name:crm.menu_report_crm_opportunities_tree
     msgid "Opportunities Analysis"
    -msgstr ""
    +msgstr "商机分析"
     
     #. module: crm
     #: field:crm.lead,partner_id:0
    @@ -225,7 +225,7 @@ msgstr "业务伙伴"
     #: field:crm.meeting,organizer:0
     #: field:crm.meeting,organizer_id:0
     msgid "Organizer"
    -msgstr ""
    +msgstr "组织者"
     
     #. module: crm
     #: view:crm.phonecall:0
    @@ -233,12 +233,12 @@ msgstr ""
     #: model:ir.actions.act_window,name:crm.phonecall_to_phonecall_act
     #: view:res.partner:0
     msgid "Schedule Other Call"
    -msgstr ""
    +msgstr "安排其它电话访问"
     
     #. module: crm
     #: help:crm.meeting,edit_all:0
     msgid "Edit all Occurrences  of recurrent Meeting."
    -msgstr ""
    +msgstr "编辑经常性的会议"
     
     #. module: crm
     #: code:addons/crm/wizard/crm_opportunity_to_phonecall.py:134
    @@ -249,18 +249,18 @@ msgstr ""
     #: view:res.partner:0
     #, python-format
     msgid "Phone Call"
    -msgstr "电话呼叫"
    +msgstr "电话访问"
     
     #. module: crm
     #: field:crm.lead,optout:0
     msgid "Opt-Out"
    -msgstr ""
    +msgstr "退订"
     
     #. module: crm
     #: code:addons/crm/crm_opportunity.py:108
     #, python-format
     msgid "The opportunity '%s' has been marked as lost."
    -msgstr ""
    +msgstr "商机 '%s' 已丢失."
     
     #. module: crm
     #: model:ir.actions.act_window,help:crm.action_report_crm_lead
    @@ -269,17 +269,17 @@ msgid ""
     "for treatment delays, number of responses given and emails sent. You can "
     "sort out your leads analysis by different groups to get accurate grained "
     "analysis."
    -msgstr ""
    +msgstr "线索分析允许你检查业务关系管理的关息,检查耽搁的处理,回复的邮件l数量。你能整理出对不同群体的线索分析去获得更准确的细粒度分析。"
     
     #. module: crm
     #: view:crm.lead:0
     msgid "Send New Email"
    -msgstr "发送新Email"
    +msgstr "发送新的电子邮件"
     
     #. module: crm
     #: field:crm.segmentation,segmentation_line:0
     msgid "Criteria"
    -msgstr "标准"
    +msgstr "规则"
     
     #. module: crm
     #: view:crm.segmentation:0
    @@ -289,19 +289,19 @@ msgstr "排除的答案:"
     #. module: crm
     #: field:crm.case.stage,section_ids:0
     msgid "Sections"
    -msgstr "划分的业务个案"
    +msgstr "分类"
     
     #. module: crm
     #: view:crm.merge.opportunity:0
     msgid "_Merge"
    -msgstr ""
    +msgstr "合并(_M)"
     
     #. module: crm
     #: view:crm.lead.report:0
     #: model:ir.actions.act_window,name:crm.action_report_crm_lead
     #: model:ir.ui.menu,name:crm.menu_report_crm_leads_tree
     msgid "Leads Analysis"
    -msgstr ""
    +msgstr "线索分析"
     
     #. module: crm
     #: view:crm.lead2opportunity.action:0
    @@ -309,37 +309,37 @@ msgid ""
     "If you select Merge with existing Opportunity, the lead details(with the "
     "communication history) will be merged with existing Opportunity of Selected "
     "partner."
    -msgstr ""
    +msgstr "如果你选择将现有的商机,线索细节(沟通的历史记录)合并那将是和选定的合作伙伴合并现有的商机"
     
     #. module: crm
     #: selection:crm.meeting,class:0
     msgid "Public"
    -msgstr ""
    +msgstr "公开"
     
     #. module: crm
     #: model:ir.actions.act_window,name:crm.crm_case_resource_type_act
     #: model:ir.ui.menu,name:crm.menu_crm_case_resource_type_act
     msgid "Campaigns"
    -msgstr ""
    +msgstr "营销活动"
     
     #. module: crm
     #: model:ir.actions.act_window,name:crm.crm_lead_categ_action
     #: model:ir.ui.menu,name:crm.menu_crm_case_phonecall-act
     #: model:ir.ui.menu,name:crm.menu_crm_lead_categ
     msgid "Categories"
    -msgstr "分类"
    +msgstr "类型"
     
     #. module: crm
     #: selection:crm.meeting,end_type:0
     msgid "Forever"
    -msgstr ""
    +msgstr "永远"
     
     #. module: crm
     #: help:crm.lead,optout:0
     msgid ""
     "If opt-out is checked, this contact has refused to receive emails or "
     "unsubscribed to a campaign."
    -msgstr ""
    +msgstr "如果选择退订,这联系人将不再向其发送邮件或取消订阅营销活动。"
     
     #. module: crm
     #: model:process.transition,name:crm.process_transition_leadpartner0
    @@ -368,23 +368,23 @@ msgstr "联系方式"
     #. module: crm
     #: view:crm.installer:0
     msgid "Enhance your core CRM Application with additional functionalities."
    -msgstr ""
    +msgstr "增强你的业务关系应用和增加功能。"
     
     #. module: crm
     #: field:crm.case.stage,on_change:0
     msgid "Change Probability Automatically"
    -msgstr ""
    +msgstr "自动修改概率"
     
     #. module: crm
     #: field:base.action.rule,regex_history:0
     msgid "Regular Expression on Case History"
    -msgstr "业务个案日志的正则表达式"
    +msgstr "业务日志的规则表达式"
     
     #. module: crm
     #: code:addons/crm/crm_lead.py:209
     #, python-format
     msgid "The lead '%s' has been opened."
    -msgstr ""
    +msgstr "这线索'%s'已经开启"
     
     #. module: crm
     #: model:process.transition,name:crm.process_transition_opportunitymeeting0
    @@ -395,28 +395,28 @@ msgstr "商机会议"
     #: help:crm.lead.report,delay_close:0
     #: help:crm.phonecall.report,delay_close:0
     msgid "Number of Days to close the case"
    -msgstr ""
    +msgstr "到期天数"
     
     #. module: crm
     #: model:process.node,note:crm.process_node_opportunities0
     msgid "When a real project/opportunity is detected"
    -msgstr "当发现一个明确的项目/ 商机"
    +msgstr "当发现一个明确的项目/商机"
     
     #. module: crm
     #: field:crm.installer,crm_fundraising:0
     msgid "Fundraising"
    -msgstr ""
    +msgstr "集资"
     
     #. module: crm
     #: view:res.partner:0
     #: field:res.partner,opportunity_ids:0
     msgid "Leads and Opportunities"
    -msgstr ""
    +msgstr "线索与商机"
     
     #. module: crm
     #: view:crm.send.mail:0
     msgid "_Send"
    -msgstr ""
    +msgstr "发送(_S)"
     
     #. module: crm
     #: view:crm.lead:0
    @@ -426,12 +426,12 @@ msgstr "沟通"
     #. module: crm
     #: field:crm.case.section,change_responsible:0
     msgid "Change Responsible"
    -msgstr ""
    +msgstr "修改负责人"
     
     #. module: crm
     #: field:crm.merge.opportunity,state:0
     msgid "Set State To"
    -msgstr ""
    +msgstr "设状态为"
     
     #. module: crm
     #: model:ir.actions.act_window,help:crm.crm_case_categ_phone_outgoing0
    @@ -442,22 +442,24 @@ msgid ""
     "customer. You can also import a .CSV file with a list of calls to be done by "
     "your sales team."
     msgstr ""
    +"你销售团队电话访问所有要完成的的呼出列表,一个业务员可以在电话访问窗体记录有关信息。这些信息将保存在相关业务伙伴的窗体跟踪每个与客户的沟通。你可以用.cs"
    +"c文件导入你销售团队将要完成的电话访问列表。"
     
     #. module: crm
     #: model:ir.model,name:crm.model_crm_lead2opportunity_action
     msgid "Convert/Merge Opportunity"
    -msgstr ""
    +msgstr "转换/合并 商机"
     
     #. module: crm
     #: field:crm.lead,write_date:0
     msgid "Update Date"
    -msgstr ""
    +msgstr "更新日期"
     
     #. module: crm
     #: view:crm.lead2opportunity.action:0
     #: field:crm.lead2opportunity.action,name:0
     msgid "Select Action"
    -msgstr ""
    +msgstr "选择动作"
     
     #. module: crm
     #: field:base.action.rule,trg_categ_id:0
    @@ -470,22 +472,22 @@ msgstr ""
     #: field:crm.phonecall.report,categ_id:0
     #: field:crm.phonecall2phonecall,categ_id:0
     msgid "Category"
    -msgstr "分类"
    +msgstr "类型"
     
     #. module: crm
     #: view:crm.lead.report:0
     msgid "#Opportunities"
    -msgstr ""
    +msgstr "#商机"
     
     #. module: crm
     #: model:crm.case.resource.type,name:crm.type_oppor2
     msgid "Campaign 1"
    -msgstr ""
    +msgstr "营销活动 1"
     
     #. module: crm
     #: model:crm.case.resource.type,name:crm.type_oppor1
     msgid "Campaign 2"
    -msgstr ""
    +msgstr "营销活动 2"
     
     #. module: crm
     #: view:crm.meeting:0
    @@ -495,32 +497,32 @@ msgstr "隐私"
     #. module: crm
     #: view:crm.lead.report:0
     msgid "Opportunity Analysis"
    -msgstr ""
    +msgstr "商机分析"
     
     #. module: crm
     #: help:crm.meeting,location:0
     msgid "Location of Event"
    -msgstr ""
    +msgstr "地点"
     
     #. module: crm
     #: field:crm.meeting,rrule:0
     msgid "Recurrent Rule"
    -msgstr "周期性规则"
    +msgstr "循环性规则"
     
     #. module: crm
     #: model:crm.case.resource.type,name:crm.type_lead1
     msgid "Version 4.2"
    -msgstr ""
    +msgstr "4.2版本"
     
     #. module: crm
     #: model:crm.case.resource.type,name:crm.type_lead2
     msgid "Version 4.4"
    -msgstr ""
    +msgstr "4.4版本"
     
     #. module: crm
     #: help:crm.installer,fetchmail:0
     msgid "Allows you to receive E-Mails from POP/IMAP server."
    -msgstr ""
    +msgstr "允许你通过POP/IMAP协议接收邮件"
     
     #. module: crm
     #: model:process.transition,note:crm.process_transition_opportunitymeeting0
    @@ -549,7 +551,7 @@ msgstr "建立商机"
     #. module: crm
     #: view:crm.installer:0
     msgid "Configure"
    -msgstr ""
    +msgstr "设置"
     
     #. module: crm
     #: code:addons/crm/crm.py:378
    @@ -580,17 +582,17 @@ msgstr "未运行"
     #: view:crm.send.mail:0
     #: model:ir.actions.act_window,name:crm.action_crm_reply_mail
     msgid "Reply to last Mail"
    -msgstr ""
    +msgstr "最后回复邮件"
     
     #. module: crm
     #: field:crm.lead,email:0
     msgid "E-Mail"
    -msgstr ""
    +msgstr "电子邮件"
     
     #. module: crm
     #: field:crm.installer,wiki_sale_faq:0
     msgid "Sale FAQ"
    -msgstr ""
    +msgstr "销售FAQ"
     
     #. module: crm
     #: model:ir.model,name:crm.model_crm_send_mail_attachment
    @@ -607,19 +609,19 @@ msgstr "10月"
     #. module: crm
     #: view:crm.segmentation:0
     msgid "Included Answers :"
    -msgstr "包括回答:"
    +msgstr "包括答案:"
     
     #. module: crm
     #: help:crm.meeting,email_from:0
     #: help:crm.phonecall,email_from:0
     msgid "These people will receive email."
    -msgstr "这些人将受到电子邮件。"
    +msgstr "这些人将收到电子邮件。"
     
     #. module: crm
     #: view:crm.meeting:0
     #: field:crm.meeting,name:0
     msgid "Summary"
    -msgstr ""
    +msgstr "摘要"
     
     #. module: crm
     #: view:crm.segmentation:0
    @@ -631,7 +633,7 @@ msgstr "满意度计算"
     msgid ""
     "Thick this box if you want that on escalation, the responsible of this sale "
     "team automatically becomes responsible of the lead/opportunity escaladed"
    -msgstr ""
    +msgstr "弹出窗体,如果你希望提升这负责的销售团队自动提升负责的线索/商机。"
     
     #. module: crm
     #: help:crm.installer,outlook:0
    @@ -639,29 +641,29 @@ msgstr ""
     msgid ""
     "Allows you to link your e-mail to OpenERP's documents. You can attach it to "
     "any existing one in OpenERP or create a new one."
    -msgstr ""
    +msgstr "允许你链接你的电子邮件到系统的文档模块。你可以添加到任意一个现存的文档中或新增一个。"
     
     #. module: crm
     #: view:crm.case.categ:0
     msgid "Case Category"
    -msgstr "业务个案分类"
    +msgstr "业务类型"
     
     #. module: crm
     #: help:crm.segmentation,som_interval_default:0
     msgid ""
     "Default state of mind for period preceeding the 'Max Interval' computation. "
     "This is the starting state of mind by default if the partner has no event."
    -msgstr "前期的默认满意度以'最大间隔'计算. 如果业务伙伴没有事件这是默认的开始满意度"
    +msgstr "默认的开始满意度以'最大间隔'计算. 如果业务伙伴没有事件这是默认的开始满意度"
     
     #. module: crm
     #: selection:crm.meeting,end_type:0
     msgid "End date"
    -msgstr ""
    +msgstr "结束日期"
     
     #. module: crm
     #: constraint:base.action.rule:0
     msgid "Error: The mail is not well formated"
    -msgstr ""
    +msgstr "错误:邮件没有正确的格式"
     
     #. module: crm
     #: view:crm.segmentation:0
    @@ -671,14 +673,14 @@ msgstr "特征选项"
     #. module: crm
     #: view:crm.phonecall.report:0
     msgid "#Phone calls"
    -msgstr ""
    +msgstr "电话访问"
     
     #. module: crm
     #: help:crm.segmentation,categ_id:0
     msgid ""
     "The partner category that will be added to partners that match the "
     "segmentation criterions after computation."
    -msgstr "这业务伙伴分类将加入到符合的业务伙伴细分准则"
    +msgstr "这业务伙伴类型将加到计算匹配业务伙伴的业务伙伴细分规则中"
     
     #. module: crm
     #: view:crm.lead:0
    @@ -691,13 +693,13 @@ msgid ""
     "The channels represent the different communication                         "
     "modes available with the customer. With each commercial opportunity, you can "
     "indicate                         the canall which is this opportunity source."
    -msgstr ""
    +msgstr "途径表示与客户联系用到的不同沟通方式,每一个商机你可以标示商机来源的管道。"
     
     #. module: crm
     #: code:addons/crm/crm_meeting.py:93
     #, python-format
     msgid "The meeting '%s' has been confirmed."
    -msgstr ""
    +msgstr "这会议'%s'已确认"
     
     #. module: crm
     #: field:crm.case.section,user_id:0
    @@ -708,31 +710,31 @@ msgstr "负责用户"
     #: code:addons/crm/wizard/crm_phonecall_to_partner.py:53
     #, python-format
     msgid "A partner is already defined on this phonecall."
    -msgstr "在这电话呼叫中一个业务伙伴已定义"
    +msgstr "业务伙伴已定义在这电话访问中"
     
     #. module: crm
     #: help:crm.case.section,reply_to:0
     msgid ""
     "The email address put in the 'Reply-To' of all emails sent by OpenERP about "
     "cases in this sales team"
    -msgstr ""
    +msgstr "'回复到'电子邮件地址填入该业务的团队在系统里设定的发送所有邮件的地址"
     
     #. module: crm
     #: view:res.users:0
     msgid "Current Activity"
    -msgstr ""
    +msgstr "当前活动"
     
     #. module: crm
     #: help:crm.meeting,exrule:0
     msgid ""
     "Defines a rule or repeating pattern of time to exclude from the recurring "
     "rule."
    -msgstr ""
    +msgstr "定义一个规则或时间重复模式以排除循环性规则"
     
     #. module: crm
     #: field:crm.case.section,resource_calendar_id:0
     msgid "Working Time"
    -msgstr ""
    +msgstr "工作时间"
     
     #. module: crm
     #: view:crm.segmentation.line:0
    @@ -743,31 +745,31 @@ msgstr "业务伙伴细分明细"
     #: view:crm.lead:0
     #: view:crm.meeting:0
     msgid "Details"
    -msgstr ""
    +msgstr "详细信息"
     
     #. module: crm
     #: help:crm.installer,crm_caldav:0
     msgid ""
     "Helps you to synchronize the meetings with other calendar clients and "
     "mobiles."
    -msgstr ""
    +msgstr "协助你同步会议到其它的日程客户端"
     
     #. module: crm
     #: selection:crm.meeting,freq:0
     msgid "Years"
    -msgstr ""
    +msgstr "年"
     
     #. module: crm
     #: help:crm.installer,crm_claim:0
     msgid ""
     "Manages the suppliers and customers claims, including your corrective or "
     "preventive actions."
    -msgstr ""
    +msgstr "管理供应商和客户的索赔,包括纠正或预防措施。"
     
     #. module: crm
     #: view:crm.lead:0
     msgid "Leads Form"
    -msgstr "营销线索表"
    +msgstr "线索表单"
     
     #. module: crm
     #: view:crm.segmentation:0
    @@ -778,7 +780,7 @@ msgstr "业务伙伴细分"
     #. module: crm
     #: field:crm.lead.report,probable_revenue:0
     msgid "Probable Revenue"
    -msgstr ""
    +msgstr "可能收入"
     
     #. module: crm
     #: help:crm.segmentation,name:0
    @@ -794,13 +796,13 @@ msgstr "概率(%)"
     #. module: crm
     #: view:crm.lead:0
     msgid "Leads Generation"
    -msgstr ""
    +msgstr "产生线索"
     
     #. module: crm
     #: view:board.board:0
     #: model:ir.ui.menu,name:crm.menu_board_statistics_dash
     msgid "Statistics Dashboard"
    -msgstr ""
    +msgstr "统计控制台"
     
     #. module: crm
     #: code:addons/crm/wizard/crm_lead_to_opportunity.py:86
    @@ -825,7 +827,7 @@ msgstr "电视"
     #. module: crm
     #: field:crm.installer,crm_caldav:0
     msgid "Calendar Synchronizing"
    -msgstr ""
    +msgstr "同步日程"
     
     #. module: crm
     #: view:crm.segmentation:0
    @@ -835,7 +837,7 @@ msgstr "停止处理"
     #. module: crm
     #: view:crm.phonecall:0
     msgid "Search Phonecalls"
    -msgstr "查询电话呼叫"
    +msgstr "查询电话访问"
     
     #. module: crm
     #: view:crm.lead2opportunity.partner:0
    @@ -852,18 +854,18 @@ msgstr "每个期间的天数"
     #. module: crm
     #: field:crm.meeting,byday:0
     msgid "By day"
    -msgstr ""
    +msgstr "按天"
     
     #. module: crm
     #: field:base.action.rule,act_section_id:0
     msgid "Set Team to"
    -msgstr ""
    +msgstr "设定团队"
     
     #. module: crm
     #: view:calendar.attendee:0
     #: field:calendar.attendee,categ_id:0
     msgid "Event Type"
    -msgstr ""
    +msgstr "事件类型"
     
     #. module: crm
     #: model:ir.model,name:crm.model_crm_installer
    @@ -879,7 +881,7 @@ msgstr "唯一的"
     #: code:addons/crm/crm_opportunity.py:91
     #, python-format
     msgid "The opportunity '%s' has been won."
    -msgstr ""
    +msgstr "这个商机 '%s'已获得"
     
     #. module: crm
     #: help:crm.meeting,alarm_id:0
    @@ -920,12 +922,29 @@ msgid ""
     "    * My Cases (list)\n"
     "    * Jobs Tracking (graph)\n"
     msgstr ""
    +"系统的CRM模块能使用户智能高效地管理线索、商机、会议、电话访问等。\n"
    +"它管理关键任务如:沟通、识别、优先等级、分配任务、决定和通知。\n"
    +"\n"
    +"系统确保能成功跟踪用户、客户和供应商的所有业务,它能听自动发提醒,提升请求、触发根据企业其定义规则下的特定方法和大量其他动作。\n"
    +"\n"
    +"系统最牛的事是无需用户做什么特别的事它能根据请求的追踪到正确目标发邮件。系统将根据信息自动路由转交给合适的责任者,并确保以后所有邮件都按照这个路径发到正确"
    +"的地方。\n"
    +"\n"
    +"这CRM模块有一邮件网关作为邮件和系统的同步接口\n"
    +"\n"
    +"CRM控制台包括i:\n"
    +"    *我的线索(列表)\n"
    +"    *线索阶段(图)\n"
    +"    *我的会议(列表)\n"
    +"    *销售渠道阶段(图)\n"
    +"    *我的业务(列表)\n"
    +"    *工作任务(图)\n"
     
     #. module: crm
     #: field:crm.lead.report,create_date:0
     #: field:crm.phonecall.report,create_date:0
     msgid "Create Date"
    -msgstr ""
    +msgstr "建立日期"
     
     #. module: crm
     #: field:crm.lead,ref2:0
    @@ -941,24 +960,24 @@ msgstr "销售采购"
     #: view:crm.case.stage:0
     #: field:crm.case.stage,requirements:0
     msgid "Requirements"
    -msgstr ""
    +msgstr "必备条件"
     
     #. module: crm
     #: help:crm.meeting,exdate:0
     msgid ""
     "This property defines the list of date/time exceptions for a recurring "
     "calendar component."
    -msgstr ""
    +msgstr "这属性定义循环日程的日期/时间异常列表。"
     
     #. module: crm
     #: view:crm.phonecall2opportunity:0
     msgid "Convert To Opportunity "
    -msgstr ""
    +msgstr "转换为商机 "
     
     #. module: crm
     #: help:crm.case.stage,sequence:0
     msgid "Gives the sequence order when displaying a list of case stages."
    -msgstr "在显示业务个案阶段列表时提供序列顺序"
    +msgstr "提供在显示业务列表时的次序"
     
     #. module: crm
     #: view:crm.lead:0
    @@ -967,33 +986,33 @@ msgstr "在显示业务个案阶段列表时提供序列顺序"
     #: model:ir.ui.menu,name:crm.menu_crm_case_opp
     #: model:process.node,name:crm.process_node_opportunities0
     msgid "Opportunities"
    -msgstr "商机"
    +msgstr "商机列表"
     
     #. module: crm
     #: field:crm.segmentation,categ_id:0
     msgid "Partner Category"
    -msgstr "业务伙伴分类"
    +msgstr "业务伙伴类型"
     
     #. module: crm
     #: view:crm.add.note:0
     #: model:ir.actions.act_window,name:crm.action_crm_add_note
     msgid "Add Note"
    -msgstr ""
    +msgstr "添加备注"
     
     #. module: crm
     #: field:crm.lead,is_supplier_add:0
     msgid "Supplier"
    -msgstr ""
    +msgstr "供应商"
     
     #. module: crm
     #: help:crm.send.mail,reply_to:0
     msgid "Reply-to of the Sales team defined on this case"
    -msgstr ""
    +msgstr "在这业务销售团队定义的“回复到”"
     
     #. module: crm
     #: view:crm.lead:0
     msgid "Mark Won"
    -msgstr ""
    +msgstr "获得标记"
     
     #. module: crm
     #: selection:crm.segmentation.line,expr_name:0
    @@ -1003,7 +1022,7 @@ msgstr "采购金额"
     #. module: crm
     #: view:crm.lead:0
     msgid "Mark Lost"
    -msgstr ""
    +msgstr "失去标记"
     
     #. module: crm
     #: selection:crm.lead.report,month:0
    @@ -1016,17 +1035,17 @@ msgstr "3月"
     #: code:addons/crm/crm_lead.py:230
     #, python-format
     msgid "The opportunity '%s' has been closed."
    -msgstr ""
    +msgstr "商机 '%s' 已关闭."
     
     #. module: crm
     #: field:crm.lead,day_open:0
     msgid "Days to Open"
    -msgstr ""
    +msgstr "开启天数"
     
     #. module: crm
     #: view:crm.meeting:0
     msgid "Show time as"
    -msgstr ""
    +msgstr "显示时间为"
     
     #. module: crm
     #: code:addons/crm/crm_lead.py:264
    @@ -1049,19 +1068,19 @@ msgstr "手机"
     #. module: crm
     #: field:crm.meeting,end_type:0
     msgid "Way to end reccurency"
    -msgstr ""
    +msgstr "结束循环的方式"
     
     #. module: crm
     #: code:addons/crm/wizard/crm_merge_opportunities.py:53
     #, python-format
     msgid ""
     "There are no other 'Open' or 'Pending' Opportunities for the partner '%s'."
    -msgstr ""
    +msgstr "业务伙伴‘%s’有没有其他‘开启’或‘待处理’商机"
     
     #. module: crm
     #: view:crm.lead:0
     msgid "Next Stage"
    -msgstr ""
    +msgstr "下一阶段"
     
     #. module: crm
     #: view:board.board:0
    @@ -1076,7 +1095,7 @@ msgstr "参考"
     #. module: crm
     #: field:crm.lead,optin:0
     msgid "Opt-In"
    -msgstr ""
    +msgstr "订阅"
     
     #. module: crm
     #: code:addons/crm/crm_opportunity.py:208
    @@ -1097,7 +1116,7 @@ msgstr "会议"
     #. module: crm
     #: view:crm.meeting:0
     msgid "Choose day where repeat the meeting"
    -msgstr ""
    +msgstr "为重复的会议选择日期"
     
     #. module: crm
     #: field:crm.lead,date_action_next:0
    @@ -1110,7 +1129,7 @@ msgstr "下一动作"
     #. module: crm
     #: field:crm.meeting,end_date:0
     msgid "Repeat Until"
    -msgstr ""
    +msgstr "重复直到"
     
     #. module: crm
     #: field:crm.meeting,date_deadline:0
    @@ -1122,13 +1141,13 @@ msgstr "截止日期"
     msgid ""
     "If the active field is set to          true, it will allow you to hide the "
     "event alarm information without removing it."
    -msgstr ""
    +msgstr "如果有效字段设为true,他将允许你忽略在外面将其删除。"
     
     #. module: crm
     #: code:addons/crm/wizard/crm_phonecall_to_opportunity.py:57
     #, python-format
     msgid "Closed/Cancelled Phone Call Could not convert into Opportunity"
    -msgstr ""
    +msgstr "关闭、取消的电话访问不能转换为商机"
     
     #. module: crm
     #: view:crm.segmentation:0
    @@ -1147,51 +1166,51 @@ msgstr "负责人"
     #. module: crm
     #: view:res.partner:0
     msgid "Previous"
    -msgstr ""
    +msgstr "前一个"
     
     #. module: crm
     #: view:crm.lead:0
     msgid "Statistics"
    -msgstr ""
    +msgstr "统计"
     
     #. module: crm
     #: view:crm.meeting:0
     #: field:crm.send.mail,email_from:0
     msgid "From"
    -msgstr ""
    +msgstr "来自"
     
     #. module: crm
     #: view:crm.lead2opportunity.action:0
     #: view:res.partner:0
     msgid "Next"
    -msgstr ""
    +msgstr "下一个"
     
     #. module: crm
     #: view:crm.lead:0
     msgid "Stage:"
    -msgstr ""
    +msgstr "阶段:"
     
     #. module: crm
     #: model:crm.case.stage,name:crm.stage_lead5
     #: model:crm.case.stage,name:crm.stage_opportunity5
     #: view:crm.lead:0
     msgid "Won"
    -msgstr ""
    +msgstr "获得"
     
     #. module: crm
     #: field:crm.lead.report,delay_expected:0
     msgid "Overpassed Deadline"
    -msgstr ""
    +msgstr "超越截止日期"
     
     #. module: crm
     #: model:crm.case.section,name:crm.section_sales_department
     msgid "Sales Department"
    -msgstr ""
    +msgstr "销售部"
     
     #. module: crm
     #: field:crm.send.mail,html:0
     msgid "HTML formatting?"
    -msgstr ""
    +msgstr "HTML格式?"
     
     #. module: crm
     #: field:crm.case.stage,type:0
    @@ -1222,7 +1241,7 @@ msgstr "最低"
     #: view:crm.send.mail:0
     #: field:crm.send.mail.attachment,binary:0
     msgid "Attachment"
    -msgstr ""
    +msgstr "附件"
     
     #. module: crm
     #: selection:crm.lead.report,month:0
    @@ -1244,12 +1263,12 @@ msgstr "创建日期"
     #. module: crm
     #: model:crm.case.categ,name:crm.categ_oppor5
     msgid "Need a Website Design"
    -msgstr ""
    +msgstr "需要网站设计"
     
     #. module: crm
     #: field:crm.meeting,recurrent_uid:0
     msgid "Recurrent ID"
    -msgstr ""
    +msgstr "循环ID"
     
     #. module: crm
     #: view:crm.lead:0
    @@ -1262,7 +1281,7 @@ msgstr "主题"
     #. module: crm
     #: field:crm.meeting,tu:0
     msgid "Tue"
    -msgstr ""
    +msgstr "周二"
     
     #. module: crm
     #: code:addons/crm/crm_lead.py:300
    @@ -1278,37 +1297,37 @@ msgstr "阶段"
     #. module: crm
     #: view:crm.lead:0
     msgid "History Information"
    -msgstr ""
    +msgstr "日志信息"
     
     #. module: crm
     #: field:base.action.rule,act_mail_to_partner:0
     msgid "Mail to Partner"
    -msgstr ""
    +msgstr "向业务伙伴发邮件"
     
     #. module: crm
     #: view:crm.lead:0
     msgid "Mailings"
    -msgstr ""
    +msgstr "邮件"
     
     #. module: crm
     #: field:crm.meeting,class:0
     msgid "Mark as"
    -msgstr ""
    +msgstr "标记为"
     
     #. module: crm
     #: field:crm.meeting,count:0
     msgid "Repeat"
    -msgstr ""
    +msgstr "重复"
     
     #. module: crm
     #: help:crm.meeting,rrule_type:0
     msgid "Let the event automatically repeat at that interval"
    -msgstr ""
    +msgstr "让事件在该时间间隔自动重复"
     
     #. module: crm
     #: view:base.action.rule:0
     msgid "Condition Case Fields"
    -msgstr ""
    +msgstr "业务状态字段"
     
     #. module: crm
     #: view:crm.case.section:0
    @@ -1335,7 +1354,7 @@ msgstr "预期收益"
     msgid ""
     "Create specific phone call categories to better define the type of calls "
     "tracked in the system."
    -msgstr ""
    +msgstr "在系统中创建指定的电话访问类型以方便定义电话访问跟踪类型"
     
     #. module: crm
     #: selection:crm.lead.report,month:0
    @@ -1353,23 +1372,23 @@ msgstr "处理的最大业务伙伴ID"
     #: model:ir.actions.act_window,name:crm.action_report_crm_phonecall
     #: model:ir.ui.menu,name:crm.menu_report_crm_phonecalls_tree
     msgid "Phone Calls Analysis"
    -msgstr ""
    +msgstr "电话访问分析"
     
     #. module: crm
     #: field:crm.lead.report,opening_date:0
     #: field:crm.phonecall.report,opening_date:0
     msgid "Opening Date"
    -msgstr ""
    +msgstr "开启日期"
     
     #. module: crm
     #: help:crm.phonecall,duration:0
     msgid "Duration in Minutes"
    -msgstr ""
    +msgstr "持续时间(分钟)"
     
     #. module: crm
     #: help:crm.installer,crm_helpdesk:0
     msgid "Manages a Helpdesk service."
    -msgstr ""
    +msgstr "管理一个服务台服务"
     
     #. module: crm
     #: field:crm.partner2opportunity,name:0
    @@ -1381,23 +1400,23 @@ msgstr "商机名称"
     msgid ""
     "If the active field is set to true, it will allow you to hide the sales team "
     "without removing it."
    -msgstr ""
    +msgstr "如果有效字段设为true,它将允许你忽略销售团队在外面删除它。"
     
     #. module: crm
     #: view:crm.lead.report:0
     #: view:crm.phonecall.report:0
     msgid "  Year  "
    -msgstr ""
    +msgstr "  年  "
     
     #. module: crm
     #: field:crm.meeting,edit_all:0
     msgid "Edit All"
    -msgstr ""
    +msgstr "编辑所有"
     
     #. module: crm
     #: field:crm.meeting,fr:0
     msgid "Fri"
    -msgstr ""
    +msgstr "周五"
     
     #. module: crm
     #: model:ir.model,name:crm.model_crm_lead
    @@ -1407,12 +1426,12 @@ msgstr ""
     #. module: crm
     #: field:crm.meeting,write_date:0
     msgid "Write Date"
    -msgstr ""
    +msgstr "写日期"
     
     #. module: crm
     #: view:crm.meeting:0
     msgid "End of recurrency"
    -msgstr ""
    +msgstr "结束循环"
     
     #. module: crm
     #: view:crm.meeting:0
    @@ -1435,7 +1454,7 @@ msgstr "勾选此项, 如果你要使用此标签上的细分规则. 如果不
     #: model:ir.actions.act_window,name:crm.action_crm_phonecall2partner
     #: view:res.partner:0
     msgid "Create a Partner"
    -msgstr ""
    +msgstr "创建业务伙伴"
     
     #. module: crm
     #: field:crm.segmentation,state:0
    @@ -1445,19 +1464,19 @@ msgstr "执行状态"
     #. module: crm
     #: selection:crm.meeting,week_list:0
     msgid "Monday"
    -msgstr ""
    +msgstr "周一"
     
     #. module: crm
     #: field:crm.lead,day_close:0
     msgid "Days to Close"
    -msgstr ""
    +msgstr "结束日期"
     
     #. module: crm
     #: field:crm.add.note,attachment_ids:0
     #: field:crm.case.section,complete_name:0
     #: field:crm.send.mail,attachment_ids:0
     msgid "unknown"
    -msgstr ""
    +msgstr "未知"
     
     #. module: crm
     #: field:crm.lead,id:0
    @@ -1469,7 +1488,7 @@ msgstr "ID"
     #. module: crm
     #: model:ir.model,name:crm.model_crm_partner2opportunity
     msgid "Partner To Opportunity"
    -msgstr ""
    +msgstr "业务伙伴的商机"
     
     #. module: crm
     #: view:crm.meeting:0
    @@ -1488,7 +1507,7 @@ msgstr "日期"
     #: view:crm.meeting:0
     #: view:crm.phonecall.report:0
     msgid "Extended Filters..."
    -msgstr ""
    +msgstr "扩展过滤器..."
     
     #. module: crm
     #: field:crm.phonecall2opportunity,name:0
    @@ -1498,17 +1517,17 @@ msgstr "商机综述"
     #. module: crm
     #: view:crm.phonecall.report:0
     msgid "Search"
    -msgstr ""
    +msgstr "查找"
     
     #. module: crm
     #: view:board.board:0
     msgid "Opportunities by Categories"
    -msgstr ""
    +msgstr "商机类型"
     
     #. module: crm
     #: view:crm.meeting:0
     msgid "Choose day in the month where repeat the meeting"
    -msgstr ""
    +msgstr "在本月为循环的会议选择日期"
     
     #. module: crm
     #: view:crm.segmentation:0
    @@ -1527,17 +1546,17 @@ msgid ""
     "Create specific partner categories which you can assign to your partners to "
     "better manage your interactions with them. The segmentation tool is able to "
     "assign categories to partners according to criteria you set."
    -msgstr ""
    +msgstr "创建指定的业务伙伴类型,细分规则可以根据你设定的规则去指定业务伙伴的类型,以便你可以为更好管理他们和他们互动。"
     
     #. module: crm
     #: field:crm.case.section,code:0
     msgid "Code"
    -msgstr ""
    +msgstr "编码"
     
     #. module: crm
     #: field:crm.case.section,child_ids:0
     msgid "Child Teams"
    -msgstr ""
    +msgstr "子"
     
     #. module: crm
     #: view:crm.lead:0
    @@ -1555,12 +1574,12 @@ msgstr "状态"
     #. module: crm
     #: field:crm.meeting,freq:0
     msgid "Frequency"
    -msgstr ""
    +msgstr "频率"
     
     #. module: crm
     #: view:crm.lead:0
     msgid "References"
    -msgstr "参照"
    +msgstr "参考"
     
     #. module: crm
     #: code:addons/crm/crm.py:392
    @@ -1584,19 +1603,19 @@ msgstr ""
     #. module: crm
     #: model:ir.model,name:crm.model_crm_merge_opportunity
     msgid "Merge two Opportunities"
    -msgstr ""
    +msgstr "合并两个商机"
     
     #. module: crm
     #: selection:crm.meeting,end_type:0
     msgid "Fix amout of times"
    -msgstr ""
    +msgstr "修改的时间"
     
     #. module: crm
     #: view:crm.lead:0
     #: view:crm.meeting:0
     #: view:crm.phonecall:0
     msgid "Current"
    -msgstr ""
    +msgstr "当前的"
     
     #. module: crm
     #: field:crm.meeting,exrule:0
    @@ -1606,27 +1625,27 @@ msgstr "例外规则"
     #. module: crm
     #: help:base.action.rule,act_mail_to_partner:0
     msgid "Check this if you want the rule to send an email to the partner."
    -msgstr "勾选此项, 如果你想规定发Email给业务伙伴"
    +msgstr "勾选此项, 如果你想规定发邮件l给业务伙伴"
     
     #. module: crm
     #: model:ir.actions.act_window,name:crm.crm_phonecall_categ_action
     msgid "Phonecall Categories"
    -msgstr ""
    +msgstr "电话访问类型"
     
     #. module: crm
     #: view:crm.meeting:0
     msgid "Invite People"
    -msgstr ""
    +msgstr "邀请他人"
     
     #. module: crm
     #: constraint:crm.case.section:0
     msgid "Error ! You cannot create recursive Sales team."
    -msgstr ""
    +msgstr "错误!你不能创建递归的销售团队"
     
     #. module: crm
     #: view:crm.meeting:0
     msgid "Search Meetings"
    -msgstr "查询会议"
    +msgstr "查找会议"
     
     #. module: crm
     #: selection:crm.segmentation.line,expr_name:0
    @@ -1637,7 +1656,7 @@ msgstr "销售金额"
     #: code:addons/crm/wizard/crm_send_email.py:141
     #, python-format
     msgid "Unable to send mail. Please check SMTP is configured properly."
    -msgstr ""
    +msgstr "无法发送邮件。请检查SMTP是否设置正确。"
     
     #. module: crm
     #: selection:crm.segmentation.line,expr_operator:0
    @@ -1647,7 +1666,7 @@ msgstr "="
     #. module: crm
     #: selection:crm.meeting,state:0
     msgid "Unconfirmed"
    -msgstr ""
    +msgstr "未确认"
     
     #. module: crm
     #: model:ir.actions.act_window,help:crm.action_report_crm_opportunity
    @@ -1658,6 +1677,7 @@ msgid ""
     "mainly used by the sales manager in order to do the periodic review with the "
     "teams of the sales pipeline."
     msgstr ""
    +"商机分析给你随时访问商机的信息如:预期收入、计划成本、错过的最后时限或者每个商机的互动次数。这个报表主要给销售经理定期审查这团队里的业务员。"
     
     #. module: crm
     #: field:crm.case.categ,name:0
    @@ -1672,7 +1692,7 @@ msgstr "名称"
     #: field:crm.meeting,alarm_id:0
     #: field:crm.meeting,base_calendar_alarm_id:0
     msgid "Alarm"
    -msgstr "报警"
    +msgstr "警告"
     
     #. module: crm
     #: model:ir.actions.act_window,help:crm.crm_lead_stage_act
    @@ -1680,41 +1700,41 @@ msgid ""
     "Add specific stages to leads and opportunities allowing your sales to better "
     "organise their sales pipeline. Stages will allow them to easily track how a "
     "specific lead or opportunity is positioned in the sales cycle."
    -msgstr ""
    +msgstr "为你的销售的线索和商机增加特定的阶段以便更好组织你的销售渠道。阶段使你更轻松跟踪指定的线索或在销售周期中的商机。"
     
     #. module: crm
     #: view:crm.lead.report:0
     #: view:crm.phonecall.report:0
     msgid "My Case(s)"
    -msgstr ""
    +msgstr "我的业务"
     
     #. module: crm
     #: field:crm.lead,birthdate:0
     msgid "Birthdate"
    -msgstr ""
    +msgstr "生日"
     
     #. module: crm
     #: view:crm.meeting:0
     msgid "The"
    -msgstr ""
    +msgstr "这"
     
     #. module: crm
     #: field:crm.send.mail.attachment,wizard_id:0
     msgid "Wizard"
    -msgstr ""
    +msgstr "向导"
     
     #. module: crm
     #: help:crm.lead,section_id:0
     msgid ""
     "Sales team to which this case belongs to. Defines responsible user and e-"
     "mail address for the mail gateway."
    -msgstr ""
    +msgstr "设定这业务销售团队的负责人和邮件地址"
     
     #. module: crm
     #: view:crm.lead:0
     #: view:crm.phonecall:0
     msgid "Creation"
    -msgstr ""
    +msgstr "创建时间"
     
     #. module: crm
     #: selection:crm.lead,priority:0
    @@ -1732,7 +1752,7 @@ msgstr "把潜在客户转成业务伙伴"
     #. module: crm
     #: view:crm.phonecall2opportunity:0
     msgid "_Convert"
    -msgstr ""
    +msgstr "转换(_C)"
     
     #. module: crm
     #: model:ir.actions.act_window,help:crm.action_view_attendee_form
    @@ -1740,12 +1760,12 @@ msgid ""
     "With Meeting Invitations you can create and manage the meeting invitations "
     "sent/to be sent to your colleagues/partners. You can not only invite OpenERP "
     "users, but also external parties, such as a customer."
    -msgstr ""
    +msgstr "与会邀请你可以创建和管理会议邀请发送给你的同事、业务伙伴。你不仅能邀请系统的用户还可以邀请外部人士如客户。"
     
     #. module: crm
     #: selection:crm.meeting,week_list:0
     msgid "Saturday"
    -msgstr ""
    +msgstr "周六"
     
     #. module: crm
     #: selection:crm.meeting,byday:0
    @@ -1755,22 +1775,22 @@ msgstr ""
     #. module: crm
     #: view:crm.phonecall2phonecall:0
     msgid "_Schedule"
    -msgstr ""
    +msgstr "时间表(S)"
     
     #. module: crm
     #: field:crm.lead.report,delay_close:0
     msgid "Delay to Close"
    -msgstr ""
    +msgstr "延迟关闭"
     
     #. module: crm
     #: field:crm.meeting,we:0
     msgid "Wed"
    -msgstr ""
    +msgstr "周三"
     
     #. module: crm
     #: model:crm.case.categ,name:crm.categ_oppor6
     msgid "Potential Reseller"
    -msgstr ""
    +msgstr "潜在分销商"
     
     #. module: crm
     #: field:crm.lead.report,planned_revenue:0
    @@ -1784,32 +1804,32 @@ msgstr "计划收入"
     #: view:crm.phonecall:0
     #: view:crm.phonecall.report:0
     msgid "Group By..."
    -msgstr ""
    +msgstr "分组于"
     
     #. module: crm
     #: help:crm.lead,partner_id:0
     msgid "Optional linked partner, usually after conversion of the lead"
    -msgstr ""
    +msgstr "可选联系业务伙伴,通常在线索转换后"
     
     #. module: crm
     #: view:crm.meeting:0
     msgid "Invitation details"
    -msgstr ""
    +msgstr "邀请详情"
     
     #. module: crm
     #: field:crm.case.section,parent_id:0
     msgid "Parent Team"
    -msgstr ""
    +msgstr "父团队"
     
     #. module: crm
     #: field:crm.lead,date_action:0
     msgid "Next Action Date"
    -msgstr ""
    +msgstr "下一动作日期"
     
     #. module: crm
     #: selection:crm.segmentation,state:0
     msgid "Running"
    -msgstr "正在运行"
    +msgstr "运行中"
     
     #. module: crm
     #: selection:crm.meeting,freq:0
    @@ -1825,12 +1845,12 @@ msgstr ""
     #: code:addons/crm/crm_lead.py:213
     #, python-format
     msgid "The case '%s' has been opened."
    -msgstr ""
    +msgstr "这业务'%s'已开启"
     
     #. module: crm
     #: view:crm.installer:0
     msgid "title"
    -msgstr ""
    +msgstr "标题"
     
     #. module: crm
     #: model:crm.case.categ,name:crm.categ_phone1
    @@ -1844,28 +1864,28 @@ msgstr "来电"
     msgid ""
     "This percentage depicts the default/average probability of the Case for this "
     "stage to be a success"
    -msgstr ""
    +msgstr "这默认百分比描述业务在这阶段的平均的成功概率"
     
     #. module: crm
     #: view:crm.phonecall.report:0
     #: model:ir.actions.act_window,name:crm.act_crm_opportunity_crm_phonecall_new
     msgid "Phone calls"
    -msgstr ""
    +msgstr "电话访问"
     
     #. module: crm
     #: view:crm.lead:0
     msgid "Communication  History"
    -msgstr ""
    +msgstr "沟通日志"
     
     #. module: crm
     #: selection:crm.meeting,show_as:0
     msgid "Free"
    -msgstr ""
    +msgstr "自由"
     
     #. module: crm
     #: view:crm.installer:0
     msgid "Synchronization"
    -msgstr ""
    +msgstr "同步"
     
     #. module: crm
     #: field:crm.case.section,allow_unlink:0
    @@ -1875,7 +1895,7 @@ msgstr "允许删除"
     #. module: crm
     #: field:crm.meeting,mo:0
     msgid "Mon"
    -msgstr ""
    +msgstr "周一"
     
     #. module: crm
     #: selection:crm.lead,priority:0
    @@ -1893,18 +1913,19 @@ msgid ""
     "with a partner. From the phone call form, you can trigger a request for "
     "another call, a meeting or an opportunity."
     msgstr ""
    +"来电管理可以让你记录你的来电,每通电话访问你将出现在业务伙伴界面追溯每个与业务伙伴的联系。从电话访问你可以触发其它的电话访问、会议或商机。"
     
     #. module: crm
     #: help:crm.meeting,recurrency:0
     msgid "Recurrent Meeting"
    -msgstr ""
    +msgstr "循环性会议"
     
     #. module: crm
     #: view:crm.case.section:0
     #: view:crm.lead:0
     #: field:crm.lead,description:0
     msgid "Notes"
    -msgstr ""
    +msgstr "备注"
     
     #. module: crm
     #: selection:crm.meeting,freq:0
    @@ -1920,13 +1941,13 @@ msgstr "值"
     #: view:crm.lead:0
     #: view:crm.lead.report:0
     msgid "Opportunity by Categories"
    -msgstr ""
    +msgstr "商机类型"
     
     #. module: crm
     #: view:crm.lead:0
     #: field:crm.lead,partner_name:0
     msgid "Customer Name"
    -msgstr ""
    +msgstr "客户名称"
     
     #. module: crm
     #: model:ir.actions.act_window,help:crm.crm_case_categ_meet
    @@ -1935,12 +1956,12 @@ msgid ""
     "with other applications such as the employee holidays or the business "
     "opportunities. You can also synchronize meetings with your mobile phone "
     "using the caldav interface."
    -msgstr ""
    +msgstr "会议日程是在销售团队间共享并与其它应用充分集成。如雇员假期或商机。你还可以通过caldav接口同步你的手机和会议"
     
     #. module: crm
     #: model:ir.model,name:crm.model_crm_phonecall2opportunity
     msgid "Phonecall To Opportunity"
    -msgstr ""
    +msgstr "电话访问转换到商机"
     
     #. module: crm
     #: field:crm.case.section,reply_to:0
    @@ -1950,29 +1971,29 @@ msgstr "回复到"
     #. module: crm
     #: view:crm.case.section:0
     msgid "Select stages for this Sales Team"
    -msgstr ""
    +msgstr "为销售团队选择阶段"
     
     #. module: crm
     #: view:board.board:0
     msgid "Opportunities by Stage"
    -msgstr ""
    +msgstr "商机的阶段"
     
     #. module: crm
     #: view:crm.meeting:0
     msgid "Recurrency Option"
    -msgstr ""
    +msgstr "循环选择"
     
     #. module: crm
     #: model:process.transition,note:crm.process_transition_leadpartner0
     msgid "Prospect is converting to business partner"
    -msgstr "潜在客户转为业务伙伴"
    +msgstr "潜在客户转换为业务伙伴"
     
     #. module: crm
     #: view:crm.lead2opportunity:0
     #: view:crm.partner2opportunity:0
     #: model:ir.actions.act_window,name:crm.phonecall2opportunity_act
     msgid "Convert To Opportunity"
    -msgstr "转为商机"
    +msgstr "转换为商机"
     
     #. module: crm
     #: view:crm.phonecall:0
    @@ -1998,12 +2019,12 @@ msgstr "额外信息"
     #: model:ir.actions.act_window,name:crm.action_merge_opportunities
     #: model:ir.actions.act_window,name:crm.merge_opportunity_act
     msgid "Merge Opportunities"
    -msgstr ""
    +msgstr "合并商机"
     
     #. module: crm
     #: model:crm.case.resource.type,name:crm.type_lead5
     msgid "Google Adwords"
    -msgstr ""
    +msgstr "google"
     
     #. module: crm
     #: model:ir.model,name:crm.model_crm_phonecall
    @@ -2013,12 +2034,12 @@ msgstr ""
     #. module: crm
     #: model:crm.case.resource.type,name:crm.type_lead3
     msgid "Mail Campaign 2"
    -msgstr ""
    +msgstr "邮件营销活动 2"
     
     #. module: crm
     #: view:crm.lead:0
     msgid "Create"
    -msgstr ""
    +msgstr "创建"
     
     #. module: crm
     #: view:crm.lead:0
    @@ -2040,7 +2061,7 @@ msgstr "发送"
     #: view:crm.phonecall.report:0
     #: field:crm.phonecall.report,priority:0
     msgid "Priority"
    -msgstr "优先级"
    +msgstr "优先级(0=紧急)"
     
     #. module: crm
     #: field:crm.segmentation,sales_purchase_active:0
    @@ -2050,7 +2071,7 @@ msgstr "使用这销售采购规则"
     #. module: crm
     #: model:ir.model,name:crm.model_crm_lead2opportunity_partner
     msgid "Lead To Opportunity Partner"
    -msgstr ""
    +msgstr "线索转换为业务伙伴或商机"
     
     #. module: crm
     #: field:crm.meeting,location:0
    @@ -2060,12 +2081,12 @@ msgstr "地点"
     #. module: crm
     #: view:crm.lead:0
     msgid "Reply"
    -msgstr ""
    +msgstr "回复"
     
     #. module: crm
     #: selection:crm.meeting,freq:0
     msgid "Weeks"
    -msgstr ""
    +msgstr "周"
     
     #. module: crm
     #: model:process.node,note:crm.process_node_meeting0
    @@ -2083,7 +2104,7 @@ msgstr "错误!"
     msgid ""
     "Create different meeting categories to better organize and classify your "
     "meetings."
    -msgstr ""
    +msgstr "创建不同类型的会议以便更好组织和把会议分类"
     
     #. module: crm
     #: model:ir.model,name:crm.model_crm_segmentation_line
    @@ -2104,23 +2125,23 @@ msgstr "Caldav 服务的URL"
     #. module: crm
     #: view:crm.lead:0
     msgid "Expected Revenues"
    -msgstr ""
    +msgstr "预期收入"
     
     #. module: crm
     #: model:crm.case.resource.type,name:crm.type_lead6
     msgid "Google Adwords 2"
    -msgstr ""
    +msgstr "google 2"
     
     #. module: crm
     #: help:crm.lead,type:0
     #: help:crm.lead.report,type:0
     msgid "Type is used to separate Leads and Opportunities"
    -msgstr ""
    +msgstr "类型用于区分线索和商机"
     
     #. module: crm
     #: view:crm.phonecall2partner:0
     msgid "Are you sure you want to create a partner based on this Phonecall ?"
    -msgstr ""
    +msgstr "你确定你基于这电话访问创建的业务伙伴?"
     
     #. module: crm
     #: selection:crm.lead.report,month:0
    @@ -2138,23 +2159,25 @@ msgid ""
     "The opportunities and sales order displayed, will automatically be filtered "
     "according to his team."
     msgstr ""
    +"定义销售团队组织你不同的业务员或者销售部门成立一个独立的团队。每个团队工作在自己的商机‘销售单,如每个用户能设置默认的团队的客户偏好。商机和销售订单将根据"
    +"他的团队自动过滤。"
     
     #. module: crm
     #: help:crm.meeting,count:0
     msgid "Repeat x times"
    -msgstr ""
    +msgstr "重复 x 时间"
     
     #. module: crm
     #: model:ir.actions.act_window,name:crm.crm_case_section_act
     #: model:ir.model,name:crm.model_crm_case_section
     #: model:ir.ui.menu,name:crm.menu_crm_case_section_act
     msgid "Sales Teams"
    -msgstr ""
    +msgstr "销售团队"
     
     #. module: crm
     #: model:ir.model,name:crm.model_crm_lead2partner
     msgid "Lead to Partner"
    -msgstr ""
    +msgstr "线索转换为业务伙伴"
     
     #. module: crm
     #: view:crm.segmentation:0
    @@ -2166,7 +2189,7 @@ msgstr "细分"
     #. module: crm
     #: view:crm.lead:0
     msgid "Team"
    -msgstr ""
    +msgstr "团队"
     
     #. module: crm
     #: field:crm.installer,outlook:0
    @@ -2183,7 +2206,7 @@ msgstr "不保留"
     #. module: crm
     #: field:crm.lead.report,probability:0
     msgid "Probability"
    -msgstr ""
    +msgstr "概率"
     
     #. module: crm
     #: view:crm.lead.report:0
    @@ -2200,7 +2223,7 @@ msgstr "月份"
     #: model:ir.ui.menu,name:crm.menu_crm_case_categ0_act_leads
     #: model:process.node,name:crm.process_node_leads0
     msgid "Leads"
    -msgstr "营销线索"
    +msgstr "线索"
     
     #. module: crm
     #: model:ir.actions.act_window,help:crm.crm_case_category_act_leads_all
    @@ -2215,6 +2238,9 @@ msgid ""
     "email gateway: new emails may create leads, each of them automatically gets "
     "the history of the conversation with the prospect."
     msgstr ""
    +"线索允许你管理和跟踪对对你产品或服务有兴趣的潜在业务伙伴的初次接触。通常线索是你销售周期的第一步。一旦合适,线索转换为商机,同时创建与相关业务伙伴的进一步"
    +"详细跟踪链接活动。你可以导入潜在业务伙伴的数据,跟踪你的商业活动或整合系统线索和与你的联系。线索能连接到邮件网关:新的邮件可能创造线索,它能自动获得与潜在"
    +"业务伙伴的每个联系日志。"
     
     #. module: crm
     #: selection:crm.lead2opportunity.partner,action:0
    @@ -2227,28 +2253,28 @@ msgstr "创建新的业务伙伴"
     #: view:crm.meeting:0
     #: view:res.partner:0
     msgid "Start Date"
    -msgstr ""
    +msgstr "开启日期"
     
     #. module: crm
     #: selection:crm.phonecall,state:0
     #: view:crm.phonecall.report:0
     msgid "Todo"
    -msgstr ""
    +msgstr "待办"
     
     #. module: crm
     #: view:crm.meeting:0
     msgid "Delegate"
    -msgstr ""
    +msgstr "委派"
     
     #. module: crm
     #: view:crm.meeting:0
     msgid "Decline"
    -msgstr ""
    +msgstr "拒绝"
     
     #. module: crm
     #: help:crm.lead,optin:0
     msgid "If opt-in is checked, this contact has accepted to receive emails."
    -msgstr ""
    +msgstr "如果选择订阅,这联系人同意接收邮件。"
     
     #. module: crm
     #: view:crm.meeting:0
    @@ -2265,7 +2291,7 @@ msgstr "备注"
     #. module: crm
     #: constraint:res.users:0
     msgid "The chosen company is not in the allowed companies for this user"
    -msgstr ""
    +msgstr "选择的公司不属于此用户允许访问的公司。"
     
     #. module: crm
     #: selection:crm.lead,priority:0
    @@ -2292,7 +2318,7 @@ msgstr "已关闭"
     #. module: crm
     #: view:crm.installer:0
     msgid "Plug-In"
    -msgstr ""
    +msgstr "插件"
     
     #. module: crm
     #: model:crm.case.categ,name:crm.categ_meet2
    @@ -2312,7 +2338,7 @@ msgstr "内部会议"
     #: selection:crm.send.mail,state:0
     #, python-format
     msgid "Pending"
    -msgstr "悬而未决"
    +msgstr "待处理"
     
     #. module: crm
     #: model:crm.case.categ,name:crm.categ_meet1
    @@ -2323,7 +2349,7 @@ msgstr "客户会议"
     #: view:crm.lead:0
     #: field:crm.lead,email_cc:0
     msgid "Global CC"
    -msgstr ""
    +msgstr "完整抄送"
     
     #. module: crm
     #: view:crm.phonecall:0
    @@ -2331,13 +2357,13 @@ msgstr ""
     #: model:ir.ui.menu,name:crm.menu_crm_case_phone
     #: view:res.partner:0
     msgid "Phone Calls"
    -msgstr "电话呼叫"
    +msgstr "电话访问"
     
     #. module: crm
     #: help:crm.lead.report,delay_open:0
     #: help:crm.phonecall.report,delay_open:0
     msgid "Number of Days to open the case"
    -msgstr ""
    +msgstr "业务开启的天数"
     
     #. module: crm
     #: field:crm.lead,phone:0
    @@ -2358,13 +2384,13 @@ msgstr "有效"
     #: code:addons/crm/crm_lead.py:306
     #, python-format
     msgid "The stage of opportunity '%s' has been changed to '%s'."
    -msgstr ""
    +msgstr "这商机的阶段’%s'已改为'%s'。"
     
     #. module: crm
     #: code:addons/crm/crm_lead.py:282
     #, python-format
     msgid "Changed Stage to: %s"
    -msgstr ""
    +msgstr "修改阶段为'%s'"
     
     #. module: crm
     #: selection:crm.segmentation.line,operator:0
    @@ -2379,7 +2405,7 @@ msgstr ">"
     #. module: crm
     #: view:crm.meeting:0
     msgid "Uncertain"
    -msgstr ""
    +msgstr "不确定"
     
     #. module: crm
     #: field:crm.send.mail,email_cc:0
    @@ -2395,19 +2421,19 @@ msgstr "发送邮件"
     #. module: crm
     #: selection:crm.meeting,freq:0
     msgid "Months"
    -msgstr "月份"
    +msgstr "月"
     
     #. module: crm
     #: help:crm.installer,wiki_sale_faq:0
     msgid ""
     "Helps you manage wiki pages for Frequently Asked Questions on Sales "
     "Application."
    -msgstr ""
    +msgstr "帮助你管理销售应用程序问题与解答的wiki网页"
     
     #. module: crm
     #: help:crm.installer,crm_fundraising:0
     msgid "This may help associations in their fundraising process and tracking."
    -msgstr ""
    +msgstr "这可能会帮助组织集资的处理和跟踪"
     
     #. module: crm
     #: field:crm.lead2opportunity.partner,action:0
    @@ -2431,12 +2457,12 @@ msgstr "下降因子(0.0>1.0)"
     #: view:crm.lead:0
     #: view:crm.send.mail:0
     msgid "Attachments"
    -msgstr ""
    +msgstr "附件"
     
     #. module: crm
     #: selection:crm.meeting,rrule_type:0
     msgid "Weekly"
    -msgstr ""
    +msgstr "按周"
     
     #. module: crm
     #: code:addons/crm/wizard/crm_send_email.py:72
    @@ -2444,12 +2470,12 @@ msgstr ""
     #: code:addons/crm/wizard/crm_send_email.py:270
     #, python-format
     msgid "Can not send mail!"
    -msgstr ""
    +msgstr "发送邮件失败!"
     
     #. module: crm
     #: view:crm.lead:0
     msgid "Misc"
    -msgstr ""
    +msgstr "杂项"
     
     #. module: crm
     #: model:crm.case.categ,name:crm.categ_oppor8
    @@ -2467,7 +2493,7 @@ msgstr "完成"
     #. module: crm
     #: help:crm.meeting,interval:0
     msgid "Repeat every (Days/Week/Month/Year)"
    -msgstr ""
    +msgstr "重复间隔(日/周/年)"
     
     #. module: crm
     #: field:crm.segmentation,som_interval_max:0
    @@ -2477,7 +2503,7 @@ msgstr "最大间隔"
     #. module: crm
     #: view:crm.opportunity2phonecall:0
     msgid "_Schedule Call"
    -msgstr ""
    +msgstr "_计划的电话访问"
     
     #. module: crm
     #: code:addons/crm/crm.py:326
    @@ -2492,64 +2518,64 @@ msgstr ""
     #: view:res.partner:0
     #, python-format
     msgid "Open"
    -msgstr "待处理"
    +msgstr "开启"
     
     #. module: crm
     #: selection:crm.meeting,week_list:0
     msgid "Tuesday"
    -msgstr ""
    +msgstr "周二"
     
     #. module: crm
     #: field:crm.lead,city:0
     msgid "City"
    -msgstr ""
    +msgstr "城市"
     
     #. module: crm
     #: selection:crm.meeting,show_as:0
     msgid "Busy"
    -msgstr ""
    +msgstr "忙碌"
     
     #. module: crm
     #: field:crm.meeting,interval:0
     msgid "Repeat every"
    -msgstr ""
    +msgstr "重复间隔"
     
     #. module: crm
     #: field:crm.installer,crm_helpdesk:0
     msgid "Helpdesk"
    -msgstr "帮助平台"
    +msgstr "服务台"
     
     #. module: crm
     #: field:crm.meeting,recurrency:0
     msgid "Recurrent"
    -msgstr ""
    +msgstr "循环"
     
     #. module: crm
     #: code:addons/crm/crm.py:397
     #, python-format
     msgid "The case '%s' has been cancelled."
    -msgstr ""
    +msgstr "这业务'%s'已取消"
     
     #. module: crm
     #: field:crm.installer,sale_crm:0
     msgid "Opportunity to Quotation"
    -msgstr ""
    +msgstr "商机转换为报价"
     
     #. module: crm
     #: model:ir.model,name:crm.model_crm_send_mail
     msgid "Send new email"
    -msgstr ""
    +msgstr "发送新的邮件"
     
     #. module: crm
     #: view:board.board:0
     #: model:ir.actions.act_window,name:crm.act_my_oppor
     msgid "My Open Opportunities"
    -msgstr ""
    +msgstr "我开启的商机"
     
     #. module: crm
     #: model:ir.actions.act_window,name:crm.open_board_statistical_dash
     msgid "CRM - Statistics Dashboard"
    -msgstr ""
    +msgstr "客户关系管理 - 统计控制台"
     
     #. module: crm
     #: help:crm.meeting,rrule:0
    @@ -2558,34 +2584,36 @@ msgid ""
     "e.g.: Every other month on the last Sunday of the month for 10 occurrences:  "
     "      FREQ=MONTHLY;INTERVAL=2;COUNT=10;BYDAY=-1SU"
     msgstr ""
    +"为循环事件定义一个规则或重复模式。\n"
    +"如:在每隔一个月在这个月的最后一个星期天出现10次; FREQ=MONTHLY;INTERVAL=2;COUNT=10;BYDAY=-1SU"
     
     #. module: crm
     #: field:crm.lead,job_id:0
     msgid "Main Job"
    -msgstr ""
    +msgstr "主业"
     
     #. module: crm
     #: field:base.action.rule,trg_max_history:0
     msgid "Maximum Communication History"
    -msgstr "最多的沟通日志"
    +msgstr "最大的沟通日志"
     
     #. module: crm
     #: view:crm.lead2opportunity.partner:0
     #: view:crm.lead2partner:0
     msgid "Are you sure you want to create a partner based on this lead ?"
    -msgstr "你确定要根据这营销线索创建这业务伙伴?"
    +msgstr "你确定要根据这条线索创建这业务伙伴?"
     
     #. module: crm
     #: view:crm.meeting:0
     #: field:crm.meeting,categ_id:0
     msgid "Meeting Type"
    -msgstr ""
    +msgstr "会议类型"
     
     #. module: crm
     #: code:addons/crm/wizard/crm_lead_to_opportunity.py:312
     #, python-format
     msgid "Merge with Existing Opportunity"
    -msgstr ""
    +msgstr "合并现有的商机"
     
     #. module: crm
     #: help:crm.lead,state:0
    @@ -2599,80 +2627,80 @@ msgid ""
     "       \n"
     "If the case needs to be reviewed then the state is set to 'Pending'."
     msgstr ""
    -"当一个业务个案创建时状态设为'草稿'\n"
    -"如果业务个案正在处理状态设为'待处理'\n"
    -"当业务个案结束状态设为'完成'\n"
    -"如果业务个案需要审查状态设为'悬而未决'"
    +"当一个业务创建时状态设为'草稿'\n"
    +"如果业务正在处理状态设为'开启'\n"
    +"当业务结束状态设为'完成'\n"
    +"如果业务需要审查状态设为'待定'"
     
     #. module: crm
     #: view:crm.meeting:0
     #: view:res.partner:0
     msgid "End Date"
    -msgstr ""
    +msgstr "结束日期"
     
     #. module: crm
     #: selection:crm.meeting,byday:0
     msgid "Third"
    -msgstr ""
    +msgstr "其三"
     
     #. module: crm
     #: help:crm.segmentation,som_interval_max:0
     msgid ""
     "The computation is made on all events that occured during this interval, the "
     "past X periods."
    -msgstr "此计算是基于在在此期间发生的所有事件, 过去的X期间"
    +msgstr "这计算是基于在过去 X 期间发生的所有事件。"
     
     #. module: crm
     #: view:board.board:0
     msgid "My Win/Lost Ratio for the Last Year"
    -msgstr ""
    +msgstr "在过去一年我获得/丢失的比例"
     
     #. module: crm
     #: field:crm.installer,thunderbird:0
     msgid "Thunderbird"
    -msgstr ""
    +msgstr "雷鸟邮件客户端"
     
     #. module: crm
     #: view:crm.lead.report:0
     msgid "# of Emails"
    -msgstr ""
    +msgstr "邮件"
     
     #. module: crm
     #: view:crm.lead:0
     msgid "Search Leads"
    -msgstr "查询营销线索"
    +msgstr "查询线索"
     
     #. module: crm
     #: view:crm.lead.report:0
     #: view:crm.phonecall.report:0
     #: field:crm.phonecall.report,delay_open:0
     msgid "Delay to open"
    -msgstr ""
    +msgstr "延迟开启"
     
     #. module: crm
     #: view:crm.meeting:0
     msgid "Recurrency period"
    -msgstr ""
    +msgstr "循环周期"
     
     #. module: crm
     #: field:crm.meeting,week_list:0
     msgid "Weekday"
    -msgstr ""
    +msgstr "工作日"
     
     #. module: crm
     #: view:crm.lead:0
     msgid "Referrer"
    -msgstr ""
    +msgstr "参考"
     
     #. module: crm
     #: model:ir.model,name:crm.model_crm_lead2opportunity
     msgid "Lead To Opportunity"
    -msgstr ""
    +msgstr "线索转换为商机"
     
     #. module: crm
     #: model:ir.model,name:crm.model_calendar_attendee
     msgid "Attendee information"
    -msgstr ""
    +msgstr "附件信息"
     
     #. module: crm
     #: view:crm.segmentation:0
    @@ -2687,19 +2715,19 @@ msgstr "继续处理"
     #. module: crm
     #: view:crm.installer:0
     msgid "Configure Your CRM Application"
    -msgstr ""
    +msgstr "设置你的客户关系模块"
     
     #. module: crm
     #: model:ir.model,name:crm.model_crm_phonecall2partner
     msgid "Phonecall to Partner"
    -msgstr ""
    +msgstr "电话访问业务伙伴"
     
     #. module: crm
     #: help:crm.lead,partner_name:0
     msgid ""
     "The name of the future partner that will be created while converting the "
     "into opportunity"
    -msgstr ""
    +msgstr "当转换为商机时创建未来业务伙伴名称"
     
     #. module: crm
     #: field:crm.opportunity2phonecall,user_id:0
    @@ -2711,7 +2739,7 @@ msgstr "分配到"
     #: field:crm.add.note,state:0
     #: field:crm.send.mail,state:0
     msgid "Set New State To"
    -msgstr ""
    +msgstr "设定新状态"
     
     #. module: crm
     #: field:crm.lead,date_action_last:0
    @@ -2730,42 +2758,42 @@ msgstr "持续时间"
     #. module: crm
     #: field:crm.send.mail,reply_to:0
     msgid "Reply To"
    -msgstr ""
    +msgstr "回复"
     
     #. module: crm
     #: view:board.board:0
     #: model:ir.actions.act_window,name:crm.open_board_crm
     #: model:ir.ui.menu,name:crm.menu_board_crm
     msgid "Sales Dashboard"
    -msgstr ""
    +msgstr "销售控制台"
     
     #. module: crm
     #: code:addons/crm/wizard/crm_lead_to_partner.py:56
     #, python-format
     msgid "A partner is already defined on this lead."
    -msgstr "此营销线索已定义业务伙伴"
    +msgstr "这线索已定义业务伙伴"
     
     #. module: crm
     #: field:crm.lead.report,nbr:0
     #: field:crm.phonecall.report,nbr:0
     msgid "# of Cases"
    -msgstr "# 业务个案"
    +msgstr "# 业务"
     
     #. module: crm
     #: help:crm.meeting,section_id:0
     #: help:crm.phonecall,section_id:0
     msgid "Sales team to which Case belongs to."
    -msgstr ""
    +msgstr "销售团队属于那个业务"
     
     #. module: crm
     #: selection:crm.meeting,week_list:0
     msgid "Sunday"
    -msgstr ""
    +msgstr "周日"
     
     #. module: crm
     #: selection:crm.meeting,byday:0
     msgid "Fourth"
    -msgstr ""
    +msgstr "4"
     
     #. module: crm
     #: selection:crm.add.note,state:0
    @@ -2778,12 +2806,12 @@ msgstr "未更改"
     #: model:ir.actions.act_window,name:crm.crm_segmentation_tree-act
     #: model:ir.ui.menu,name:crm.menu_crm_segmentation-act
     msgid "Partners Segmentation"
    -msgstr ""
    +msgstr "业务伙伴细分"
     
     #. module: crm
     #: field:crm.lead,fax:0
     msgid "Fax"
    -msgstr ""
    +msgstr "传真"
     
     #. module: crm
     #: model:ir.actions.act_window,help:crm.crm_case_category_act_oppor11
    @@ -2800,11 +2828,15 @@ msgid ""
     "opportunities, convert them into quotations, manage related documents, track "
     "all customer related activities, and much more."
     msgstr ""
    +"对于商机你可以管理和与你的销售渠道创建的特定客户或者跟进潜在销售相关的销售单保持联系,信息如:预期收入,商机的阶段,预计结束日期,大量的沟通日志,通过邮件"
    +"网关商机能和邮件相连:新的邮件可能能创建新的商机,他们能自动获得和客户交流的日志。\n"
    +"\n"
    +"你和你的团队可以为会议和从电话访问来的商机做计划,把它们转换成报价,管理相关文档,跟踪所有相关客户的活动等。。"
     
     #. module: crm
     #: view:crm.meeting:0
     msgid "Assignment"
    -msgstr ""
    +msgstr "分配"
     
     #. module: crm
     #: field:crm.lead,company_id:0
    @@ -2819,12 +2851,12 @@ msgstr "公司"
     #. module: crm
     #: selection:crm.meeting,week_list:0
     msgid "Friday"
    -msgstr ""
    +msgstr "周五"
     
     #. module: crm
     #: field:crm.meeting,allday:0
     msgid "All Day"
    -msgstr ""
    +msgstr "整天"
     
     #. module: crm
     #: field:crm.segmentation.line,operator:0
    @@ -2835,51 +2867,51 @@ msgstr "强制的/ 可选的"
     #: model:ir.actions.act_window,name:crm.action_view_attendee_form
     #: model:ir.ui.menu,name:crm.menu_attendee_invitations
     msgid "Meeting Invitations"
    -msgstr ""
    +msgstr "会议邀请"
     
     #. module: crm
     #: field:crm.case.categ,object_id:0
     msgid "Object Name"
    -msgstr ""
    +msgstr "对象名"
     
     #. module: crm
     #: help:crm.lead,email_from:0
     msgid "E-mail address of the contact"
    -msgstr ""
    +msgstr "这联系的邮件地址"
     
     #. module: crm
     #: field:crm.lead,referred:0
     msgid "Referred By"
    -msgstr ""
    +msgstr "参考来自"
     
     #. module: crm
     #: view:crm.lead:0
     #: model:ir.model,name:crm.model_crm_add_note
     msgid "Add Internal Note"
    -msgstr ""
    +msgstr "添加内部备注"
     
     #. module: crm
     #: code:addons/crm/crm_lead.py:304
     #, python-format
     msgid "The stage of lead '%s' has been changed to '%s'."
    -msgstr ""
    +msgstr "这线索的阶段从 '%s' 改为 '%s'"
     
     #. module: crm
     #: selection:crm.meeting,byday:0
     msgid "Last"
    -msgstr ""
    +msgstr "最后"
     
     #. module: crm
     #: field:crm.lead,message_ids:0
     #: field:crm.meeting,message_ids:0
     #: field:crm.phonecall,message_ids:0
     msgid "Messages"
    -msgstr ""
    +msgstr "消息"
     
     #. module: crm
     #: help:crm.case.stage,on_change:0
     msgid "Change Probability on next and previous stages."
    -msgstr ""
    +msgstr "在下一和前一阶段修改可能性"
     
     #. module: crm
     #: code:addons/crm/crm.py:455
    @@ -2894,7 +2926,7 @@ msgstr "错误!"
     #: field:crm.opportunity2phonecall,name:0
     #: field:crm.phonecall2phonecall,name:0
     msgid "Call summary"
    -msgstr ""
    +msgstr "电话访问摘要"
     
     #. module: crm
     #: selection:crm.add.note,state:0
    @@ -2911,29 +2943,29 @@ msgstr "已取消"
     #. module: crm
     #: field:crm.add.note,body:0
     msgid "Note Body"
    -msgstr ""
    +msgstr "备注内容"
     
     #. module: crm
     #: view:board.board:0
     msgid "My Planned Revenues by Stage"
    -msgstr ""
    +msgstr "这阶段我的计划收入"
     
     #. module: crm
     #: field:crm.lead.report,date_closed:0
     #: field:crm.phonecall.report,date_closed:0
     msgid "Close Date"
    -msgstr ""
    +msgstr "结束日期"
     
     #. module: crm
     #: view:crm.lead.report:0
     #: view:crm.phonecall.report:0
     msgid "   Month   "
    -msgstr ""
    +msgstr "   月   "
     
     #. module: crm
     #: view:crm.lead:0
     msgid "Links"
    -msgstr ""
    +msgstr "链接"
     
     #. module: crm
     #: model:ir.actions.act_window,help:crm.crm_lead_categ_action
    @@ -2942,14 +2974,14 @@ msgid ""
     "classify and analyse your leads and opportunities. Such categories could for "
     "instance reflect your product structure or the different types of sales you "
     "do."
    -msgstr ""
    +msgstr "创建具体合适你公司营销活动的类型以便更好地分类和分析线索和商机。例如这类型能反映你的产品结构或对不同类型的销售该怎么做。"
     
     #. module: crm
     #: help:crm.segmentation,som_interval_decrease:0
     msgid ""
     "If the partner has not purchased (or bought) during a period, decrease the "
     "state of mind by this factor. It's a multiplication"
    -msgstr ""
    +msgstr "如果业务伙伴在一段时间都没有买卖,减少满意度这是一个乘法。"
     
     #. module: crm
     #: model:ir.actions.act_window,help:crm.action_report_crm_phonecall
    @@ -2958,34 +2990,34 @@ msgid ""
     "on their phone calls. You can group or filter the information according to "
     "several criteria and drill down the information, by adding more groups in "
     "the report."
    -msgstr ""
    +msgstr "在这报表中,你能分析你的销售团队在电话访问上的业绩。你能根据几个标准和向下钻取数据组织或过滤信息。它能在报表中加入更多的组。"
     
     #. module: crm
     #: view:crm.case.section:0
     msgid "Mailgateway"
    -msgstr ""
    +msgstr "邮件网关"
     
     #. module: crm
     #: help:crm.lead,user_id:0
     msgid "By Default Salesman is Administrator when create New User"
    -msgstr ""
    +msgstr "当管理员创建新用户时默认是业务员"
     
     #. module: crm
     #: view:crm.lead.report:0
     msgid "# Mails"
    -msgstr ""
    +msgstr "邮件"
     
     #. module: crm
     #: code:addons/crm/wizard/crm_phonecall_to_opportunity.py:57
     #, python-format
     msgid "Warning"
    -msgstr ""
    +msgstr "警告"
     
     #. module: crm
     #: field:crm.phonecall,name:0
     #: view:res.partner:0
     msgid "Call Summary"
    -msgstr "呼叫概要"
    +msgstr "电话访问摘要"
     
     #. module: crm
     #: field:crm.segmentation.line,expr_operator:0
    @@ -2995,17 +3027,17 @@ msgstr "运算符"
     #. module: crm
     #: model:ir.model,name:crm.model_crm_phonecall2phonecall
     msgid "Phonecall To Phonecall"
    -msgstr ""
    +msgstr "电话访问到电话访问"
     
     #. module: crm
     #: view:crm.lead:0
     msgid "Schedule/Log Call"
    -msgstr ""
    +msgstr "计划/电话访问的记录"
     
     #. module: crm
     #: field:crm.installer,fetchmail:0
     msgid "Fetch Emails"
    -msgstr ""
    +msgstr "取邮件"
     
     #. module: crm
     #: selection:crm.meeting,state:0
    @@ -3017,27 +3049,27 @@ msgstr "已确认"
     msgid ""
     "These addresses will receive a copy of this email. To modify the permanent "
     "CC list, edit the global CC field of this case"
    -msgstr ""
    +msgstr "这些地址讲收到这邮件的副本。要永久修改这些抄送地址列表编辑这业务的全局抄送字段。"
     
     #. module: crm
     #: view:crm.meeting:0
     msgid "Confirm"
    -msgstr ""
    +msgstr "确定"
     
     #. module: crm
     #: field:crm.meeting,su:0
     msgid "Sun"
    -msgstr ""
    +msgstr "周日"
     
     #. module: crm
     #: field:crm.phonecall.report,section_id:0
     msgid "Section"
    -msgstr "划分的业务个案"
    +msgstr "分类"
     
     #. module: crm
     #: view:crm.lead:0
     msgid "Total of Planned Revenue"
    -msgstr ""
    +msgstr "计划收入合计"
     
     #. module: crm
     #: code:addons/crm/crm.py:375
    @@ -3045,7 +3077,7 @@ msgstr ""
     msgid ""
     "You can not escalate, You are already at the top level regarding your sales-"
     "team category."
    -msgstr ""
    +msgstr "你不能再提升了,因为你已经在你的销售团队类型的最高级"
     
     #. module: crm
     #: selection:crm.segmentation.line,operator:0
    @@ -3055,12 +3087,12 @@ msgstr "可选表达式"
     #. module: crm
     #: selection:crm.meeting,select1:0
     msgid "Day of month"
    -msgstr ""
    +msgstr "日"
     
     #. module: crm
     #: field:crm.lead2opportunity,probability:0
     msgid "Success Rate (%)"
    -msgstr ""
    +msgstr "成功率(%)"
     
     #. module: crm
     #: model:crm.case.stage,name:crm.stage_lead1
    @@ -3071,7 +3103,7 @@ msgstr "新建"
     #. module: crm
     #: view:crm.meeting:0
     msgid "Mail TO"
    -msgstr ""
    +msgstr "发邮件到"
     
     #. module: crm
     #: view:crm.lead:0
    @@ -3079,7 +3111,7 @@ msgstr ""
     #: field:crm.meeting,email_from:0
     #: field:crm.phonecall,email_from:0
     msgid "Email"
    -msgstr "Email"
    +msgstr "电子邮件"
     
     #. module: crm
     #: view:crm.lead:0
    @@ -3088,19 +3120,19 @@ msgstr "Email"
     #: field:crm.lead.report,channel_id:0
     #: field:crm.phonecall,canal_id:0
     msgid "Channel"
    -msgstr "渠道"
    +msgstr "途径"
     
     #. module: crm
     #: model:ir.actions.act_window,name:crm.opportunity2phonecall_act
     msgid "Schedule Call"
    -msgstr ""
    +msgstr "计划的电话访问"
     
     #. module: crm
     #: code:addons/crm/wizard/crm_lead_to_opportunity.py:133
     #: code:addons/crm/wizard/crm_lead_to_opportunity.py:258
     #, python-format
     msgid "Closed/Cancelled Leads Could not convert into Opportunity"
    -msgstr ""
    +msgstr "已结束/已取消的线索不能转换为商机"
     
     #. module: crm
     #: view:crm.segmentation:0
    @@ -3115,43 +3147,45 @@ msgid ""
     "If checked, remove the category from partners that doesn't match "
     "segmentation criterions"
     msgstr ""
    +"检测如果这业务伙伴在类型的细分规则下是受限制。\n"
    +"如果要选定,请删除在业务伙伴类型细分规则中不匹配的规则"
     
     #. module: crm
     #: field:crm.meeting,exdate:0
     msgid "Exception Date/Times"
    -msgstr "异常日期/ 时间"
    +msgstr "例外的日期/ 时间"
     
     #. module: crm
     #: selection:crm.meeting,class:0
     msgid "Confidential"
    -msgstr ""
    +msgstr "机密"
     
     #. module: crm
     #: help:crm.meeting,date_deadline:0
     msgid ""
     "Deadline Date is automatically                         computed from Start "
     "Date + Duration"
    -msgstr ""
    +msgstr "截止日期是自动计算的:开始日期 +  持续时间"
     
     #. module: crm
     #: field:crm.lead,state_id:0
     msgid "Fed. State"
    -msgstr ""
    +msgstr "省/州"
     
     #. module: crm
     #: model:process.transition,note:crm.process_transition_leadopportunity0
     msgid "Creating business opportunities from Leads"
    -msgstr "从营销线索创建商机"
    +msgstr "从线索创建商机"
     
     #. module: crm
     #: help:crm.send.mail,html:0
     msgid "Select this if you want to send email with HTML formatting."
    -msgstr ""
    +msgstr "如果你想发送HTML格式的邮件,选此"
     
     #. module: crm
     #: model:crm.case.categ,name:crm.categ_oppor4
     msgid "Need Information"
    -msgstr ""
    +msgstr "需要信息"
     
     #. module: crm
     #: model:process.transition,name:crm.process_transition_leadopportunity0
    @@ -3162,12 +3196,12 @@ msgstr "探查商机"
     #: view:crm.installer:0
     #: model:ir.actions.act_window,name:crm.action_crm_installer
     msgid "CRM Application Configuration"
    -msgstr ""
    +msgstr "业务关系管理模块设置"
     
     #. module: crm
     #: field:base.action.rule,act_categ_id:0
     msgid "Set Category to"
    -msgstr ""
    +msgstr "设类型为"
     
     #. module: crm
     #: view:crm.case.section:0
    @@ -3177,7 +3211,7 @@ msgstr "设置"
     #. module: crm
     #: field:crm.meeting,th:0
     msgid "Thu"
    -msgstr ""
    +msgstr "周四"
     
     #. module: crm
     #: view:crm.add.note:0
    @@ -3194,33 +3228,33 @@ msgstr "取消(_C)"
     #: view:crm.lead.report:0
     #: view:crm.phonecall.report:0
     msgid "    Month-1    "
    -msgstr ""
    +msgstr "    上月    "
     
     #. module: crm
     #: help:crm.installer,sale_crm:0
     msgid "This module relates sale from opportunity cases in the CRM."
    -msgstr ""
    +msgstr "这模块涉及在业务关系管理中业务的销售商机"
     
     #. module: crm
     #: selection:crm.meeting,rrule_type:0
     msgid "Daily"
    -msgstr ""
    +msgstr "每天"
     
     #. module: crm
     #: model:crm.case.stage,name:crm.stage_lead2
     #: model:crm.case.stage,name:crm.stage_opportunity2
     msgid "Qualification"
    -msgstr ""
    +msgstr "资格条件"
     
     #. module: crm
     #: view:crm.case.stage:0
     msgid "Stage Definition"
    -msgstr ""
    +msgstr "阶段定义"
     
     #. module: crm
     #: selection:crm.meeting,byday:0
     msgid "First"
    -msgstr ""
    +msgstr "首页"
     
     #. module: crm
     #: selection:crm.lead.report,month:0
    @@ -3232,7 +3266,7 @@ msgstr "12月"
     #. module: crm
     #: field:crm.installer,config_logo:0
     msgid "Image"
    -msgstr ""
    +msgstr "图像"
     
     #. module: crm
     #: view:base.action.rule:0
    @@ -3250,16 +3284,20 @@ msgid ""
     "bought goods to another supplier.                  \n"
     "Use this functionality for recurring businesses."
     msgstr ""
    +"在一个期间两个周期间这细分的业务伙伴销售或采购的平均天数。\n"
    +"它主要用来检查业务伙伴有没有业务或者多长时间有。\n"
    +"所以因此我们假定他的满意度下降因此向其它供应商采购。\n"
    +"对经常的业务使用这功能。"
     
     #. module: crm
     #: view:crm.send.mail:0
     msgid "_Send Reply"
    -msgstr ""
    +msgstr "_发送回复"
     
     #. module: crm
     #: field:crm.meeting,vtimezone:0
     msgid "Timezone"
    -msgstr ""
    +msgstr "时区"
     
     #. module: crm
     #: field:crm.lead2opportunity.partner,msg:0
    @@ -3271,7 +3309,7 @@ msgstr "消息"
     #. module: crm
     #: field:crm.meeting,sa:0
     msgid "Sat"
    -msgstr ""
    +msgstr "周六"
     
     #. module: crm
     #: view:crm.lead:0
    @@ -3279,32 +3317,32 @@ msgstr ""
     #: view:crm.lead.report:0
     #: view:crm.phonecall.report:0
     msgid "Salesman"
    -msgstr "销售员"
    +msgstr "业务员"
     
     #. module: crm
     #: field:crm.lead,date_deadline:0
     msgid "Expected Closing"
    -msgstr ""
    +msgstr "预期结束"
     
     #. module: crm
     #: model:ir.model,name:crm.model_crm_opportunity2phonecall
     msgid "Opportunity to Phonecall"
    -msgstr ""
    +msgstr "商机转换为电话访问"
     
     #. module: crm
     #: help:crm.case.section,allow_unlink:0
     msgid "Allows to delete non draft cases"
    -msgstr "允许删除不是草稿的业务个案"
    +msgstr "允许删除不是草稿的业务"
     
     #. module: crm
     #: view:crm.lead:0
     msgid "Schedule Meeting"
    -msgstr "会议时间表"
    +msgstr "会议计划"
     
     #. module: crm
     #: view:crm.lead:0
     msgid "Partner Name"
    -msgstr ""
    +msgstr "业务伙伴名称"
     
     #. module: crm
     #: model:crm.case.categ,name:crm.categ_phone2
    @@ -3317,13 +3355,13 @@ msgstr "致电"
     #: field:crm.lead,date_open:0
     #: field:crm.phonecall,date_open:0
     msgid "Opened"
    -msgstr ""
    +msgstr "已开启"
     
     #. module: crm
     #: view:crm.case.section:0
     #: field:crm.case.section,member_ids:0
     msgid "Team Members"
    -msgstr ""
    +msgstr "团队成员"
     
     #. module: crm
     #: view:crm.lead:0
    @@ -3332,17 +3370,17 @@ msgstr ""
     #: view:crm.phonecall:0
     #: view:res.partner:0
     msgid "Contacts"
    -msgstr ""
    +msgstr "联系人列表"
     
     #. module: crm
     #: model:crm.case.categ,name:crm.categ_oppor1
     msgid "Interest in Computer"
    -msgstr ""
    +msgstr "计算兴趣"
     
     #. module: crm
     #: view:crm.meeting:0
     msgid "Invitation Detail"
    -msgstr ""
    +msgstr "邀请内容"
     
     #. module: crm
     #: field:crm.segmentation,som_interval_default:0
    @@ -3355,12 +3393,12 @@ msgid ""
     "These email addresses will be added to the CC field of all inbound and "
     "outbound emails for this record before being sent. Separate multiple email "
     "addresses with a comma"
    -msgstr ""
    +msgstr "这些邮件地址将添加到之前发送记录的发送和接收邮件的抄送字段,分隔多个邮件地址有逗号。"
     
     #. module: crm
     #: constraint:res.partner:0
     msgid "Error ! You can not create recursive associated members."
    -msgstr ""
    +msgstr "错误!您不能创建递归的相关成员。"
     
     #. module: crm
     #: field:crm.partner2opportunity,probability:0
    @@ -3384,7 +3422,7 @@ msgstr "草稿"
     #. module: crm
     #: model:ir.actions.act_window,name:crm.crm_case_section_act_tree
     msgid "Cases by Sales Team"
    -msgstr ""
    +msgstr "该业务的销售团队"
     
     #. module: crm
     #: field:crm.meeting,attendee_ids:0
    @@ -3403,33 +3441,33 @@ msgstr "会议"
     #. module: crm
     #: model:ir.model,name:crm.model_crm_case_categ
     msgid "Category of Case"
    -msgstr ""
    +msgstr "业务类型"
     
     #. module: crm
     #: view:crm.lead:0
     #: view:crm.phonecall:0
     msgid "7 Days"
    -msgstr ""
    +msgstr "7天"
     
     #. module: crm
     #: view:board.board:0
     msgid "Planned Revenue by Stage and User"
    -msgstr ""
    +msgstr "阶段的计划收入和用户"
     
     #. module: crm
     #: view:crm.lead:0
     msgid "Communication & History"
    -msgstr ""
    +msgstr "沟通&日志"
     
     #. module: crm
     #: model:ir.model,name:crm.model_crm_lead_report
     msgid "CRM Lead Report"
    -msgstr ""
    +msgstr "客户关系管理线索报表"
     
     #. module: crm
     #: field:crm.installer,progress:0
     msgid "Configuration Progress"
    -msgstr ""
    +msgstr "设置进度"
     
     #. module: crm
     #: selection:crm.lead,priority:0
    @@ -3442,13 +3480,13 @@ msgstr "普通"
     #. module: crm
     #: field:crm.lead,street2:0
     msgid "Street2"
    -msgstr ""
    +msgstr "街道 2"
     
     #. module: crm
     #: model:ir.actions.act_window,name:crm.crm_meeting_categ_action
     #: model:ir.ui.menu,name:crm.menu_crm_case_meeting-act
     msgid "Meeting Categories"
    -msgstr ""
    +msgstr "会议类型"
     
     #. module: crm
     #: view:crm.lead2opportunity.partner:0
    @@ -3460,7 +3498,7 @@ msgstr "你可能要核实这个业务伙伴是否已不存在"
     #. module: crm
     #: field:crm.lead.report,delay_open:0
     msgid "Delay to Open"
    -msgstr ""
    +msgstr "延迟开启"
     
     #. module: crm
     #: field:crm.lead.report,user_id:0
    @@ -3484,12 +3522,12 @@ msgstr "没建立你的公司地址邮箱ID!"
     #. module: crm
     #: view:crm.lead.report:0
     msgid "Opportunities By Stage"
    -msgstr ""
    +msgstr "商机的阶段"
     
     #. module: crm
     #: model:ir.actions.act_window,name:crm.crm_case_categ_phone_create_partner
     msgid "Schedule Phone Call"
    -msgstr "电话呼叫时间表"
    +msgstr "计划的电话访问"
     
     #. module: crm
     #: selection:crm.lead.report,month:0
    @@ -3505,7 +3543,7 @@ msgid ""
     "pipeline by maintaining them to their sales opportunities. It will allow "
     "them to easily track how is positioned a specific opportunity in the sales "
     "cycle."
    -msgstr ""
    +msgstr "创建具体的阶段这将有助你的销售通过组织好销售渠道维护这销售商机。它将使你在销售周期轻松地跟踪和定位一个具体的商机。"
     
     #. module: crm
     #: model:process.process,name:crm.process_process_contractprocess0
    @@ -3515,7 +3553,7 @@ msgstr "合同"
     #. module: crm
     #: model:crm.case.resource.type,name:crm.type_lead4
     msgid "Twitter Ads"
    -msgstr ""
    +msgstr "Twitter地址"
     
     #. module: crm
     #: code:addons/crm/wizard/crm_add_note.py:26
    @@ -3529,23 +3567,23 @@ msgstr "错误"
     #. module: crm
     #: view:crm.lead.report:0
     msgid "Planned Revenues"
    -msgstr ""
    +msgstr "计划收入"
     
     #. module: crm
     #: model:crm.case.categ,name:crm.categ_oppor7
     msgid "Need Consulting"
    -msgstr ""
    +msgstr "需要咨询"
     
     #. module: crm
     #: constraint:crm.segmentation:0
     msgid "Error ! You can not create recursive profiles."
    -msgstr ""
    +msgstr "错误! 你不能创建递归的特征。"
     
     #. module: crm
     #: code:addons/crm/crm_lead.py:232
     #, python-format
     msgid "The case '%s' has been closed."
    -msgstr ""
    +msgstr "这业务'%s'已结束"
     
     #. module: crm
     #: field:crm.lead,partner_address_id:0
    @@ -3557,18 +3595,18 @@ msgstr "业务伙伴联系方式"
     #. module: crm
     #: field:crm.meeting,recurrent_id:0
     msgid "Recurrent ID date"
    -msgstr ""
    +msgstr "循环日期"
     
     #. module: crm
     #: sql_constraint:res.users:0
     msgid "You can not have two users with the same login !"
    -msgstr ""
    +msgstr "你不能同时登录两个用户!"
     
     #. module: crm
     #: code:addons/crm/wizard/crm_merge_opportunities.py:100
     #, python-format
     msgid "Merged into Opportunity: %s"
    -msgstr ""
    +msgstr "合并商机: %s"
     
     #. module: crm
     #: code:addons/crm/crm.py:347
    @@ -3576,34 +3614,34 @@ msgstr ""
     #: view:res.partner:0
     #, python-format
     msgid "Close"
    -msgstr "关闭"
    +msgstr "结束"
     
     #. module: crm
     #: view:crm.lead:0
     #: view:crm.phonecall:0
     #: view:res.partner:0
     msgid "Categorization"
    -msgstr ""
    +msgstr "归类"
     
     #. module: crm
     #: model:ir.model,name:crm.model_base_action_rule
     msgid "Action Rules"
    -msgstr ""
    +msgstr "动作规则"
     
     #. module: crm
     #: field:crm.meeting,rrule_type:0
     msgid "Recurrency"
    -msgstr ""
    +msgstr "循环"
     
     #. module: crm
     #: field:crm.meeting,phonecall_id:0
     msgid "Phonecall"
    -msgstr ""
    +msgstr "电话访问"
     
     #. module: crm
     #: selection:crm.meeting,week_list:0
     msgid "Thursday"
    -msgstr ""
    +msgstr "周四"
     
     #. module: crm
     #: view:crm.meeting:0
    @@ -3614,17 +3652,17 @@ msgstr "到"
     #. module: crm
     #: selection:crm.meeting,class:0
     msgid "Private"
    -msgstr ""
    +msgstr "私有的"
     
     #. module: crm
     #: field:crm.lead,function:0
     msgid "Function"
    -msgstr ""
    +msgstr "职务"
     
     #. module: crm
     #: view:crm.add.note:0
     msgid "_Add"
    -msgstr ""
    +msgstr "添加"
     
     #. module: crm
     #: selection:crm.segmentation.line,expr_name:0
    @@ -3660,7 +3698,7 @@ msgstr "说明"
     #: field:res.partner,section_id:0
     #: field:res.users,context_section_id:0
     msgid "Sales Team"
    -msgstr ""
    +msgstr "销售团队"
     
     #. module: crm
     #: selection:crm.lead.report,month:0
    @@ -3672,39 +3710,39 @@ msgstr "5月"
     #. module: crm
     #: model:crm.case.categ,name:crm.categ_oppor2
     msgid "Interest in Accessories"
    -msgstr ""
    +msgstr "感兴趣"
     
     #. module: crm
     #: code:addons/crm/crm_lead.py:211
     #, python-format
     msgid "The opportunity '%s' has been opened."
    -msgstr ""
    +msgstr "这商机 \"%s\" 已开启"
     
     #. module: crm
     #: field:crm.lead.report,email:0
     msgid "# Emails"
    -msgstr ""
    +msgstr "电子邮件"
     
     #. module: crm
     #: field:crm.lead,street:0
     msgid "Street"
    -msgstr ""
    +msgstr "街道"
     
     #. module: crm
     #: view:crm.lead.report:0
     msgid "Opportunities by User and Team"
    -msgstr ""
    +msgstr "用户和团队的商机"
     
     #. module: crm
     #: field:crm.case.section,working_hours:0
     msgid "Working Hours"
    -msgstr ""
    +msgstr "工作时间"
     
     #. module: crm
     #: view:crm.lead:0
     #: field:crm.lead,is_customer_add:0
     msgid "Customer"
    -msgstr ""
    +msgstr "客户"
     
     #. module: crm
     #: selection:crm.lead.report,month:0
    @@ -3725,14 +3763,14 @@ msgstr "安排一个会议"
     #: model:crm.case.stage,name:crm.stage_opportunity6
     #: view:crm.lead:0
     msgid "Lost"
    -msgstr ""
    +msgstr "丢失"
     
     #. module: crm
     #: field:crm.lead,country_id:0
     #: view:crm.lead.report:0
     #: field:crm.lead.report,country_id:0
     msgid "Country"
    -msgstr ""
    +msgstr "国家"
     
     #. module: crm
     #: view:crm.lead:0
    @@ -3740,12 +3778,12 @@ msgstr ""
     #: view:crm.phonecall:0
     #: view:res.partner:0
     msgid "Convert to Opportunity"
    -msgstr "转换到商机"
    +msgstr "转换为商机"
     
     #. module: crm
     #: selection:crm.meeting,week_list:0
     msgid "Wednesday"
    -msgstr ""
    +msgstr "周三"
     
     #. module: crm
     #: selection:crm.lead.report,month:0
    @@ -3757,33 +3795,33 @@ msgstr "4月"
     #. module: crm
     #: field:crm.case.resource.type,name:0
     msgid "Campaign Name"
    -msgstr ""
    +msgstr "营销活动名称"
     
     #. module: crm
     #: model:ir.model,name:crm.model_crm_phonecall_report
     msgid "Phone calls by user and section"
    -msgstr ""
    +msgstr "用户和业务分类的电话访问"
     
     #. module: crm
     #: selection:crm.lead2opportunity.action,name:0
     msgid "Merge with existing Opportunity"
    -msgstr ""
    +msgstr "合并现有的商机"
     
     #. module: crm
     #: field:crm.meeting,select1:0
     msgid "Option"
    -msgstr ""
    +msgstr "选项"
     
     #. module: crm
     #: model:crm.case.stage,name:crm.stage_lead4
     #: model:crm.case.stage,name:crm.stage_opportunity4
     msgid "Negotiation"
    -msgstr ""
    +msgstr "协商"
     
     #. module: crm
     #: view:crm.lead:0
     msgid "Exp.Closing"
    -msgstr ""
    +msgstr "结束中"
     
     #. module: crm
     #: field:crm.case.stage,sequence:0
    @@ -3794,12 +3832,12 @@ msgstr "序列"
     #. module: crm
     #: field:crm.send.mail,body:0
     msgid "Message Body"
    -msgstr ""
    +msgstr "消息正文"
     
     #. module: crm
     #: view:crm.meeting:0
     msgid "Accept"
    -msgstr ""
    +msgstr "同意"
     
     #. module: crm
     #: field:crm.segmentation.line,expr_name:0
    @@ -3809,18 +3847,18 @@ msgstr "控制变量"
     #. module: crm
     #: selection:crm.meeting,byday:0
     msgid "Second"
    -msgstr ""
    +msgstr "第二人称"
     
     #. module: crm
     #: model:crm.case.stage,name:crm.stage_lead3
     #: model:crm.case.stage,name:crm.stage_opportunity3
     msgid "Proposition"
    -msgstr ""
    +msgstr "建议"
     
     #. module: crm
     #: field:res.partner,phonecall_ids:0
     msgid "Phonecalls"
    -msgstr ""
    +msgstr "电话访问列表"
     
     #. module: crm
     #: view:crm.lead.report:0
    @@ -3828,7 +3866,7 @@ msgstr ""
     #: view:crm.phonecall.report:0
     #: field:crm.phonecall.report,name:0
     msgid "Year"
    -msgstr "年份"
    +msgstr "年"
     
     #. module: crm
     #: model:crm.case.resource.type,name:crm.type_lead8
    diff --git a/addons/crm_caldav/i18n/zh_CN.po b/addons/crm_caldav/i18n/zh_CN.po
    new file mode 100644
    index 00000000000..b3f0b638dca
    --- /dev/null
    +++ b/addons/crm_caldav/i18n/zh_CN.po
    @@ -0,0 +1,49 @@
    +# Chinese (Simplified) translation for openobject-addons
    +# Copyright (c) 2011 Rosetta Contributors and Canonical Ltd 2011
    +# This file is distributed under the same license as the openobject-addons package.
    +# FIRST AUTHOR , 2011.
    +#
    +msgid ""
    +msgstr ""
    +"Project-Id-Version: openobject-addons\n"
    +"Report-Msgid-Bugs-To: FULL NAME \n"
    +"POT-Creation-Date: 2011-01-11 11:15+0000\n"
    +"PO-Revision-Date: 2011-04-10 17:34+0000\n"
    +"Last-Translator: Black Jack \n"
    +"Language-Team: Chinese (Simplified) \n"
    +"MIME-Version: 1.0\n"
    +"Content-Type: text/plain; charset=UTF-8\n"
    +"Content-Transfer-Encoding: 8bit\n"
    +"X-Launchpad-Export-Date: 2011-04-11 04:54+0000\n"
    +"X-Generator: Launchpad (build 12735)\n"
    +
    +#. module: crm_caldav
    +#: model:ir.actions.act_window,name:crm_caldav.action_caldav_browse
    +msgid "Caldav Browse"
    +msgstr "Caldav翻阅"
    +
    +#. module: crm_caldav
    +#: model:ir.model,name:crm_caldav.model_crm_meeting
    +msgid "Meeting"
    +msgstr "会议"
    +
    +#. module: crm_caldav
    +#: model:ir.module.module,shortdesc:crm_caldav.module_meta_information
    +msgid "Extended Module to Add CalDav feature on Meeting"
    +msgstr "扩展模块增加会议的Caldav功能"
    +
    +#. module: crm_caldav
    +#: model:ir.module.module,description:crm_caldav.module_meta_information
    +msgid ""
    +"\n"
    +"    New Features in Meeting:\n"
    +"        *  Share meeting with other calendar clients like sunbird\n"
    +msgstr ""
    +"\n"
    +"    会议的新功能\n"
    +"     *通过连接Mozilla Sunbird与使用日程表的客户共享会议\n"
    +
    +#. module: crm_caldav
    +#: model:ir.ui.menu,name:crm_caldav.menu_caldav_browse
    +msgid "Synchronyze this calendar"
    +msgstr "同步calendar"
    diff --git a/addons/crm_claim/i18n/gl.po b/addons/crm_claim/i18n/gl.po
    new file mode 100644
    index 00000000000..e3a05b59c69
    --- /dev/null
    +++ b/addons/crm_claim/i18n/gl.po
    @@ -0,0 +1,778 @@
    +# Galician translation for openobject-addons
    +# Copyright (c) 2011 Rosetta Contributors and Canonical Ltd 2011
    +# This file is distributed under the same license as the openobject-addons package.
    +# FIRST AUTHOR , 2011.
    +#
    +msgid ""
    +msgstr ""
    +"Project-Id-Version: openobject-addons\n"
    +"Report-Msgid-Bugs-To: FULL NAME \n"
    +"POT-Creation-Date: 2011-01-11 11:15+0000\n"
    +"PO-Revision-Date: 2011-04-07 07:21+0000\n"
    +"Last-Translator: FULL NAME \n"
    +"Language-Team: Galician \n"
    +"MIME-Version: 1.0\n"
    +"Content-Type: text/plain; charset=UTF-8\n"
    +"Content-Transfer-Encoding: 8bit\n"
    +"X-Launchpad-Export-Date: 2011-04-08 04:45+0000\n"
    +"X-Generator: Launchpad (build 12735)\n"
    +
    +#. module: crm_claim
    +#: field:crm.claim.report,nbr:0
    +msgid "# of Cases"
    +msgstr "Nº de casos"
    +
    +#. module: crm_claim
    +#: view:crm.claim:0
    +#: view:crm.claim.report:0
    +msgid "Group By..."
    +msgstr "Agrupar por..."
    +
    +#. module: crm_claim
    +#: view:crm.claim:0
    +msgid "Responsibilities"
    +msgstr "Responsabilidades"
    +
    +#. module: crm_claim
    +#: field:crm.claim,date_action_next:0
    +msgid "Next Action Date"
    +msgstr "Fecha da próxima acción"
    +
    +#. module: crm_claim
    +#: field:crm.claim.report,probability:0
    +msgid "Probability"
    +msgstr "Probabilidade"
    +
    +#. module: crm_claim
    +#: selection:crm.claim.report,month:0
    +msgid "March"
    +msgstr "Marzo"
    +
    +#. module: crm_claim
    +#: field:crm.claim.report,delay_close:0
    +msgid "Delay to close"
    +msgstr "Demora peche"
    +
    +#. module: crm_claim
    +#: field:crm.claim,resolution:0
    +msgid "Resolution"
    +msgstr "Resolución"
    +
    +#. module: crm_claim
    +#: field:crm.claim,company_id:0
    +#: view:crm.claim.report:0
    +#: field:crm.claim.report,company_id:0
    +msgid "Company"
    +msgstr "Compañía"
    +
    +#. module: crm_claim
    +#: field:crm.claim,email_cc:0
    +msgid "Watchers Emails"
    +msgstr "Destinatarios de correos electrónicos (CC)"
    +
    +#. module: crm_claim
    +#: view:crm.claim.report:0
    +msgid "#Claim"
    +msgstr "Nº reclamación"
    +
    +#. module: crm_claim
    +#: model:ir.actions.act_window,help:crm_claim.crm_claim_stage_act
    +msgid ""
    +"You can create claim stages to categorize the status of every claim entered "
    +"in the system. The stages define all the steps required for the resolution "
    +"of a claim."
    +msgstr ""
    +"Pode crear etapas para clasificar os estados de cada reclamación introducida "
    +"no sistema. As etapas definen tódolos pasos necesarios para a resolución "
    +"dunha reclamación."
    +
    +#. module: crm_claim
    +#: selection:crm.claim,priority:0
    +#: selection:crm.claim.report,priority:0
    +msgid "Highest"
    +msgstr "A máis alta"
    +
    +#. module: crm_claim
    +#: view:crm.claim.report:0
    +#: field:crm.claim.report,day:0
    +msgid "Day"
    +msgstr "Día"
    +
    +#. module: crm_claim
    +#: view:crm.claim:0
    +msgid "Add Internal Note"
    +msgstr "Engadir nota interna"
    +
    +#. module: crm_claim
    +#: help:crm.claim,section_id:0
    +msgid ""
    +"Sales team to which Case belongs to.Define Responsible user and Email "
    +"account for mail gateway."
    +msgstr ""
    +"Equipo de vendas ó cal pertence o caso. Define o usuario responsable e a "
    +"conta de email para a pasarela de correo."
    +
    +#. module: crm_claim
    +#: view:crm.claim:0
    +msgid "Claim Description"
    +msgstr "Descrición da reclamación"
    +
    +#. module: crm_claim
    +#: field:crm.claim,message_ids:0
    +msgid "Messages"
    +msgstr "Mensaxes"
    +
    +#. module: crm_claim
    +#: model:crm.case.categ,name:crm_claim.categ_claim1
    +msgid "Factual Claims"
    +msgstr "Reclamacións obxectivas"
    +
    +#. module: crm_claim
    +#: selection:crm.claim,state:0
    +#: selection:crm.claim.report,state:0
    +msgid "Cancelled"
    +msgstr "Anulado"
    +
    +#. module: crm_claim
    +#: model:crm.case.resource.type,name:crm_claim.type_claim2
    +msgid "Preventive"
    +msgstr "Preventivo"
    +
    +#. module: crm_claim
    +#: model:crm.case.stage,name:crm_claim.stage_claim2
    +msgid "Fixed"
    +msgstr "Fixo"
    +
    +#. module: crm_claim
    +#: field:crm.claim,partner_address_id:0
    +msgid "Partner Contact"
    +msgstr "Contacto"
    +
    +#. module: crm_claim
    +#: field:crm.claim.report,date_closed:0
    +msgid "Close Date"
    +msgstr "Data de peche"
    +
    +#. module: crm_claim
    +#: view:crm.claim.report:0
    +msgid "   Month   "
    +msgstr "   Mes   "
    +
    +#. module: crm_claim
    +#: field:crm.claim,ref:0
    +msgid "Reference"
    +msgstr "Referencia"
    +
    +#. module: crm_claim
    +#: field:crm.claim,action_next:0
    +msgid "Next Action"
    +msgstr "Seguinte acción"
    +
    +#. module: crm_claim
    +#: view:crm.claim:0
    +msgid "Reset to Draft"
    +msgstr "Cambiar a modo Borrador"
    +
    +#. module: crm_claim
    +#: view:crm.claim:0
    +#: field:crm.claim,date_deadline:0
    +#: field:crm.claim.report,date_deadline:0
    +msgid "Deadline"
    +msgstr "Data límite"
    +
    +#. module: crm_claim
    +#: view:crm.claim:0
    +#: field:crm.claim,partner_id:0
    +#: view:crm.claim.report:0
    +#: field:crm.claim.report,partner_id:0
    +msgid "Partner"
    +msgstr "Socio"
    +
    +#. module: crm_claim
    +#: selection:crm.claim,type_action:0
    +#: selection:crm.claim.report,type_action:0
    +msgid "Preventive Action"
    +msgstr "Acción preventiva"
    +
    +#. module: crm_claim
    +#: field:crm.claim.report,section_id:0
    +msgid "Section"
    +msgstr "Sección"
    +
    +#. module: crm_claim
    +#: view:crm.claim:0
    +msgid "Root Causes"
    +msgstr "Causas principais"
    +
    +#. module: crm_claim
    +#: field:crm.claim,user_fault:0
    +msgid "Trouble Responsible"
    +msgstr "Responsable do problema"
    +
    +#. module: crm_claim
    +#: field:crm.claim,priority:0
    +#: view:crm.claim.report:0
    +#: field:crm.claim.report,priority:0
    +msgid "Priority"
    +msgstr "Prioridade"
    +
    +#. module: crm_claim
    +#: view:crm.claim:0
    +msgid "Send New Email"
    +msgstr "Enviar novo email"
    +
    +#. module: crm_claim
    +#: field:crm.claim.report,delay_expected:0
    +msgid "Overpassed Deadline"
    +msgstr "Data límite excedida"
    +
    +#. module: crm_claim
    +#: view:crm.claim:0
    +#: view:crm.claim.report:0
    +msgid "Type"
    +msgstr "Tipo"
    +
    +#. module: crm_claim
    +#: field:crm.claim,email_from:0
    +msgid "Email"
    +msgstr "E-mail"
    +
    +#. module: crm_claim
    +#: selection:crm.claim,priority:0
    +#: selection:crm.claim.report,priority:0
    +msgid "Lowest"
    +msgstr "A máis baixa"
    +
    +#. module: crm_claim
    +#: field:crm.claim,create_date:0
    +msgid "Creation Date"
    +msgstr "Data de creación"
    +
    +#. module: crm_claim
    +#: field:crm.claim,name:0
    +msgid "Claim Subject"
    +msgstr "Obxecto da reclamación"
    +
    +#. module: crm_claim
    +#: model:ir.actions.act_window,help:crm_claim.action_report_crm_claim
    +msgid ""
    +"Have a general overview of all claims processed in the system by sorting "
    +"them with specific criteria."
    +msgstr ""
    +"Obteña unha visión global de tódalas reclamacións procesadas no sistema "
    +"ordenándoas con criterios específicos."
    +
    +#. module: crm_claim
    +#: selection:crm.claim.report,month:0
    +msgid "July"
    +msgstr "Xullo"
    +
    +#. module: crm_claim
    +#: model:ir.actions.act_window,name:crm_claim.crm_claim_stage_act
    +msgid "Claim Stages"
    +msgstr "Etapas das reclamacións"
    +
    +#. module: crm_claim
    +#: model:ir.ui.menu,name:crm_claim.menu_crm_case_claim-act
    +msgid "Categories"
    +msgstr "Categorías"
    +
    +#. module: crm_claim
    +#: view:crm.claim:0
    +#: field:crm.claim,stage_id:0
    +#: view:crm.claim.report:0
    +#: field:crm.claim.report,stage_id:0
    +msgid "Stage"
    +msgstr "Fase"
    +
    +#. module: crm_claim
    +#: view:crm.claim:0
    +msgid "History Information"
    +msgstr "Información histórica"
    +
    +#. module: crm_claim
    +#: view:crm.claim:0
    +msgid "Dates"
    +msgstr "Datas"
    +
    +#. module: crm_claim
    +#: view:crm.claim.report:0
    +msgid "    Month-1    "
    +msgstr "    Mes-1    "
    +
    +#. module: crm_claim
    +#: view:crm.claim:0
    +msgid "Contact"
    +msgstr "Contacto"
    +
    +#. module: crm_claim
    +#: model:ir.ui.menu,name:crm_claim.menu_crm_claim_stage_act
    +msgid "Stages"
    +msgstr "Etapas"
    +
    +#. module: crm_claim
    +#: model:ir.ui.menu,name:crm_claim.menu_report_crm_claim_tree
    +msgid "Claims Analysis"
    +msgstr "Análise das reclamacións"
    +
    +#. module: crm_claim
    +#: help:crm.claim.report,delay_close:0
    +msgid "Number of Days to close the case"
    +msgstr "Número de días para pechar o caso"
    +
    +#. module: crm_claim
    +#: model:ir.model,name:crm_claim.model_crm_claim_report
    +msgid "CRM Claim Report"
    +msgstr "Informe das reclamacións CRM"
    +
    +#. module: crm_claim
    +#: model:crm.case.stage,name:crm_claim.stage_claim1
    +msgid "Accepted as Claim"
    +msgstr "Aceptado como reclamación"
    +
    +#. module: crm_claim
    +#: model:crm.case.resource.type,name:crm_claim.type_claim1
    +msgid "Corrective"
    +msgstr "Correctivo"
    +
    +#. module: crm_claim
    +#: selection:crm.claim.report,month:0
    +msgid "September"
    +msgstr "Setembro"
    +
    +#. module: crm_claim
    +#: selection:crm.claim.report,month:0
    +msgid "December"
    +msgstr "Decembro"
    +
    +#. module: crm_claim
    +#: view:crm.claim.report:0
    +#: field:crm.claim.report,month:0
    +msgid "Month"
    +msgstr "Mes"
    +
    +#. module: crm_claim
    +#: field:crm.claim,type_action:0
    +#: field:crm.claim.report,type_action:0
    +msgid "Action Type"
    +msgstr "Tipo de acción"
    +
    +#. module: crm_claim
    +#: field:crm.claim,write_date:0
    +msgid "Update Date"
    +msgstr "Data de actualización"
    +
    +#. module: crm_claim
    +#: view:crm.claim.report:0
    +msgid "Salesman"
    +msgstr "Vendedor"
    +
    +#. module: crm_claim
    +#: field:crm.claim,categ_id:0
    +#: view:crm.claim.report:0
    +#: field:crm.claim.report,categ_id:0
    +msgid "Category"
    +msgstr "Categoría"
    +
    +#. module: crm_claim
    +#: model:crm.case.categ,name:crm_claim.categ_claim2
    +msgid "Value Claims"
    +msgstr "Valor reclamacións"
    +
    +#. module: crm_claim
    +#: view:crm.claim.report:0
    +msgid "  Year  "
    +msgstr "  Ano  "
    +
    +#. module: crm_claim
    +#: help:crm.claim,email_cc:0
    +msgid ""
    +"These email addresses will be added to the CC field of all inbound and "
    +"outbound emails for this record before being sent. Separate multiple email "
    +"addresses with a comma"
    +msgstr ""
    +"Estes enderezos de correo engadiranse ó campo CC para tódolos correos "
    +"entrantes e saíntes deste rexistro antes de ser enviados. Separe os "
    +"diferentes enderezos de correo cunha coma."
    +
    +#. module: crm_claim
    +#: selection:crm.claim,state:0
    +#: view:crm.claim.report:0
    +#: selection:crm.claim.report,state:0
    +msgid "Draft"
    +msgstr "Borrador"
    +
    +#. module: crm_claim
    +#: selection:crm.claim,priority:0
    +#: selection:crm.claim.report,priority:0
    +msgid "Low"
    +msgstr "Baixo"
    +
    +#. module: crm_claim
    +#: field:crm.claim,date_closed:0
    +#: selection:crm.claim,state:0
    +#: selection:crm.claim.report,state:0
    +msgid "Closed"
    +msgstr "Pechado"
    +
    +#. module: crm_claim
    +#: view:crm.claim:0
    +#: selection:crm.claim,state:0
    +#: view:crm.claim.report:0
    +#: selection:crm.claim.report,state:0
    +msgid "Pending"
    +msgstr "Pendente"
    +
    +#. module: crm_claim
    +#: view:crm.claim:0
    +msgid "Communication & History"
    +msgstr "Comunicación e historial"
    +
    +#. module: crm_claim
    +#: selection:crm.claim.report,month:0
    +msgid "August"
    +msgstr "Agosto"
    +
    +#. module: crm_claim
    +#: selection:crm.claim,priority:0
    +#: selection:crm.claim.report,priority:0
    +msgid "Normal"
    +msgstr "Normal"
    +
    +#. module: crm_claim
    +#: view:crm.claim:0
    +msgid "Global CC"
    +msgstr "CC global"
    +
    +#. module: crm_claim
    +#: model:ir.module.module,shortdesc:crm_claim.module_meta_information
    +msgid "Customer & Supplier Relationship Management"
    +msgstr "Xestión de relacións con clientes e provedores"
    +
    +#. module: crm_claim
    +#: selection:crm.claim.report,month:0
    +msgid "June"
    +msgstr "Xuño"
    +
    +#. module: crm_claim
    +#: field:crm.claim,partner_phone:0
    +msgid "Phone"
    +msgstr "Teléfono"
    +
    +#. module: crm_claim
    +#: field:crm.claim.report,user_id:0
    +msgid "User"
    +msgstr "Usuario"
    +
    +#. module: crm_claim
    +#: model:crm.case.stage,name:crm_claim.stage_claim5
    +msgid "Awaiting Response"
    +msgstr "Esperando resposta"
    +
    +#. module: crm_claim
    +#: model:ir.actions.act_window,name:crm_claim.crm_claim_categ_action
    +msgid "Claim Categories"
    +msgstr "Categorías das reclamacións"
    +
    +#. module: crm_claim
    +#: selection:crm.claim.report,month:0
    +msgid "November"
    +msgstr "Novembro"
    +
    +#. module: crm_claim
    +#: view:crm.claim.report:0
    +msgid "Extended Filters..."
    +msgstr "Filtros extendidos..."
    +
    +#. module: crm_claim
    +#: view:crm.claim:0
    +msgid "Closure"
    +msgstr "Peche"
    +
    +#. module: crm_claim
    +#: view:crm.claim.report:0
    +msgid "Search"
    +msgstr "Buscar"
    +
    +#. module: crm_claim
    +#: selection:crm.claim.report,month:0
    +msgid "October"
    +msgstr "Outubro"
    +
    +#. module: crm_claim
    +#: model:ir.module.module,description:crm_claim.module_meta_information
    +msgid ""
    +"\n"
    +"This modules allows you to track your customers/suppliers claims and "
    +"flames.\n"
    +"It is fully integrated with the email gateway so that you can create\n"
    +"automatically new claims based on incoming emails.\n"
    +"    "
    +msgstr ""
    +"\n"
    +"Este módulo permítelle realizar un seguimento das reclamacións e urxencias "
    +"dos seus clientes/provedores. Está totalmente integrado na pasarela de "
    +"correo electrónico para que poida crear automaticamente as novas "
    +"reclamacións a partir dos correos electrónicos entrantes.\n"
    +"    "
    +
    +#. module: crm_claim
    +#: selection:crm.claim.report,month:0
    +msgid "January"
    +msgstr "Xaneiro"
    +
    +#. module: crm_claim
    +#: view:crm.claim:0
    +#: field:crm.claim,date:0
    +msgid "Claim Date"
    +msgstr "Data da reclamación"
    +
    +#. module: crm_claim
    +#: help:crm.claim,email_from:0
    +msgid "These people will receive email."
    +msgstr "Estas persoas recibirán un e-mail."
    +
    +#. module: crm_claim
    +#: view:crm.claim:0
    +#: view:crm.claim.report:0
    +#: model:ir.actions.act_window,name:crm_claim.action_report_crm_claim
    +#: model:ir.actions.act_window,name:crm_claim.crm_case_categ_claim0
    +#: model:ir.ui.menu,name:crm_claim.menu_crm_case_claims
    +msgid "Claims"
    +msgstr "Reclamacións"
    +
    +#. module: crm_claim
    +#: selection:crm.claim,type_action:0
    +#: selection:crm.claim.report,type_action:0
    +msgid "Corrective Action"
    +msgstr "Acción correctiva"
    +
    +#. module: crm_claim
    +#: model:crm.case.categ,name:crm_claim.categ_claim3
    +msgid "Policy Claims"
    +msgstr "Política de reclamacións"
    +
    +#. module: crm_claim
    +#: view:crm.claim:0
    +msgid "History"
    +msgstr "Historia"
    +
    +#. module: crm_claim
    +#: model:ir.model,name:crm_claim.model_crm_claim
    +#: model:ir.ui.menu,name:crm_claim.menu_config_claim
    +msgid "Claim"
    +msgstr "Reclamación"
    +
    +#. module: crm_claim
    +#: view:crm.claim:0
    +msgid "Attachments"
    +msgstr "Anexos"
    +
    +#. module: crm_claim
    +#: model:ir.model,name:crm_claim.model_crm_case_stage
    +msgid "Stage of case"
    +msgstr "Fase do caso"
    +
    +#. module: crm_claim
    +#: view:crm.claim:0
    +#: field:crm.claim,state:0
    +#: view:crm.claim.report:0
    +#: field:crm.claim.report,state:0
    +msgid "State"
    +msgstr "Estado"
    +
    +#. module: crm_claim
    +#: view:crm.claim:0
    +#: view:crm.claim.report:0
    +msgid "Done"
    +msgstr "Feito"
    +
    +#. module: crm_claim
    +#: view:crm.claim:0
    +msgid "Claim Reporter"
    +msgstr "Persoa que reportou a reclamación"
    +
    +#. module: crm_claim
    +#: view:crm.claim:0
    +#: view:crm.claim.report:0
    +msgid "Cancel"
    +msgstr "Anular"
    +
    +#. module: crm_claim
    +#: view:crm.claim:0
    +msgid "Close"
    +msgstr "Pechar"
    +
    +#. module: crm_claim
    +#: view:crm.claim:0
    +#: selection:crm.claim,state:0
    +#: view:crm.claim.report:0
    +#: selection:crm.claim.report,state:0
    +msgid "Open"
    +msgstr "Abrir"
    +
    +#. module: crm_claim
    +#: view:crm.claim:0
    +msgid "In Progress"
    +msgstr "En curso"
    +
    +#. module: crm_claim
    +#: view:crm.claim:0
    +#: field:crm.claim,user_id:0
    +msgid "Responsible"
    +msgstr "Responsable"
    +
    +#. module: crm_claim
    +#: view:crm.claim:0
    +msgid "Current"
    +msgstr "Actual"
    +
    +#. module: crm_claim
    +#: view:crm.claim:0
    +msgid "Details"
    +msgstr "Detalles"
    +
    +#. module: crm_claim
    +#: view:crm.claim:0
    +msgid "Reply"
    +msgstr "Resposta"
    +
    +#. module: crm_claim
    +#: field:crm.claim,cause:0
    +msgid "Root Cause"
    +msgstr "Causa principal"
    +
    +#. module: crm_claim
    +#: view:crm.claim:0
    +msgid "Claim/Action Description"
    +msgstr "Descrición da reclamación/acción"
    +
    +#. module: crm_claim
    +#: field:crm.claim,description:0
    +msgid "Description"
    +msgstr "Descrición"
    +
    +#. module: crm_claim
    +#: view:crm.claim:0
    +msgid "Search Claims"
    +msgstr "Buscar reclamacións"
    +
    +#. module: crm_claim
    +#: field:crm.claim,section_id:0
    +#: view:crm.claim.report:0
    +msgid "Sales Team"
    +msgstr "Equipo de vendas"
    +
    +#. module: crm_claim
    +#: selection:crm.claim.report,month:0
    +msgid "May"
    +msgstr "Maio"
    +
    +#. module: crm_claim
    +#: view:crm.claim:0
    +msgid "Resolution Actions"
    +msgstr "Accións para resolución"
    +
    +#. module: crm_claim
    +#: model:ir.actions.act_window,name:crm_claim.act_claim_partner
    +#: model:ir.actions.act_window,name:crm_claim.act_claim_partner_address
    +msgid "Report a Claim"
    +msgstr "Introducir reclamación"
    +
    +#. module: crm_claim
    +#: model:ir.actions.act_window,help:crm_claim.crm_case_categ_claim0
    +msgid ""
    +"Record and track your customers' claims. Claims may be linked to a sales "
    +"order or a lot. You can send emails with attachments and keep the full "
    +"history for a claim (emails sent, intervention type and so on). Claims may "
    +"automatically be linked to an email address using the mail gateway module."
    +msgstr ""
    +"Rexistre e faga o seguimento das reclamacións dos seus clientes. Pódense "
    +"vincular as reclamacións a un pedido de venda ou a  un lote. Pode enviar "
    +"correos electrónicos con arquivos adxuntos e manter o historial completo "
    +"dunha reclamación (correos electrónicos enviados, tipo de intervención, "
    +"etc.). Pódense vincular as reclamacións automaticamente a un enderezo de "
    +"correo electrónico utilizando o módulo pasarela de correo."
    +
    +#. module: crm_claim
    +#: field:crm.claim.report,email:0
    +msgid "# Emails"
    +msgstr "Nº de emails"
    +
    +#. module: crm_claim
    +#: view:crm.claim:0
    +msgid "Follow Up"
    +msgstr "Seguimento"
    +
    +#. module: crm_claim
    +#: help:crm.claim,state:0
    +msgid ""
    +"The state is set to 'Draft', when a case is created.                         "
    +"         \n"
    +"If the case is in progress the state is set to 'Open'.                       "
    +"           \n"
    +"When the case is over, the state is set to 'Done'.                           "
    +"       \n"
    +"If the case needs to be reviewed then the state is set to 'Pending'."
    +msgstr ""
    +"O estado configúrase como \"Borrador\", cando se crea un caso. Se o caso "
    +"está en curso, o estado configúrase como \"Aberto\". Cando se pecha o caso, "
    +"o estado configúrase como \"Realizado\". Se cómpre revisar o caso, o estado "
    +"configúrase como \"Pendente\"."
    +
    +#. module: crm_claim
    +#: selection:crm.claim.report,month:0
    +msgid "February"
    +msgstr "Febreiro"
    +
    +#. module: crm_claim
    +#: model:crm.case.stage,name:crm_claim.stage_claim3
    +msgid "Won't fix"
    +msgstr "No se corrixirá"
    +
    +#. module: crm_claim
    +#: selection:crm.claim.report,month:0
    +msgid "April"
    +msgstr "Abril"
    +
    +#. module: crm_claim
    +#: view:crm.claim.report:0
    +msgid "My Case(s)"
    +msgstr "O(s) meu(s) caso(s)"
    +
    +#. module: crm_claim
    +#: field:crm.claim,id:0
    +msgid "ID"
    +msgstr "ID"
    +
    +#. module: crm_claim
    +#: view:crm.claim:0
    +msgid "Actions"
    +msgstr "Accións"
    +
    +#. module: crm_claim
    +#: selection:crm.claim,priority:0
    +#: selection:crm.claim.report,priority:0
    +msgid "High"
    +msgstr "Alto"
    +
    +#. module: crm_claim
    +#: model:ir.actions.act_window,help:crm_claim.crm_claim_categ_action
    +msgid ""
    +"Create claim categories to better manage and classify your claims. Some "
    +"example of claims can be: preventive action, corrective action."
    +msgstr ""
    +"Cree categorías de reclamacións para xestionar e clasificar mellor as súas "
    +"reclamacións. Algúns exemplos de reclamacións son: acción preventiva, acción "
    +"correctiva."
    +
    +#. module: crm_claim
    +#: field:crm.claim.report,create_date:0
    +msgid "Create Date"
    +msgstr "Crear data"
    +
    +#. module: crm_claim
    +#: view:crm.claim.report:0
    +#: field:crm.claim.report,name:0
    +msgid "Year"
    +msgstr "Ano"
    diff --git a/addons/crm_claim/i18n/zh_CN.po b/addons/crm_claim/i18n/zh_CN.po
    new file mode 100644
    index 00000000000..7667ba03a12
    --- /dev/null
    +++ b/addons/crm_claim/i18n/zh_CN.po
    @@ -0,0 +1,749 @@
    +# Chinese (Simplified) translation for openobject-addons
    +# Copyright (c) 2011 Rosetta Contributors and Canonical Ltd 2011
    +# This file is distributed under the same license as the openobject-addons package.
    +# FIRST AUTHOR , 2011.
    +#
    +msgid ""
    +msgstr ""
    +"Project-Id-Version: openobject-addons\n"
    +"Report-Msgid-Bugs-To: FULL NAME \n"
    +"POT-Creation-Date: 2011-01-11 11:15+0000\n"
    +"PO-Revision-Date: 2011-04-11 04:47+0000\n"
    +"Last-Translator: Black Jack \n"
    +"Language-Team: Chinese (Simplified) \n"
    +"MIME-Version: 1.0\n"
    +"Content-Type: text/plain; charset=UTF-8\n"
    +"Content-Transfer-Encoding: 8bit\n"
    +"X-Launchpad-Export-Date: 2011-04-11 04:54+0000\n"
    +"X-Generator: Launchpad (build 12735)\n"
    +
    +#. module: crm_claim
    +#: field:crm.claim.report,nbr:0
    +msgid "# of Cases"
    +msgstr "# 业务"
    +
    +#. module: crm_claim
    +#: view:crm.claim:0
    +#: view:crm.claim.report:0
    +msgid "Group By..."
    +msgstr "分组..."
    +
    +#. module: crm_claim
    +#: view:crm.claim:0
    +msgid "Responsibilities"
    +msgstr "责任人"
    +
    +#. module: crm_claim
    +#: field:crm.claim,date_action_next:0
    +msgid "Next Action Date"
    +msgstr "下一动作日期"
    +
    +#. module: crm_claim
    +#: field:crm.claim.report,probability:0
    +msgid "Probability"
    +msgstr "概率"
    +
    +#. module: crm_claim
    +#: selection:crm.claim.report,month:0
    +msgid "March"
    +msgstr "3月"
    +
    +#. module: crm_claim
    +#: field:crm.claim.report,delay_close:0
    +msgid "Delay to close"
    +msgstr "延迟关闭"
    +
    +#. module: crm_claim
    +#: field:crm.claim,resolution:0
    +msgid "Resolution"
    +msgstr "解决方案"
    +
    +#. module: crm_claim
    +#: field:crm.claim,company_id:0
    +#: view:crm.claim.report:0
    +#: field:crm.claim.report,company_id:0
    +msgid "Company"
    +msgstr "公司"
    +
    +#. module: crm_claim
    +#: field:crm.claim,email_cc:0
    +msgid "Watchers Emails"
    +msgstr "关注者的电子邮件"
    +
    +#. module: crm_claim
    +#: view:crm.claim.report:0
    +msgid "#Claim"
    +msgstr "#索赔"
    +
    +#. module: crm_claim
    +#: model:ir.actions.act_window,help:crm_claim.crm_claim_stage_act
    +msgid ""
    +"You can create claim stages to categorize the status of every claim entered "
    +"in the system. The stages define all the steps required for the resolution "
    +"of a claim."
    +msgstr "你能创建索赔阶段的类型把每个索赔的状况输入到系统。阶段定义所有索赔请求的解决步骤。"
    +
    +#. module: crm_claim
    +#: selection:crm.claim,priority:0
    +#: selection:crm.claim.report,priority:0
    +msgid "Highest"
    +msgstr "最高"
    +
    +#. module: crm_claim
    +#: view:crm.claim.report:0
    +#: field:crm.claim.report,day:0
    +msgid "Day"
    +msgstr "日"
    +
    +#. module: crm_claim
    +#: view:crm.claim:0
    +msgid "Add Internal Note"
    +msgstr "添加内部备注"
    +
    +#. module: crm_claim
    +#: help:crm.claim,section_id:0
    +msgid ""
    +"Sales team to which Case belongs to.Define Responsible user and Email "
    +"account for mail gateway."
    +msgstr "业务的销售团队定义负责用户和邮件网关的邮件地址。"
    +
    +#. module: crm_claim
    +#: view:crm.claim:0
    +msgid "Claim Description"
    +msgstr "索陪说明"
    +
    +#. module: crm_claim
    +#: field:crm.claim,message_ids:0
    +msgid "Messages"
    +msgstr "消息"
    +
    +#. module: crm_claim
    +#: model:crm.case.categ,name:crm_claim.categ_claim1
    +msgid "Factual Claims"
    +msgstr "实际索赔"
    +
    +#. module: crm_claim
    +#: selection:crm.claim,state:0
    +#: selection:crm.claim.report,state:0
    +msgid "Cancelled"
    +msgstr "已取消"
    +
    +#. module: crm_claim
    +#: model:crm.case.resource.type,name:crm_claim.type_claim2
    +msgid "Preventive"
    +msgstr "预防"
    +
    +#. module: crm_claim
    +#: model:crm.case.stage,name:crm_claim.stage_claim2
    +msgid "Fixed"
    +msgstr "固定的"
    +
    +#. module: crm_claim
    +#: field:crm.claim,partner_address_id:0
    +msgid "Partner Contact"
    +msgstr "业务伙伴联系方式"
    +
    +#. module: crm_claim
    +#: field:crm.claim.report,date_closed:0
    +msgid "Close Date"
    +msgstr "结束日期"
    +
    +#. module: crm_claim
    +#: view:crm.claim.report:0
    +msgid "   Month   "
    +msgstr "   月   "
    +
    +#. module: crm_claim
    +#: field:crm.claim,ref:0
    +msgid "Reference"
    +msgstr "参考"
    +
    +#. module: crm_claim
    +#: field:crm.claim,action_next:0
    +msgid "Next Action"
    +msgstr "下一动作"
    +
    +#. module: crm_claim
    +#: view:crm.claim:0
    +msgid "Reset to Draft"
    +msgstr "重置为草稿"
    +
    +#. module: crm_claim
    +#: view:crm.claim:0
    +#: field:crm.claim,date_deadline:0
    +#: field:crm.claim.report,date_deadline:0
    +msgid "Deadline"
    +msgstr "截止日期"
    +
    +#. module: crm_claim
    +#: view:crm.claim:0
    +#: field:crm.claim,partner_id:0
    +#: view:crm.claim.report:0
    +#: field:crm.claim.report,partner_id:0
    +msgid "Partner"
    +msgstr "业务伙伴"
    +
    +#. module: crm_claim
    +#: selection:crm.claim,type_action:0
    +#: selection:crm.claim.report,type_action:0
    +msgid "Preventive Action"
    +msgstr "预防性动作"
    +
    +#. module: crm_claim
    +#: field:crm.claim.report,section_id:0
    +msgid "Section"
    +msgstr "分类"
    +
    +#. module: crm_claim
    +#: view:crm.claim:0
    +msgid "Root Causes"
    +msgstr "根本原因"
    +
    +#. module: crm_claim
    +#: field:crm.claim,user_fault:0
    +msgid "Trouble Responsible"
    +msgstr "故障责任"
    +
    +#. module: crm_claim
    +#: field:crm.claim,priority:0
    +#: view:crm.claim.report:0
    +#: field:crm.claim.report,priority:0
    +msgid "Priority"
    +msgstr "优先级"
    +
    +#. module: crm_claim
    +#: view:crm.claim:0
    +msgid "Send New Email"
    +msgstr "发送新的电子邮件"
    +
    +#. module: crm_claim
    +#: field:crm.claim.report,delay_expected:0
    +msgid "Overpassed Deadline"
    +msgstr "超越截止日期"
    +
    +#. module: crm_claim
    +#: view:crm.claim:0
    +#: view:crm.claim.report:0
    +msgid "Type"
    +msgstr "类型:"
    +
    +#. module: crm_claim
    +#: field:crm.claim,email_from:0
    +msgid "Email"
    +msgstr "电子邮件"
    +
    +#. module: crm_claim
    +#: selection:crm.claim,priority:0
    +#: selection:crm.claim.report,priority:0
    +msgid "Lowest"
    +msgstr "最低"
    +
    +#. module: crm_claim
    +#: field:crm.claim,create_date:0
    +msgid "Creation Date"
    +msgstr ""
    +
    +#. module: crm_claim
    +#: field:crm.claim,name:0
    +msgid "Claim Subject"
    +msgstr ""
    +
    +#. module: crm_claim
    +#: model:ir.actions.act_window,help:crm_claim.action_report_crm_claim
    +msgid ""
    +"Have a general overview of all claims processed in the system by sorting "
    +"them with specific criteria."
    +msgstr ""
    +
    +#. module: crm_claim
    +#: selection:crm.claim.report,month:0
    +msgid "July"
    +msgstr ""
    +
    +#. module: crm_claim
    +#: model:ir.actions.act_window,name:crm_claim.crm_claim_stage_act
    +msgid "Claim Stages"
    +msgstr ""
    +
    +#. module: crm_claim
    +#: model:ir.ui.menu,name:crm_claim.menu_crm_case_claim-act
    +msgid "Categories"
    +msgstr ""
    +
    +#. module: crm_claim
    +#: view:crm.claim:0
    +#: field:crm.claim,stage_id:0
    +#: view:crm.claim.report:0
    +#: field:crm.claim.report,stage_id:0
    +msgid "Stage"
    +msgstr ""
    +
    +#. module: crm_claim
    +#: view:crm.claim:0
    +msgid "History Information"
    +msgstr ""
    +
    +#. module: crm_claim
    +#: view:crm.claim:0
    +msgid "Dates"
    +msgstr ""
    +
    +#. module: crm_claim
    +#: view:crm.claim.report:0
    +msgid "    Month-1    "
    +msgstr ""
    +
    +#. module: crm_claim
    +#: view:crm.claim:0
    +msgid "Contact"
    +msgstr ""
    +
    +#. module: crm_claim
    +#: model:ir.ui.menu,name:crm_claim.menu_crm_claim_stage_act
    +msgid "Stages"
    +msgstr ""
    +
    +#. module: crm_claim
    +#: model:ir.ui.menu,name:crm_claim.menu_report_crm_claim_tree
    +msgid "Claims Analysis"
    +msgstr ""
    +
    +#. module: crm_claim
    +#: help:crm.claim.report,delay_close:0
    +msgid "Number of Days to close the case"
    +msgstr ""
    +
    +#. module: crm_claim
    +#: model:ir.model,name:crm_claim.model_crm_claim_report
    +msgid "CRM Claim Report"
    +msgstr ""
    +
    +#. module: crm_claim
    +#: model:crm.case.stage,name:crm_claim.stage_claim1
    +msgid "Accepted as Claim"
    +msgstr ""
    +
    +#. module: crm_claim
    +#: model:crm.case.resource.type,name:crm_claim.type_claim1
    +msgid "Corrective"
    +msgstr ""
    +
    +#. module: crm_claim
    +#: selection:crm.claim.report,month:0
    +msgid "September"
    +msgstr ""
    +
    +#. module: crm_claim
    +#: selection:crm.claim.report,month:0
    +msgid "December"
    +msgstr ""
    +
    +#. module: crm_claim
    +#: view:crm.claim.report:0
    +#: field:crm.claim.report,month:0
    +msgid "Month"
    +msgstr ""
    +
    +#. module: crm_claim
    +#: field:crm.claim,type_action:0
    +#: field:crm.claim.report,type_action:0
    +msgid "Action Type"
    +msgstr ""
    +
    +#. module: crm_claim
    +#: field:crm.claim,write_date:0
    +msgid "Update Date"
    +msgstr ""
    +
    +#. module: crm_claim
    +#: view:crm.claim.report:0
    +msgid "Salesman"
    +msgstr ""
    +
    +#. module: crm_claim
    +#: field:crm.claim,categ_id:0
    +#: view:crm.claim.report:0
    +#: field:crm.claim.report,categ_id:0
    +msgid "Category"
    +msgstr ""
    +
    +#. module: crm_claim
    +#: model:crm.case.categ,name:crm_claim.categ_claim2
    +msgid "Value Claims"
    +msgstr ""
    +
    +#. module: crm_claim
    +#: view:crm.claim.report:0
    +msgid "  Year  "
    +msgstr ""
    +
    +#. module: crm_claim
    +#: help:crm.claim,email_cc:0
    +msgid ""
    +"These email addresses will be added to the CC field of all inbound and "
    +"outbound emails for this record before being sent. Separate multiple email "
    +"addresses with a comma"
    +msgstr ""
    +
    +#. module: crm_claim
    +#: selection:crm.claim,state:0
    +#: view:crm.claim.report:0
    +#: selection:crm.claim.report,state:0
    +msgid "Draft"
    +msgstr ""
    +
    +#. module: crm_claim
    +#: selection:crm.claim,priority:0
    +#: selection:crm.claim.report,priority:0
    +msgid "Low"
    +msgstr ""
    +
    +#. module: crm_claim
    +#: field:crm.claim,date_closed:0
    +#: selection:crm.claim,state:0
    +#: selection:crm.claim.report,state:0
    +msgid "Closed"
    +msgstr ""
    +
    +#. module: crm_claim
    +#: view:crm.claim:0
    +#: selection:crm.claim,state:0
    +#: view:crm.claim.report:0
    +#: selection:crm.claim.report,state:0
    +msgid "Pending"
    +msgstr ""
    +
    +#. module: crm_claim
    +#: view:crm.claim:0
    +msgid "Communication & History"
    +msgstr ""
    +
    +#. module: crm_claim
    +#: selection:crm.claim.report,month:0
    +msgid "August"
    +msgstr ""
    +
    +#. module: crm_claim
    +#: selection:crm.claim,priority:0
    +#: selection:crm.claim.report,priority:0
    +msgid "Normal"
    +msgstr ""
    +
    +#. module: crm_claim
    +#: view:crm.claim:0
    +msgid "Global CC"
    +msgstr ""
    +
    +#. module: crm_claim
    +#: model:ir.module.module,shortdesc:crm_claim.module_meta_information
    +msgid "Customer & Supplier Relationship Management"
    +msgstr ""
    +
    +#. module: crm_claim
    +#: selection:crm.claim.report,month:0
    +msgid "June"
    +msgstr ""
    +
    +#. module: crm_claim
    +#: field:crm.claim,partner_phone:0
    +msgid "Phone"
    +msgstr ""
    +
    +#. module: crm_claim
    +#: field:crm.claim.report,user_id:0
    +msgid "User"
    +msgstr ""
    +
    +#. module: crm_claim
    +#: model:crm.case.stage,name:crm_claim.stage_claim5
    +msgid "Awaiting Response"
    +msgstr ""
    +
    +#. module: crm_claim
    +#: model:ir.actions.act_window,name:crm_claim.crm_claim_categ_action
    +msgid "Claim Categories"
    +msgstr ""
    +
    +#. module: crm_claim
    +#: selection:crm.claim.report,month:0
    +msgid "November"
    +msgstr ""
    +
    +#. module: crm_claim
    +#: view:crm.claim.report:0
    +msgid "Extended Filters..."
    +msgstr ""
    +
    +#. module: crm_claim
    +#: view:crm.claim:0
    +msgid "Closure"
    +msgstr ""
    +
    +#. module: crm_claim
    +#: view:crm.claim.report:0
    +msgid "Search"
    +msgstr ""
    +
    +#. module: crm_claim
    +#: selection:crm.claim.report,month:0
    +msgid "October"
    +msgstr ""
    +
    +#. module: crm_claim
    +#: model:ir.module.module,description:crm_claim.module_meta_information
    +msgid ""
    +"\n"
    +"This modules allows you to track your customers/suppliers claims and "
    +"flames.\n"
    +"It is fully integrated with the email gateway so that you can create\n"
    +"automatically new claims based on incoming emails.\n"
    +"    "
    +msgstr ""
    +
    +#. module: crm_claim
    +#: selection:crm.claim.report,month:0
    +msgid "January"
    +msgstr ""
    +
    +#. module: crm_claim
    +#: view:crm.claim:0
    +#: field:crm.claim,date:0
    +msgid "Claim Date"
    +msgstr ""
    +
    +#. module: crm_claim
    +#: help:crm.claim,email_from:0
    +msgid "These people will receive email."
    +msgstr ""
    +
    +#. module: crm_claim
    +#: view:crm.claim:0
    +#: view:crm.claim.report:0
    +#: model:ir.actions.act_window,name:crm_claim.action_report_crm_claim
    +#: model:ir.actions.act_window,name:crm_claim.crm_case_categ_claim0
    +#: model:ir.ui.menu,name:crm_claim.menu_crm_case_claims
    +msgid "Claims"
    +msgstr ""
    +
    +#. module: crm_claim
    +#: selection:crm.claim,type_action:0
    +#: selection:crm.claim.report,type_action:0
    +msgid "Corrective Action"
    +msgstr ""
    +
    +#. module: crm_claim
    +#: model:crm.case.categ,name:crm_claim.categ_claim3
    +msgid "Policy Claims"
    +msgstr ""
    +
    +#. module: crm_claim
    +#: view:crm.claim:0
    +msgid "History"
    +msgstr ""
    +
    +#. module: crm_claim
    +#: model:ir.model,name:crm_claim.model_crm_claim
    +#: model:ir.ui.menu,name:crm_claim.menu_config_claim
    +msgid "Claim"
    +msgstr ""
    +
    +#. module: crm_claim
    +#: view:crm.claim:0
    +msgid "Attachments"
    +msgstr ""
    +
    +#. module: crm_claim
    +#: model:ir.model,name:crm_claim.model_crm_case_stage
    +msgid "Stage of case"
    +msgstr ""
    +
    +#. module: crm_claim
    +#: view:crm.claim:0
    +#: field:crm.claim,state:0
    +#: view:crm.claim.report:0
    +#: field:crm.claim.report,state:0
    +msgid "State"
    +msgstr ""
    +
    +#. module: crm_claim
    +#: view:crm.claim:0
    +#: view:crm.claim.report:0
    +msgid "Done"
    +msgstr ""
    +
    +#. module: crm_claim
    +#: view:crm.claim:0
    +msgid "Claim Reporter"
    +msgstr ""
    +
    +#. module: crm_claim
    +#: view:crm.claim:0
    +#: view:crm.claim.report:0
    +msgid "Cancel"
    +msgstr ""
    +
    +#. module: crm_claim
    +#: view:crm.claim:0
    +msgid "Close"
    +msgstr ""
    +
    +#. module: crm_claim
    +#: view:crm.claim:0
    +#: selection:crm.claim,state:0
    +#: view:crm.claim.report:0
    +#: selection:crm.claim.report,state:0
    +msgid "Open"
    +msgstr ""
    +
    +#. module: crm_claim
    +#: view:crm.claim:0
    +msgid "In Progress"
    +msgstr ""
    +
    +#. module: crm_claim
    +#: view:crm.claim:0
    +#: field:crm.claim,user_id:0
    +msgid "Responsible"
    +msgstr ""
    +
    +#. module: crm_claim
    +#: view:crm.claim:0
    +msgid "Current"
    +msgstr ""
    +
    +#. module: crm_claim
    +#: view:crm.claim:0
    +msgid "Details"
    +msgstr ""
    +
    +#. module: crm_claim
    +#: view:crm.claim:0
    +msgid "Reply"
    +msgstr ""
    +
    +#. module: crm_claim
    +#: field:crm.claim,cause:0
    +msgid "Root Cause"
    +msgstr ""
    +
    +#. module: crm_claim
    +#: view:crm.claim:0
    +msgid "Claim/Action Description"
    +msgstr ""
    +
    +#. module: crm_claim
    +#: field:crm.claim,description:0
    +msgid "Description"
    +msgstr ""
    +
    +#. module: crm_claim
    +#: view:crm.claim:0
    +msgid "Search Claims"
    +msgstr ""
    +
    +#. module: crm_claim
    +#: field:crm.claim,section_id:0
    +#: view:crm.claim.report:0
    +msgid "Sales Team"
    +msgstr ""
    +
    +#. module: crm_claim
    +#: selection:crm.claim.report,month:0
    +msgid "May"
    +msgstr ""
    +
    +#. module: crm_claim
    +#: view:crm.claim:0
    +msgid "Resolution Actions"
    +msgstr ""
    +
    +#. module: crm_claim
    +#: model:ir.actions.act_window,name:crm_claim.act_claim_partner
    +#: model:ir.actions.act_window,name:crm_claim.act_claim_partner_address
    +msgid "Report a Claim"
    +msgstr ""
    +
    +#. module: crm_claim
    +#: model:ir.actions.act_window,help:crm_claim.crm_case_categ_claim0
    +msgid ""
    +"Record and track your customers' claims. Claims may be linked to a sales "
    +"order or a lot. You can send emails with attachments and keep the full "
    +"history for a claim (emails sent, intervention type and so on). Claims may "
    +"automatically be linked to an email address using the mail gateway module."
    +msgstr ""
    +
    +#. module: crm_claim
    +#: field:crm.claim.report,email:0
    +msgid "# Emails"
    +msgstr ""
    +
    +#. module: crm_claim
    +#: view:crm.claim:0
    +msgid "Follow Up"
    +msgstr ""
    +
    +#. module: crm_claim
    +#: help:crm.claim,state:0
    +msgid ""
    +"The state is set to 'Draft', when a case is created.                         "
    +"         \n"
    +"If the case is in progress the state is set to 'Open'.                       "
    +"           \n"
    +"When the case is over, the state is set to 'Done'.                           "
    +"       \n"
    +"If the case needs to be reviewed then the state is set to 'Pending'."
    +msgstr ""
    +
    +#. module: crm_claim
    +#: selection:crm.claim.report,month:0
    +msgid "February"
    +msgstr ""
    +
    +#. module: crm_claim
    +#: model:crm.case.stage,name:crm_claim.stage_claim3
    +msgid "Won't fix"
    +msgstr ""
    +
    +#. module: crm_claim
    +#: selection:crm.claim.report,month:0
    +msgid "April"
    +msgstr ""
    +
    +#. module: crm_claim
    +#: view:crm.claim.report:0
    +msgid "My Case(s)"
    +msgstr ""
    +
    +#. module: crm_claim
    +#: field:crm.claim,id:0
    +msgid "ID"
    +msgstr ""
    +
    +#. module: crm_claim
    +#: view:crm.claim:0
    +msgid "Actions"
    +msgstr ""
    +
    +#. module: crm_claim
    +#: selection:crm.claim,priority:0
    +#: selection:crm.claim.report,priority:0
    +msgid "High"
    +msgstr ""
    +
    +#. module: crm_claim
    +#: model:ir.actions.act_window,help:crm_claim.crm_claim_categ_action
    +msgid ""
    +"Create claim categories to better manage and classify your claims. Some "
    +"example of claims can be: preventive action, corrective action."
    +msgstr ""
    +
    +#. module: crm_claim
    +#: field:crm.claim.report,create_date:0
    +msgid "Create Date"
    +msgstr ""
    +
    +#. module: crm_claim
    +#: view:crm.claim.report:0
    +#: field:crm.claim.report,name:0
    +msgid "Year"
    +msgstr ""
    diff --git a/addons/crm_helpdesk/i18n/zh_CN.po b/addons/crm_helpdesk/i18n/zh_CN.po
    new file mode 100644
    index 00000000000..64b2efba789
    --- /dev/null
    +++ b/addons/crm_helpdesk/i18n/zh_CN.po
    @@ -0,0 +1,697 @@
    +# Chinese (Simplified) translation for openobject-addons
    +# Copyright (c) 2011 Rosetta Contributors and Canonical Ltd 2011
    +# This file is distributed under the same license as the openobject-addons package.
    +# FIRST AUTHOR , 2011.
    +#
    +msgid ""
    +msgstr ""
    +"Project-Id-Version: openobject-addons\n"
    +"Report-Msgid-Bugs-To: FULL NAME \n"
    +"POT-Creation-Date: 2011-01-11 11:15+0000\n"
    +"PO-Revision-Date: 2011-04-10 17:19+0000\n"
    +"Last-Translator: Black Jack \n"
    +"Language-Team: Chinese (Simplified) \n"
    +"MIME-Version: 1.0\n"
    +"Content-Type: text/plain; charset=UTF-8\n"
    +"Content-Transfer-Encoding: 8bit\n"
    +"X-Launchpad-Export-Date: 2011-04-11 04:54+0000\n"
    +"X-Generator: Launchpad (build 12735)\n"
    +
    +#. module: crm_helpdesk
    +#: field:crm.helpdesk.report,delay_close:0
    +msgid "Delay to Close"
    +msgstr "延迟关闭"
    +
    +#. module: crm_helpdesk
    +#: field:crm.helpdesk.report,nbr:0
    +msgid "# of Cases"
    +msgstr "# 业务"
    +
    +#. module: crm_helpdesk
    +#: view:crm.helpdesk:0
    +#: view:crm.helpdesk.report:0
    +msgid "Group By..."
    +msgstr "分组..."
    +
    +#. module: crm_helpdesk
    +#: view:crm.helpdesk:0
    +msgid "Today"
    +msgstr "今日"
    +
    +#. module: crm_helpdesk
    +#: selection:crm.helpdesk.report,month:0
    +msgid "March"
    +msgstr "3月"
    +
    +#. module: crm_helpdesk
    +#: field:crm.helpdesk,company_id:0
    +#: view:crm.helpdesk.report:0
    +#: field:crm.helpdesk.report,company_id:0
    +msgid "Company"
    +msgstr "公司"
    +
    +#. module: crm_helpdesk
    +#: field:crm.helpdesk,email_cc:0
    +msgid "Watchers Emails"
    +msgstr "关注者的电子邮件"
    +
    +#. module: crm_helpdesk
    +#: selection:crm.helpdesk,priority:0
    +#: selection:crm.helpdesk.report,priority:0
    +msgid "Highest"
    +msgstr "最高"
    +
    +#. module: crm_helpdesk
    +#: view:crm.helpdesk.report:0
    +#: field:crm.helpdesk.report,day:0
    +msgid "Day"
    +msgstr "日"
    +
    +#. module: crm_helpdesk
    +#: view:crm.helpdesk:0
    +msgid "Add Internal Note"
    +msgstr "添加内部备注"
    +
    +#. module: crm_helpdesk
    +#: view:crm.helpdesk:0
    +msgid "Notes"
    +msgstr "备注"
    +
    +#. module: crm_helpdesk
    +#: field:crm.helpdesk,message_ids:0
    +msgid "Messages"
    +msgstr "消息"
    +
    +#. module: crm_helpdesk
    +#: selection:crm.helpdesk,state:0
    +#: selection:crm.helpdesk.report,state:0
    +msgid "Cancelled"
    +msgstr "已取消"
    +
    +#. module: crm_helpdesk
    +#: field:crm.helpdesk,partner_address_id:0
    +msgid "Partner Contact"
    +msgstr "业务伙伴联系方式"
    +
    +#. module: crm_helpdesk
    +#: model:ir.ui.menu,name:crm_helpdesk.menu_report_crm_helpdesks_tree
    +msgid "Helpdesk Analysis"
    +msgstr "服务台分析"
    +
    +#. module: crm_helpdesk
    +#: view:crm.helpdesk.report:0
    +#: field:crm.helpdesk.report,date_closed:0
    +msgid "Close Date"
    +msgstr "结束日期"
    +
    +#. module: crm_helpdesk
    +#: view:crm.helpdesk.report:0
    +msgid "   Month   "
    +msgstr "   月   "
    +
    +#. module: crm_helpdesk
    +#: field:crm.helpdesk,ref:0
    +msgid "Reference"
    +msgstr "参考"
    +
    +#. module: crm_helpdesk
    +#: field:crm.helpdesk,date_action_next:0
    +msgid "Next Action"
    +msgstr "下一动作"
    +
    +#. module: crm_helpdesk
    +#: view:crm.helpdesk:0
    +msgid "Helpdesk Supports"
    +msgstr "服务台支持"
    +
    +#. module: crm_helpdesk
    +#: view:crm.helpdesk:0
    +msgid "Extra Info"
    +msgstr "额外信息"
    +
    +#. module: crm_helpdesk
    +#: view:crm.helpdesk:0
    +#: field:crm.helpdesk,partner_id:0
    +#: view:crm.helpdesk.report:0
    +#: field:crm.helpdesk.report,partner_id:0
    +msgid "Partner"
    +msgstr "业务伙伴"
    +
    +#. module: crm_helpdesk
    +#: view:crm.helpdesk:0
    +msgid "Estimates"
    +msgstr "估计"
    +
    +#. module: crm_helpdesk
    +#: field:crm.helpdesk.report,section_id:0
    +msgid "Section"
    +msgstr "分类"
    +
    +#. module: crm_helpdesk
    +#: view:crm.helpdesk:0
    +#: field:crm.helpdesk,priority:0
    +#: view:crm.helpdesk.report:0
    +#: field:crm.helpdesk.report,priority:0
    +msgid "Priority"
    +msgstr "优先级"
    +
    +#. module: crm_helpdesk
    +#: view:crm.helpdesk:0
    +msgid "Send New Email"
    +msgstr "发送新的电子邮件"
    +
    +#. module: crm_helpdesk
    +#: view:crm.helpdesk.report:0
    +msgid "Won"
    +msgstr "获得"
    +
    +#. module: crm_helpdesk
    +#: field:crm.helpdesk.report,delay_expected:0
    +msgid "Overpassed Deadline"
    +msgstr "超越截止日期"
    +
    +#. module: crm_helpdesk
    +#: model:ir.model,name:crm_helpdesk.model_crm_helpdesk_report
    +msgid "Helpdesk report after Sales Services"
    +msgstr "售后服务服务台报表"
    +
    +#. module: crm_helpdesk
    +#: field:crm.helpdesk,email_from:0
    +msgid "Email"
    +msgstr "电子邮件"
    +
    +#. module: crm_helpdesk
    +#: field:crm.helpdesk,canal_id:0
    +#: view:crm.helpdesk.report:0
    +#: field:crm.helpdesk.report,canal_id:0
    +msgid "Channel"
    +msgstr "途径"
    +
    +#. module: crm_helpdesk
    +#: selection:crm.helpdesk,priority:0
    +#: selection:crm.helpdesk.report,priority:0
    +msgid "Lowest"
    +msgstr "最低"
    +
    +#. module: crm_helpdesk
    +#: view:crm.helpdesk.report:0
    +msgid "# Mails"
    +msgstr "邮件"
    +
    +#. module: crm_helpdesk
    +#: field:crm.helpdesk,create_date:0
    +#: field:crm.helpdesk.report,create_date:0
    +msgid "Creation Date"
    +msgstr "创建日期"
    +
    +#. module: crm_helpdesk
    +#: view:crm.helpdesk:0
    +msgid "Reset to Draft"
    +msgstr "重置为草稿"
    +
    +#. module: crm_helpdesk
    +#: view:crm.helpdesk:0
    +#: selection:crm.helpdesk,state:0
    +#: selection:crm.helpdesk.report,state:0
    +msgid "Pending"
    +msgstr "待处理"
    +
    +#. module: crm_helpdesk
    +#: view:crm.helpdesk:0
    +#: field:crm.helpdesk,date_deadline:0
    +#: field:crm.helpdesk.report,date_deadline:0
    +msgid "Deadline"
    +msgstr "截止日期"
    +
    +#. module: crm_helpdesk
    +#: selection:crm.helpdesk.report,month:0
    +msgid "July"
    +msgstr "7月"
    +
    +#. module: crm_helpdesk
    +#: model:ir.actions.act_window,name:crm_helpdesk.crm_helpdesk_categ_action
    +msgid "Helpdesk Categories"
    +msgstr "服务台类型"
    +
    +#. module: crm_helpdesk
    +#: model:ir.ui.menu,name:crm_helpdesk.menu_crm_case_helpdesk-act
    +msgid "Categories"
    +msgstr "类型"
    +
    +#. module: crm_helpdesk
    +#: view:crm.helpdesk:0
    +msgid "History Information"
    +msgstr "日志信息"
    +
    +#. module: crm_helpdesk
    +#: view:crm.helpdesk:0
    +msgid "Dates"
    +msgstr "日期"
    +
    +#. module: crm_helpdesk
    +#: view:crm.helpdesk.report:0
    +msgid "    Month-1    "
    +msgstr "    上月    "
    +
    +#. module: crm_helpdesk
    +#: view:crm.helpdesk.report:0
    +msgid "#Helpdesk"
    +msgstr "服务台"
    +
    +#. module: crm_helpdesk
    +#: help:crm.helpdesk,email_cc:0
    +msgid ""
    +"These email addresses will be added to the CC field of all inbound and "
    +"outbound emails for this record before being sent. Separate multiple email "
    +"addresses with a comma"
    +msgstr "这些邮件地址将添加到之前发送记录的发送和接收邮件的抄送字段,分隔多个邮件地址有逗号。"
    +
    +#. module: crm_helpdesk
    +#: view:crm.helpdesk:0
    +msgid "References"
    +msgstr "参考"
    +
    +#. module: crm_helpdesk
    +#: selection:crm.helpdesk.report,month:0
    +msgid "September"
    +msgstr "9月"
    +
    +#. module: crm_helpdesk
    +#: view:crm.helpdesk:0
    +msgid "Communication"
    +msgstr "沟通"
    +
    +#. module: crm_helpdesk
    +#: view:crm.helpdesk.report:0
    +#: field:crm.helpdesk.report,month:0
    +msgid "Month"
    +msgstr "月份"
    +
    +#. module: crm_helpdesk
    +#: view:crm.helpdesk:0
    +msgid "Escalate"
    +msgstr "提升"
    +
    +#. module: crm_helpdesk
    +#: field:crm.helpdesk,write_date:0
    +msgid "Update Date"
    +msgstr "更新日期"
    +
    +#. module: crm_helpdesk
    +#: view:crm.helpdesk:0
    +msgid "Query"
    +msgstr "查询"
    +
    +#. module: crm_helpdesk
    +#: view:crm.helpdesk.report:0
    +msgid "Salesman"
    +msgstr "业务员"
    +
    +#. module: crm_helpdesk
    +#: field:crm.helpdesk,ref2:0
    +msgid "Reference 2"
    +msgstr "参考2"
    +
    +#. module: crm_helpdesk
    +#: field:crm.helpdesk,categ_id:0
    +#: field:crm.helpdesk.report,categ_id:0
    +msgid "Category"
    +msgstr "类型"
    +
    +#. module: crm_helpdesk
    +#: view:crm.helpdesk.report:0
    +msgid "  Year  "
    +msgstr "  年  "
    +
    +#. module: crm_helpdesk
    +#: view:crm.helpdesk:0
    +msgid "Helpdesk Support"
    +msgstr ""
    +
    +#. module: crm_helpdesk
    +#: field:crm.helpdesk,planned_cost:0
    +#: field:crm.helpdesk.report,planned_cost:0
    +msgid "Planned Costs"
    +msgstr "计划成本"
    +
    +#. module: crm_helpdesk
    +#: model:ir.module.module,description:crm_helpdesk.module_meta_information
    +msgid "Helpdesk Management"
    +msgstr "服务台管理"
    +
    +#. module: crm_helpdesk
    +#: view:crm.helpdesk:0
    +msgid "Search Helpdesk"
    +msgstr "查询服务台"
    +
    +#. module: crm_helpdesk
    +#: selection:crm.helpdesk,state:0
    +#: selection:crm.helpdesk.report,state:0
    +msgid "Draft"
    +msgstr "草稿"
    +
    +#. module: crm_helpdesk
    +#: selection:crm.helpdesk,priority:0
    +#: selection:crm.helpdesk.report,priority:0
    +msgid "Low"
    +msgstr "低"
    +
    +#. module: crm_helpdesk
    +#: field:crm.helpdesk,date_closed:0
    +#: selection:crm.helpdesk,state:0
    +#: selection:crm.helpdesk.report,state:0
    +msgid "Closed"
    +msgstr "已结束"
    +
    +#. module: crm_helpdesk
    +#: view:crm.helpdesk:0
    +msgid "7 Days"
    +msgstr "7天"
    +
    +#. module: crm_helpdesk
    +#: view:crm.helpdesk:0
    +msgid "Communication & History"
    +msgstr "沟通&日志"
    +
    +#. module: crm_helpdesk
    +#: selection:crm.helpdesk.report,month:0
    +msgid "August"
    +msgstr "8月"
    +
    +#. module: crm_helpdesk
    +#: selection:crm.helpdesk,priority:0
    +#: selection:crm.helpdesk.report,priority:0
    +msgid "Normal"
    +msgstr "普通"
    +
    +#. module: crm_helpdesk
    +#: view:crm.helpdesk:0
    +msgid "Global CC"
    +msgstr "完整抄送"
    +
    +#. module: crm_helpdesk
    +#: selection:crm.helpdesk.report,month:0
    +msgid "June"
    +msgstr "6月"
    +
    +#. module: crm_helpdesk
    +#: field:crm.helpdesk,planned_revenue:0
    +msgid "Planned Revenue"
    +msgstr "计划收入"
    +
    +#. module: crm_helpdesk
    +#: field:crm.helpdesk.report,user_id:0
    +msgid "User"
    +msgstr "用户"
    +
    +#. module: crm_helpdesk
    +#: field:crm.helpdesk,active:0
    +msgid "Active"
    +msgstr "有效"
    +
    +#. module: crm_helpdesk
    +#: model:ir.module.module,shortdesc:crm_helpdesk.module_meta_information
    +msgid "CRM Helpdesk"
    +msgstr "客户关系管理 服务台"
    +
    +#. module: crm_helpdesk
    +#: view:crm.helpdesk.report:0
    +msgid "Extended Filters..."
    +msgstr "扩展过滤..."
    +
    +#. module: crm_helpdesk
    +#: model:ir.actions.act_window,name:crm_helpdesk.crm_case_helpdesk_act111
    +msgid "Helpdesk Requests"
    +msgstr "服务台请求"
    +
    +#. module: crm_helpdesk
    +#: view:crm.helpdesk.report:0
    +msgid "Search"
    +msgstr "查找"
    +
    +#. module: crm_helpdesk
    +#: selection:crm.helpdesk.report,month:0
    +msgid "October"
    +msgstr "10月"
    +
    +#. module: crm_helpdesk
    +#: selection:crm.helpdesk.report,month:0
    +msgid "January"
    +msgstr "1月"
    +
    +#. module: crm_helpdesk
    +#: help:crm.helpdesk,email_from:0
    +msgid "These people will receive email."
    +msgstr "这些人将收到电子邮件。"
    +
    +#. module: crm_helpdesk
    +#: view:crm.helpdesk:0
    +#: field:crm.helpdesk,date:0
    +msgid "Date"
    +msgstr "日期"
    +
    +#. module: crm_helpdesk
    +#: selection:crm.helpdesk.report,month:0
    +msgid "November"
    +msgstr "11月"
    +
    +#. module: crm_helpdesk
    +#: view:crm.helpdesk:0
    +msgid "History"
    +msgstr "日志"
    +
    +#. module: crm_helpdesk
    +#: view:crm.helpdesk:0
    +msgid "Attachments"
    +msgstr "附件"
    +
    +#. module: crm_helpdesk
    +#: view:crm.helpdesk:0
    +msgid "Misc"
    +msgstr "杂项"
    +
    +#. module: crm_helpdesk
    +#: view:crm.helpdesk:0
    +#: field:crm.helpdesk,state:0
    +#: view:crm.helpdesk.report:0
    +#: field:crm.helpdesk.report,state:0
    +msgid "State"
    +msgstr "州/省"
    +
    +#. module: crm_helpdesk
    +#: view:crm.helpdesk:0
    +msgid "General"
    +msgstr "通用"
    +
    +#. module: crm_helpdesk
    +#: view:crm.helpdesk:0
    +msgid "Send Reminder"
    +msgstr "发送提醒"
    +
    +#. module: crm_helpdesk
    +#: help:crm.helpdesk,section_id:0
    +msgid ""
    +"Sales team to which Case belongs to.                                 Define "
    +"Responsible user and Email account for mail gateway."
    +msgstr "销售团队属于这业务.定义负责用户和电子邮件帐户和网关"
    +
    +#. module: crm_helpdesk
    +#: view:crm.helpdesk:0
    +msgid "Done"
    +msgstr "完成"
    +
    +#. module: crm_helpdesk
    +#: selection:crm.helpdesk.report,month:0
    +msgid "December"
    +msgstr "12月"
    +
    +#. module: crm_helpdesk
    +#: view:crm.helpdesk:0
    +msgid "Cancel"
    +msgstr "取消"
    +
    +#. module: crm_helpdesk
    +#: view:crm.helpdesk:0
    +msgid "Close"
    +msgstr "结束"
    +
    +#. module: crm_helpdesk
    +#: view:crm.helpdesk:0
    +#: selection:crm.helpdesk,state:0
    +#: selection:crm.helpdesk.report,state:0
    +msgid "Open"
    +msgstr "开启"
    +
    +#. module: crm_helpdesk
    +#: view:crm.helpdesk:0
    +msgid "Helpdesk Support Tree"
    +msgstr "服务台支持树"
    +
    +#. module: crm_helpdesk
    +#: view:crm.helpdesk:0
    +msgid "Categorization"
    +msgstr "归类"
    +
    +#. module: crm_helpdesk
    +#: view:crm.helpdesk.report:0
    +#: model:ir.actions.act_window,name:crm_helpdesk.action_report_crm_helpdesk
    +#: model:ir.model,name:crm_helpdesk.model_crm_helpdesk
    +#: model:ir.ui.menu,name:crm_helpdesk.menu_config_helpdesk
    +msgid "Helpdesk"
    +msgstr "服务台"
    +
    +#. module: crm_helpdesk
    +#: view:crm.helpdesk:0
    +#: field:crm.helpdesk,user_id:0
    +msgid "Responsible"
    +msgstr "负责人"
    +
    +#. module: crm_helpdesk
    +#: view:crm.helpdesk.report:0
    +msgid "Current"
    +msgstr "当前的"
    +
    +#. module: crm_helpdesk
    +#: view:crm.helpdesk:0
    +msgid "Details"
    +msgstr "明细行"
    +
    +#. module: crm_helpdesk
    +#: view:crm.helpdesk:0
    +msgid "Reply"
    +msgstr "回复"
    +
    +#. module: crm_helpdesk
    +#: field:crm.helpdesk,description:0
    +msgid "Description"
    +msgstr "说明"
    +
    +#. module: crm_helpdesk
    +#: selection:crm.helpdesk.report,month:0
    +msgid "May"
    +msgstr "5月"
    +
    +#. module: crm_helpdesk
    +#: field:crm.helpdesk,probability:0
    +msgid "Probability (%)"
    +msgstr "概率(%)"
    +
    +#. module: crm_helpdesk
    +#: field:crm.helpdesk.report,email:0
    +msgid "# Emails"
    +msgstr "电子邮件"
    +
    +#. module: crm_helpdesk
    +#: model:ir.actions.act_window,help:crm_helpdesk.action_report_crm_helpdesk
    +msgid ""
    +"Have a general overview of all support requests by sorting them with "
    +"specific criteria such as the processing time, number of requests answered, "
    +"emails sent and costs."
    +msgstr "所有的支持请求都有分类,具体标准都有大致的描述如: 处理时间,请求回复的次数,邮件的发送成本."
    +
    +#. module: crm_helpdesk
    +#: help:crm.helpdesk,canal_id:0
    +msgid ""
    +"The channels represent the different communication  modes available with the "
    +"customer."
    +msgstr "途径代表与客户沟通的不同方式"
    +
    +#. module: crm_helpdesk
    +#: help:crm.helpdesk,state:0
    +msgid ""
    +"The state is set to 'Draft', when a case is created.                         "
    +"         \n"
    +"If the case is in progress the state is set to 'Open'.                       "
    +"           \n"
    +"When the case is over, the state is set to 'Done'.                           "
    +"       \n"
    +"If the case needs to be reviewed then the state is set to 'Pending'."
    +msgstr ""
    +"当一个业务创建时状态设为'草稿'\n"
    +"如果业务正在处理状态设为'开启'\n"
    +"当业务结束状态设为'完成'\n"
    +"如果业务需要审查状态设为'待定'"
    +
    +#. module: crm_helpdesk
    +#: selection:crm.helpdesk.report,month:0
    +msgid "February"
    +msgstr "2月"
    +
    +#. module: crm_helpdesk
    +#: field:crm.helpdesk,name:0
    +msgid "Name"
    +msgstr "名称"
    +
    +#. module: crm_helpdesk
    +#: view:crm.helpdesk.report:0
    +msgid "Lost"
    +msgstr "丢失"
    +
    +#. module: crm_helpdesk
    +#: model:ir.ui.menu,name:crm_helpdesk.menu_help_support_main
    +msgid "Helpdesk and Support"
    +msgstr "服务台和支持"
    +
    +#. module: crm_helpdesk
    +#: selection:crm.helpdesk.report,month:0
    +msgid "April"
    +msgstr "4月"
    +
    +#. module: crm_helpdesk
    +#: view:crm.helpdesk.report:0
    +msgid "My Case(s)"
    +msgstr "我的业务"
    +
    +#. module: crm_helpdesk
    +#: field:crm.helpdesk,id:0
    +msgid "ID"
    +msgstr ""
    +
    +#. module: crm_helpdesk
    +#: model:ir.actions.act_window,help:crm_helpdesk.crm_helpdesk_categ_action
    +msgid ""
    +"Create and manage helpdesk categories to better manage and classify your "
    +"support requests."
    +msgstr "创建和管理服务台类型去更好管理和分类你的支持的请求"
    +
    +#. module: crm_helpdesk
    +#: selection:crm.helpdesk,priority:0
    +#: selection:crm.helpdesk.report,priority:0
    +msgid "High"
    +msgstr "高"
    +
    +#. module: crm_helpdesk
    +#: view:crm.helpdesk:0
    +#: field:crm.helpdesk,section_id:0
    +#: view:crm.helpdesk.report:0
    +msgid "Sales Team"
    +msgstr "销售团队"
    +
    +#. module: crm_helpdesk
    +#: field:crm.helpdesk,date_action_last:0
    +msgid "Last Action"
    +msgstr "最近动作"
    +
    +#. module: crm_helpdesk
    +#: model:ir.actions.act_window,help:crm_helpdesk.crm_case_helpdesk_act111
    +msgid ""
    +"Helpdesk and Support allow you to track your interventions. Select a "
    +"customer, add notes and categorize interventions with partners if necessary. "
    +"You can also assign a priority level. Use the OpenERP Issues system to "
    +"manage your support activities. Issues can be connected to the email "
    +"gateway: new emails may create issues, each of them automatically gets the "
    +"history of the conversation with the customer."
    +msgstr ""
    +"服务台和支持使你可以去跟踪你的介入.如果需要选择一个客户增加备注和类型介入这业务伙伴.你可以分配一优先级用系统问题模块来管理的的支持活动.问题能链接邮件网"
    +"关.新的邮件可能创建新的问题,它们能自动写入与客户沟通的日志."
    +
    +#. module: crm_helpdesk
    +#: view:crm.helpdesk.report:0
    +#: field:crm.helpdesk.report,name:0
    +msgid "Year"
    +msgstr "年"
    +
    +#. module: crm_helpdesk
    +#: field:crm.helpdesk,duration:0
    +msgid "Duration"
    +msgstr "持续时间"
    diff --git a/addons/crm_profiling/i18n/zh_CN.po b/addons/crm_profiling/i18n/zh_CN.po
    index f675cfc6ac9..bd41fa82d37 100644
    --- a/addons/crm_profiling/i18n/zh_CN.po
    +++ b/addons/crm_profiling/i18n/zh_CN.po
    @@ -7,19 +7,19 @@ msgstr ""
     "Project-Id-Version: OpenERP Server 6.0dev\n"
     "Report-Msgid-Bugs-To: support@openerp.com\n"
     "POT-Creation-Date: 2011-01-11 11:15+0000\n"
    -"PO-Revision-Date: 2010-08-03 03:23+0000\n"
    -"Last-Translator: Black Jack \n"
    +"PO-Revision-Date: 2011-04-10 18:32+0000\n"
    +"Last-Translator: Black Jack \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: 2011-01-15 05:42+0000\n"
    -"X-Generator: Launchpad (build 12177)\n"
    +"X-Launchpad-Export-Date: 2011-04-11 04:53+0000\n"
    +"X-Generator: Launchpad (build 12735)\n"
     
     #. module: crm_profiling
     #: view:crm_profiling.questionnaire:0
     msgid "Questions List"
    -msgstr ""
    +msgstr "问题列表"
     
     #. module: crm_profiling
     #: model:ir.module.module,description:crm_profiling.module_meta_information
    @@ -41,6 +41,15 @@ msgid ""
     "since it's the same which has been renamed.\n"
     "    "
     msgstr ""
    +"\n"
    +"    这模块允许用户去细分业务伙伴。\n"
    +"它使用先前和修改好的细分模块的客户概括标准,以问卷调查的方式,你能组合新的问卷调查给业务伙伴。\n"
    +"\n"
    +"它已经合并到客户关系管理中\n"
    +"菜单在客户关系管理\\设置\\细分\n"
    +"\n"
    +"* 备注:这模块不兼容细分模块因为它们是同名的。\n"
    +"    "
     
     #. module: crm_profiling
     #: model:ir.actions.act_window,help:crm_profiling.open_questionnaires
    @@ -49,7 +58,7 @@ msgid ""
     "in the sales cycle by helping them to ask the right questions. The "
     "segmentation tool allows you to automatically assign a partner to a category "
     "according to his answers to the different questionnaires."
    -msgstr ""
    +msgstr "你能创建特定主题的问卷调查去指导你的团队在销售周期向客户询问合适的问题。这细分工具能根据不同问题的答案自动划分业务伙伴到不同的类型。"
     
     #. module: crm_profiling
     #: field:crm_profiling.answer,question_id:0
    @@ -61,12 +70,12 @@ msgstr "问题"
     #. module: crm_profiling
     #: wizard_button:open_questionnaire,init,open:0
     msgid "Open Questionnaire"
    -msgstr "待处理调查问卷"
    +msgstr "开启的问卷调查"
     
     #. module: crm_profiling
     #: constraint:res.partner:0
     msgid "Error ! You can not create recursive associated members."
    -msgstr ""
    +msgstr "错误!您不能创建递归的相关成员。"
     
     #. module: crm_profiling
     #: view:crm.segmentation:0
    @@ -82,17 +91,17 @@ msgstr "答案"
     #. module: crm_profiling
     #: model:ir.model,name:crm_profiling.model_crm_segmentation
     msgid "Partner Segmentation"
    -msgstr ""
    +msgstr "业务伙伴细分"
     
     #. module: crm_profiling
     #: view:res.partner:0
     msgid "Profiling"
    -msgstr "配置中"
    +msgstr "概况"
     
     #. module: crm_profiling
     #: model:ir.module.module,shortdesc:crm_profiling.module_meta_information
     msgid "Crm Profiling management - To Perform Segmentation within Partners"
    -msgstr ""
    +msgstr "客户关系管理 客户概况管理 - 进行业务伙伴的细分"
     
     #. module: crm_profiling
     #: view:crm_profiling.questionnaire:0
    @@ -115,19 +124,19 @@ msgstr "答案"
     #. module: crm_profiling
     #: wizard_field:open_questionnaire,init,questionnaire_name:0
     msgid "Questionnaire name"
    -msgstr "调查问卷名称"
    +msgstr "问卷调查名称"
     
     #. module: crm_profiling
     #: view:res.partner:0
     msgid "Use a questionnaire"
    -msgstr "使用的调查问卷"
    +msgstr "使用一问卷调查"
     
     #. module: crm_profiling
     #: view:crm_profiling.questionnaire:0
     #: model:ir.actions.act_window,name:crm_profiling.open_questionnaires
     #: model:ir.ui.menu,name:crm_profiling.menu_segm_questionnaire
     msgid "Questionnaires"
    -msgstr "调查问卷"
    +msgstr "问卷调查"
     
     #. module: crm_profiling
     #: help:crm.segmentation,profiling_active:0
    @@ -135,17 +144,17 @@ msgid ""
     "Check                             this box if you want to use this tab as "
     "part of the                              segmentation rule. If not checked, "
     "the criteria beneath will be ignored"
    -msgstr ""
    +msgstr "选中这选项,如果你想使用这标签作为细分规则的一部分。如果不选中,这规则将被忽略"
     
     #. module: crm_profiling
     #: constraint:crm.segmentation:0
     msgid "Error ! You can not create recursive profiles."
    -msgstr "错误! 你不能创建递归的配置"
    +msgstr "错误! 你不能创建递归的客户概况。"
     
     #. module: crm_profiling
     #: field:crm.segmentation,profiling_active:0
     msgid "Use The Profiling Rules"
    -msgstr "使用这配置规则"
    +msgstr "使用这客户概况规则"
     
     #. module: crm_profiling
     #: view:crm_profiling.question:0
    @@ -156,12 +165,12 @@ msgstr "可用答案"
     #. module: crm_profiling
     #: field:crm.segmentation,answer_yes:0
     msgid "Included Answers"
    -msgstr "包括答案"
    +msgstr "包括的答案"
     
     #. module: crm_profiling
     #: field:crm.segmentation,child_ids:0
     msgid "Child Profiles"
    -msgstr "子配置"
    +msgstr "子客户概况"
     
     #. module: crm_profiling
     #: view:crm_profiling.question:0
    @@ -174,7 +183,7 @@ msgstr "问题"
     #. module: crm_profiling
     #: field:crm.segmentation,parent_id:0
     msgid "Parent Profile"
    -msgstr "上级配置"
    +msgstr "上级客户概况"
     
     #. module: crm_profiling
     #: wizard_button:open_questionnaire,init,end:0
    @@ -185,7 +194,7 @@ msgstr "取消"
     #. module: crm_profiling
     #: model:ir.model,name:crm_profiling.model_res_partner
     msgid "Partner"
    -msgstr ""
    +msgstr "业务伙伴"
     
     #. module: crm_profiling
     #: code:addons/crm_profiling/crm_profiling.py:178
    @@ -194,12 +203,12 @@ msgstr ""
     #: wizard_view:open_questionnaire,init:0
     #, python-format
     msgid "Questionnaire"
    -msgstr "调查问卷"
    +msgstr "问卷调查"
     
     #. module: crm_profiling
     #: model:ir.actions.wizard,name:crm_profiling.wizard_open_questionnaire
     msgid "Using a questionnaire"
    -msgstr "使用一调查问卷"
    +msgstr "使用一问卷调查"
     
     #. module: crm_profiling
     #: wizard_button:open_questionnaire,open,compute:0
    diff --git a/addons/document_webdav/i18n/ca.po b/addons/document_webdav/i18n/ca.po
    new file mode 100644
    index 00000000000..83590b5c383
    --- /dev/null
    +++ b/addons/document_webdav/i18n/ca.po
    @@ -0,0 +1,206 @@
    +# Catalan translation for openobject-addons
    +# Copyright (c) 2011 Rosetta Contributors and Canonical Ltd 2011
    +# This file is distributed under the same license as the openobject-addons package.
    +# FIRST AUTHOR , 2011.
    +#
    +msgid ""
    +msgstr ""
    +"Project-Id-Version: openobject-addons\n"
    +"Report-Msgid-Bugs-To: FULL NAME \n"
    +"POT-Creation-Date: 2011-01-11 11:15+0000\n"
    +"PO-Revision-Date: 2011-04-10 16:26+0000\n"
    +"Last-Translator: FULL NAME \n"
    +"Language-Team: Catalan \n"
    +"MIME-Version: 1.0\n"
    +"Content-Type: text/plain; charset=UTF-8\n"
    +"Content-Transfer-Encoding: 8bit\n"
    +"X-Launchpad-Export-Date: 2011-04-11 04:53+0000\n"
    +"X-Generator: Launchpad (build 12735)\n"
    +
    +#. module: document_webdav
    +#: field:document.webdav.dir.property,create_date:0
    +#: field:document.webdav.file.property,create_date:0
    +msgid "Date Created"
    +msgstr ""
    +
    +#. module: document_webdav
    +#: constraint:document.directory:0
    +msgid "Error! You can not create recursive Directories."
    +msgstr ""
    +
    +#. module: document_webdav
    +#: view:document.webdav.dir.property:0
    +#: view:document.webdav.file.property:0
    +msgid "Search Document properties"
    +msgstr ""
    +
    +#. module: document_webdav
    +#: view:document.webdav.dir.property:0
    +#: field:document.webdav.dir.property,namespace:0
    +#: view:document.webdav.file.property:0
    +#: field:document.webdav.file.property,namespace:0
    +msgid "Namespace"
    +msgstr ""
    +
    +#. module: document_webdav
    +#: field:document.directory,dav_prop_ids:0
    +msgid "DAV properties"
    +msgstr ""
    +
    +#. module: document_webdav
    +#: model:ir.model,name:document_webdav.model_document_webdav_file_property
    +msgid "document.webdav.file.property"
    +msgstr ""
    +
    +#. module: document_webdav
    +#: view:document.webdav.dir.property:0
    +#: view:document.webdav.file.property:0
    +msgid "Group By..."
    +msgstr ""
    +
    +#. module: document_webdav
    +#: view:document.directory:0
    +msgid "These properties will be added to WebDAV requests"
    +msgstr ""
    +
    +#. module: document_webdav
    +#: model:ir.ui.menu,name:document_webdav.menu_file_props
    +msgid "DAV properties for documents"
    +msgstr ""
    +
    +#. module: document_webdav
    +#: code:addons/document_webdav/webdav.py:37
    +#, python-format
    +msgid "PyWebDAV Import Error!"
    +msgstr ""
    +
    +#. module: document_webdav
    +#: view:document.webdav.file.property:0
    +#: field:document.webdav.file.property,file_id:0
    +msgid "Document"
    +msgstr ""
    +
    +#. module: document_webdav
    +#: model:ir.module.module,description:document_webdav.module_meta_information
    +msgid ""
    +" With this module, the WebDAV server for the documents is activated.\n"
    +"        You can then use any compatible browser to remotely see the "
    +"attachments of OpenObject.\n"
    +"\n"
    +"        After installation, the webDAV server can be controlled by a "
    +"[webdav] section in the server's config.\n"
    +"        Server Configuration Parameter:\n"
    +"        [webdav]\n"
    +"        ; enable = True ; Serve webdav over the http(s) servers\n"
    +"        ; vdir = webdav ; the directory that webdav will be served at\n"
    +"          ; this default val means that webdav will be\n"
    +"          ; on \"http://localhost:8069/webdav/\n"
    +"        ; verbose = True ; Turn on the verbose messages of webdav\n"
    +"        ; debug = True ; Turn on the debugging messages of webdav\n"
    +"          ; since the messages are routed to the python logging, with\n"
    +"          ; levels \"debug\" and \"debug_rpc\" respectively, you can leave\n"
    +"          ; these options on\n"
    +msgstr ""
    +
    +#. module: document_webdav
    +#: sql_constraint:document.directory:0
    +msgid "Directory cannot be parent of itself!"
    +msgstr ""
    +
    +#. module: document_webdav
    +#: view:document.directory:0
    +msgid "Dynamic context"
    +msgstr ""
    +
    +#. module: document_webdav
    +#: view:document.directory:0
    +msgid "WebDAV properties"
    +msgstr ""
    +
    +#. module: document_webdav
    +#: sql_constraint:document.directory:0
    +msgid "The directory name must be unique !"
    +msgstr ""
    +
    +#. module: document_webdav
    +#: code:addons/document_webdav/webdav.py:37
    +#, python-format
    +msgid ""
    +"Please install PyWebDAV from "
    +"http://code.google.com/p/pywebdav/downloads/detail?name=PyWebDAV-"
    +"0.9.4.tar.gz&can=2&q=/"
    +msgstr ""
    +
    +#. module: document_webdav
    +#: model:ir.ui.menu,name:document_webdav.menu_dir_props
    +msgid "DAV properties for folders"
    +msgstr ""
    +
    +#. module: document_webdav
    +#: view:document.directory:0
    +#: view:document.webdav.dir.property:0
    +#: view:document.webdav.file.property:0
    +msgid "Properties"
    +msgstr ""
    +
    +#. module: document_webdav
    +#: field:document.webdav.dir.property,name:0
    +#: field:document.webdav.file.property,name:0
    +msgid "Name"
    +msgstr ""
    +
    +#. module: document_webdav
    +#: model:ir.model,name:document_webdav.model_document_webdav_dir_property
    +msgid "document.webdav.dir.property"
    +msgstr ""
    +
    +#. module: document_webdav
    +#: field:document.webdav.dir.property,value:0
    +#: field:document.webdav.file.property,value:0
    +msgid "Value"
    +msgstr ""
    +
    +#. module: document_webdav
    +#: field:document.webdav.dir.property,dir_id:0
    +#: model:ir.model,name:document_webdav.model_document_directory
    +msgid "Directory"
    +msgstr ""
    +
    +#. module: document_webdav
    +#: field:document.webdav.dir.property,write_uid:0
    +#: field:document.webdav.file.property,write_uid:0
    +msgid "Last Modification User"
    +msgstr ""
    +
    +#. module: document_webdav
    +#: view:document.webdav.dir.property:0
    +msgid "Dir"
    +msgstr ""
    +
    +#. module: document_webdav
    +#: field:document.webdav.dir.property,write_date:0
    +#: field:document.webdav.file.property,write_date:0
    +msgid "Date Modified"
    +msgstr ""
    +
    +#. module: document_webdav
    +#: field:document.webdav.dir.property,create_uid:0
    +#: field:document.webdav.file.property,create_uid:0
    +msgid "Creator"
    +msgstr ""
    +
    +#. module: document_webdav
    +#: model:ir.module.module,shortdesc:document_webdav.module_meta_information
    +msgid "WebDAV server for Document Management"
    +msgstr ""
    +
    +#. module: document_webdav
    +#: sql_constraint:document.directory:0
    +msgid "Directory must have a parent or a storage"
    +msgstr ""
    +
    +#. module: document_webdav
    +#: field:document.webdav.dir.property,do_subst:0
    +#: field:document.webdav.file.property,do_subst:0
    +msgid "Substitute"
    +msgstr ""
    diff --git a/addons/fetchmail/i18n/ca.po b/addons/fetchmail/i18n/ca.po
    new file mode 100644
    index 00000000000..04bef6e3258
    --- /dev/null
    +++ b/addons/fetchmail/i18n/ca.po
    @@ -0,0 +1,317 @@
    +# Catalan translation for openobject-addons
    +# Copyright (c) 2011 Rosetta Contributors and Canonical Ltd 2011
    +# This file is distributed under the same license as the openobject-addons package.
    +# FIRST AUTHOR , 2011.
    +#
    +msgid ""
    +msgstr ""
    +"Project-Id-Version: openobject-addons\n"
    +"Report-Msgid-Bugs-To: FULL NAME \n"
    +"POT-Creation-Date: 2011-01-11 11:15+0000\n"
    +"PO-Revision-Date: 2011-04-10 14:45+0000\n"
    +"Last-Translator: FULL NAME \n"
    +"Language-Team: Catalan \n"
    +"MIME-Version: 1.0\n"
    +"Content-Type: text/plain; charset=UTF-8\n"
    +"Content-Transfer-Encoding: 8bit\n"
    +"X-Launchpad-Export-Date: 2011-04-11 04:54+0000\n"
    +"X-Generator: Launchpad (build 12735)\n"
    +
    +#. module: fetchmail
    +#: constraint:email.server:0
    +msgid ""
    +"Warning! Record for selected Model can not be created\n"
    +"Please choose valid Model"
    +msgstr ""
    +"Atenció! No es poden crear registres per al model seleccionat\n"
    +"Seleccioneu un model vàlid"
    +
    +#. module: fetchmail
    +#: selection:email.server,state:0
    +msgid "Confirmed"
    +msgstr "Confirmat"
    +
    +#. module: fetchmail
    +#: view:email.server:0
    +msgid "Confirm"
    +msgstr "Confirma"
    +
    +#. module: fetchmail
    +#: view:email.server:0
    +msgid "Group By..."
    +msgstr "Agrupa per..."
    +
    +#. module: fetchmail
    +#: view:email.server:0
    +#: field:email.server,state:0
    +msgid "State"
    +msgstr "Estat"
    +
    +#. module: fetchmail
    +#: view:email.server:0
    +msgid "POP"
    +msgstr "POP"
    +
    +#. module: fetchmail
    +#: selection:email.server,state:0
    +msgid "Not Confirmed"
    +msgstr "No confirmat"
    +
    +#. module: fetchmail
    +#: field:email.server,user:0
    +msgid "User Name"
    +msgstr "Nom de l'usuari"
    +
    +#. module: fetchmail
    +#: view:email.server:0
    +msgid "Type"
    +msgstr "Tipus"
    +
    +#. module: fetchmail
    +#: view:email.server:0
    +msgid "POP/IMAP Servers"
    +msgstr "Servidores POP/IMAP"
    +
    +#. module: fetchmail
    +#: model:ir.module.module,shortdesc:fetchmail.module_meta_information
    +msgid "Fetchmail Server"
    +msgstr "Servidor Fetchmail"
    +
    +#. module: fetchmail
    +#: view:email.server:0
    +#: field:email.server,note:0
    +msgid "Description"
    +msgstr "Descripció"
    +
    +#. module: fetchmail
    +#: help:email.server,object_id:0
    +msgid ""
    +"OpenObject Model. Generates a record of this model.\n"
    +"Select Object with message_new attrbutes."
    +msgstr ""
    +"Model OpenObject. Genera un registre d'aquest model.\n"
    +"Seleccioneu un objecte amb atributs message_new (nou missatge)."
    +
    +#. module: fetchmail
    +#: field:email.server,attach:0
    +msgid "Add Attachments ?"
    +msgstr "Afegeix adjunts?"
    +
    +#. module: fetchmail
    +#: view:email.server:0
    +msgid "# of emails"
    +msgstr "nombre d'emails"
    +
    +#. module: fetchmail
    +#: model:ir.actions.act_window,name:fetchmail.act_server_history
    +msgid "Email History"
    +msgstr "Historial d'emails"
    +
    +#. module: fetchmail
    +#: field:email.server,user_id:0
    +msgid "User"
    +msgstr "Usuari"
    +
    +#. module: fetchmail
    +#: field:email.server,date:0
    +msgid "Date"
    +msgstr "Data"
    +
    +#. module: fetchmail
    +#: selection:email.server,state:0
    +msgid "Waiting for Verification"
    +msgstr "Esperant verificació"
    +
    +#. module: fetchmail
    +#: field:email.server,password:0
    +msgid "Password"
    +msgstr "Contrasenya"
    +
    +#. module: fetchmail
    +#: view:mailgate.message:0
    +msgid "Emails"
    +msgstr "Emails"
    +
    +#. module: fetchmail
    +#: view:email.server:0
    +msgid "Search Email Servers"
    +msgstr "Buscar servidores de correo"
    +
    +#. module: fetchmail
    +#: view:email.server:0
    +msgid "Server & Login"
    +msgstr "Servidor i connexió"
    +
    +#. module: fetchmail
    +#: view:email.server:0
    +msgid "Auto Reply?"
    +msgstr "¿Auto responder?"
    +
    +#. module: fetchmail
    +#: field:email.server,name:0
    +msgid "Name"
    +msgstr "Nom"
    +
    +#. module: fetchmail
    +#: model:ir.model,name:fetchmail.model_mailgate_message
    +msgid "Mailgateway Message"
    +msgstr "Missatge passarel·la de correu"
    +
    +#. module: fetchmail
    +#: model:ir.actions.act_window,name:fetchmail.action_email_server_tree
    +msgid "POP Servers"
    +msgstr "Servidores POP"
    +
    +#. module: fetchmail
    +#: view:email.server:0
    +msgid "Set to Draft"
    +msgstr "Canvia a esborrany"
    +
    +#. module: fetchmail
    +#: field:email.server,message_ids:0
    +#: model:ir.actions.act_window,name:fetchmail.action_view_mail_message_emails
    +msgid "Messages"
    +msgstr "Missatges"
    +
    +#. module: fetchmail
    +#: model:ir.ui.menu,name:fetchmail.menu_action_fetchmail_server_tree
    +msgid "Fetchmail Services"
    +msgstr "Servicios Fetchmail"
    +
    +#. module: fetchmail
    +#: field:email.server,server:0
    +msgid "Server"
    +msgstr "Servidor"
    +
    +#. module: fetchmail
    +#: field:email.server,active:0
    +msgid "Active"
    +msgstr "Actiu"
    +
    +#. module: fetchmail
    +#: view:email.server:0
    +msgid "Process Parameter"
    +msgstr "Paràmetre procés"
    +
    +#. module: fetchmail
    +#: field:email.server,is_ssl:0
    +msgid "SSL ?"
    +msgstr "SSL"
    +
    +#. module: fetchmail
    +#: selection:email.server,type:0
    +#: selection:mailgate.message,server_type:0
    +msgid "IMAP Server"
    +msgstr "Servidor IMAP"
    +
    +#. module: fetchmail
    +#: field:email.server,object_id:0
    +msgid "Model"
    +msgstr "Model"
    +
    +#. module: fetchmail
    +#: view:email.server:0
    +msgid "IMAP"
    +msgstr "IMAP"
    +
    +#. module: fetchmail
    +#: view:email.server:0
    +#: model:ir.model,name:fetchmail.model_email_server
    +msgid "POP/IMAP Server"
    +msgstr "Servidor POP/IMAP"
    +
    +#. module: fetchmail
    +#: constraint:email.server:0
    +msgid "Warning! Can't have duplicate server configuration!"
    +msgstr "¡Aviso! No puede tener la configuración del servidor duplicada."
    +
    +#. module: fetchmail
    +#: field:email.server,type:0
    +#: field:mailgate.message,server_type:0
    +msgid "Server Type"
    +msgstr "Tipus de servidor"
    +
    +#. module: fetchmail
    +#: view:email.server:0
    +msgid "Login Information"
    +msgstr "Informació de connexió"
    +
    +#. module: fetchmail
    +#: view:email.server:0
    +msgid "Server Information"
    +msgstr "Informació del servidor"
    +
    +#. module: fetchmail
    +#: help:email.server,attach:0
    +msgid "Fetches mail with attachments if true."
    +msgstr "Si está marcado, obtiene correo con documentos adjuntos."
    +
    +#. module: fetchmail
    +#: selection:email.server,type:0
    +#: selection:mailgate.message,server_type:0
    +msgid "POP Server"
    +msgstr "Servidor POP"
    +
    +#. module: fetchmail
    +#: field:email.server,port:0
    +msgid "Port"
    +msgstr "Port"
    +
    +#. module: fetchmail
    +#: model:ir.module.module,description:fetchmail.module_meta_information
    +msgid ""
    +"Fetchmail: \n"
    +"    * Fetch email from Pop / IMAP server\n"
    +"    * Support SSL\n"
    +"    * Integrated with all Modules\n"
    +"    * Automatic Email Receive\n"
    +"    * Email based Records (Add, Update)\n"
    +"    "
    +msgstr ""
    +"Fetchmail: \n"
    +"    * Recuperar email des de servidor POP / IMAP\n"
    +"    * Compatibilitat amb SSL\n"
    +"    * Integració amb tots els mòduls\n"
    +"    * Recepció automàtica d'emails\n"
    +"    * Registres basats en email (afegir, actualitzar)\n"
    +"    "
    +
    +#. module: fetchmail
    +#: view:email.server:0
    +msgid "SSL"
    +msgstr "SSL"
    +
    +#. module: fetchmail
    +#: help:email.server,action_id:0
    +msgid ""
    +"An Email Server Action. It will be run whenever an e-mail is fetched from "
    +"server."
    +msgstr ""
    +"Una acció de servidor de correu. S'executarà sempre que s'obtingui un email "
    +"des del servidor."
    +
    +#. module: fetchmail
    +#: help:email.server,priority:0
    +msgid "Priority between 0 to 10, select define the order of Processing"
    +msgstr "Prioritat entre 0 i 10, defineix l'ordre de procés."
    +
    +#. module: fetchmail
    +#: field:email.server,action_id:0
    +msgid "Email Server Action"
    +msgstr "Acción d'email del servidor"
    +
    +#. module: fetchmail
    +#: field:email.server,priority:0
    +msgid "Server Priority"
    +msgstr "Prioridad servidor"
    +
    +#. module: fetchmail
    +#: view:mailgate.message:0
    +#: field:mailgate.message,server_id:0
    +msgid "Mail Server"
    +msgstr "Servidor de correu"
    +
    +#. module: fetchmail
    +#: view:email.server:0
    +msgid "Fetch Emails"
    +msgstr "Recupera emails"
    diff --git a/addons/hr_payroll/i18n/vi.po b/addons/hr_payroll/i18n/vi.po
    new file mode 100644
    index 00000000000..86ca6bf8ef1
    --- /dev/null
    +++ b/addons/hr_payroll/i18n/vi.po
    @@ -0,0 +1,1538 @@
    +# Vietnamese translation for openobject-addons
    +# Copyright (c) 2011 Rosetta Contributors and Canonical Ltd 2011
    +# This file is distributed under the same license as the openobject-addons package.
    +# FIRST AUTHOR , 2011.
    +#
    +msgid ""
    +msgstr ""
    +"Project-Id-Version: openobject-addons\n"
    +"Report-Msgid-Bugs-To: FULL NAME \n"
    +"POT-Creation-Date: 2011-01-11 11:15+0000\n"
    +"PO-Revision-Date: 2011-04-07 16:44+0000\n"
    +"Last-Translator: Phong Nguyen-Thanh \n"
    +"Language-Team: Vietnamese \n"
    +"MIME-Version: 1.0\n"
    +"Content-Type: text/plain; charset=UTF-8\n"
    +"Content-Transfer-Encoding: 8bit\n"
    +"X-Launchpad-Export-Date: 2011-04-08 04:45+0000\n"
    +"X-Generator: Launchpad (build 12735)\n"
    +
    +#. module: hr_payroll
    +#: rml:employees.salary:0
    +msgid "E-mail Address"
    +msgstr "E-mail Address"
    +
    +#. module: hr_payroll
    +#: view:hr.allounce.deduction.categoty:0
    +msgid "Based"
    +msgstr ""
    +
    +#. module: hr_payroll
    +#: field:hr.payroll.register,net:0
    +#: field:hr.payslip,net:0
    +msgid "Net Salary"
    +msgstr "Net Salary"
    +
    +#. module: hr_payroll
    +#: view:hr.payslip:0
    +msgid "Recompute Sheet"
    +msgstr ""
    +
    +#. module: hr_payroll
    +#: rml:employees.salary:0
    +msgid "Employees Salary Details"
    +msgstr ""
    +
    +#. module: hr_payroll
    +#: rml:employees.salary:0
    +msgid "Allowances with Basic:"
    +msgstr ""
    +
    +#. module: hr_payroll
    +#: rml:employees.salary:0
    +#: rml:salary.structure:0
    +msgid "Department"
    +msgstr "Phòng/Ban"
    +
    +#. module: hr_payroll
    +#: rml:employees.salary:0
    +msgid "Deductions:"
    +msgstr ""
    +
    +#. module: hr_payroll
    +#: field:hr.allounce.deduction.categoty,gratuity:0
    +msgid "Use for Gratuity ?"
    +msgstr ""
    +
    +#. module: hr_payroll
    +#: field:hr.payslip,working_days:0
    +msgid "Working Days"
    +msgstr ""
    +
    +#. module: hr_payroll
    +#: selection:hr.payslip.line,type:0
    +msgid "Loan"
    +msgstr "Khoản vay"
    +
    +#. module: hr_payroll
    +#: rml:hr.payroll.register.sheet:0
    +msgid "Salary Payment Register"
    +msgstr ""
    +
    +#. module: hr_payroll
    +#: field:hr.employee,slip_ids:0
    +#: view:hr.payroll.register:0
    +#: field:hr.payroll.register,line_ids:0
    +msgid "Payslips"
    +msgstr ""
    +
    +#. module: hr_payroll
    +#: model:ir.actions.report.xml,name:hr_payroll.year_salary_report
    +msgid "Year Salary Report"
    +msgstr ""
    +
    +#. module: hr_payroll
    +#: selection:hr.payroll.register,state:0
    +#: selection:hr.payslip,state:0
    +msgid "Paid Salary"
    +msgstr ""
    +
    +#. module: hr_payroll
    +#: report:payslip.pdf:0
    +msgid "("
    +msgstr ""
    +
    +#. module: hr_payroll
    +#: field:hr.payroll.register,company_id:0
    +#: field:hr.payslip,company_id:0
    +#: wizard_field:payroll.analysis,init,company_id:0
    +msgid "Company"
    +msgstr "Công ty"
    +
    +#. module: hr_payroll
    +#: rml:payroll.advice:0
    +msgid "The Manager"
    +msgstr ""
    +
    +#. module: hr_payroll
    +#: view:hr.payroll.advice:0
    +msgid "Letter Details"
    +msgstr ""
    +
    +#. module: hr_payroll
    +#: rml:hr.payroll.register.sheet:0
    +msgid ","
    +msgstr ","
    +
    +#. module: hr_payroll
    +#: view:hr.payroll.advice:0
    +#: view:hr.payroll.register:0
    +#: view:hr.payslip:0
    +msgid "Set to Draft"
    +msgstr ""
    +
    +#. module: hr_payroll
    +#: code:addons/hr_payroll/hr_payroll.py:180
    +#: code:addons/hr_payroll/hr_payroll.py:195
    +#: code:addons/hr_payroll/hr_payroll.py:285
    +#: code:addons/hr_payroll/hr_payroll.py:835
    +#: code:addons/hr_payroll/hr_payroll.py:1111
    +#: code:addons/hr_payroll/hr_payroll.py:1126
    +#: code:addons/hr_payroll/hr_payroll.py:1410
    +#, python-format
    +msgid "Variable Error: %s "
    +msgstr ""
    +
    +#. module: hr_payroll
    +#: view:hr.passport:0
    +msgid "Expire"
    +msgstr ""
    +
    +#. module: hr_payroll
    +#: selection:hr.holidays.status,type:0
    +msgid "Half-Pay Holiday"
    +msgstr ""
    +
    +#. module: hr_payroll
    +#: selection:hr.allounce.deduction.categoty,type:0
    +#: rml:hr.payroll.register.sheet:0
    +#: field:hr.payslip,other_pay:0
    +msgid "Others"
    +msgstr "Khác"
    +
    +#. module: hr_payroll
    +#: field:hr.payslip.line,slip_id:0
    +#: model:ir.model,name:hr_payroll.model_hr_payslip
    +#: rml:payslip.pdf:0
    +msgid "Pay Slip"
    +msgstr ""
    +
    +#. module: hr_payroll
    +#: rml:salary.structure:0
    +msgid "Contract Detail:"
    +msgstr ""
    +
    +#. module: hr_payroll
    +#: field:hr.payslip,igross:0
    +#: field:hr.payslip,inet:0
    +msgid "Calculaton Field"
    +msgstr ""
    +
    +#. module: hr_payroll
    +#: help:hr.payroll.advice,bank_id:0
    +#: help:hr.payroll.register,bank_id:0
    +msgid "Select the Bank Address from whcih the salary is going to be paid"
    +msgstr ""
    +
    +#. module: hr_payroll
    +#: view:hr.payroll.advice:0
    +#: field:hr.payroll.advice.line,advice_id:0
    +msgid "Bank Advice"
    +msgstr ""
    +
    +#. module: hr_payroll
    +#: selection:hr.payroll.advice,state:0
    +#: selection:hr.payroll.register,state:0
    +#: selection:hr.payslip,state:0
    +msgid "Reject"
    +msgstr "Từ chối"
    +
    +#. module: hr_payroll
    +#: selection:hr.payslip.line,type:0
    +msgid "Leaves"
    +msgstr ""
    +
    +#. module: hr_payroll
    +#: field:hr.payslip,register_id:0
    +msgid "Register"
    +msgstr "Đăng ký"
    +
    +#. module: hr_payroll
    +#: constraint:hr.employee:0
    +msgid ""
    +"Error ! You cannot select a department for which the employee is the manager."
    +msgstr ""
    +
    +#. module: hr_payroll
    +#: rml:payslip.pdf:0
    +msgid "Total Deductions"
    +msgstr ""
    +
    +#. module: hr_payroll
    +#: field:hr.allounce.deduction.categoty.line,value:0
    +msgid "Value"
    +msgstr "Giá trị"
    +
    +#. module: hr_payroll
    +#: rml:payroll.advice:0
    +msgid "Name of the Employee"
    +msgstr ""
    +
    +#. module: hr_payroll
    +#: view:hr.contibution.register:0
    +msgid "Register Lines"
    +msgstr ""
    +
    +#. module: hr_payroll
    +#: view:hr.payslip:0
    +msgid "Salary Computation"
    +msgstr ""
    +
    +#. module: hr_payroll
    +#: field:hr.payroll.advice.line,amount:0
    +#: rml:payroll.advice:0
    +msgid "Amount"
    +msgstr "Số tiền"
    +
    +#. module: hr_payroll
    +#: code:addons/hr_payroll/hr_payroll.py:1225
    +#, python-format
    +msgid "Please check configuration of %s, payroll head is missing"
    +msgstr ""
    +
    +#. module: hr_payroll
    +#: selection:company.contribution,amount_type:0
    +msgid "Percentage"
    +msgstr ""
    +
    +#. module: hr_payroll
    +#: view:company.contribution:0
    +#: view:hr.allounce.deduction.categoty:0
    +msgid "Other Information"
    +msgstr ""
    +
    +#. module: hr_payroll
    +#: field:hr.passport,country_id:0
    +msgid "Country of Issue"
    +msgstr ""
    +
    +#. module: hr_payroll
    +#: field:hr.contibution.register.line,emp_deduction:0
    +msgid "Employee Deduction"
    +msgstr ""
    +
    +#. module: hr_payroll
    +#: selection:hr.payslip.line,type:0
    +msgid "Other Deduction"
    +msgstr ""
    +
    +#. module: hr_payroll
    +#: selection:hr.holidays.status,type:0
    +msgid "Paid Holiday"
    +msgstr ""
    +
    +#. module: hr_payroll
    +#: view:company.contribution:0
    +#: view:hr.allounce.deduction.categoty:0
    +#: view:hr.passport:0
    +#: view:hr.payslip:0
    +msgid "Group By..."
    +msgstr ""
    +
    +#. module: hr_payroll
    +#: field:hr.passport,date_expire:0
    +msgid "Passport Expire Date"
    +msgstr ""
    +
    +#. module: hr_payroll
    +#: selection:hr.holidays.status,type:0
    +msgid "Un-Paid Holiday"
    +msgstr ""
    +
    +#. module: hr_payroll
    +#: view:hr.passport:0
    +msgid "Valid From"
    +msgstr ""
    +
    +#. module: hr_payroll
    +#: help:hr.payslip,igross:0
    +#: help:hr.payslip,inet:0
    +msgid ""
    +"Calculation field used for internal calculation, do not place this on form"
    +msgstr ""
    +
    +#. module: hr_payroll
    +#: rml:payslip.pdf:0
    +msgid "Amount (in words) :"
    +msgstr ""
    +
    +#. module: hr_payroll
    +#: field:hr.holidays.status,type:0
    +msgid "Payment"
    +msgstr ""
    +
    +#. module: hr_payroll
    +#: field:hr.payslip,line_ids:0
    +#: view:hr.payslip.line:0
    +#: model:ir.model,name:hr_payroll.model_hr_payslip_line
    +msgid "Payslip Line"
    +msgstr ""
    +
    +#. module: hr_payroll
    +#: report:payslip.pdf:0
    +msgid "Identification No"
    +msgstr ""
    +
    +#. module: hr_payroll
    +#: field:hr.allounce.deduction.categoty,base:0
    +msgid "Based on"
    +msgstr ""
    +
    +#. module: hr_payroll
    +#: selection:hr.payroll.register,state:0
    +#: selection:hr.payslip,state:0
    +msgid "Wating for Verification"
    +msgstr ""
    +
    +#. module: hr_payroll
    +#: model:ir.module.module,shortdesc:hr_payroll.module_meta_information
    +msgid "Human Resource Payroll"
    +msgstr ""
    +
    +#. module: hr_payroll
    +#: report:payroll.advice:0
    +msgid "Total:"
    +msgstr ""
    +
    +#. module: hr_payroll
    +#: view:hr.payslip:0
    +msgid "Posted"
    +msgstr ""
    +
    +#. module: hr_payroll
    +#: model:ir.module.module,description:hr_payroll.module_meta_information
    +msgid ""
    +"Generic Payroll system\n"
    +"    * Employee Details\n"
    +"    * Employee Contracts\n"
    +"    * Passport based Contract\n"
    +"    * Allowances / Deductions\n"
    +"    * Allow to configure Basic / Grows / Net Salary\n"
    +"    * Employee Payslip\n"
    +"    * Monthly Payroll Register\n"
    +"    * Integrated with Holiday Management\n"
    +"    "
    +msgstr ""
    +
    +#. module: hr_payroll
    +#: model:ir.model,name:hr_payroll.model_hr_holidays_status
    +msgid "Leave Type"
    +msgstr ""
    +
    +#. module: hr_payroll
    +#: report:hr.payroll.register.sheet:0
    +msgid "Date :"
    +msgstr ""
    +
    +#. module: hr_payroll
    +#: field:hr.payslip.line,total:0
    +msgid "Sub Total"
    +msgstr ""
    +
    +#. module: hr_payroll
    +#: report:payslip.pdf:0
    +msgid "Payments -"
    +msgstr ""
    +
    +#. module: hr_payroll
    +#: field:hr.contract,visa_no:0
    +msgid "Visa No"
    +msgstr ""
    +
    +#. module: hr_payroll
    +#: field:hr.allounce.deduction.categoty.line,from:0
    +msgid "From"
    +msgstr ""
    +
    +#. module: hr_payroll
    +#: field:hr.payroll.advice.line,bysal:0
    +msgid "By Salary"
    +msgstr ""
    +
    +#. module: hr_payroll
    +#: rml:salary.structure:0
    +msgid "End Date"
    +msgstr ""
    +
    +#. module: hr_payroll
    +#: model:ir.actions.report.xml,name:hr_payroll.salary_payslip
    +msgid "Employee PaySlip"
    +msgstr ""
    +
    +#. module: hr_payroll
    +#: field:hr.payslip,leaves:0
    +msgid "Leave Deductions"
    +msgstr ""
    +
    +#. module: hr_payroll
    +#: rml:hr.payroll.register.sheet:0
    +#: rml:payroll.advice:0
    +msgid "Authorised Signature"
    +msgstr ""
    +
    +#. module: hr_payroll
    +#: selection:hr.payslip.line,amount_type:0
    +msgid "Function Value"
    +msgstr ""
    +
    +#. module: hr_payroll
    +#: model:ir.model,name:hr_payroll.model_hr_contibution_register_line
    +msgid "Contribution Register Line"
    +msgstr ""
    +
    +#. module: hr_payroll
    +#: rml:salary.structure:0
    +msgid "Notes:"
    +msgstr ""
    +
    +#. module: hr_payroll
    +#: field:hr.allounce.deduction.categoty,based_on:0
    +#: field:hr.payroll.advice,state:0
    +#: field:hr.payroll.register,state:0
    +#: field:hr.payslip,state:0
    +msgid "State"
    +msgstr ""
    +
    +#. module: hr_payroll
    +#: view:hr.payroll.advice:0
    +msgid "Paymeny Lines"
    +msgstr ""
    +
    +#. module: hr_payroll
    +#: report:payslip.pdf:0
    +msgid "Other Lines"
    +msgstr ""
    +
    +#. module: hr_payroll
    +#: view:company.contribution:0
    +#: view:hr.allounce.deduction.categoty:0
    +#: view:hr.payroll.structure:0
    +#: view:hr.payslip:0
    +#: view:hr.payslip.line:0
    +msgid "Function Arguments"
    +msgstr ""
    +
    +#. module: hr_payroll
    +#: model:ir.actions.act_window,name:hr_payroll.action_hr_company_contribution_tree
    +#: model:ir.ui.menu,name:hr_payroll.menu_hr_company_contribution_tree
    +msgid "Company Contributions"
    +msgstr ""
    +
    +#. module: hr_payroll
    +#: field:hr.passport,employee_id:0
    +#: field:hr.payroll.advice.line,employee_id:0
    +#: field:hr.payslip,employee_id:0
    +#: field:hr.payslip.line,employee_id:0
    +msgid "Employee"
    +msgstr ""
    +
    +#. module: hr_payroll
    +#: field:hr.payslip.line,base:0
    +msgid "Formula"
    +msgstr ""
    +
    +#. module: hr_payroll
    +#: model:ir.model,name:hr_payroll.model_hr_payroll_advice_line
    +msgid "Bank Advice Lines"
    +msgstr ""
    +
    +#. module: hr_payroll
    +#: field:hr.allounce.deduction.categoty,type:0
    +#: field:hr.payslip.line,type:0
    +#: wizard_field:payroll.analysis,init,type:0
    +#: rml:salary.structure:0
    +msgid "Type"
    +msgstr ""
    +
    +#. module: hr_payroll
    +#: report:payslip.pdf:0
    +msgid "Email"
    +msgstr ""
    +
    +#. module: hr_payroll
    +#: rml:hr.payroll.register.sheet:0
    +msgid "#"
    +msgstr ""
    +
    +#. module: hr_payroll
    +#: code:addons/hr_payroll/hr_payroll.py:469
    +#: code:addons/hr_payroll/hr_payroll.py:1225
    +#, python-format
    +msgid "Error !"
    +msgstr ""
    +
    +#. module: hr_payroll
    +#: view:hr.payroll.register:0
    +#: view:hr.payslip:0
    +msgid "Verify Sheet"
    +msgstr ""
    +
    +#. module: hr_payroll
    +#: help:hr.contract,working_days_per_week:0
    +msgid "No of Working days / week for an employee"
    +msgstr ""
    +
    +#. module: hr_payroll
    +#: selection:hr.payroll.register,state:0
    +#: selection:hr.payslip,state:0
    +msgid "New Slip"
    +msgstr ""
    +
    +#. module: hr_payroll
    +#: field:hr.payslip,basic:0
    +msgid "Net Basic"
    +msgstr ""
    +
    +#. module: hr_payroll
    +#: field:hr.payroll.register,grows:0
    +#: field:hr.payslip,grows:0
    +msgid "Gross Salary"
    +msgstr ""
    +
    +#. module: hr_payroll
    +#: rml:payslip.pdf:0
    +msgid "Total Earnings"
    +msgstr ""
    +
    +#. module: hr_payroll
    +#: model:ir.actions.act_window,name:hr_payroll.action_hr_payroll_employees_detail
    +#: model:ir.ui.menu,name:hr_payroll.menu_hr_payroll_employees_detail
    +msgid "Employee Salary Statement"
    +msgstr ""
    +
    +#. module: hr_payroll
    +#: selection:hr.payslip.line,type:0
    +msgid "Other Payment"
    +msgstr ""
    +
    +#. module: hr_payroll
    +#: rml:payslip.pdf:0
    +msgid "Deductions"
    +msgstr ""
    +
    +#. module: hr_payroll
    +#: rml:payroll.advice:0
    +msgid "C/D"
    +msgstr ""
    +
    +#. module: hr_payroll
    +#: field:hr.contract,permit_no:0
    +msgid "Work Permit No"
    +msgstr ""
    +
    +#. module: hr_payroll
    +#: field:hr.payroll.advice,line_ids:0
    +msgid "Employee Salary"
    +msgstr ""
    +
    +#. module: hr_payroll
    +#: field:hr.payroll.advice,chaque_nos:0
    +msgid "Chaque Nos"
    +msgstr ""
    +
    +#. module: hr_payroll
    +#: field:hr.contibution.register,monthly_total_by_emp:0
    +msgid "Total By Employee"
    +msgstr ""
    +
    +#. module: hr_payroll
    +#: selection:hr.allounce.deduction.categoty.line,amount_type:0
    +#: selection:hr.payslip.line,amount_type:0
    +msgid "Fixed Amount"
    +msgstr ""
    +
    +#. module: hr_payroll
    +#: field:hr.allounce.deduction.categoty.line,to:0
    +msgid "To"
    +msgstr ""
    +
    +#. module: hr_payroll
    +#: code:addons/hr_payroll/hr_payroll.py:180
    +#: code:addons/hr_payroll/hr_payroll.py:195
    +#: code:addons/hr_payroll/hr_payroll.py:285
    +#: code:addons/hr_payroll/hr_payroll.py:835
    +#: code:addons/hr_payroll/hr_payroll.py:1111
    +#: code:addons/hr_payroll/hr_payroll.py:1126
    +#: code:addons/hr_payroll/hr_payroll.py:1410
    +#, python-format
    +msgid "Variable Error !"
    +msgstr ""
    +
    +#. module: hr_payroll
    +#: model:ir.model,name:hr_payroll.model_hr_payroll_employees_detail
    +msgid "hr.payroll.employees.detail"
    +msgstr ""
    +
    +#. module: hr_payroll
    +#: view:hr.payroll.register:0
    +#: view:hr.payslip:0
    +msgid "Pay Salary"
    +msgstr ""
    +
    +#. module: hr_payroll
    +#: field:hr.payroll.advice.line,name:0
    +msgid "Bank Account A/C"
    +msgstr ""
    +
    +#. module: hr_payroll
    +#: view:hr.contibution.register:0
    +msgid "Contribution Lines"
    +msgstr ""
    +
    +#. module: hr_payroll
    +#: rml:hr.payroll.register.sheet:0
    +#: rml:payslip.pdf:0
    +msgid "For the month of"
    +msgstr ""
    +
    +#. module: hr_payroll
    +#: selection:hr.allounce.deduction.categoty,type:0
    +#: field:hr.payroll.register,deduction:0
    +#: rml:hr.payroll.register.sheet:0
    +#: field:hr.payslip,deduction:0
    +#: selection:hr.payslip.line,type:0
    +msgid "Deduction"
    +msgstr ""
    +
    +#. module: hr_payroll
    +#: model:ir.model,name:hr_payroll.model_hr_payroll_advice
    +msgid "Bank Advice Note"
    +msgstr ""
    +
    +#. module: hr_payroll
    +#: view:hr.payroll.register:0
    +#: view:hr.payslip:0
    +msgid "Payslip"
    +msgstr ""
    +
    +#. module: hr_payroll
    +#: constraint:hr.contract:0
    +msgid "Error! contract start-date must be lower then contract end-date."
    +msgstr ""
    +
    +#. module: hr_payroll
    +#: selection:hr.payslip.line,type:0
    +msgid "Loan Installment"
    +msgstr ""
    +
    +#. module: hr_payroll
    +#: view:hr.payroll.register:0
    +#: view:hr.payslip:0
    +msgid "Complete HR Checking"
    +msgstr ""
    +
    +#. module: hr_payroll
    +#: rml:payroll.advice:0
    +msgid "Yours Sincerely"
    +msgstr ""
    +
    +#. module: hr_payroll
    +#: rml:payroll.advice:0
    +msgid "SI. No."
    +msgstr ""
    +
    +#. module: hr_payroll
    +#: rml:payslip.pdf:0
    +msgid "Net Amount"
    +msgstr ""
    +
    +#. module: hr_payroll
    +#: rml:salary.structure:0
    +msgid "Salary Structure:"
    +msgstr ""
    +
    +#. module: hr_payroll
    +#: model:ir.actions.report.xml,name:hr_payroll.year_employees_detail
    +#: model:ir.actions.wizard,name:hr_payroll.wizard_print_employees_detail
    +#: model:ir.ui.menu,name:hr_payroll.menu_wizard_print_employees_detail
    +msgid "Employees Salary Detail"
    +msgstr ""
    +
    +#. module: hr_payroll
    +#: model:ir.model,name:hr_payroll.model_hr_payslip_line_line
    +msgid "Function Line"
    +msgstr ""
    +
    +#. module: hr_payroll
    +#: view:hr.payroll.advice:0
    +#: selection:hr.payroll.advice,state:0
    +#: selection:hr.payroll.register,state:0
    +#: selection:hr.payslip,state:0
    +msgid "Confirm Sheet"
    +msgstr ""
    +
    +#. module: hr_payroll
    +#: rml:employees.salary:0
    +msgid "Others:"
    +msgstr ""
    +
    +#. module: hr_payroll
    +#: view:company.contribution:0
    +#: selection:company.contribution,amount_type:0
    +msgid "Function Calculation"
    +msgstr ""
    +
    +#. module: hr_payroll
    +#: field:hr.payslip,worked_days:0
    +msgid "Worked Day"
    +msgstr ""
    +
    +#. module: hr_payroll
    +#: field:hr.contibution.register,monthly_total_by_comp:0
    +msgid "Total By Company"
    +msgstr ""
    +
    +#. module: hr_payroll
    +#: field:hr.payroll.advice.line,flag:0
    +msgid "D/C"
    +msgstr ""
    +
    +#. module: hr_payroll
    +#: view:hr.passport:0
    +msgid "Country & Address"
    +msgstr ""
    +
    +#. module: hr_payroll
    +#: rml:employees.salary:0
    +msgid "Employee Code"
    +msgstr ""
    +
    +#. module: hr_payroll
    +#: report:payslip.pdf:0
    +msgid "Basic Salary – Leaves"
    +msgstr ""
    +
    +#. module: hr_payroll
    +#: field:hr.allounce.deduction.categoty.line,amount_type:0
    +#: field:hr.payslip.line,amount_type:0
    +#: rml:salary.structure:0
    +msgid "Amount Type"
    +msgstr ""
    +
    +#. module: hr_payroll
    +#: field:hr.allounce.deduction.categoty.line,category_id:0
    +#: field:hr.payslip.line,category_id:0
    +#: rml:salary.structure:0
    +msgid "Category"
    +msgstr ""
    +
    +#. module: hr_payroll
    +#: view:company.contribution:0
    +#: view:hr.allounce.deduction.categoty:0
    +#: field:hr.payslip.line,company_contrib:0
    +#: model:ir.model,name:hr_payroll.model_company_contribution
    +msgid "Company Contribution"
    +msgstr ""
    +
    +#. module: hr_payroll
    +#: field:company.contribution,category_id:0
    +msgid "Heads"
    +msgstr ""
    +
    +#. module: hr_payroll
    +#: model:ir.actions.report.xml,name:hr_payroll.year_payroll_register
    +msgid "Print Statement"
    +msgstr ""
    +
    +#. module: hr_payroll
    +#: view:hr.payslip:0
    +msgid "Draft"
    +msgstr ""
    +
    +#. module: hr_payroll
    +#: rml:payslip.pdf:0
    +msgid "Earnings"
    +msgstr ""
    +
    +#. module: hr_payroll
    +#: report:hr.payroll.register.sheet:0
    +#: report:salary.structure:0
    +msgid "Basic"
    +msgstr ""
    +
    +#. module: hr_payroll
    +#: model:ir.actions.act_window,name:hr_payroll.action_hr_passport_tree
    +#: model:ir.ui.menu,name:hr_payroll.menu_action_hr_passport_tree
    +msgid "All Passports"
    +msgstr ""
    +
    +#. module: hr_payroll
    +#: model:ir.actions.act_window,name:hr_payroll.action_hr_payroll_year_salary
    +#: model:ir.ui.menu,name:hr_payroll.menu_wizard_print_year_salary
    +msgid "Salary Register"
    +msgstr ""
    +
    +#. module: hr_payroll
    +#: rml:employees.salary:0
    +#: rml:hr.payroll.register.sheet:0
    +#: rml:payslip.pdf:0
    +msgid "Employee Name"
    +msgstr ""
    +
    +#. module: hr_payroll
    +#: model:ir.model,name:hr_payroll.model_hr_passport
    +msgid "Passport Detail"
    +msgstr ""
    +
    +#. module: hr_payroll
    +#: selection:hr.allounce.deduction.categoty.line,amount_type:0
    +#: selection:hr.payslip.line,amount_type:0
    +msgid "Percentage (%)"
    +msgstr ""
    +
    +#. module: hr_payroll
    +#: field:hr.payroll.advice,register_id:0
    +#: view:hr.payroll.register:0
    +#: model:ir.actions.act_window,name:hr_payroll.action_view_hr_payroll_register_form
    +#: model:ir.model,name:hr_payroll.model_hr_payroll_register
    +#: model:ir.ui.menu,name:hr_payroll.hr_menu_payroll_register
    +msgid "Payroll Register"
    +msgstr ""
    +
    +#. module: hr_payroll
    +#: rml:employees.salary:0
    +#: rml:hr.payroll.register.sheet:0
    +#: rml:payroll.advice:0
    +#: rml:salary.structure:0
    +#: rml:year.salary:0
    +msgid "For"
    +msgstr ""
    +
    +#. module: hr_payroll
    +#: view:hr.employee:0
    +#: field:hr.passport,contracts_ids:0
    +msgid "Contracts"
    +msgstr ""
    +
    +#. module: hr_payroll
    +#: view:hr.employee.grade:0
    +msgid "Employee Function"
    +msgstr ""
    +
    +#. module: hr_payroll
    +#: view:hr.payslip:0
    +msgid "Paid"
    +msgstr ""
    +
    +#. module: hr_payroll
    +#: view:hr.payslip:0
    +msgid "Approve Sheet"
    +msgstr ""
    +
    +#. module: hr_payroll
    +#: field:hr.payslip,paid:0
    +msgid "Paid ? "
    +msgstr ""
    +
    +#. module: hr_payroll
    +#: view:hr.holidays.status:0
    +msgid "Validation"
    +msgstr ""
    +
    +#. module: hr_payroll
    +#: rml:employees.salary:0
    +msgid "Title"
    +msgstr ""
    +
    +#. module: hr_payroll
    +#: view:company.contribution:0
    +msgid "Search Company Contribution"
    +msgstr ""
    +
    +#. module: hr_payroll
    +#: field:hr.allounce.deduction.categoty,user_id:0
    +msgid "User"
    +msgstr ""
    +
    +#. module: hr_payroll
    +#: view:hr.payroll.advice:0
    +#: view:hr.payslip:0
    +#: field:hr.payslip,move_payment_ids:0
    +msgid "Payment Lines"
    +msgstr ""
    +
    +#. module: hr_payroll
    +#: view:hr.payslip:0
    +msgid "Compute Sheet"
    +msgstr ""
    +
    +#. module: hr_payroll
    +#: field:hr.payroll.register,active:0
    +msgid "Active"
    +msgstr ""
    +
    +#. module: hr_payroll
    +#: help:hr.allounce.deduction.categoty,condition:0
    +msgid "Applied this head for calculation if condition is true"
    +msgstr ""
    +
    +#. module: hr_payroll
    +#: rml:year.salary:0
    +msgid "Yearly Salary Details"
    +msgstr ""
    +
    +#. module: hr_payroll
    +#: constraint:hr.employee:0
    +msgid "Error ! You cannot create recursive Hierarchy of Employees."
    +msgstr ""
    +
    +#. module: hr_payroll
    +#: field:hr.allounce.deduction.categoty,condition:0
    +msgid "Condition"
    +msgstr ""
    +
    +#. module: hr_payroll
    +#: selection:hr.payroll.register,state:0
    +#: selection:hr.payslip,state:0
    +msgid "Wating for HR Verification"
    +msgstr ""
    +
    +#. module: hr_payroll
    +#: report:payroll.advice:0
    +msgid "Payment Advice:"
    +msgstr ""
    +
    +#. module: hr_payroll
    +#: view:hr.payroll.register:0
    +msgid "Compute"
    +msgstr ""
    +
    +#. module: hr_payroll
    +#: rml:employees.salary:0
    +#: field:hr.payslip,deg_id:0
    +#: rml:payslip.pdf:0
    +#: rml:salary.structure:0
    +msgid "Designation"
    +msgstr ""
    +
    +#. module: hr_payroll
    +#: rml:hr.payroll.register.sheet:0
    +msgid "HR Manager"
    +msgstr ""
    +
    +#. module: hr_payroll
    +#: selection:hr.allounce.deduction.categoty,based_on:0
    +#: field:hr.payslip,basic_before_leaves:0
    +#: rml:payslip.pdf:0
    +msgid "Basic Salary"
    +msgstr ""
    +
    +#. module: hr_payroll
    +#: field:hr.allounce.deduction.categoty,code:0
    +msgid "Category Code"
    +msgstr ""
    +
    +#. module: hr_payroll
    +#: view:hr.payroll.register:0
    +msgid "Salary Information"
    +msgstr ""
    +
    +#. module: hr_payroll
    +#: model:ir.model,name:hr_payroll.model_hr_allounce_deduction_categoty
    +#: model:ir.model,name:hr_payroll.model_hr_allounce_deduction_categoty_line
    +msgid "Allowance Deduction Categoty"
    +msgstr ""
    +
    +#. module: hr_payroll
    +#: view:hr.payslip:0
    +msgid "Companies"
    +msgstr ""
    +
    +#. module: hr_payroll
    +#: rml:payslip.pdf:0
    +msgid "Authorized Signature"
    +msgstr ""
    +
    +#. module: hr_payroll
    +#: view:hr.employee:0
    +msgid "Contract"
    +msgstr ""
    +
    +#. module: hr_payroll
    +#: selection:hr.payroll.advice,state:0
    +msgid "Draft Sheet"
    +msgstr ""
    +
    +#. module: hr_payroll
    +#: selection:wizard.year.salary,init,salary_on:0
    +msgid "Next Month Date"
    +msgstr ""
    +
    +#. module: hr_payroll
    +#: field:hr.payroll.advice,date:0
    +#: field:hr.payroll.register,date:0
    +#: rml:hr.payroll.register.sheet:0
    +#: field:hr.payslip,date:0
    +msgid "Date"
    +msgstr ""
    +
    +#. module: hr_payroll
    +#: field:hr.contract,visa_expire:0
    +msgid "Visa Expire Date"
    +msgstr ""
    +
    +#. module: hr_payroll
    +#: view:hr.passport:0
    +msgid "Search Passport"
    +msgstr ""
    +
    +#. module: hr_payroll
    +#: rml:employees.salary:0
    +#: rml:salary.structure:0
    +msgid "Phone No."
    +msgstr ""
    +
    +#. module: hr_payroll
    +#: field:company.contribution,contribute_per:0
    +#: field:company.contribution.line,contribution_id:0
    +#: view:hr.allounce.deduction.categoty:0
    +#: view:hr.contibution.register:0
    +#: view:hr.contibution.register.line:0
    +msgid "Contribution"
    +msgstr ""
    +
    +#. module: hr_payroll
    +#: field:hr.allounce.deduction.categoty,state:0
    +msgid "Label"
    +msgstr ""
    +
    +#. module: hr_payroll
    +#: view:hr.payroll.structure:0
    +#: view:hr.payslip:0
    +#: view:hr.payslip.line:0
    +msgid "Company contribution"
    +msgstr ""
    +
    +#. module: hr_payroll
    +#: report:employees.salary:0
    +#: report:salary.structure:0
    +msgid "Other No."
    +msgstr ""
    +
    +#. module: hr_payroll
    +#: field:hr.holidays.status,code:0
    +#: field:hr.payslip.line,code:0
    +#: rml:salary.structure:0
    +msgid "Code"
    +msgstr ""
    +
    +#. module: hr_payroll
    +#: model:ir.actions.act_window,name:hr_payroll.action_view_hr_bank_advice_tree
    +#: model:ir.ui.menu,name:hr_payroll.hr_menu_payment_advice
    +#: rml:payroll.advice:0
    +msgid "Payment Advice"
    +msgstr ""
    +
    +#. module: hr_payroll
    +#: report:hr.payroll.register.sheet:0
    +msgid "Number :"
    +msgstr ""
    +
    +#. module: hr_payroll
    +#: help:hr.allounce.deduction.categoty,base:0
    +msgid ""
    +"This will use to computer the % fields values, in general its on basic, but "
    +"You can use all heads code field in small letter as a variable name i.e. "
    +"hra, ma, lta, etc...., also you can use, static varible basic"
    +msgstr ""
    +
    +#. module: hr_payroll
    +#: view:hr.payslip:0
    +msgid "Computation Overview"
    +msgstr ""
    +
    +#. module: hr_payroll
    +#: wizard_field:wizard.year.salary,init,salary_on:0
    +msgid "Salary On"
    +msgstr ""
    +
    +#. module: hr_payroll
    +#: field:hr.payroll.advice,number:0
    +#: field:hr.payroll.register,number:0
    +#: rml:hr.payroll.register.sheet:0
    +#: field:hr.payslip,number:0
    +msgid "Number"
    +msgstr ""
    +
    +#. module: hr_payroll
    +#: view:hr.employee:0
    +#: field:hr.employee,line_ids:0
    +#: view:hr.employee.grade:0
    +#: field:hr.employee.grade,line_ids:0
    +#: rml:salary.structure:0
    +msgid "Salary Structure"
    +msgstr ""
    +
    +#. module: hr_payroll
    +#: field:hr.contibution.register,register_line_ids:0
    +msgid "Register Line"
    +msgstr ""
    +
    +#. module: hr_payroll
    +#: view:hr.payroll.register:0
    +#: view:hr.payslip:0
    +#: wizard_button:payroll.analysis,init,end:0
    +#: wizard_button:wizard.employees.detail,init,end:0
    +#: wizard_button:wizard.year.salary,init,end:0
    +msgid "Cancel"
    +msgstr ""
    +
    +#. module: hr_payroll
    +#: view:hr.payroll.employees.detail:0
    +#: view:hr.payroll.year.salary:0
    +msgid "Close"
    +msgstr ""
    +
    +#. module: hr_payroll
    +#: field:hr.payslip.line,amount:0
    +#: rml:salary.structure:0
    +msgid "Amount / Percentage"
    +msgstr ""
    +
    +#. module: hr_payroll
    +#: rml:hr.payroll.register.sheet:0
    +msgid "Allowances"
    +msgstr ""
    +
    +#. module: hr_payroll
    +#: selection:wizard.year.salary,init,salary_on:0
    +msgid "Current Month Date"
    +msgstr ""
    +
    +#. module: hr_payroll
    +#: view:hr.employee:0
    +#: rml:salary.structure:0
    +msgid "Salary"
    +msgstr ""
    +
    +#. module: hr_payroll
    +#: field:hr.passport,name:0
    +msgid "Passport No"
    +msgstr ""
    +
    +#. module: hr_payroll
    +#: field:hr.contract,passport_id:0
    +#: field:hr.employee,passport_id:0
    +#: view:hr.passport:0
    +msgid "Passport"
    +msgstr ""
    +
    +#. module: hr_payroll
    +#: report:hr.payroll.register.sheet:0
    +msgid "Total Salary"
    +msgstr ""
    +
    +#. module: hr_payroll
    +#: rml:payroll.advice:0
    +msgid "for period"
    +msgstr ""
    +
    +#. module: hr_payroll
    +#: field:hr.expense.expense,category_id:0
    +#: field:hr.holidays.status,head_id:0
    +msgid "Payroll Head"
    +msgstr ""
    +
    +#. module: hr_payroll
    +#: field:company.contribution,register_id:0
    +#: model:ir.actions.act_window,name:hr_payroll.action_contibution_register_form
    +#: model:ir.model,name:hr_payroll.model_hr_contibution_register
    +#: model:ir.ui.menu,name:hr_payroll.menu_action_hr_contibution_register_form
    +msgid "Contribution Register"
    +msgstr ""
    +
    +#. module: hr_payroll
    +#: rml:salary.structure:0
    +msgid "E-mail"
    +msgstr ""
    +
    +#. module: hr_payroll
    +#: view:hr.allounce.deduction.categoty:0
    +#: model:ir.actions.act_window,name:hr_payroll.hr_allounce_deduction_tree
    +#: model:ir.ui.menu,name:hr_payroll.menu_hr_allounce_deduction_tree
    +msgid "Salary Heads"
    +msgstr ""
    +
    +#. module: hr_payroll
    +#: view:hr.payroll.employees.detail:0
    +#: view:hr.payroll.year.salary:0
    +msgid "Print Report"
    +msgstr ""
    +
    +#. module: hr_payroll
    +#: view:hr.allounce.deduction.categoty:0
    +#: field:hr.allounce.deduction.categoty,line_ids:0
    +msgid "Calculations"
    +msgstr ""
    +
    +#. module: hr_payroll
    +#: help:company.contribution,contribute_per:0
    +msgid ""
    +"Define Company contribution ratio 1.00=100% contribution, If Employee "
    +"Contribute 5% then company will and here 0.50 defined then company will "
    +"contribute 50% on employee 5% contribution"
    +msgstr ""
    +
    +#. module: hr_payroll
    +#: view:hr.payslip:0
    +msgid "Other Informations"
    +msgstr ""
    +
    +#. module: hr_payroll
    +#: view:hr.contibution.register:0
    +msgid "Month"
    +msgstr ""
    +
    +#. module: hr_payroll
    +#: view:hr.passport:0
    +msgid "Issue"
    +msgstr ""
    +
    +#. module: hr_payroll
    +#: view:hr.allounce.deduction.categoty:0
    +msgid "Dynamic Computation"
    +msgstr ""
    +
    +#. module: hr_payroll
    +#: report:payslip.pdf:0
    +msgid "Basic Salary without Leave:"
    +msgstr ""
    +
    +#. module: hr_payroll
    +#: field:hr.employee.grade,function_id:0
    +#: field:hr.payslip.line,function_id:0
    +msgid "Function"
    +msgstr ""
    +
    +#. module: hr_payroll
    +#: view:hr.payslip:0
    +msgid "States"
    +msgstr ""
    +
    +#. module: hr_payroll
    +#: rml:payroll.advice:0
    +msgid "Dear Sir/Madam,"
    +msgstr ""
    +
    +#. module: hr_payroll
    +#: model:ir.model,name:hr_payroll.model_hr_allounce_deduction_categoty
    +msgid "Allowance Deduction Heads"
    +msgstr ""
    +
    +#. module: hr_payroll
    +#: report:hr.payroll.register.sheet:0
    +msgid "Gross Sal."
    +msgstr ""
    +
    +#. module: hr_payroll
    +#: field:hr.payroll.advice,note:0
    +msgid "Description"
    +msgstr ""
    +
    +#. module: hr_payroll
    +#: rml:salary.structure:0
    +msgid "Start Date"
    +msgstr ""
    +
    +#. module: hr_payroll
    +#: report:payslip.pdf:0
    +msgid "Deduction -"
    +msgstr ""
    +
    +#. module: hr_payroll
    +#: report:payslip.pdf:0
    +msgid ")"
    +msgstr ""
    +
    +#. module: hr_payroll
    +#: view:hr.contibution.register:0
    +msgid "Contribution Registers"
    +msgstr ""
    +
    +#. module: hr_payroll
    +#: model:ir.ui.menu,name:hr_payroll.menu_hr_payroll_reporting
    +#: model:ir.ui.menu,name:hr_payroll.menu_hr_root_payroll
    +msgid "Payroll"
    +msgstr ""
    +
    +#. module: hr_payroll
    +#: model:ir.model,name:hr_payroll.model_hr_contract_wage_type
    +msgid "Wage Type"
    +msgstr ""
    +
    +#. module: hr_payroll
    +#: report:hr.payroll.register.sheet:0
    +msgid "Net Sal."
    +msgstr ""
    +
    +#. module: hr_payroll
    +#: sql_constraint:hr.passport:0
    +msgid "The Passport No must be unique !"
    +msgstr ""
    +
    +#. module: hr_payroll
    +#: field:hr.allounce.deduction.categoty,name:0
    +msgid "Category Name"
    +msgstr ""
    +
    +#. module: hr_payroll
    +#: model:ir.model,name:hr_payroll.model_hr_payroll_year_salary
    +msgid "hr.payroll.year.salary"
    +msgstr ""
    +
    +#. module: hr_payroll
    +#: rml:employees.salary:0
    +#: rml:payslip.pdf:0
    +#: rml:salary.structure:0
    +msgid "Address"
    +msgstr ""
    +
    +#. module: hr_payroll
    +#: field:hr.payslip.line.line,slipline_id:0
    +msgid "Slip Line"
    +msgstr ""
    +
    +#. module: hr_payroll
    +#: report:payslip.pdf:0
    +msgid "Number of Leaves"
    +msgstr ""
    +
    +#. module: hr_payroll
    +#: rml:employees.salary:0
    +#: rml:salary.structure:0
    +msgid "Bank"
    +msgstr ""
    +
    +#. module: hr_payroll
    +#: view:hr.payroll.advice:0
    +msgid "Cancel Sheet"
    +msgstr ""
    +
    +#. module: hr_payroll
    +#: selection:hr.payslip.line,type:0
    +msgid "Advance"
    +msgstr ""
    +
    +#. module: hr_payroll
    +#: rml:salary.structure:0
    +msgid "Special Allowances and Deductions For Employee:"
    +msgstr ""
    +
    +#. module: hr_payroll
    +#: field:hr.allounce.deduction.categoty.line,name:0
    +#: field:hr.payroll.advice,name:0
    +#: field:hr.payroll.register,name:0
    +#: field:hr.payslip,name:0
    +#: field:hr.payslip.line,name:0
    +#: rml:salary.structure:0
    +#: rml:year.salary:0
    +msgid "Name"
    +msgstr ""
    +
    +#. module: hr_payroll
    +#: field:hr.payslip,leaves:0
    +msgid "Leaved Deduction"
    +msgstr ""
    +
    +#. module: hr_payroll
    +#: view:hr.passport:0
    +msgid "Country"
    +msgstr ""
    +
    +#. module: hr_payroll
    +#: wizard_field:wizard.employees.detail,init,employee_ids:0
    +#: wizard_field:wizard.year.salary,init,employee_ids:0
    +msgid "Employees"
    +msgstr ""
    +
    +#. module: hr_payroll
    +#: field:hr.employee,property_bank_account:0
    +#: rml:payroll.advice:0
    +msgid "Bank Account"
    +msgstr ""
    +
    +#. module: hr_payroll
    +#: help:company.contribution,register_id:0
    +msgid "Contribution register based on company"
    +msgstr ""
    +
    +#. module: hr_payroll
    +#: help:hr.allounce.deduction.categoty,sequence:0
    +msgid "Use to arrange calculation sequence"
    +msgstr ""
    +
    +#. module: hr_payroll
    +#: field:hr.payslip,total_pay:0
    +msgid "Total Payment"
    +msgstr ""
    +
    +#. module: hr_payroll
    +#: report:payslip.pdf:0
    +msgid "Leave Deductions Line:"
    +msgstr ""
    +
    +#. module: hr_payroll
    +#: selection:hr.payroll.register,state:0
    +#: selection:hr.payslip,state:0
    +msgid "Wating for Account Verification"
    +msgstr ""
    +
    +#. module: hr_payroll
    +#: field:hr.contibution.register.line,comp_deduction:0
    +msgid "Company Deduction"
    +msgstr ""
    +
    +#. module: hr_payroll
    +#: view:hr.holidays.status:0
    +msgid "Payroll Configurtion"
    +msgstr ""
    +
    +#. module: hr_payroll
    +#: code:addons/hr_payroll/hr_payroll.py:469
    +#, python-format
    +msgid "Please define bank account for the %s employee"
    +msgstr ""
    +
    +#. module: hr_payroll
    +#: field:hr.passport,date_issue:0
    +msgid "Passport Issue Date"
    +msgstr ""
    +
    +#. module: hr_payroll
    +#: selection:hr.allounce.deduction.categoty,type:0
    +#: field:hr.payroll.register,allounce:0
    +#: field:hr.payslip,allounce:0
    +#: selection:hr.payslip.line,type:0
    +msgid "Allowance"
    +msgstr ""
    +
    +#. module: hr_payroll
    +#: field:hr.payslip,holiday_days:0
    +msgid "No of Leaves"
    +msgstr ""
    +
    +#. module: hr_payroll
    +#: field:hr.employee,otherid:0
    +msgid "Other Id"
    +msgstr ""
    +
    +#. module: hr_payroll
    +#: rml:payslip.pdf:0
    +msgid "Bank Details"
    +msgstr ""
    +
    +#. module: hr_payroll
    +#: report:payslip.pdf:0
    +msgid "Slip ID"
    +msgstr ""
    +
    +#. module: hr_payroll
    +#: field:hr.allounce.deduction.categoty,sequence:0
    +msgid "Sequence"
    +msgstr ""
    +
    +#. module: hr_payroll
    +#: model:ir.actions.act_window,name:hr_payroll.action_view_hr_payslip_form
    +#: model:ir.ui.menu,name:hr_payroll.menu_department_tree
    +msgid "Employee Payslip"
    +msgstr ""
    +
    +#. module: hr_payroll
    +#: view:hr.payroll.advice:0
    +msgid "Letter Content"
    +msgstr ""
    +
    +#. module: hr_payroll
    +#: wizard_view:wizard.employees.detail,init:0
    +#: wizard_view:wizard.year.salary,init:0
    +msgid "Year Salary"
    +msgstr ""
    +
    +#. module: hr_payroll
    +#: view:hr.payroll.register:0
    +msgid "Allowance / Deduction"
    +msgstr ""
    +
    +#. module: hr_payroll
    +#: model:ir.actions.report.xml,name:hr_payroll.payroll_advice
    +msgid "Bank Payment Advice"
    +msgstr ""
    +
    +#. module: hr_payroll
    +#: view:hr.payslip:0
    +msgid "Search Payslips"
    +msgstr ""
    +
    +#. module: hr_payroll
    +#: rml:employees.salary:0
    +#: rml:payroll.advice:0
    +#: rml:year.salary:0
    +msgid "Total"
    +msgstr ""
    +
    +#. module: hr_payroll
    +#: view:company.contribution:0
    +#: view:hr.allounce.deduction.categoty:0
    +#: field:hr.allounce.deduction.categoty,contribute_ids:0
    +msgid "Contributions"
    +msgstr ""
    diff --git a/addons/hr_timesheet/i18n/nb.po b/addons/hr_timesheet/i18n/nb.po
    new file mode 100644
    index 00000000000..c17f2492caa
    --- /dev/null
    +++ b/addons/hr_timesheet/i18n/nb.po
    @@ -0,0 +1,702 @@
    +# Norwegian Bokmal translation for openobject-addons
    +# Copyright (c) 2011 Rosetta Contributors and Canonical Ltd 2011
    +# This file is distributed under the same license as the openobject-addons package.
    +# FIRST AUTHOR , 2011.
    +#
    +msgid ""
    +msgstr ""
    +"Project-Id-Version: openobject-addons\n"
    +"Report-Msgid-Bugs-To: FULL NAME \n"
    +"POT-Creation-Date: 2011-01-11 11:15+0000\n"
    +"PO-Revision-Date: 2011-04-07 06:53+0000\n"
    +"Last-Translator: FULL NAME \n"
    +"Language-Team: Norwegian Bokmal \n"
    +"MIME-Version: 1.0\n"
    +"Content-Type: text/plain; charset=UTF-8\n"
    +"Content-Transfer-Encoding: 8bit\n"
    +"X-Launchpad-Export-Date: 2011-04-08 04:45+0000\n"
    +"X-Generator: Launchpad (build 12735)\n"
    +
    +#. module: hr_timesheet
    +#: model:product.template,name:hr_timesheet.product_consultant_product_template
    +msgid "Service on Timesheet"
    +msgstr ""
    +
    +#. module: hr_timesheet
    +#: code:addons/hr_timesheet/report/user_timesheet.py:42
    +#: code:addons/hr_timesheet/report/users_timesheet.py:76
    +#, python-format
    +msgid "Wed"
    +msgstr "Ons"
    +
    +#. module: hr_timesheet
    +#: view:hr.sign.out.project:0
    +msgid "(Keep empty for current_time)"
    +msgstr "(La stå blank for å benytte nåværende tid)"
    +
    +#. module: hr_timesheet
    +#: code:addons/hr_timesheet/wizard/hr_timesheet_sign_in_out.py:132
    +#, python-format
    +msgid "No employee defined for your user !"
    +msgstr "Ingen ansatt definert for brukeren din !"
    +
    +#. module: hr_timesheet
    +#: view:hr.analytic.timesheet:0
    +msgid "Group By..."
    +msgstr "Grupper etter..."
    +
    +#. module: hr_timesheet
    +#: model:ir.actions.act_window,help:hr_timesheet.action_hr_timesheet_sign_in
    +msgid ""
    +"Employees can encode their time spent on the different projects. A project "
    +"is an analytic account and the time spent on a project generate costs on the "
    +"analytic account. This feature allows to record at the same time the "
    +"attendance and the timesheet."
    +msgstr ""
    +
    +#. module: hr_timesheet
    +#: view:hr.analytic.timesheet:0
    +msgid "Today"
    +msgstr "Idag"
    +
    +#. module: hr_timesheet
    +#: field:hr.employee,journal_id:0
    +msgid "Analytic Journal"
    +msgstr "Analytisk Journal"
    +
    +#. module: hr_timesheet
    +#: view:hr.sign.out.project:0
    +msgid "Stop Working"
    +msgstr ""
    +
    +#. module: hr_timesheet
    +#: model:ir.actions.act_window,name:hr_timesheet.action_hr_timesheet_employee
    +#: model:ir.ui.menu,name:hr_timesheet.menu_hr_timesheet_employee
    +msgid "Employee Timesheet"
    +msgstr ""
    +
    +#. module: hr_timesheet
    +#: view:account.analytic.account:0
    +msgid "Work done stats"
    +msgstr ""
    +
    +#. module: hr_timesheet
    +#: view:hr.analytic.timesheet:0
    +#: model:ir.ui.menu,name:hr_timesheet.menu_hr_reporting_timesheet
    +msgid "Timesheet"
    +msgstr "Timeliste"
    +
    +#. module: hr_timesheet
    +#: selection:hr.analytical.timesheet.employee,month:0
    +#: selection:hr.analytical.timesheet.users,month:0
    +msgid "janvier"
    +msgstr ""
    +
    +#. module: hr_timesheet
    +#: code:addons/hr_timesheet/report/user_timesheet.py:42
    +#: code:addons/hr_timesheet/report/users_timesheet.py:76
    +#, python-format
    +msgid "Mon"
    +msgstr "Man"
    +
    +#. module: hr_timesheet
    +#: view:hr.sign.in.project:0
    +msgid "Sign in"
    +msgstr "Logg på"
    +
    +#. module: hr_timesheet
    +#: view:hr.sign.in.project:0
    +msgid ""
    +"Employees can encode their time spent on the different projects they are "
    +"assigned on. A  project is an analytic account and the time spent on a "
    +"project generates costs on the analytic account. This feature allows to "
    +"record at the same time the attendance and the timesheet."
    +msgstr ""
    +
    +#. module: hr_timesheet
    +#: field:hr.sign.out.project,analytic_amount:0
    +msgid "Minimum Analytic Amount"
    +msgstr ""
    +
    +#. module: hr_timesheet
    +#: view:hr.analytical.timesheet.employee:0
    +msgid "Monthly Employee Timesheet"
    +msgstr ""
    +
    +#. module: hr_timesheet
    +#: view:hr.sign.out.project:0
    +msgid "Work done in the last period"
    +msgstr "Arbeid utført i forrige periode"
    +
    +#. module: hr_timesheet
    +#: constraint:hr.employee:0
    +msgid ""
    +"Error ! You cannot select a department for which the employee is the manager."
    +msgstr ""
    +
    +#. module: hr_timesheet
    +#: field:hr.sign.in.project,state:0
    +#: field:hr.sign.out.project,state:0
    +msgid "Current state"
    +msgstr ""
    +
    +#. module: hr_timesheet
    +#: field:hr.sign.in.project,name:0
    +#: field:hr.sign.out.project,name:0
    +msgid "Employees name"
    +msgstr ""
    +
    +#. module: hr_timesheet
    +#: model:ir.model,name:hr_timesheet.model_hr_analytical_timesheet_users
    +msgid "Print Employees Timesheet"
    +msgstr "Skriv ut ansattes timelister"
    +
    +#. module: hr_timesheet
    +#: code:addons/hr_timesheet/hr_timesheet.py:174
    +#: code:addons/hr_timesheet/hr_timesheet.py:176
    +#, python-format
    +msgid "Warning !"
    +msgstr "Advarsel !"
    +
    +#. module: hr_timesheet
    +#: code:addons/hr_timesheet/wizard/hr_timesheet_sign_in_out.py:77
    +#: code:addons/hr_timesheet/wizard/hr_timesheet_sign_in_out.py:132
    +#, python-format
    +msgid "UserError"
    +msgstr "BrukerFeil"
    +
    +#. module: hr_timesheet
    +#: code:addons/hr_timesheet/wizard/hr_timesheet_sign_in_out.py:77
    +#, python-format
    +msgid "No cost unit defined for this employee !"
    +msgstr "Ingen kostenhet angitt for denne brukeren !"
    +
    +#. module: hr_timesheet
    +#: code:addons/hr_timesheet/report/user_timesheet.py:42
    +#: code:addons/hr_timesheet/report/users_timesheet.py:76
    +#, python-format
    +msgid "Tue"
    +msgstr "Tir"
    +
    +#. module: hr_timesheet
    +#: field:hr.sign.out.project,account_id:0
    +msgid "Analytic Account"
    +msgstr "Analytisk konto"
    +
    +#. module: hr_timesheet
    +#: code:addons/hr_timesheet/wizard/hr_timesheet_print_employee.py:42
    +#, python-format
    +msgid "Warning"
    +msgstr "Advarsel"
    +
    +#. module: hr_timesheet
    +#: model:ir.module.module,shortdesc:hr_timesheet.module_meta_information
    +msgid "Human Resources (Timesheet encoding)"
    +msgstr ""
    +
    +#. module: hr_timesheet
    +#: view:hr.sign.in.project:0
    +#: view:hr.sign.out.project:0
    +msgid "Sign In/Out By Project"
    +msgstr ""
    +
    +#. module: hr_timesheet
    +#: code:addons/hr_timesheet/report/user_timesheet.py:42
    +#: code:addons/hr_timesheet/report/users_timesheet.py:76
    +#, python-format
    +msgid "Sat"
    +msgstr "Lør"
    +
    +#. module: hr_timesheet
    +#: code:addons/hr_timesheet/report/user_timesheet.py:42
    +#: code:addons/hr_timesheet/report/users_timesheet.py:76
    +#, python-format
    +msgid "Sun"
    +msgstr "Søn"
    +
    +#. module: hr_timesheet
    +#: view:hr.analytical.timesheet.employee:0
    +#: view:hr.analytical.timesheet.users:0
    +msgid "Print"
    +msgstr "Skriv ut"
    +
    +#. module: hr_timesheet
    +#: view:hr.analytic.timesheet:0
    +msgid "Timesheet Lines"
    +msgstr ""
    +
    +#. module: hr_timesheet
    +#: selection:hr.analytical.timesheet.employee,month:0
    +#: selection:hr.analytical.timesheet.users,month:0
    +msgid "juillet"
    +msgstr ""
    +
    +#. module: hr_timesheet
    +#: view:hr.analytical.timesheet.users:0
    +msgid "Monthly Employees Timesheet"
    +msgstr ""
    +
    +#. module: hr_timesheet
    +#: code:addons/hr_timesheet/report/user_timesheet.py:39
    +#: code:addons/hr_timesheet/report/users_timesheet.py:72
    +#, python-format
    +msgid "July"
    +msgstr "Juli"
    +
    +#. module: hr_timesheet
    +#: field:hr.sign.in.project,date:0
    +#: field:hr.sign.out.project,date_start:0
    +msgid "Starting Date"
    +msgstr "Startdato"
    +
    +#. module: hr_timesheet
    +#: view:hr.employee:0
    +msgid "Categories"
    +msgstr "Kategorier"
    +
    +#. module: hr_timesheet
    +#: selection:hr.analytical.timesheet.employee,month:0
    +#: selection:hr.analytical.timesheet.users,month:0
    +msgid "novembre"
    +msgstr ""
    +
    +#. module: hr_timesheet
    +#: model:ir.actions.act_window,help:hr_timesheet.act_hr_timesheet_line_evry1_all_form
    +msgid ""
    +"Through Working Hours you can register your working hours by project every "
    +"day."
    +msgstr ""
    +
    +#. module: hr_timesheet
    +#: model:ir.module.module,description:hr_timesheet.module_meta_information
    +msgid ""
    +"\n"
    +"This module implements a timesheet system. Each employee can encode and\n"
    +"track their time spent on the different projects. A project is an\n"
    +"analytic account and the time spent on a project generates costs on\n"
    +"the analytic account.\n"
    +"\n"
    +"Lots of reporting on time and employee tracking are provided.\n"
    +"\n"
    +"It is completely integrated with the cost accounting module. It allows you\n"
    +"to set up a management by affair.\n"
    +"    "
    +msgstr ""
    +
    +#. module: hr_timesheet
    +#: code:addons/hr_timesheet/report/user_timesheet.py:39
    +#: code:addons/hr_timesheet/report/users_timesheet.py:72
    +#, python-format
    +msgid "March"
    +msgstr "Mars"
    +
    +#. module: hr_timesheet
    +#: view:hr.analytic.timesheet:0
    +msgid "Total cost"
    +msgstr ""
    +
    +#. module: hr_timesheet
    +#: selection:hr.analytical.timesheet.employee,month:0
    +#: selection:hr.analytical.timesheet.users,month:0
    +msgid "décembre"
    +msgstr ""
    +
    +#. module: hr_timesheet
    +#: code:addons/hr_timesheet/report/user_timesheet.py:39
    +#: code:addons/hr_timesheet/report/users_timesheet.py:72
    +#, python-format
    +msgid "September"
    +msgstr "September"
    +
    +#. module: hr_timesheet
    +#: model:ir.model,name:hr_timesheet.model_hr_analytic_timesheet
    +msgid "Timesheet Line"
    +msgstr "Timelistelinje"
    +
    +#. module: hr_timesheet
    +#: field:hr.analytical.timesheet.users,employee_ids:0
    +msgid "employees"
    +msgstr "ansatte"
    +
    +#. module: hr_timesheet
    +#: view:account.analytic.account:0
    +msgid "Stats by month"
    +msgstr "Statistikk pr. måned"
    +
    +#. module: hr_timesheet
    +#: view:account.analytic.account:0
    +#: field:hr.analytical.timesheet.employee,month:0
    +#: field:hr.analytical.timesheet.users,month:0
    +msgid "Month"
    +msgstr "Måned"
    +
    +#. module: hr_timesheet
    +#: field:hr.sign.out.project,info:0
    +msgid "Work Description"
    +msgstr "Arbeidsbeskrivelse"
    +
    +#. module: hr_timesheet
    +#: view:account.analytic.account:0
    +msgid "To be invoiced"
    +msgstr ""
    +
    +#. module: hr_timesheet
    +#: model:ir.actions.report.xml,name:hr_timesheet.report_user_timesheet
    +msgid "Employee timesheet"
    +msgstr ""
    +
    +#. module: hr_timesheet
    +#: model:ir.actions.act_window,name:hr_timesheet.action_hr_timesheet_sign_in
    +#: model:ir.actions.act_window,name:hr_timesheet.action_hr_timesheet_sign_out
    +msgid "Sign in / Sign out by project"
    +msgstr ""
    +
    +#. module: hr_timesheet
    +#: code:addons/hr_timesheet/report/user_timesheet.py:42
    +#: code:addons/hr_timesheet/report/users_timesheet.py:76
    +#, python-format
    +msgid "Fri"
    +msgstr "Fre"
    +
    +#. module: hr_timesheet
    +#: view:hr.sign.in.project:0
    +msgid "Sign in / Sign out"
    +msgstr "Logg inn / Logg ut"
    +
    +#. module: hr_timesheet
    +#: code:addons/hr_timesheet/hr_timesheet.py:174
    +#, python-format
    +msgid ""
    +"Analytic journal is not defined for employee %s \n"
    +"Define an employee for the selected user and assign an analytic journal!"
    +msgstr ""
    +
    +#. module: hr_timesheet
    +#: view:hr.sign.in.project:0
    +msgid "(Keep empty for current time)"
    +msgstr ""
    +
    +#. module: hr_timesheet
    +#: view:hr.employee:0
    +msgid "Timesheets"
    +msgstr "Timelister"
    +
    +#. module: hr_timesheet
    +#: help:hr.employee,product_id:0
    +msgid "Specifies employee's designation as a product with type 'service'."
    +msgstr ""
    +
    +#. module: hr_timesheet
    +#: selection:hr.analytical.timesheet.employee,month:0
    +#: selection:hr.analytical.timesheet.users,month:0
    +msgid "août"
    +msgstr ""
    +
    +#. module: hr_timesheet
    +#: code:addons/hr_timesheet/report/user_timesheet.py:39
    +#: code:addons/hr_timesheet/report/users_timesheet.py:72
    +#, python-format
    +msgid "August"
    +msgstr "August"
    +
    +#. module: hr_timesheet
    +#: code:addons/hr_timesheet/report/user_timesheet.py:39
    +#: code:addons/hr_timesheet/report/users_timesheet.py:72
    +#, python-format
    +msgid "June"
    +msgstr "Juni"
    +
    +#. module: hr_timesheet
    +#: view:hr.analytical.timesheet.employee:0
    +msgid "Print My Timesheet"
    +msgstr "Skriv ut min timeliste"
    +
    +#. module: hr_timesheet
    +#: selection:hr.analytical.timesheet.employee,month:0
    +#: selection:hr.analytical.timesheet.users,month:0
    +msgid "mars"
    +msgstr "mars"
    +
    +#. module: hr_timesheet
    +#: view:hr.analytic.timesheet:0
    +msgid "Date"
    +msgstr "Dato"
    +
    +#. module: hr_timesheet
    +#: code:addons/hr_timesheet/report/user_timesheet.py:39
    +#: code:addons/hr_timesheet/report/users_timesheet.py:72
    +#, python-format
    +msgid "November"
    +msgstr "November"
    +
    +#. module: hr_timesheet
    +#: constraint:hr.employee:0
    +msgid "Error ! You cannot create recursive Hierarchy of Employees."
    +msgstr ""
    +
    +#. module: hr_timesheet
    +#: field:hr.sign.out.project,date:0
    +msgid "Closing Date"
    +msgstr ""
    +
    +#. module: hr_timesheet
    +#: code:addons/hr_timesheet/report/user_timesheet.py:39
    +#: code:addons/hr_timesheet/report/users_timesheet.py:72
    +#, python-format
    +msgid "October"
    +msgstr "Oktober"
    +
    +#. module: hr_timesheet
    +#: code:addons/hr_timesheet/report/user_timesheet.py:39
    +#: code:addons/hr_timesheet/report/users_timesheet.py:72
    +#, python-format
    +msgid "January"
    +msgstr "Januar"
    +
    +#. module: hr_timesheet
    +#: view:account.analytic.account:0
    +msgid "Key dates"
    +msgstr ""
    +
    +#. module: hr_timesheet
    +#: code:addons/hr_timesheet/report/user_timesheet.py:42
    +#: code:addons/hr_timesheet/report/users_timesheet.py:76
    +#, python-format
    +msgid "Thu"
    +msgstr "Tor"
    +
    +#. module: hr_timesheet
    +#: view:account.analytic.account:0
    +msgid "Analysis stats"
    +msgstr ""
    +
    +#. module: hr_timesheet
    +#: model:ir.model,name:hr_timesheet.model_hr_analytical_timesheet_employee
    +msgid "Print Employee Timesheet & Print My Timesheet"
    +msgstr ""
    +
    +#. module: hr_timesheet
    +#: field:hr.sign.in.project,emp_id:0
    +#: field:hr.sign.out.project,emp_id:0
    +msgid "Employee ID"
    +msgstr "Ansatt-ID"
    +
    +#. module: hr_timesheet
    +#: view:hr.sign.out.project:0
    +msgid "General Information"
    +msgstr "Generell informasjon"
    +
    +#. module: hr_timesheet
    +#: model:ir.actions.act_window,name:hr_timesheet.action_hr_timesheet_my
    +msgid "My Timesheet"
    +msgstr "Min timeliste"
    +
    +#. module: hr_timesheet
    +#: view:account.analytic.account:0
    +msgid "Analysis summary"
    +msgstr ""
    +
    +#. module: hr_timesheet
    +#: code:addons/hr_timesheet/report/user_timesheet.py:39
    +#: code:addons/hr_timesheet/report/users_timesheet.py:72
    +#, python-format
    +msgid "December"
    +msgstr "Desember"
    +
    +#. module: hr_timesheet
    +#: view:hr.analytical.timesheet.employee:0
    +#: view:hr.analytical.timesheet.users:0
    +#: view:hr.sign.in.project:0
    +#: view:hr.sign.out.project:0
    +msgid "Cancel"
    +msgstr "Avbryt"
    +
    +#. module: hr_timesheet
    +#: model:ir.actions.act_window,name:hr_timesheet.action_hr_timesheet_users
    +#: model:ir.actions.report.xml,name:hr_timesheet.report_users_timesheet
    +#: model:ir.actions.wizard,name:hr_timesheet.wizard_hr_timesheet_users
    +#: model:ir.ui.menu,name:hr_timesheet.menu_hr_timesheet_users
    +msgid "Employees Timesheet"
    +msgstr ""
    +
    +#. module: hr_timesheet
    +#: selection:hr.analytical.timesheet.employee,month:0
    +#: selection:hr.analytical.timesheet.users,month:0
    +msgid "février"
    +msgstr ""
    +
    +#. module: hr_timesheet
    +#: view:hr.analytic.timesheet:0
    +msgid "Information"
    +msgstr "Informasjon"
    +
    +#. module: hr_timesheet
    +#: field:hr.analytical.timesheet.employee,employee_id:0
    +#: model:ir.model,name:hr_timesheet.model_hr_employee
    +msgid "Employee"
    +msgstr "Ansatt"
    +
    +#. module: hr_timesheet
    +#: selection:hr.analytical.timesheet.employee,month:0
    +#: selection:hr.analytical.timesheet.users,month:0
    +msgid "avril"
    +msgstr ""
    +
    +#. module: hr_timesheet
    +#: field:hr.sign.in.project,server_date:0
    +#: field:hr.sign.out.project,server_date:0
    +msgid "Current Date"
    +msgstr "Dagens dato"
    +
    +#. module: hr_timesheet
    +#: view:hr.analytic.timesheet:0
    +msgid "Anlytic account"
    +msgstr "Analytisk konto"
    +
    +#. module: hr_timesheet
    +#: view:hr.analytical.timesheet.employee:0
    +msgid "This wizard will print monthly timesheet"
    +msgstr ""
    +
    +#. module: hr_timesheet
    +#: view:hr.analytic.timesheet:0
    +#: field:hr.employee,product_id:0
    +msgid "Product"
    +msgstr "Produkt"
    +
    +#. module: hr_timesheet
    +#: view:hr.analytic.timesheet:0
    +msgid "Invoicing"
    +msgstr "Fakturering"
    +
    +#. module: hr_timesheet
    +#: code:addons/hr_timesheet/report/user_timesheet.py:39
    +#: code:addons/hr_timesheet/report/users_timesheet.py:72
    +#, python-format
    +msgid "May"
    +msgstr "Mai"
    +
    +#. module: hr_timesheet
    +#: view:hr.analytic.timesheet:0
    +msgid "Total time"
    +msgstr "Totaltid"
    +
    +#. module: hr_timesheet
    +#: selection:hr.analytical.timesheet.employee,month:0
    +#: selection:hr.analytical.timesheet.users,month:0
    +msgid "juin"
    +msgstr ""
    +
    +#. module: hr_timesheet
    +#: view:hr.sign.in.project:0
    +msgid "(local time on the server side)"
    +msgstr ""
    +
    +#. module: hr_timesheet
    +#: model:ir.actions.act_window,name:hr_timesheet.act_hr_timesheet_line_evry1_all_form
    +#: model:ir.ui.menu,name:hr_timesheet.menu_hr_working_hours
    +msgid "Working Hours"
    +msgstr "Arbeidstid"
    +
    +#. module: hr_timesheet
    +#: model:ir.model,name:hr_timesheet.model_hr_sign_in_project
    +msgid "Sign In By Project"
    +msgstr ""
    +
    +#. module: hr_timesheet
    +#: code:addons/hr_timesheet/report/user_timesheet.py:39
    +#: code:addons/hr_timesheet/report/users_timesheet.py:72
    +#, python-format
    +msgid "February"
    +msgstr "Februar"
    +
    +#. module: hr_timesheet
    +#: field:hr.analytic.timesheet,line_id:0
    +msgid "Analytic line"
    +msgstr "Analytisk linje"
    +
    +#. module: hr_timesheet
    +#: model:ir.model,name:hr_timesheet.model_hr_sign_out_project
    +msgid "Sign Out By Project"
    +msgstr ""
    +
    +#. module: hr_timesheet
    +#: view:hr.analytical.timesheet.users:0
    +msgid "Employees"
    +msgstr "Ansatte"
    +
    +#. module: hr_timesheet
    +#: selection:hr.analytical.timesheet.employee,month:0
    +#: selection:hr.analytical.timesheet.users,month:0
    +msgid "octobre"
    +msgstr ""
    +
    +#. module: hr_timesheet
    +#: code:addons/hr_timesheet/report/user_timesheet.py:39
    +#: code:addons/hr_timesheet/report/users_timesheet.py:72
    +#, python-format
    +msgid "April"
    +msgstr "April"
    +
    +#. module: hr_timesheet
    +#: code:addons/hr_timesheet/hr_timesheet.py:176
    +#, python-format
    +msgid ""
    +"No analytic account defined on the project.\n"
    +"Please set one or we can not automatically fill the timesheet."
    +msgstr ""
    +
    +#. module: hr_timesheet
    +#: selection:hr.analytical.timesheet.employee,month:0
    +#: selection:hr.analytical.timesheet.users,month:0
    +msgid "mai"
    +msgstr ""
    +
    +#. module: hr_timesheet
    +#: view:account.analytic.account:0
    +#: view:hr.analytic.timesheet:0
    +msgid "Users"
    +msgstr "Brukere"
    +
    +#. module: hr_timesheet
    +#: view:hr.sign.in.project:0
    +msgid "Start Working"
    +msgstr "Begynn arbeid"
    +
    +#. module: hr_timesheet
    +#: view:account.analytic.account:0
    +msgid "Stats by user"
    +msgstr "Statistikk pr. bruker"
    +
    +#. module: hr_timesheet
    +#: code:addons/hr_timesheet/wizard/hr_timesheet_print_employee.py:42
    +#, python-format
    +msgid "No employee defined for this user"
    +msgstr "Ingen ansatt er angitt for denne brukeren"
    +
    +#. module: hr_timesheet
    +#: field:hr.analytical.timesheet.employee,year:0
    +#: field:hr.analytical.timesheet.users,year:0
    +msgid "Year"
    +msgstr "År"
    +
    +#. module: hr_timesheet
    +#: view:hr.analytic.timesheet:0
    +msgid "Accounting"
    +msgstr ""
    +
    +#. module: hr_timesheet
    +#: field:hr.analytic.timesheet,partner_id:0
    +msgid "Partner Id"
    +msgstr ""
    +
    +#. module: hr_timesheet
    +#: view:hr.sign.out.project:0
    +msgid "Change Work"
    +msgstr ""
    +
    +#. module: hr_timesheet
    +#: selection:hr.analytical.timesheet.employee,month:0
    +#: selection:hr.analytical.timesheet.users,month:0
    +msgid "septembre"
    +msgstr ""
    diff --git a/addons/product/i18n/ro.po b/addons/product/i18n/ro.po
    index b0e9742b03b..d0fa6617a42 100644
    --- a/addons/product/i18n/ro.po
    +++ b/addons/product/i18n/ro.po
    @@ -13,7 +13,7 @@ msgstr ""
     "MIME-Version: 1.0\n"
     "Content-Type: text/plain; charset=UTF-8\n"
     "Content-Transfer-Encoding: 8bit\n"
    -"X-Launchpad-Export-Date: 2011-04-07 04:37+0000\n"
    +"X-Launchpad-Export-Date: 2011-04-08 04:45+0000\n"
     "X-Generator: Launchpad (build 12735)\n"
     
     #. module: product
    diff --git a/addons/product_margin/i18n/gl.po b/addons/product_margin/i18n/gl.po
    new file mode 100644
    index 00000000000..3826f599bdc
    --- /dev/null
    +++ b/addons/product_margin/i18n/gl.po
    @@ -0,0 +1,305 @@
    +# Galician translation for openobject-addons
    +# Copyright (c) 2011 Rosetta Contributors and Canonical Ltd 2011
    +# This file is distributed under the same license as the openobject-addons package.
    +# FIRST AUTHOR , 2011.
    +#
    +msgid ""
    +msgstr ""
    +"Project-Id-Version: openobject-addons\n"
    +"Report-Msgid-Bugs-To: FULL NAME \n"
    +"POT-Creation-Date: 2011-01-11 11:15+0000\n"
    +"PO-Revision-Date: 2011-04-07 08:52+0000\n"
    +"Last-Translator: FULL NAME \n"
    +"Language-Team: Galician \n"
    +"MIME-Version: 1.0\n"
    +"Content-Type: text/plain; charset=UTF-8\n"
    +"Content-Transfer-Encoding: 8bit\n"
    +"X-Launchpad-Export-Date: 2011-04-08 04:45+0000\n"
    +"X-Generator: Launchpad (build 12735)\n"
    +
    +#. module: product_margin
    +#: view:product.product:0
    +#: field:product.product,turnover:0
    +msgid "Turnover"
    +msgstr "Volume de negocio"
    +
    +#. module: product_margin
    +#: field:product.product,expected_margin_rate:0
    +msgid "Expected Margin (%)"
    +msgstr "Marxe prevista (%)"
    +
    +#. module: product_margin
    +#: field:product.margin,from_date:0
    +msgid "From"
    +msgstr "Desde"
    +
    +#. module: product_margin
    +#: help:product.product,sale_expected:0
    +msgid ""
    +"Sum of Multification of Sale Catalog price and quantity of Customer Invoices"
    +msgstr ""
    +"Suma da multiplicación do prezo do catálogo de venda e cantidade das "
    +"facturas do cliente"
    +
    +#. module: product_margin
    +#: help:product.product,total_margin:0
    +msgid "Turnorder - Standard price"
    +msgstr "Volume de negocio - Prezo estándar"
    +
    +#. module: product_margin
    +#: field:product.margin,to_date:0
    +msgid "To"
    +msgstr "Ata"
    +
    +#. module: product_margin
    +#: field:product.product,date_to:0
    +msgid "To Date"
    +msgstr "Ata a data"
    +
    +#. module: product_margin
    +#: field:product.product,date_from:0
    +msgid "From Date"
    +msgstr "Desde a data"
    +
    +#. module: product_margin
    +#: selection:product.margin,invoice_state:0
    +#: selection:product.product,invoice_state:0
    +msgid "Draft, Open and Paid"
    +msgstr "Borrador, aberto e pagado"
    +
    +#. module: product_margin
    +#: field:product.product,purchase_avg_price:0
    +#: field:product.product,sale_avg_price:0
    +msgid "Avg. Unit Price"
    +msgstr "Media prezo unidade"
    +
    +#. module: product_margin
    +#: model:ir.module.module,shortdesc:product_margin.module_meta_information
    +msgid "Margins in Product"
    +msgstr "Marxes en produtos"
    +
    +#. module: product_margin
    +#: model:ir.model,name:product_margin.model_product_product
    +msgid "Product"
    +msgstr "Produto"
    +
    +#. module: product_margin
    +#: view:product.product:0
    +msgid "Catalog Price"
    +msgstr "Prezo catálogo"
    +
    +#. module: product_margin
    +#: selection:product.margin,invoice_state:0
    +#: selection:product.product,invoice_state:0
    +msgid "Paid"
    +msgstr "Pagado"
    +
    +#. module: product_margin
    +#: help:product.product,sales_gap:0
    +msgid "Expected Sale - Turn Over"
    +msgstr "Venda prevista - Volume de negocio"
    +
    +#. module: product_margin
    +#: model:ir.module.module,description:product_margin.module_meta_information
    +msgid ""
    +"\n"
    +"Adds a reporting menu in products that computes sales, purchases, margins\n"
    +"and other interesting indicators based on invoices. The wizard to launch\n"
    +"the report has several options to help you get the data you need.\n"
    +msgstr ""
    +"\n"
    +"Engade un menú de informes ós produtos, que calcula as vendas, as compras, "
    +"as marxes e outros indicadores interesantes en base ás facturas. O asistente "
    +"ofrécelle varias opcións para axudarlle a obter os datos que precisa.\n"
    +
    +#. module: product_margin
    +#: view:product.product:0
    +msgid "Standard Price"
    +msgstr "Prezo estándar"
    +
    +#. module: product_margin
    +#: field:product.product,sale_expected:0
    +msgid "Expected Sale"
    +msgstr "Venda prevista"
    +
    +#. module: product_margin
    +#: help:product.product,normal_cost:0
    +msgid "Sum of Multification of Cost price and quantity of Supplier Invoices"
    +msgstr ""
    +"Suma da multiplicación do prezo de custo e da cantidade das facturas do "
    +"provedor"
    +
    +#. module: product_margin
    +#: help:product.product,expected_margin:0
    +msgid "Expected Sale - Normal Cost"
    +msgstr "Venda prevista - Custo normal"
    +
    +#. module: product_margin
    +#: view:product.product:0
    +msgid "Analysis Criteria"
    +msgstr "Criterios de análise"
    +
    +#. module: product_margin
    +#: view:product.product:0
    +#: field:product.product,total_cost:0
    +msgid "Total Cost"
    +msgstr "Custo total"
    +
    +#. module: product_margin
    +#: field:product.product,expected_margin:0
    +msgid "Expected Margin"
    +msgstr "Marxe prevista"
    +
    +#. module: product_margin
    +#: view:product.product:0
    +msgid "#Purchased"
    +msgstr "Núm. mercados"
    +
    +#. module: product_margin
    +#: help:product.product,turnover:0
    +msgid ""
    +"Sum of Multification of Invoice price and quantity of Customer Invoices"
    +msgstr ""
    +"Suma da multiplicación do prezo da factura e da cantidade de facturas do "
    +"cliente"
    +
    +#. module: product_margin
    +#: help:product.product,expected_margin_rate:0
    +msgid "Expected margin * 100 / Expected Sale"
    +msgstr "Marxe prevista * 100 / Venda prevista"
    +
    +#. module: product_margin
    +#: help:product.product,sale_avg_price:0
    +msgid "Avg. Price in Customer Invoices)"
    +msgstr "Prezo medio en facturas de cliente)"
    +
    +#. module: product_margin
    +#: help:product.product,total_cost:0
    +msgid ""
    +"Sum of Multification of Invoice price and quantity of Supplier Invoices "
    +msgstr ""
    +"Suma da multiplicación do prezo da factura e da cantidade de facturas do "
    +"provedor "
    +
    +#. module: product_margin
    +#: field:product.margin,invoice_state:0
    +#: field:product.product,invoice_state:0
    +msgid "Invoice State"
    +msgstr "Estado da factura"
    +
    +#. module: product_margin
    +#: help:product.product,purchase_gap:0
    +msgid "Normal Cost - Total Cost"
    +msgstr "Custo normal - Custo total"
    +
    +#. module: product_margin
    +#: field:product.product,total_margin:0
    +msgid "Total Margin"
    +msgstr "Marxe total"
    +
    +#. module: product_margin
    +#: view:product.product:0
    +#: field:product.product,sales_gap:0
    +msgid "Sales Gap"
    +msgstr "Diferenza vendas"
    +
    +#. module: product_margin
    +#: field:product.product,normal_cost:0
    +msgid "Normal Cost"
    +msgstr "Custo normal"
    +
    +#. module: product_margin
    +#: view:product.product:0
    +msgid "Purchases"
    +msgstr "Compras"
    +
    +#. module: product_margin
    +#: help:product.product,purchase_avg_price:0
    +msgid "Avg. Price in Supplier Invoices "
    +msgstr "Prezo medio en facturas de provedor "
    +
    +#. module: product_margin
    +#: help:product.product,purchase_num_invoiced:0
    +msgid "Sum of Quantity in Supplier Invoices"
    +msgstr "Suma da cantidade en facturas provedor"
    +
    +#. module: product_margin
    +#: view:product.margin:0
    +msgid "Properties categories"
    +msgstr "Categorías das propiedades"
    +
    +#. module: product_margin
    +#: help:product.product,total_margin_rate:0
    +msgid "Total margin * 100 / Turnover"
    +msgstr "Marxe total * 100 / Volume de negocio"
    +
    +#. module: product_margin
    +#: field:product.product,purchase_num_invoiced:0
    +#: field:product.product,sale_num_invoiced:0
    +msgid "# Invoiced"
    +msgstr "Nº facturado"
    +
    +#. module: product_margin
    +#: selection:product.margin,invoice_state:0
    +#: selection:product.product,invoice_state:0
    +msgid "Open and Paid"
    +msgstr "Aberto e pechado"
    +
    +#. module: product_margin
    +#: view:product.product:0
    +msgid "Sales"
    +msgstr "Vendas"
    +
    +#. module: product_margin
    +#: code:addons/product_margin/wizard/product_margin.py:73
    +#: model:ir.actions.act_window,name:product_margin.product_margin_act_window
    +#: model:ir.ui.menu,name:product_margin.menu_action_product_margin
    +#: view:product.product:0
    +#, python-format
    +msgid "Product Margins"
    +msgstr "Marxes de produto"
    +
    +#. module: product_margin
    +#: view:product.margin:0
    +msgid "General Information"
    +msgstr "Información xeral"
    +
    +#. module: product_margin
    +#: constraint:product.product:0
    +msgid "Error: Invalid ean code"
    +msgstr "Erro: Código EAN non válido"
    +
    +#. module: product_margin
    +#: field:product.product,purchase_gap:0
    +msgid "Purchase Gap"
    +msgstr "Diferenza compra"
    +
    +#. module: product_margin
    +#: field:product.product,total_margin_rate:0
    +msgid "Total Margin (%)"
    +msgstr "Total marxe (%)"
    +
    +#. module: product_margin
    +#: view:product.margin:0
    +msgid "Open Margins"
    +msgstr "Abrir marxes"
    +
    +#. module: product_margin
    +#: view:product.margin:0
    +msgid "Cancel"
    +msgstr "Anular"
    +
    +#. module: product_margin
    +#: view:product.product:0
    +msgid "Margins"
    +msgstr "Marxes"
    +
    +#. module: product_margin
    +#: help:product.product,sale_num_invoiced:0
    +msgid "Sum of Quantity in Customer Invoices"
    +msgstr "Suma da cantidade en facturas de cliente"
    +
    +#. module: product_margin
    +#: model:ir.model,name:product_margin.model_product_margin
    +msgid "Product Margin"
    +msgstr "Marxe produto"
    diff --git a/addons/project/i18n/nb.po b/addons/project/i18n/nb.po
    index 0b2bbcc78cf..be530dd028f 100644
    --- a/addons/project/i18n/nb.po
    +++ b/addons/project/i18n/nb.po
    @@ -8,13 +8,13 @@ msgstr ""
     "Project-Id-Version: openobject-addons\n"
     "Report-Msgid-Bugs-To: FULL NAME \n"
     "POT-Creation-Date: 2011-01-11 11:15+0000\n"
    -"PO-Revision-Date: 2011-04-05 22:52+0000\n"
    -"Last-Translator: Rolv Råen \n"
    +"PO-Revision-Date: 2011-04-07 06:42+0000\n"
    +"Last-Translator: Rolv Råen (adEgo) \n"
     "Language-Team: Norwegian Bokmal \n"
     "MIME-Version: 1.0\n"
     "Content-Type: text/plain; charset=UTF-8\n"
     "Content-Transfer-Encoding: 8bit\n"
    -"X-Launchpad-Export-Date: 2011-04-07 04:37+0000\n"
    +"X-Launchpad-Export-Date: 2011-04-08 04:45+0000\n"
     "X-Generator: Launchpad (build 12735)\n"
     
     #. module: project
    @@ -446,7 +446,7 @@ msgstr "Task '%s' lukket"
     #: model:ir.model,name:project.model_account_analytic_account
     #: field:project.project,analytic_account_id:0
     msgid "Analytic Account"
    -msgstr "Kontodimensjon"
    +msgstr "Analytisk konto"
     
     #. module: project
     #: field:project.task.work,user_id:0
    diff --git a/addons/warning/i18n/nb.po b/addons/warning/i18n/nb.po
    new file mode 100644
    index 00000000000..a7b1bb332e8
    --- /dev/null
    +++ b/addons/warning/i18n/nb.po
    @@ -0,0 +1,235 @@
    +# Norwegian Bokmal translation for openobject-addons
    +# Copyright (c) 2011 Rosetta Contributors and Canonical Ltd 2011
    +# This file is distributed under the same license as the openobject-addons package.
    +# FIRST AUTHOR , 2011.
    +#
    +msgid ""
    +msgstr ""
    +"Project-Id-Version: openobject-addons\n"
    +"Report-Msgid-Bugs-To: FULL NAME \n"
    +"POT-Creation-Date: 2011-01-11 11:16+0000\n"
    +"PO-Revision-Date: 2011-04-07 07:25+0000\n"
    +"Last-Translator: FULL NAME \n"
    +"Language-Team: Norwegian Bokmal \n"
    +"MIME-Version: 1.0\n"
    +"Content-Type: text/plain; charset=UTF-8\n"
    +"Content-Transfer-Encoding: 8bit\n"
    +"X-Launchpad-Export-Date: 2011-04-08 04:45+0000\n"
    +"X-Generator: Launchpad (build 12735)\n"
    +
    +#. module: warning
    +#: model:ir.model,name:warning.model_purchase_order_line
    +#: field:product.product,purchase_line_warn:0
    +msgid "Purchase Order Line"
    +msgstr "Innkjøpsordrelinje"
    +
    +#. module: warning
    +#: field:product.product,sale_line_warn_msg:0
    +msgid "Message for Sale Order Line"
    +msgstr "Melding for salgsordrelinje"
    +
    +#. module: warning
    +#: field:product.product,purchase_line_warn_msg:0
    +msgid "Message for Purchase Order Line"
    +msgstr "Melding for innkjøpsordelinje"
    +
    +#. module: warning
    +#: constraint:res.partner:0
    +msgid "Error ! You can not create recursive associated members."
    +msgstr ""
    +
    +#. module: warning
    +#: model:ir.model,name:warning.model_stock_picking
    +msgid "Picking List"
    +msgstr "Plukkliste"
    +
    +#. module: warning
    +#: field:product.product,sale_line_warn:0
    +msgid "Sale Order Line"
    +msgstr "Salgsordrelinje"
    +
    +#. module: warning
    +#: view:product.product:0
    +msgid "Warning when Purchasing this Product"
    +msgstr "Advarsel ved kjøp av dette produktet"
    +
    +#. module: warning
    +#: model:ir.model,name:warning.model_product_product
    +msgid "Product"
    +msgstr "Produkt"
    +
    +#. module: warning
    +#: sql_constraint:purchase.order:0
    +#: sql_constraint:sale.order:0
    +msgid "Order Reference must be unique !"
    +msgstr "Ordrereferanse må være unik !"
    +
    +#. module: warning
    +#: view:product.product:0
    +#: view:res.partner:0
    +msgid "Warnings"
    +msgstr "Advarsler"
    +
    +#. module: warning
    +#: selection:product.product,purchase_line_warn:0
    +#: selection:product.product,sale_line_warn:0
    +#: selection:res.partner,invoice_warn:0
    +#: selection:res.partner,picking_warn:0
    +#: selection:res.partner,purchase_warn:0
    +#: selection:res.partner,sale_warn:0
    +msgid "Warning"
    +msgstr "Advarsel"
    +
    +#. module: warning
    +#: selection:product.product,purchase_line_warn:0
    +#: selection:product.product,sale_line_warn:0
    +#: selection:res.partner,invoice_warn:0
    +#: selection:res.partner,picking_warn:0
    +#: selection:res.partner,purchase_warn:0
    +#: selection:res.partner,sale_warn:0
    +msgid "Blocking Message"
    +msgstr ""
    +
    +#. module: warning
    +#: view:res.partner:0
    +msgid "Warning on the Invoice"
    +msgstr "Advarsel på faktuaren"
    +
    +#. module: warning
    +#: selection:product.product,purchase_line_warn:0
    +#: selection:product.product,sale_line_warn:0
    +#: selection:res.partner,invoice_warn:0
    +#: selection:res.partner,picking_warn:0
    +#: selection:res.partner,purchase_warn:0
    +#: selection:res.partner,sale_warn:0
    +msgid "No Message"
    +msgstr "Ingen melding"
    +
    +#. module: warning
    +#: model:ir.model,name:warning.model_account_invoice
    +#: field:res.partner,invoice_warn:0
    +msgid "Invoice"
    +msgstr "Faktura"
    +
    +#. module: warning
    +#: model:ir.module.module,shortdesc:warning.module_meta_information
    +msgid "Module for Warnings form onchange Event"
    +msgstr ""
    +
    +#. module: warning
    +#: view:product.product:0
    +msgid "Warning when Selling this Product"
    +msgstr "Advarsel ved salg av dette produktet"
    +
    +#. module: warning
    +#: field:res.partner,sale_warn:0
    +msgid "Sale Order"
    +msgstr "Salgsordre"
    +
    +#. module: warning
    +#: field:res.partner,picking_warn:0
    +msgid "Stock Picking"
    +msgstr ""
    +
    +#. module: warning
    +#: model:ir.model,name:warning.model_purchase_order
    +#: field:res.partner,purchase_warn:0
    +msgid "Purchase Order"
    +msgstr "Innkjøpsordre"
    +
    +#. module: warning
    +#: field:res.partner,sale_warn_msg:0
    +msgid "Message for Sale Order"
    +msgstr "Melding for salgsordre"
    +
    +#. module: warning
    +#: field:res.partner,purchase_warn_msg:0
    +msgid "Message for Purchase Order"
    +msgstr "Melding for innkjøpsordre"
    +
    +#. module: warning
    +#: code:addons/warning/warning.py:32
    +#: help:product.product,purchase_line_warn:0
    +#: help:product.product,sale_line_warn:0
    +#: help:res.partner,invoice_warn:0
    +#: help:res.partner,picking_warn:0
    +#: help:res.partner,purchase_warn:0
    +#: help:res.partner,sale_warn:0
    +#, python-format
    +msgid ""
    +"Selecting the \"Warning\" option will notify user with the message, "
    +"Selecting \"Blocking Message\" will throw an exception with the message and "
    +"block the flow. The Message has to be written in the next field."
    +msgstr ""
    +
    +#. module: warning
    +#: code:addons/warning/warning.py:67
    +#: code:addons/warning/warning.py:96
    +#: code:addons/warning/warning.py:132
    +#: code:addons/warning/warning.py:163
    +#: code:addons/warning/warning.py:213
    +#: code:addons/warning/warning.py:246
    +#, python-format
    +msgid "Alert for %s !"
    +msgstr ""
    +
    +#. module: warning
    +#: field:res.partner,invoice_warn_msg:0
    +msgid "Message for Invoice"
    +msgstr "Melding for faktura"
    +
    +#. module: warning
    +#: model:ir.module.module,description:warning.module_meta_information
    +msgid "Module for Warnings form onchange Event."
    +msgstr ""
    +
    +#. module: warning
    +#: view:res.partner:0
    +msgid "Warning on the Picking"
    +msgstr ""
    +
    +#. module: warning
    +#: view:res.partner:0
    +msgid "Warning on the Purchase Order"
    +msgstr "Advarsel på innkjøpsordren"
    +
    +#. module: warning
    +#: code:addons/warning/warning.py:68
    +#: code:addons/warning/warning.py:97
    +#: code:addons/warning/warning.py:134
    +#: code:addons/warning/warning.py:164
    +#: code:addons/warning/warning.py:214
    +#: code:addons/warning/warning.py:247
    +#, python-format
    +msgid "Warning for %s"
    +msgstr "Advarsel for %s"
    +
    +#. module: warning
    +#: view:res.partner:0
    +msgid "Warning on the Sale Order"
    +msgstr "Advarsel på salgsordren"
    +
    +#. module: warning
    +#: constraint:product.product:0
    +msgid "Error: Invalid ean code"
    +msgstr "Feil: Ugyldig ean kode"
    +
    +#. module: warning
    +#: field:res.partner,picking_warn_msg:0
    +msgid "Message for Stock Picking"
    +msgstr ""
    +
    +#. module: warning
    +#: model:ir.model,name:warning.model_res_partner
    +msgid "Partner"
    +msgstr "Partner"
    +
    +#. module: warning
    +#: model:ir.model,name:warning.model_sale_order
    +msgid "Sales Order"
    +msgstr "Salgsordre"
    +
    +#. module: warning
    +#: model:ir.model,name:warning.model_sale_order_line
    +msgid "Sales Order Line"
    +msgstr "Salgsordrelinje"
    diff --git a/addons/web_livechat/i18n/zh_CN.po b/addons/web_livechat/i18n/zh_CN.po
    new file mode 100644
    index 00000000000..273f0f0369f
    --- /dev/null
    +++ b/addons/web_livechat/i18n/zh_CN.po
    @@ -0,0 +1,39 @@
    +# Chinese (Simplified) translation for openobject-addons
    +# Copyright (c) 2011 Rosetta Contributors and Canonical Ltd 2011
    +# This file is distributed under the same license as the openobject-addons package.
    +# FIRST AUTHOR , 2011.
    +#
    +msgid ""
    +msgstr ""
    +"Project-Id-Version: openobject-addons\n"
    +"Report-Msgid-Bugs-To: FULL NAME \n"
    +"POT-Creation-Date: 2011-01-11 11:16+0000\n"
    +"PO-Revision-Date: 2011-04-08 07:20+0000\n"
    +"Last-Translator: FULL NAME \n"
    +"Language-Team: Chinese (Simplified) \n"
    +"MIME-Version: 1.0\n"
    +"Content-Type: text/plain; charset=UTF-8\n"
    +"Content-Transfer-Encoding: 8bit\n"
    +"X-Launchpad-Export-Date: 2011-04-09 05:00+0000\n"
    +"X-Generator: Launchpad (build 12735)\n"
    +
    +#. module: web_livechat
    +#: sql_constraint:publisher_warranty.contract:0
    +msgid ""
    +"Your publisher warranty contract is already subscribed in the system !"
    +msgstr ""
    +
    +#. module: web_livechat
    +#: model:ir.module.module,shortdesc:web_livechat.module_meta_information
    +msgid "Live Chat Support"
    +msgstr ""
    +
    +#. module: web_livechat
    +#: model:ir.model,name:web_livechat.model_publisher_warranty_contract
    +msgid "publisher_warranty.contract"
    +msgstr ""
    +
    +#. module: web_livechat
    +#: model:ir.module.module,description:web_livechat.module_meta_information
    +msgid "Enable live chat support for whom have a maintenance contract"
    +msgstr ""
    diff --git a/addons/web_uservoice/i18n/zh_CN.po b/addons/web_uservoice/i18n/zh_CN.po
    new file mode 100644
    index 00000000000..bd1d4d4a45d
    --- /dev/null
    +++ b/addons/web_uservoice/i18n/zh_CN.po
    @@ -0,0 +1,29 @@
    +# Chinese (Simplified) translation for openobject-addons
    +# Copyright (c) 2011 Rosetta Contributors and Canonical Ltd 2011
    +# This file is distributed under the same license as the openobject-addons package.
    +# FIRST AUTHOR , 2011.
    +#
    +msgid ""
    +msgstr ""
    +"Project-Id-Version: openobject-addons\n"
    +"Report-Msgid-Bugs-To: FULL NAME \n"
    +"POT-Creation-Date: 2011-01-12 16:15+0000\n"
    +"PO-Revision-Date: 2011-04-08 07:13+0000\n"
    +"Last-Translator: FULL NAME \n"
    +"Language-Team: Chinese (Simplified) \n"
    +"MIME-Version: 1.0\n"
    +"Content-Type: text/plain; charset=UTF-8\n"
    +"Content-Transfer-Encoding: 8bit\n"
    +"X-Launchpad-Export-Date: 2011-04-09 05:00+0000\n"
    +"X-Generator: Launchpad (build 12735)\n"
    +
    +#. module: web_uservoice
    +#: model:ir.module.module,shortdesc:web_uservoice.module_meta_information
    +msgid "Add uservoice button in header"
    +msgstr ""
    +
    +#. module: web_uservoice
    +#: code:addons/web_uservoice/web/editors.py:72
    +#, python-format
    +msgid "feedback"
    +msgstr ""
    
    From 43a6970d7a71cc89b70aa0bb5f74d541239cf2ea Mon Sep 17 00:00:00 2001
    From: "noz (OpenERP)" 
    Date: Mon, 11 Apr 2011 10:53:53 +0530
    Subject: [PATCH 123/259] [FIX] httprequest, jsonrequest conflicts testing.
    
    bzr revid: noz@tinyerp.com-20110411052353-45ftq6rb57zhxtdo
    ---
     addons/web_chat/controllers/main.py | 20 +++++++++-----------
     1 file changed, 9 insertions(+), 11 deletions(-)
    
    diff --git a/addons/web_chat/controllers/main.py b/addons/web_chat/controllers/main.py
    index 456fd0f5340..2beccdcda0c 100644
    --- a/addons/web_chat/controllers/main.py
    +++ b/addons/web_chat/controllers/main.py
    @@ -133,10 +133,10 @@ class PollServer(openerpweb.Controller):
             """
             
             for i in range(60):
    -            received_msg = mq.read('Guest2', i);
    +            received_msg = mq.read('Guest1', i);
                 if received_msg:
                     msg = self._pollParseMessages(received_msg)
    -                print "============ msg...", msg
    +                time.sleep(2)
                 else:
                     time.sleep(2)
                 
    @@ -149,12 +149,11 @@ class PollServer(openerpweb.Controller):
             # else
                 # return emptylist
                 
    -        
    -        # it's http://localhost:8002/web_chat/pollserver/poll?method=long?callback=jsonp1302147330483&_1302147330483=
    +#        print "==============poll receive...", kw.get('callback')
    +#        # it's http://localhost:8002/web_chat/pollserver/poll?method=long?callback=jsonp1302147330483&_1302147330483=
             return '%s([{"t":"m","s":"Guest130214008855.5","r":"Guest130214013134.26","m":"xxxxxx"}]);'%kw.get('callback','')
    -        return None
             
    -    @openerpweb.httprequest
    +    @openerpweb.jsonrequest
         def send(self, req, **kw):
             print "========= send ========", kw
             
    @@ -187,9 +186,10 @@ class PollServer(openerpweb.Controller):
                 return dict(r='error', e='no_recipient')
             
             if message:
    -            mq.write(m_type="text",  m_from=req.applicationsession['current_user'], m_to=to, m_message=message, m_group="Users")
    -        
    -        return {'r': 'sent'}
    +            mq.write(m_type="m",  m_from=req.applicationsession['current_user'], m_to=to, m_message=message, m_group="Users")        
    +            return {'r': 'sent'}
    +        else:
    +            return {'r': 'error', 'e': 'send error'}
     
         @openerpweb.httprequest
         def status(self, req, **kw):
    @@ -215,9 +215,7 @@ class PollServer(openerpweb.Controller):
         
         def _pollParseMessages(self, messages):
             msg_arr = []
    -        print "=========== messages...", messages
             for msg in messages:
    -            print "=========== msg..", msg
                 msg_arr.append({'t': msg['type'], 's': msg['from'], 'r': msg['to'], 'm': msg['message']})
             return msg_arr
         
    
    From 326fc1420b16e575a8f27264cf1a086c0348caf5 Mon Sep 17 00:00:00 2001
    From: Launchpad Translations on behalf of openerp <>
    Date: Mon, 11 Apr 2011 05:43:15 +0000
    Subject: [PATCH 124/259] Launchpad automatic translations update.
    
    bzr revid: launchpad_translations_on_behalf_of_openerp-20110411054240-glbtpl72fmw06spz
    bzr revid: launchpad_translations_on_behalf_of_openerp-20110409061637-9s5h5adu95tabmbp
    bzr revid: launchpad_translations_on_behalf_of_openerp-20110410060107-yhr6iuxpvirpqo8l
    bzr revid: launchpad_translations_on_behalf_of_openerp-20110411054315-0ka0kjfhsys3iuf4
    ---
     addons/account/i18n/it.po              |  12 +-
     addons/anonymization/i18n/ca.po        | 226 ++++++++
     addons/base_synchro/i18n/ca.po         | 289 ++++++++++
     addons/crm_caldav/i18n/zh_CN.po        |  49 ++
     addons/crm_claim/i18n/zh_CN.po         | 752 +++++++++++++++++++++++++
     addons/crm_helpdesk/i18n/zh_CN.po      | 697 +++++++++++++++++++++++
     addons/document/i18n/gl.po             |   2 +-
     addons/document_webdav/i18n/ca.po      | 206 +++++++
     addons/fetchmail/i18n/ca.po            | 317 +++++++++++
     addons/fetchmail/i18n/es.po            |  10 +-
     addons/hr_recruitment/i18n/ca.po       |  10 +-
     addons/hr_timesheet_invoice/i18n/it.po |  29 +-
     addons/idea/i18n/mn.po                 |  10 +-
     addons/product/i18n/id.po              |   2 +-
     addons/thunderbird/i18n/bg.po          |  18 +-
     addons/web_livechat/i18n/zh_CN.po      |  39 ++
     addons/web_uservoice/i18n/zh_CN.po     |  29 +
     bin/addons/base/i18n/nl.po             |  10 +-
     18 files changed, 2658 insertions(+), 49 deletions(-)
     create mode 100644 addons/anonymization/i18n/ca.po
     create mode 100644 addons/base_synchro/i18n/ca.po
     create mode 100644 addons/crm_caldav/i18n/zh_CN.po
     create mode 100644 addons/crm_claim/i18n/zh_CN.po
     create mode 100644 addons/crm_helpdesk/i18n/zh_CN.po
     create mode 100644 addons/document_webdav/i18n/ca.po
     create mode 100644 addons/fetchmail/i18n/ca.po
     create mode 100644 addons/web_livechat/i18n/zh_CN.po
     create mode 100644 addons/web_uservoice/i18n/zh_CN.po
    
    diff --git a/addons/account/i18n/it.po b/addons/account/i18n/it.po
    index 7ff6b4158a4..90907b4f03e 100644
    --- a/addons/account/i18n/it.po
    +++ b/addons/account/i18n/it.po
    @@ -7,14 +7,14 @@ msgstr ""
     "Project-Id-Version: OpenERP Server 6.0dev\n"
     "Report-Msgid-Bugs-To: support@openerp.com\n"
     "POT-Creation-Date: 2011-01-11 11:14+0000\n"
    -"PO-Revision-Date: 2011-03-24 08:57+0000\n"
    -"Last-Translator: Marco Pattaro \n"
    +"PO-Revision-Date: 2011-04-10 12:46+0000\n"
    +"Last-Translator: Vincenzo Marino \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: 2011-03-25 06:14+0000\n"
    -"X-Generator: Launchpad (build 12559)\n"
    +"X-Launchpad-Export-Date: 2011-04-11 05:43+0000\n"
    +"X-Generator: Launchpad (build 12735)\n"
     
     #. module: account
     #: model:process.transition,name:account.process_transition_supplierreconcilepaid0
    @@ -1421,7 +1421,7 @@ msgstr "Salta lo stato 'bozza' per registrazioni manuali"
     #: view:account.invoice.report:0
     #: field:account.invoice.report,price_total:0
     msgid "Total Without Tax"
    -msgstr "Totale senza impste"
    +msgstr "Totale senza imposte"
     
     #. module: account
     #: model:ir.actions.act_window,help:account.action_move_journal_line
    @@ -5175,6 +5175,8 @@ msgid ""
     "According value related accounts will be display on respective reports "
     "(Balance Sheet Profit & Loss Account)"
     msgstr ""
    +"I valori di raccordo dei conti saranno mostrati nei rispettivi rapporti "
    +"(Conto Economico)"
     
     #. module: account
     #: field:account.report.general.ledger,sortby:0
    diff --git a/addons/anonymization/i18n/ca.po b/addons/anonymization/i18n/ca.po
    new file mode 100644
    index 00000000000..d00ac5a62fb
    --- /dev/null
    +++ b/addons/anonymization/i18n/ca.po
    @@ -0,0 +1,226 @@
    +# Catalan translation for openobject-addons
    +# Copyright (c) 2011 Rosetta Contributors and Canonical Ltd 2011
    +# This file is distributed under the same license as the openobject-addons package.
    +# FIRST AUTHOR , 2011.
    +#
    +msgid ""
    +msgstr ""
    +"Project-Id-Version: openobject-addons\n"
    +"Report-Msgid-Bugs-To: FULL NAME \n"
    +"POT-Creation-Date: 2011-01-11 11:14+0000\n"
    +"PO-Revision-Date: 2011-04-09 18:26+0000\n"
    +"Last-Translator: FULL NAME \n"
    +"Language-Team: Catalan \n"
    +"MIME-Version: 1.0\n"
    +"Content-Type: text/plain; charset=UTF-8\n"
    +"Content-Transfer-Encoding: 8bit\n"
    +"X-Launchpad-Export-Date: 2011-04-10 06:00+0000\n"
    +"X-Generator: Launchpad (build 12735)\n"
    +
    +#. module: anonymization
    +#: model:ir.model,name:anonymization.model_ir_model_fields_anonymize_wizard
    +msgid "ir.model.fields.anonymize.wizard"
    +msgstr ""
    +
    +#. module: anonymization
    +#: field:ir.model.fields.anonymization,field_name:0
    +msgid "Field Name"
    +msgstr ""
    +
    +#. module: anonymization
    +#: field:ir.model.fields.anonymization,field_id:0
    +msgid "Field"
    +msgstr ""
    +
    +#. module: anonymization
    +#: field:ir.model.fields.anonymization.history,state:0
    +#: field:ir.model.fields.anonymize.wizard,state:0
    +msgid "State"
    +msgstr ""
    +
    +#. module: anonymization
    +#: field:ir.model.fields.anonymize.wizard,file_import:0
    +msgid "Import"
    +msgstr ""
    +
    +#. module: anonymization
    +#: model:ir.model,name:anonymization.model_ir_model_fields_anonymization
    +msgid "ir.model.fields.anonymization"
    +msgstr ""
    +
    +#. module: anonymization
    +#: model:ir.module.module,shortdesc:anonymization.module_meta_information
    +msgid "Database anonymization module"
    +msgstr ""
    +
    +#. module: anonymization
    +#: field:ir.model.fields.anonymization.history,direction:0
    +msgid "Direction"
    +msgstr ""
    +
    +#. module: anonymization
    +#: model:ir.actions.act_window,name:anonymization.action_ir_model_fields_anonymization_tree
    +#: view:ir.model.fields.anonymization:0
    +#: model:ir.ui.menu,name:anonymization.menu_administration_anonymization_fields
    +msgid "Anonymized Fields"
    +msgstr ""
    +
    +#. module: anonymization
    +#: model:ir.ui.menu,name:anonymization.menu_administration_anonymization
    +msgid "Database anonymization"
    +msgstr ""
    +
    +#. module: anonymization
    +#: code:addons/anonymization/anonymization.py:55
    +#: sql_constraint:ir.model.fields.anonymization:0
    +#, python-format
    +msgid "You cannot have two records having the same model and the same field"
    +msgstr ""
    +
    +#. module: anonymization
    +#: selection:ir.model.fields.anonymization,state:0
    +#: selection:ir.model.fields.anonymize.wizard,state:0
    +msgid "Anonymized"
    +msgstr ""
    +
    +#. module: anonymization
    +#: field:ir.model.fields.anonymization,state:0
    +msgid "unknown"
    +msgstr ""
    +
    +#. module: anonymization
    +#: field:ir.model.fields.anonymization,model_id:0
    +msgid "Object"
    +msgstr ""
    +
    +#. module: anonymization
    +#: field:ir.model.fields.anonymization.history,filepath:0
    +msgid "File path"
    +msgstr ""
    +
    +#. module: anonymization
    +#: field:ir.model.fields.anonymization.history,date:0
    +msgid "Date"
    +msgstr ""
    +
    +#. module: anonymization
    +#: field:ir.model.fields.anonymize.wizard,file_export:0
    +msgid "Export"
    +msgstr ""
    +
    +#. module: anonymization
    +#: view:ir.model.fields.anonymize.wizard:0
    +msgid "Reverse the Database Anonymization"
    +msgstr ""
    +
    +#. module: anonymization
    +#: view:ir.model.fields.anonymize.wizard:0
    +msgid "Database Anonymization"
    +msgstr ""
    +
    +#. module: anonymization
    +#: model:ir.ui.menu,name:anonymization.menu_administration_anonymization_wizard
    +msgid "Anonymize database"
    +msgstr ""
    +
    +#. module: anonymization
    +#: view:ir.model.fields.anonymization.history:0
    +#: field:ir.model.fields.anonymization.history,field_ids:0
    +msgid "Fields"
    +msgstr ""
    +
    +#. module: anonymization
    +#: selection:ir.model.fields.anonymization,state:0
    +#: selection:ir.model.fields.anonymize.wizard,state:0
    +msgid "Clear"
    +msgstr ""
    +
    +#. module: anonymization
    +#: selection:ir.model.fields.anonymization.history,direction:0
    +msgid "clear -> anonymized"
    +msgstr ""
    +
    +#. module: anonymization
    +#: view:ir.model.fields.anonymize.wizard:0
    +#: field:ir.model.fields.anonymize.wizard,summary:0
    +msgid "Summary"
    +msgstr ""
    +
    +#. module: anonymization
    +#: view:ir.model.fields.anonymization:0
    +msgid "Anonymized Field"
    +msgstr ""
    +
    +#. module: anonymization
    +#: model:ir.module.module,description:anonymization.module_meta_information
    +msgid ""
    +"\n"
    +"This module allows you to anonymize a database.\n"
    +"    "
    +msgstr ""
    +
    +#. module: anonymization
    +#: selection:ir.model.fields.anonymize.wizard,state:0
    +msgid "Unstable"
    +msgstr ""
    +
    +#. module: anonymization
    +#: selection:ir.model.fields.anonymization.history,state:0
    +msgid "Exception occured"
    +msgstr ""
    +
    +#. module: anonymization
    +#: selection:ir.model.fields.anonymization,state:0
    +#: selection:ir.model.fields.anonymize.wizard,state:0
    +msgid "Not Existing"
    +msgstr ""
    +
    +#. module: anonymization
    +#: field:ir.model.fields.anonymization,model_name:0
    +msgid "Object Name"
    +msgstr ""
    +
    +#. module: anonymization
    +#: model:ir.actions.act_window,name:anonymization.action_ir_model_fields_anonymization_history_tree
    +#: view:ir.model.fields.anonymization.history:0
    +#: model:ir.ui.menu,name:anonymization.menu_administration_anonymization_history
    +msgid "Anonymization History"
    +msgstr ""
    +
    +#. module: anonymization
    +#: model:ir.model,name:anonymization.model_ir_model_fields_anonymization_history
    +msgid "ir.model.fields.anonymization.history"
    +msgstr ""
    +
    +#. module: anonymization
    +#: model:ir.actions.act_window,name:anonymization.action_ir_model_fields_anonymize_wizard
    +#: view:ir.model.fields.anonymize.wizard:0
    +msgid "Anonymize Database"
    +msgstr ""
    +
    +#. module: anonymization
    +#: field:ir.model.fields.anonymize.wizard,name:0
    +msgid "File Name"
    +msgstr ""
    +
    +#. module: anonymization
    +#: selection:ir.model.fields.anonymization.history,direction:0
    +msgid "anonymized -> clear"
    +msgstr ""
    +
    +#. module: anonymization
    +#: selection:ir.model.fields.anonymization.history,state:0
    +msgid "Started"
    +msgstr ""
    +
    +#. module: anonymization
    +#: selection:ir.model.fields.anonymization.history,state:0
    +msgid "Done"
    +msgstr ""
    +
    +#. module: anonymization
    +#: view:ir.model.fields.anonymization.history:0
    +#: field:ir.model.fields.anonymization.history,msg:0
    +#: field:ir.model.fields.anonymize.wizard,msg:0
    +msgid "Message"
    +msgstr ""
    diff --git a/addons/base_synchro/i18n/ca.po b/addons/base_synchro/i18n/ca.po
    new file mode 100644
    index 00000000000..38ab24622ec
    --- /dev/null
    +++ b/addons/base_synchro/i18n/ca.po
    @@ -0,0 +1,289 @@
    +# Catalan translation for openobject-addons
    +# Copyright (c) 2011 Rosetta Contributors and Canonical Ltd 2011
    +# This file is distributed under the same license as the openobject-addons package.
    +# FIRST AUTHOR , 2011.
    +#
    +msgid ""
    +msgstr ""
    +"Project-Id-Version: openobject-addons\n"
    +"Report-Msgid-Bugs-To: FULL NAME \n"
    +"POT-Creation-Date: 2011-01-11 11:14+0000\n"
    +"PO-Revision-Date: 2011-04-10 21:15+0000\n"
    +"Last-Translator: FULL NAME \n"
    +"Language-Team: Catalan \n"
    +"MIME-Version: 1.0\n"
    +"Content-Type: text/plain; charset=UTF-8\n"
    +"Content-Transfer-Encoding: 8bit\n"
    +"X-Launchpad-Export-Date: 2011-04-11 05:43+0000\n"
    +"X-Generator: Launchpad (build 12735)\n"
    +
    +#. module: base_synchro
    +#: model:ir.actions.act_window,name:base_synchro.action_view_base_synchro
    +msgid "Base Synchronization"
    +msgstr ""
    +
    +#. module: base_synchro
    +#: field:base.synchro.server,server_db:0
    +msgid "Server Database"
    +msgstr ""
    +
    +#. module: base_synchro
    +#: view:base.synchro.server:0
    +#: model:ir.model,name:base_synchro.model_base_synchro_server
    +msgid "Synchronized server"
    +msgstr ""
    +
    +#. module: base_synchro
    +#: field:base.synchro.obj.avoid,name:0
    +msgid "Field Name"
    +msgstr ""
    +
    +#. module: base_synchro
    +#: field:base.synchro.obj,synchronize_date:0
    +msgid "Latest Synchronization"
    +msgstr ""
    +
    +#. module: base_synchro
    +#: field:base.synchro,user_id:0
    +msgid "Send Result To"
    +msgstr ""
    +
    +#. module: base_synchro
    +#: model:ir.model,name:base_synchro.model_base_synchro_obj_avoid
    +msgid "Fields to not synchronize"
    +msgstr ""
    +
    +#. module: base_synchro
    +#: view:base.synchro:0
    +msgid "_Close"
    +msgstr ""
    +
    +#. module: base_synchro
    +#: view:base.synchro:0
    +msgid "Transfer Data To Server"
    +msgstr ""
    +
    +#. module: base_synchro
    +#: model:ir.model,name:base_synchro.model_base_synchro_obj
    +msgid "Register Class"
    +msgstr ""
    +
    +#. module: base_synchro
    +#: view:base.synchro.obj:0
    +#: model:ir.actions.act_window,name:base_synchro.action_transfer_tree
    +#: model:ir.ui.menu,name:base_synchro.transfer_menu_id
    +msgid "Synchronized objects"
    +msgstr ""
    +
    +#. module: base_synchro
    +#: field:base.synchro.server,obj_ids:0
    +msgid "Models"
    +msgstr ""
    +
    +#. module: base_synchro
    +#: field:base.synchro.obj.avoid,obj_id:0
    +#: view:base.synchro.obj.line:0
    +#: field:base.synchro.obj.line,obj_id:0
    +msgid "Object"
    +msgstr ""
    +
    +#. module: base_synchro
    +#: field:base.synchro.server,login:0
    +msgid "User Name"
    +msgstr ""
    +
    +#. module: base_synchro
    +#: view:base.synchro.obj:0
    +#: view:base.synchro.obj.line:0
    +msgid "Group By"
    +msgstr ""
    +
    +#. module: base_synchro
    +#: selection:base.synchro.obj,action:0
    +msgid "Upload"
    +msgstr ""
    +
    +#. module: base_synchro
    +#: view:base.synchro.obj:0
    +msgid "Latest synchronization"
    +msgstr ""
    +
    +#. module: base_synchro
    +#: model:ir.module.module,description:base_synchro.module_meta_information
    +msgid "Synchronization with all objects."
    +msgstr ""
    +
    +#. module: base_synchro
    +#: view:base.synchro.obj.line:0
    +#: field:base.synchro.obj.line,name:0
    +msgid "Date"
    +msgstr ""
    +
    +#. module: base_synchro
    +#: field:base.synchro.server,password:0
    +msgid "Password"
    +msgstr ""
    +
    +#. module: base_synchro
    +#: field:base.synchro.obj,avoid_ids:0
    +msgid "Fields Not Sync."
    +msgstr ""
    +
    +#. module: base_synchro
    +#: selection:base.synchro.obj,action:0
    +msgid "Both"
    +msgstr ""
    +
    +#. module: base_synchro
    +#: field:base.synchro.obj,name:0
    +msgid "Name"
    +msgstr ""
    +
    +#. module: base_synchro
    +#: view:base.synchro.obj:0
    +msgid "Fields"
    +msgstr ""
    +
    +#. module: base_synchro
    +#: view:base.synchro.obj.line:0
    +msgid "Transfered Ids Details"
    +msgstr ""
    +
    +#. module: base_synchro
    +#: field:base.synchro.obj,action:0
    +msgid "Synchronisation direction"
    +msgstr ""
    +
    +#. module: base_synchro
    +#: field:base.synchro.obj,server_id:0
    +msgid "Server"
    +msgstr ""
    +
    +#. module: base_synchro
    +#: model:ir.actions.act_window,name:base_synchro.action_base_synchro_obj_line_tree
    +#: model:ir.model,name:base_synchro.model_base_synchro_obj_line
    +#: model:ir.ui.menu,name:base_synchro.menu_action_base_synchro_obj_line_tree
    +msgid "Synchronized instances"
    +msgstr ""
    +
    +#. module: base_synchro
    +#: field:base.synchro.obj,active:0
    +msgid "Active"
    +msgstr ""
    +
    +#. module: base_synchro
    +#: view:base.synchro.obj:0
    +#: field:base.synchro.obj,model_id:0
    +msgid "Object to synchronize"
    +msgstr ""
    +
    +#. module: base_synchro
    +#: model:ir.module.module,shortdesc:base_synchro.module_meta_information
    +msgid "Base Synchro"
    +msgstr ""
    +
    +#. module: base_synchro
    +#: model:ir.actions.act_window,name:base_synchro.action_base_synchro_server_tree
    +#: model:ir.ui.menu,name:base_synchro.synchro_server_tree_menu_id
    +msgid "Servers to be synchronized"
    +msgstr ""
    +
    +#. module: base_synchro
    +#: view:base.synchro.obj:0
    +msgid "Transfer Details"
    +msgstr ""
    +
    +#. module: base_synchro
    +#: field:base.synchro.obj.line,remote_id:0
    +msgid "Remote Id"
    +msgstr ""
    +
    +#. module: base_synchro
    +#: field:base.synchro.obj,line_id:0
    +msgid "Ids Affected"
    +msgstr ""
    +
    +#. module: base_synchro
    +#: model:ir.ui.menu,name:base_synchro.next_id_63
    +msgid "History"
    +msgstr ""
    +
    +#. module: base_synchro
    +#: model:ir.ui.menu,name:base_synchro.next_id_62
    +#: model:ir.ui.menu,name:base_synchro.synch_config
    +msgid "Synchronization"
    +msgstr ""
    +
    +#. module: base_synchro
    +#: field:base.synchro.obj,domain:0
    +msgid "Domain"
    +msgstr ""
    +
    +#. module: base_synchro
    +#: view:base.synchro:0
    +msgid "_Synchronize"
    +msgstr ""
    +
    +#. module: base_synchro
    +#: view:base.synchro:0
    +msgid "OK"
    +msgstr ""
    +
    +#. module: base_synchro
    +#: field:base.synchro.server,name:0
    +msgid "Server name"
    +msgstr ""
    +
    +#. module: base_synchro
    +#: field:base.synchro.obj,sequence:0
    +msgid "Sequence"
    +msgstr ""
    +
    +#. module: base_synchro
    +#: view:base.synchro:0
    +msgid ""
    +"The synchronisation has been started.You will receive a request when it's "
    +"done."
    +msgstr ""
    +
    +#. module: base_synchro
    +#: field:base.synchro.server,server_port:0
    +msgid "Server Port"
    +msgstr ""
    +
    +#. module: base_synchro
    +#: model:ir.ui.menu,name:base_synchro.menu_action_view_base_synchro
    +msgid "Synchronize objects"
    +msgstr ""
    +
    +#. module: base_synchro
    +#: view:base.synchro:0
    +msgid "Synchronization Complited!"
    +msgstr ""
    +
    +#. module: base_synchro
    +#: model:ir.model,name:base_synchro.model_base_synchro
    +msgid "base.synchro"
    +msgstr ""
    +
    +#. module: base_synchro
    +#: field:base.synchro.obj.line,local_id:0
    +msgid "Local Id"
    +msgstr ""
    +
    +#. module: base_synchro
    +#: model:ir.actions.act_window,name:base_synchro.actions_regclass_tree
    +#: model:ir.actions.act_window,name:base_synchro.actions_transfer_line_form
    +msgid "Filters"
    +msgstr ""
    +
    +#. module: base_synchro
    +#: selection:base.synchro.obj,action:0
    +msgid "Download"
    +msgstr ""
    +
    +#. module: base_synchro
    +#: field:base.synchro,server_url:0
    +#: field:base.synchro.server,server_url:0
    +msgid "Server URL"
    +msgstr ""
    diff --git a/addons/crm_caldav/i18n/zh_CN.po b/addons/crm_caldav/i18n/zh_CN.po
    new file mode 100644
    index 00000000000..61fd5befc80
    --- /dev/null
    +++ b/addons/crm_caldav/i18n/zh_CN.po
    @@ -0,0 +1,49 @@
    +# Chinese (Simplified) translation for openobject-addons
    +# Copyright (c) 2011 Rosetta Contributors and Canonical Ltd 2011
    +# This file is distributed under the same license as the openobject-addons package.
    +# FIRST AUTHOR , 2011.
    +#
    +msgid ""
    +msgstr ""
    +"Project-Id-Version: openobject-addons\n"
    +"Report-Msgid-Bugs-To: FULL NAME \n"
    +"POT-Creation-Date: 2011-01-11 11:15+0000\n"
    +"PO-Revision-Date: 2011-04-10 17:34+0000\n"
    +"Last-Translator: FULL NAME \n"
    +"Language-Team: Chinese (Simplified) \n"
    +"MIME-Version: 1.0\n"
    +"Content-Type: text/plain; charset=UTF-8\n"
    +"Content-Transfer-Encoding: 8bit\n"
    +"X-Launchpad-Export-Date: 2011-04-11 05:43+0000\n"
    +"X-Generator: Launchpad (build 12735)\n"
    +
    +#. module: crm_caldav
    +#: model:ir.actions.act_window,name:crm_caldav.action_caldav_browse
    +msgid "Caldav Browse"
    +msgstr "Caldav翻阅"
    +
    +#. module: crm_caldav
    +#: model:ir.model,name:crm_caldav.model_crm_meeting
    +msgid "Meeting"
    +msgstr "会议"
    +
    +#. module: crm_caldav
    +#: model:ir.module.module,shortdesc:crm_caldav.module_meta_information
    +msgid "Extended Module to Add CalDav feature on Meeting"
    +msgstr "扩展模块增加会议的Caldav功能"
    +
    +#. module: crm_caldav
    +#: model:ir.module.module,description:crm_caldav.module_meta_information
    +msgid ""
    +"\n"
    +"    New Features in Meeting:\n"
    +"        *  Share meeting with other calendar clients like sunbird\n"
    +msgstr ""
    +"\n"
    +"    会议的新功能\n"
    +"     *通过连接Mozilla Sunbird与使用日程表的客户共享会议\n"
    +
    +#. module: crm_caldav
    +#: model:ir.ui.menu,name:crm_caldav.menu_caldav_browse
    +msgid "Synchronyze this calendar"
    +msgstr "同步calendar"
    diff --git a/addons/crm_claim/i18n/zh_CN.po b/addons/crm_claim/i18n/zh_CN.po
    new file mode 100644
    index 00000000000..804f986154b
    --- /dev/null
    +++ b/addons/crm_claim/i18n/zh_CN.po
    @@ -0,0 +1,752 @@
    +# Chinese (Simplified) translation for openobject-addons
    +# Copyright (c) 2011 Rosetta Contributors and Canonical Ltd 2011
    +# This file is distributed under the same license as the openobject-addons package.
    +# FIRST AUTHOR , 2011.
    +#
    +msgid ""
    +msgstr ""
    +"Project-Id-Version: openobject-addons\n"
    +"Report-Msgid-Bugs-To: FULL NAME \n"
    +"POT-Creation-Date: 2011-01-11 11:15+0000\n"
    +"PO-Revision-Date: 2011-04-11 03:42+0000\n"
    +"Last-Translator: FULL NAME \n"
    +"Language-Team: Chinese (Simplified) \n"
    +"MIME-Version: 1.0\n"
    +"Content-Type: text/plain; charset=UTF-8\n"
    +"Content-Transfer-Encoding: 8bit\n"
    +"X-Launchpad-Export-Date: 2011-04-11 05:43+0000\n"
    +"X-Generator: Launchpad (build 12735)\n"
    +
    +#. module: crm_claim
    +#: field:crm.claim.report,nbr:0
    +msgid "# of Cases"
    +msgstr "# 业务"
    +
    +#. module: crm_claim
    +#: view:crm.claim:0
    +#: view:crm.claim.report:0
    +msgid "Group By..."
    +msgstr "分组..."
    +
    +#. module: crm_claim
    +#: view:crm.claim:0
    +msgid "Responsibilities"
    +msgstr "责任人"
    +
    +#. module: crm_claim
    +#: field:crm.claim,date_action_next:0
    +msgid "Next Action Date"
    +msgstr "下一动作日期"
    +
    +#. module: crm_claim
    +#: field:crm.claim.report,probability:0
    +msgid "Probability"
    +msgstr "概率"
    +
    +#. module: crm_claim
    +#: selection:crm.claim.report,month:0
    +msgid "March"
    +msgstr "3月"
    +
    +#. module: crm_claim
    +#: field:crm.claim.report,delay_close:0
    +msgid "Delay to close"
    +msgstr "延迟关闭"
    +
    +#. module: crm_claim
    +#: field:crm.claim,resolution:0
    +msgid "Resolution"
    +msgstr "解决方案"
    +
    +#. module: crm_claim
    +#: field:crm.claim,company_id:0
    +#: view:crm.claim.report:0
    +#: field:crm.claim.report,company_id:0
    +msgid "Company"
    +msgstr "公司"
    +
    +#. module: crm_claim
    +#: field:crm.claim,email_cc:0
    +msgid "Watchers Emails"
    +msgstr "关注者的电子邮件"
    +
    +#. module: crm_claim
    +#: view:crm.claim.report:0
    +msgid "#Claim"
    +msgstr "#索赔"
    +
    +#. module: crm_claim
    +#: model:ir.actions.act_window,help:crm_claim.crm_claim_stage_act
    +msgid ""
    +"You can create claim stages to categorize the status of every claim entered "
    +"in the system. The stages define all the steps required for the resolution "
    +"of a claim."
    +msgstr "你能创建索赔阶段的类型把每个索赔的状况输入到系统。阶段定义所有索赔请求的解决步骤。"
    +
    +#. module: crm_claim
    +#: selection:crm.claim,priority:0
    +#: selection:crm.claim.report,priority:0
    +msgid "Highest"
    +msgstr "最高"
    +
    +#. module: crm_claim
    +#: view:crm.claim.report:0
    +#: field:crm.claim.report,day:0
    +msgid "Day"
    +msgstr "日"
    +
    +#. module: crm_claim
    +#: view:crm.claim:0
    +msgid "Add Internal Note"
    +msgstr "添加内部备注"
    +
    +#. module: crm_claim
    +#: help:crm.claim,section_id:0
    +msgid ""
    +"Sales team to which Case belongs to.Define Responsible user and Email "
    +"account for mail gateway."
    +msgstr "业务的销售团队定义负责用户和邮件网关的邮件地址。"
    +
    +#. module: crm_claim
    +#: view:crm.claim:0
    +msgid "Claim Description"
    +msgstr "索陪说明"
    +
    +#. module: crm_claim
    +#: field:crm.claim,message_ids:0
    +msgid "Messages"
    +msgstr "消息"
    +
    +#. module: crm_claim
    +#: model:crm.case.categ,name:crm_claim.categ_claim1
    +msgid "Factual Claims"
    +msgstr "实际索赔"
    +
    +#. module: crm_claim
    +#: selection:crm.claim,state:0
    +#: selection:crm.claim.report,state:0
    +msgid "Cancelled"
    +msgstr "已取消"
    +
    +#. module: crm_claim
    +#: model:crm.case.resource.type,name:crm_claim.type_claim2
    +msgid "Preventive"
    +msgstr "预防"
    +
    +#. module: crm_claim
    +#: model:crm.case.stage,name:crm_claim.stage_claim2
    +msgid "Fixed"
    +msgstr "固定的"
    +
    +#. module: crm_claim
    +#: field:crm.claim,partner_address_id:0
    +msgid "Partner Contact"
    +msgstr "业务伙伴联系方式"
    +
    +#. module: crm_claim
    +#: field:crm.claim.report,date_closed:0
    +msgid "Close Date"
    +msgstr "结束日期"
    +
    +#. module: crm_claim
    +#: view:crm.claim.report:0
    +msgid "   Month   "
    +msgstr "   月   "
    +
    +#. module: crm_claim
    +#: field:crm.claim,ref:0
    +msgid "Reference"
    +msgstr "参考"
    +
    +#. module: crm_claim
    +#: field:crm.claim,action_next:0
    +msgid "Next Action"
    +msgstr "下一动作"
    +
    +#. module: crm_claim
    +#: view:crm.claim:0
    +msgid "Reset to Draft"
    +msgstr "重置为草稿"
    +
    +#. module: crm_claim
    +#: view:crm.claim:0
    +#: field:crm.claim,date_deadline:0
    +#: field:crm.claim.report,date_deadline:0
    +msgid "Deadline"
    +msgstr "截止日期"
    +
    +#. module: crm_claim
    +#: view:crm.claim:0
    +#: field:crm.claim,partner_id:0
    +#: view:crm.claim.report:0
    +#: field:crm.claim.report,partner_id:0
    +msgid "Partner"
    +msgstr "业务伙伴"
    +
    +#. module: crm_claim
    +#: selection:crm.claim,type_action:0
    +#: selection:crm.claim.report,type_action:0
    +msgid "Preventive Action"
    +msgstr "预防性动作"
    +
    +#. module: crm_claim
    +#: field:crm.claim.report,section_id:0
    +msgid "Section"
    +msgstr "分类"
    +
    +#. module: crm_claim
    +#: view:crm.claim:0
    +msgid "Root Causes"
    +msgstr "根本原因"
    +
    +#. module: crm_claim
    +#: field:crm.claim,user_fault:0
    +msgid "Trouble Responsible"
    +msgstr "故障责任"
    +
    +#. module: crm_claim
    +#: field:crm.claim,priority:0
    +#: view:crm.claim.report:0
    +#: field:crm.claim.report,priority:0
    +msgid "Priority"
    +msgstr "优先级"
    +
    +#. module: crm_claim
    +#: view:crm.claim:0
    +msgid "Send New Email"
    +msgstr "发送新的电子邮件"
    +
    +#. module: crm_claim
    +#: field:crm.claim.report,delay_expected:0
    +msgid "Overpassed Deadline"
    +msgstr "超越截止日期"
    +
    +#. module: crm_claim
    +#: view:crm.claim:0
    +#: view:crm.claim.report:0
    +msgid "Type"
    +msgstr "类型:"
    +
    +#. module: crm_claim
    +#: field:crm.claim,email_from:0
    +msgid "Email"
    +msgstr "电子邮件"
    +
    +#. module: crm_claim
    +#: selection:crm.claim,priority:0
    +#: selection:crm.claim.report,priority:0
    +msgid "Lowest"
    +msgstr "最低"
    +
    +#. module: crm_claim
    +#: field:crm.claim,create_date:0
    +msgid "Creation Date"
    +msgstr "创建日期"
    +
    +#. module: crm_claim
    +#: field:crm.claim,name:0
    +msgid "Claim Subject"
    +msgstr "索赔主题"
    +
    +#. module: crm_claim
    +#: model:ir.actions.act_window,help:crm_claim.action_report_crm_claim
    +msgid ""
    +"Have a general overview of all claims processed in the system by sorting "
    +"them with specific criteria."
    +msgstr "所有索赔都有一个一般描述在系统里还对它们按具体的标准分类。"
    +
    +#. module: crm_claim
    +#: selection:crm.claim.report,month:0
    +msgid "July"
    +msgstr "7月"
    +
    +#. module: crm_claim
    +#: model:ir.actions.act_window,name:crm_claim.crm_claim_stage_act
    +msgid "Claim Stages"
    +msgstr "索赔阶段"
    +
    +#. module: crm_claim
    +#: model:ir.ui.menu,name:crm_claim.menu_crm_case_claim-act
    +msgid "Categories"
    +msgstr "类型"
    +
    +#. module: crm_claim
    +#: view:crm.claim:0
    +#: field:crm.claim,stage_id:0
    +#: view:crm.claim.report:0
    +#: field:crm.claim.report,stage_id:0
    +msgid "Stage"
    +msgstr "阶段"
    +
    +#. module: crm_claim
    +#: view:crm.claim:0
    +msgid "History Information"
    +msgstr "日志信息"
    +
    +#. module: crm_claim
    +#: view:crm.claim:0
    +msgid "Dates"
    +msgstr "日期"
    +
    +#. module: crm_claim
    +#: view:crm.claim.report:0
    +msgid "    Month-1    "
    +msgstr "    上月    "
    +
    +#. module: crm_claim
    +#: view:crm.claim:0
    +msgid "Contact"
    +msgstr "联系方式"
    +
    +#. module: crm_claim
    +#: model:ir.ui.menu,name:crm_claim.menu_crm_claim_stage_act
    +msgid "Stages"
    +msgstr "阶段"
    +
    +#. module: crm_claim
    +#: model:ir.ui.menu,name:crm_claim.menu_report_crm_claim_tree
    +msgid "Claims Analysis"
    +msgstr "索赔分析"
    +
    +#. module: crm_claim
    +#: help:crm.claim.report,delay_close:0
    +msgid "Number of Days to close the case"
    +msgstr "到期天数"
    +
    +#. module: crm_claim
    +#: model:ir.model,name:crm_claim.model_crm_claim_report
    +msgid "CRM Claim Report"
    +msgstr "客户关系管理索赔报表"
    +
    +#. module: crm_claim
    +#: model:crm.case.stage,name:crm_claim.stage_claim1
    +msgid "Accepted as Claim"
    +msgstr "作为索赔接受"
    +
    +#. module: crm_claim
    +#: model:crm.case.resource.type,name:crm_claim.type_claim1
    +msgid "Corrective"
    +msgstr "纠正"
    +
    +#. module: crm_claim
    +#: selection:crm.claim.report,month:0
    +msgid "September"
    +msgstr "9月"
    +
    +#. module: crm_claim
    +#: selection:crm.claim.report,month:0
    +msgid "December"
    +msgstr "12月"
    +
    +#. module: crm_claim
    +#: view:crm.claim.report:0
    +#: field:crm.claim.report,month:0
    +msgid "Month"
    +msgstr "月"
    +
    +#. module: crm_claim
    +#: field:crm.claim,type_action:0
    +#: field:crm.claim.report,type_action:0
    +msgid "Action Type"
    +msgstr "动作类型"
    +
    +#. module: crm_claim
    +#: field:crm.claim,write_date:0
    +msgid "Update Date"
    +msgstr "更新日期"
    +
    +#. module: crm_claim
    +#: view:crm.claim.report:0
    +msgid "Salesman"
    +msgstr "业务员"
    +
    +#. module: crm_claim
    +#: field:crm.claim,categ_id:0
    +#: view:crm.claim.report:0
    +#: field:crm.claim.report,categ_id:0
    +msgid "Category"
    +msgstr "类型"
    +
    +#. module: crm_claim
    +#: model:crm.case.categ,name:crm_claim.categ_claim2
    +msgid "Value Claims"
    +msgstr "索赔金额"
    +
    +#. module: crm_claim
    +#: view:crm.claim.report:0
    +msgid "  Year  "
    +msgstr "  年  "
    +
    +#. module: crm_claim
    +#: help:crm.claim,email_cc:0
    +msgid ""
    +"These email addresses will be added to the CC field of all inbound and "
    +"outbound emails for this record before being sent. Separate multiple email "
    +"addresses with a comma"
    +msgstr "这些邮件地址将添加到之前发送记录的发送和接收邮件的抄送字段,分隔多个邮件地址有逗号。"
    +
    +#. module: crm_claim
    +#: selection:crm.claim,state:0
    +#: view:crm.claim.report:0
    +#: selection:crm.claim.report,state:0
    +msgid "Draft"
    +msgstr "草稿"
    +
    +#. module: crm_claim
    +#: selection:crm.claim,priority:0
    +#: selection:crm.claim.report,priority:0
    +msgid "Low"
    +msgstr "低"
    +
    +#. module: crm_claim
    +#: field:crm.claim,date_closed:0
    +#: selection:crm.claim,state:0
    +#: selection:crm.claim.report,state:0
    +msgid "Closed"
    +msgstr "已结束"
    +
    +#. module: crm_claim
    +#: view:crm.claim:0
    +#: selection:crm.claim,state:0
    +#: view:crm.claim.report:0
    +#: selection:crm.claim.report,state:0
    +msgid "Pending"
    +msgstr "待定中"
    +
    +#. module: crm_claim
    +#: view:crm.claim:0
    +msgid "Communication & History"
    +msgstr "沟通&日志"
    +
    +#. module: crm_claim
    +#: selection:crm.claim.report,month:0
    +msgid "August"
    +msgstr "8月"
    +
    +#. module: crm_claim
    +#: selection:crm.claim,priority:0
    +#: selection:crm.claim.report,priority:0
    +msgid "Normal"
    +msgstr "普通"
    +
    +#. module: crm_claim
    +#: view:crm.claim:0
    +msgid "Global CC"
    +msgstr "完整抄送"
    +
    +#. module: crm_claim
    +#: model:ir.module.module,shortdesc:crm_claim.module_meta_information
    +msgid "Customer & Supplier Relationship Management"
    +msgstr "客户&供应商关系管理"
    +
    +#. module: crm_claim
    +#: selection:crm.claim.report,month:0
    +msgid "June"
    +msgstr "6月"
    +
    +#. module: crm_claim
    +#: field:crm.claim,partner_phone:0
    +msgid "Phone"
    +msgstr "电话"
    +
    +#. module: crm_claim
    +#: field:crm.claim.report,user_id:0
    +msgid "User"
    +msgstr "用户"
    +
    +#. module: crm_claim
    +#: model:crm.case.stage,name:crm_claim.stage_claim5
    +msgid "Awaiting Response"
    +msgstr "等待回复"
    +
    +#. module: crm_claim
    +#: model:ir.actions.act_window,name:crm_claim.crm_claim_categ_action
    +msgid "Claim Categories"
    +msgstr "索赔类型"
    +
    +#. module: crm_claim
    +#: selection:crm.claim.report,month:0
    +msgid "November"
    +msgstr "11月"
    +
    +#. module: crm_claim
    +#: view:crm.claim.report:0
    +msgid "Extended Filters..."
    +msgstr "扩展过滤..."
    +
    +#. module: crm_claim
    +#: view:crm.claim:0
    +msgid "Closure"
    +msgstr "关闭"
    +
    +#. module: crm_claim
    +#: view:crm.claim.report:0
    +msgid "Search"
    +msgstr "查找"
    +
    +#. module: crm_claim
    +#: selection:crm.claim.report,month:0
    +msgid "October"
    +msgstr "10月"
    +
    +#. module: crm_claim
    +#: model:ir.module.module,description:crm_claim.module_meta_information
    +msgid ""
    +"\n"
    +"This modules allows you to track your customers/suppliers claims and "
    +"flames.\n"
    +"It is fully integrated with the email gateway so that you can create\n"
    +"automatically new claims based on incoming emails.\n"
    +"    "
    +msgstr ""
    +"\n"
    +"这模块能跟踪你客户和供应商索赔和不满,它是全面整合在电子邮件的网关中,所以你能基于收到的邮件自动创建新的索赔\n"
    +"    "
    +
    +#. module: crm_claim
    +#: selection:crm.claim.report,month:0
    +msgid "January"
    +msgstr "1月"
    +
    +#. module: crm_claim
    +#: view:crm.claim:0
    +#: field:crm.claim,date:0
    +msgid "Claim Date"
    +msgstr "索赔日期"
    +
    +#. module: crm_claim
    +#: help:crm.claim,email_from:0
    +msgid "These people will receive email."
    +msgstr "这些人将收到电子邮件。"
    +
    +#. module: crm_claim
    +#: view:crm.claim:0
    +#: view:crm.claim.report:0
    +#: model:ir.actions.act_window,name:crm_claim.action_report_crm_claim
    +#: model:ir.actions.act_window,name:crm_claim.crm_case_categ_claim0
    +#: model:ir.ui.menu,name:crm_claim.menu_crm_case_claims
    +msgid "Claims"
    +msgstr "索赔"
    +
    +#. module: crm_claim
    +#: selection:crm.claim,type_action:0
    +#: selection:crm.claim.report,type_action:0
    +msgid "Corrective Action"
    +msgstr "纠正的动作"
    +
    +#. module: crm_claim
    +#: model:crm.case.categ,name:crm_claim.categ_claim3
    +msgid "Policy Claims"
    +msgstr "保险单索赔"
    +
    +#. module: crm_claim
    +#: view:crm.claim:0
    +msgid "History"
    +msgstr "日志"
    +
    +#. module: crm_claim
    +#: model:ir.model,name:crm_claim.model_crm_claim
    +#: model:ir.ui.menu,name:crm_claim.menu_config_claim
    +msgid "Claim"
    +msgstr "索赔"
    +
    +#. module: crm_claim
    +#: view:crm.claim:0
    +msgid "Attachments"
    +msgstr "附件"
    +
    +#. module: crm_claim
    +#: model:ir.model,name:crm_claim.model_crm_case_stage
    +msgid "Stage of case"
    +msgstr "业务阶段"
    +
    +#. module: crm_claim
    +#: view:crm.claim:0
    +#: field:crm.claim,state:0
    +#: view:crm.claim.report:0
    +#: field:crm.claim.report,state:0
    +msgid "State"
    +msgstr "州/省"
    +
    +#. module: crm_claim
    +#: view:crm.claim:0
    +#: view:crm.claim.report:0
    +msgid "Done"
    +msgstr "完成"
    +
    +#. module: crm_claim
    +#: view:crm.claim:0
    +msgid "Claim Reporter"
    +msgstr "索赔记者"
    +
    +#. module: crm_claim
    +#: view:crm.claim:0
    +#: view:crm.claim.report:0
    +msgid "Cancel"
    +msgstr "取消"
    +
    +#. module: crm_claim
    +#: view:crm.claim:0
    +msgid "Close"
    +msgstr "结束"
    +
    +#. module: crm_claim
    +#: view:crm.claim:0
    +#: selection:crm.claim,state:0
    +#: view:crm.claim.report:0
    +#: selection:crm.claim.report,state:0
    +msgid "Open"
    +msgstr "开启"
    +
    +#. module: crm_claim
    +#: view:crm.claim:0
    +msgid "In Progress"
    +msgstr "进行中"
    +
    +#. module: crm_claim
    +#: view:crm.claim:0
    +#: field:crm.claim,user_id:0
    +msgid "Responsible"
    +msgstr "负责人"
    +
    +#. module: crm_claim
    +#: view:crm.claim:0
    +msgid "Current"
    +msgstr "当前的"
    +
    +#. module: crm_claim
    +#: view:crm.claim:0
    +msgid "Details"
    +msgstr "明细行"
    +
    +#. module: crm_claim
    +#: view:crm.claim:0
    +msgid "Reply"
    +msgstr "回复"
    +
    +#. module: crm_claim
    +#: field:crm.claim,cause:0
    +msgid "Root Cause"
    +msgstr "根本原因"
    +
    +#. module: crm_claim
    +#: view:crm.claim:0
    +msgid "Claim/Action Description"
    +msgstr "索赔/动作说明"
    +
    +#. module: crm_claim
    +#: field:crm.claim,description:0
    +msgid "Description"
    +msgstr ""
    +
    +#. module: crm_claim
    +#: view:crm.claim:0
    +msgid "Search Claims"
    +msgstr ""
    +
    +#. module: crm_claim
    +#: field:crm.claim,section_id:0
    +#: view:crm.claim.report:0
    +msgid "Sales Team"
    +msgstr ""
    +
    +#. module: crm_claim
    +#: selection:crm.claim.report,month:0
    +msgid "May"
    +msgstr ""
    +
    +#. module: crm_claim
    +#: view:crm.claim:0
    +msgid "Resolution Actions"
    +msgstr ""
    +
    +#. module: crm_claim
    +#: model:ir.actions.act_window,name:crm_claim.act_claim_partner
    +#: model:ir.actions.act_window,name:crm_claim.act_claim_partner_address
    +msgid "Report a Claim"
    +msgstr ""
    +
    +#. module: crm_claim
    +#: model:ir.actions.act_window,help:crm_claim.crm_case_categ_claim0
    +msgid ""
    +"Record and track your customers' claims. Claims may be linked to a sales "
    +"order or a lot. You can send emails with attachments and keep the full "
    +"history for a claim (emails sent, intervention type and so on). Claims may "
    +"automatically be linked to an email address using the mail gateway module."
    +msgstr ""
    +
    +#. module: crm_claim
    +#: field:crm.claim.report,email:0
    +msgid "# Emails"
    +msgstr ""
    +
    +#. module: crm_claim
    +#: view:crm.claim:0
    +msgid "Follow Up"
    +msgstr ""
    +
    +#. module: crm_claim
    +#: help:crm.claim,state:0
    +msgid ""
    +"The state is set to 'Draft', when a case is created.                         "
    +"         \n"
    +"If the case is in progress the state is set to 'Open'.                       "
    +"           \n"
    +"When the case is over, the state is set to 'Done'.                           "
    +"       \n"
    +"If the case needs to be reviewed then the state is set to 'Pending'."
    +msgstr ""
    +
    +#. module: crm_claim
    +#: selection:crm.claim.report,month:0
    +msgid "February"
    +msgstr ""
    +
    +#. module: crm_claim
    +#: model:crm.case.stage,name:crm_claim.stage_claim3
    +msgid "Won't fix"
    +msgstr ""
    +
    +#. module: crm_claim
    +#: selection:crm.claim.report,month:0
    +msgid "April"
    +msgstr ""
    +
    +#. module: crm_claim
    +#: view:crm.claim.report:0
    +msgid "My Case(s)"
    +msgstr ""
    +
    +#. module: crm_claim
    +#: field:crm.claim,id:0
    +msgid "ID"
    +msgstr ""
    +
    +#. module: crm_claim
    +#: view:crm.claim:0
    +msgid "Actions"
    +msgstr ""
    +
    +#. module: crm_claim
    +#: selection:crm.claim,priority:0
    +#: selection:crm.claim.report,priority:0
    +msgid "High"
    +msgstr ""
    +
    +#. module: crm_claim
    +#: model:ir.actions.act_window,help:crm_claim.crm_claim_categ_action
    +msgid ""
    +"Create claim categories to better manage and classify your claims. Some "
    +"example of claims can be: preventive action, corrective action."
    +msgstr ""
    +
    +#. module: crm_claim
    +#: field:crm.claim.report,create_date:0
    +msgid "Create Date"
    +msgstr ""
    +
    +#. module: crm_claim
    +#: view:crm.claim.report:0
    +#: field:crm.claim.report,name:0
    +msgid "Year"
    +msgstr ""
    diff --git a/addons/crm_helpdesk/i18n/zh_CN.po b/addons/crm_helpdesk/i18n/zh_CN.po
    new file mode 100644
    index 00000000000..1fa48f7ef09
    --- /dev/null
    +++ b/addons/crm_helpdesk/i18n/zh_CN.po
    @@ -0,0 +1,697 @@
    +# Chinese (Simplified) translation for openobject-addons
    +# Copyright (c) 2011 Rosetta Contributors and Canonical Ltd 2011
    +# This file is distributed under the same license as the openobject-addons package.
    +# FIRST AUTHOR , 2011.
    +#
    +msgid ""
    +msgstr ""
    +"Project-Id-Version: openobject-addons\n"
    +"Report-Msgid-Bugs-To: FULL NAME \n"
    +"POT-Creation-Date: 2011-01-11 11:15+0000\n"
    +"PO-Revision-Date: 2011-04-10 16:23+0000\n"
    +"Last-Translator: FULL NAME \n"
    +"Language-Team: Chinese (Simplified) \n"
    +"MIME-Version: 1.0\n"
    +"Content-Type: text/plain; charset=UTF-8\n"
    +"Content-Transfer-Encoding: 8bit\n"
    +"X-Launchpad-Export-Date: 2011-04-11 05:43+0000\n"
    +"X-Generator: Launchpad (build 12735)\n"
    +
    +#. module: crm_helpdesk
    +#: field:crm.helpdesk.report,delay_close:0
    +msgid "Delay to Close"
    +msgstr "延迟关闭"
    +
    +#. module: crm_helpdesk
    +#: field:crm.helpdesk.report,nbr:0
    +msgid "# of Cases"
    +msgstr "# 业务"
    +
    +#. module: crm_helpdesk
    +#: view:crm.helpdesk:0
    +#: view:crm.helpdesk.report:0
    +msgid "Group By..."
    +msgstr "分组..."
    +
    +#. module: crm_helpdesk
    +#: view:crm.helpdesk:0
    +msgid "Today"
    +msgstr "今日"
    +
    +#. module: crm_helpdesk
    +#: selection:crm.helpdesk.report,month:0
    +msgid "March"
    +msgstr "3月"
    +
    +#. module: crm_helpdesk
    +#: field:crm.helpdesk,company_id:0
    +#: view:crm.helpdesk.report:0
    +#: field:crm.helpdesk.report,company_id:0
    +msgid "Company"
    +msgstr "公司"
    +
    +#. module: crm_helpdesk
    +#: field:crm.helpdesk,email_cc:0
    +msgid "Watchers Emails"
    +msgstr "关注者的电子邮件"
    +
    +#. module: crm_helpdesk
    +#: selection:crm.helpdesk,priority:0
    +#: selection:crm.helpdesk.report,priority:0
    +msgid "Highest"
    +msgstr "最高"
    +
    +#. module: crm_helpdesk
    +#: view:crm.helpdesk.report:0
    +#: field:crm.helpdesk.report,day:0
    +msgid "Day"
    +msgstr "日"
    +
    +#. module: crm_helpdesk
    +#: view:crm.helpdesk:0
    +msgid "Add Internal Note"
    +msgstr "添加内部备注"
    +
    +#. module: crm_helpdesk
    +#: view:crm.helpdesk:0
    +msgid "Notes"
    +msgstr "备注"
    +
    +#. module: crm_helpdesk
    +#: field:crm.helpdesk,message_ids:0
    +msgid "Messages"
    +msgstr "消息"
    +
    +#. module: crm_helpdesk
    +#: selection:crm.helpdesk,state:0
    +#: selection:crm.helpdesk.report,state:0
    +msgid "Cancelled"
    +msgstr "已取消"
    +
    +#. module: crm_helpdesk
    +#: field:crm.helpdesk,partner_address_id:0
    +msgid "Partner Contact"
    +msgstr "业务伙伴联系方式"
    +
    +#. module: crm_helpdesk
    +#: model:ir.ui.menu,name:crm_helpdesk.menu_report_crm_helpdesks_tree
    +msgid "Helpdesk Analysis"
    +msgstr "服务台分析"
    +
    +#. module: crm_helpdesk
    +#: view:crm.helpdesk.report:0
    +#: field:crm.helpdesk.report,date_closed:0
    +msgid "Close Date"
    +msgstr "结束日期"
    +
    +#. module: crm_helpdesk
    +#: view:crm.helpdesk.report:0
    +msgid "   Month   "
    +msgstr "   月   "
    +
    +#. module: crm_helpdesk
    +#: field:crm.helpdesk,ref:0
    +msgid "Reference"
    +msgstr "参考"
    +
    +#. module: crm_helpdesk
    +#: field:crm.helpdesk,date_action_next:0
    +msgid "Next Action"
    +msgstr "下一动作"
    +
    +#. module: crm_helpdesk
    +#: view:crm.helpdesk:0
    +msgid "Helpdesk Supports"
    +msgstr "服务台支持"
    +
    +#. module: crm_helpdesk
    +#: view:crm.helpdesk:0
    +msgid "Extra Info"
    +msgstr "额外信息"
    +
    +#. module: crm_helpdesk
    +#: view:crm.helpdesk:0
    +#: field:crm.helpdesk,partner_id:0
    +#: view:crm.helpdesk.report:0
    +#: field:crm.helpdesk.report,partner_id:0
    +msgid "Partner"
    +msgstr "业务伙伴"
    +
    +#. module: crm_helpdesk
    +#: view:crm.helpdesk:0
    +msgid "Estimates"
    +msgstr "估计"
    +
    +#. module: crm_helpdesk
    +#: field:crm.helpdesk.report,section_id:0
    +msgid "Section"
    +msgstr "分类"
    +
    +#. module: crm_helpdesk
    +#: view:crm.helpdesk:0
    +#: field:crm.helpdesk,priority:0
    +#: view:crm.helpdesk.report:0
    +#: field:crm.helpdesk.report,priority:0
    +msgid "Priority"
    +msgstr "优先级"
    +
    +#. module: crm_helpdesk
    +#: view:crm.helpdesk:0
    +msgid "Send New Email"
    +msgstr "发送新的电子邮件"
    +
    +#. module: crm_helpdesk
    +#: view:crm.helpdesk.report:0
    +msgid "Won"
    +msgstr "获得"
    +
    +#. module: crm_helpdesk
    +#: field:crm.helpdesk.report,delay_expected:0
    +msgid "Overpassed Deadline"
    +msgstr "超越截止日期"
    +
    +#. module: crm_helpdesk
    +#: model:ir.model,name:crm_helpdesk.model_crm_helpdesk_report
    +msgid "Helpdesk report after Sales Services"
    +msgstr "售后服务服务台报表"
    +
    +#. module: crm_helpdesk
    +#: field:crm.helpdesk,email_from:0
    +msgid "Email"
    +msgstr "电子邮件"
    +
    +#. module: crm_helpdesk
    +#: field:crm.helpdesk,canal_id:0
    +#: view:crm.helpdesk.report:0
    +#: field:crm.helpdesk.report,canal_id:0
    +msgid "Channel"
    +msgstr "途径"
    +
    +#. module: crm_helpdesk
    +#: selection:crm.helpdesk,priority:0
    +#: selection:crm.helpdesk.report,priority:0
    +msgid "Lowest"
    +msgstr "最低"
    +
    +#. module: crm_helpdesk
    +#: view:crm.helpdesk.report:0
    +msgid "# Mails"
    +msgstr "邮件"
    +
    +#. module: crm_helpdesk
    +#: field:crm.helpdesk,create_date:0
    +#: field:crm.helpdesk.report,create_date:0
    +msgid "Creation Date"
    +msgstr "创建日期"
    +
    +#. module: crm_helpdesk
    +#: view:crm.helpdesk:0
    +msgid "Reset to Draft"
    +msgstr "重置为草稿"
    +
    +#. module: crm_helpdesk
    +#: view:crm.helpdesk:0
    +#: selection:crm.helpdesk,state:0
    +#: selection:crm.helpdesk.report,state:0
    +msgid "Pending"
    +msgstr "待处理"
    +
    +#. module: crm_helpdesk
    +#: view:crm.helpdesk:0
    +#: field:crm.helpdesk,date_deadline:0
    +#: field:crm.helpdesk.report,date_deadline:0
    +msgid "Deadline"
    +msgstr "截止日期"
    +
    +#. module: crm_helpdesk
    +#: selection:crm.helpdesk.report,month:0
    +msgid "July"
    +msgstr "7月"
    +
    +#. module: crm_helpdesk
    +#: model:ir.actions.act_window,name:crm_helpdesk.crm_helpdesk_categ_action
    +msgid "Helpdesk Categories"
    +msgstr "服务台类型"
    +
    +#. module: crm_helpdesk
    +#: model:ir.ui.menu,name:crm_helpdesk.menu_crm_case_helpdesk-act
    +msgid "Categories"
    +msgstr "类型"
    +
    +#. module: crm_helpdesk
    +#: view:crm.helpdesk:0
    +msgid "History Information"
    +msgstr "日志信息"
    +
    +#. module: crm_helpdesk
    +#: view:crm.helpdesk:0
    +msgid "Dates"
    +msgstr "日期"
    +
    +#. module: crm_helpdesk
    +#: view:crm.helpdesk.report:0
    +msgid "    Month-1    "
    +msgstr "    上月    "
    +
    +#. module: crm_helpdesk
    +#: view:crm.helpdesk.report:0
    +msgid "#Helpdesk"
    +msgstr "服务台"
    +
    +#. module: crm_helpdesk
    +#: help:crm.helpdesk,email_cc:0
    +msgid ""
    +"These email addresses will be added to the CC field of all inbound and "
    +"outbound emails for this record before being sent. Separate multiple email "
    +"addresses with a comma"
    +msgstr "这些邮件地址将添加到之前发送记录的发送和接收邮件的抄送字段,分隔多个邮件地址有逗号。"
    +
    +#. module: crm_helpdesk
    +#: view:crm.helpdesk:0
    +msgid "References"
    +msgstr "参考"
    +
    +#. module: crm_helpdesk
    +#: selection:crm.helpdesk.report,month:0
    +msgid "September"
    +msgstr "9月"
    +
    +#. module: crm_helpdesk
    +#: view:crm.helpdesk:0
    +msgid "Communication"
    +msgstr "沟通"
    +
    +#. module: crm_helpdesk
    +#: view:crm.helpdesk.report:0
    +#: field:crm.helpdesk.report,month:0
    +msgid "Month"
    +msgstr "月份"
    +
    +#. module: crm_helpdesk
    +#: view:crm.helpdesk:0
    +msgid "Escalate"
    +msgstr "提升"
    +
    +#. module: crm_helpdesk
    +#: field:crm.helpdesk,write_date:0
    +msgid "Update Date"
    +msgstr "更新日期"
    +
    +#. module: crm_helpdesk
    +#: view:crm.helpdesk:0
    +msgid "Query"
    +msgstr "查询"
    +
    +#. module: crm_helpdesk
    +#: view:crm.helpdesk.report:0
    +msgid "Salesman"
    +msgstr "业务员"
    +
    +#. module: crm_helpdesk
    +#: field:crm.helpdesk,ref2:0
    +msgid "Reference 2"
    +msgstr "参考2"
    +
    +#. module: crm_helpdesk
    +#: field:crm.helpdesk,categ_id:0
    +#: field:crm.helpdesk.report,categ_id:0
    +msgid "Category"
    +msgstr "类型"
    +
    +#. module: crm_helpdesk
    +#: view:crm.helpdesk.report:0
    +msgid "  Year  "
    +msgstr "  年  "
    +
    +#. module: crm_helpdesk
    +#: view:crm.helpdesk:0
    +msgid "Helpdesk Support"
    +msgstr ""
    +
    +#. module: crm_helpdesk
    +#: field:crm.helpdesk,planned_cost:0
    +#: field:crm.helpdesk.report,planned_cost:0
    +msgid "Planned Costs"
    +msgstr "计划成本"
    +
    +#. module: crm_helpdesk
    +#: model:ir.module.module,description:crm_helpdesk.module_meta_information
    +msgid "Helpdesk Management"
    +msgstr "服务台管理"
    +
    +#. module: crm_helpdesk
    +#: view:crm.helpdesk:0
    +msgid "Search Helpdesk"
    +msgstr "查询服务台"
    +
    +#. module: crm_helpdesk
    +#: selection:crm.helpdesk,state:0
    +#: selection:crm.helpdesk.report,state:0
    +msgid "Draft"
    +msgstr "草稿"
    +
    +#. module: crm_helpdesk
    +#: selection:crm.helpdesk,priority:0
    +#: selection:crm.helpdesk.report,priority:0
    +msgid "Low"
    +msgstr "低"
    +
    +#. module: crm_helpdesk
    +#: field:crm.helpdesk,date_closed:0
    +#: selection:crm.helpdesk,state:0
    +#: selection:crm.helpdesk.report,state:0
    +msgid "Closed"
    +msgstr "已结束"
    +
    +#. module: crm_helpdesk
    +#: view:crm.helpdesk:0
    +msgid "7 Days"
    +msgstr "7天"
    +
    +#. module: crm_helpdesk
    +#: view:crm.helpdesk:0
    +msgid "Communication & History"
    +msgstr "沟通&日志"
    +
    +#. module: crm_helpdesk
    +#: selection:crm.helpdesk.report,month:0
    +msgid "August"
    +msgstr "8月"
    +
    +#. module: crm_helpdesk
    +#: selection:crm.helpdesk,priority:0
    +#: selection:crm.helpdesk.report,priority:0
    +msgid "Normal"
    +msgstr "普通"
    +
    +#. module: crm_helpdesk
    +#: view:crm.helpdesk:0
    +msgid "Global CC"
    +msgstr "完整抄送"
    +
    +#. module: crm_helpdesk
    +#: selection:crm.helpdesk.report,month:0
    +msgid "June"
    +msgstr "6月"
    +
    +#. module: crm_helpdesk
    +#: field:crm.helpdesk,planned_revenue:0
    +msgid "Planned Revenue"
    +msgstr "计划收入"
    +
    +#. module: crm_helpdesk
    +#: field:crm.helpdesk.report,user_id:0
    +msgid "User"
    +msgstr "用户"
    +
    +#. module: crm_helpdesk
    +#: field:crm.helpdesk,active:0
    +msgid "Active"
    +msgstr "有效"
    +
    +#. module: crm_helpdesk
    +#: model:ir.module.module,shortdesc:crm_helpdesk.module_meta_information
    +msgid "CRM Helpdesk"
    +msgstr "客户关系管理 服务台"
    +
    +#. module: crm_helpdesk
    +#: view:crm.helpdesk.report:0
    +msgid "Extended Filters..."
    +msgstr "扩展过滤..."
    +
    +#. module: crm_helpdesk
    +#: model:ir.actions.act_window,name:crm_helpdesk.crm_case_helpdesk_act111
    +msgid "Helpdesk Requests"
    +msgstr "服务台请求"
    +
    +#. module: crm_helpdesk
    +#: view:crm.helpdesk.report:0
    +msgid "Search"
    +msgstr "查找"
    +
    +#. module: crm_helpdesk
    +#: selection:crm.helpdesk.report,month:0
    +msgid "October"
    +msgstr "10月"
    +
    +#. module: crm_helpdesk
    +#: selection:crm.helpdesk.report,month:0
    +msgid "January"
    +msgstr "1月"
    +
    +#. module: crm_helpdesk
    +#: help:crm.helpdesk,email_from:0
    +msgid "These people will receive email."
    +msgstr "这些人将收到电子邮件。"
    +
    +#. module: crm_helpdesk
    +#: view:crm.helpdesk:0
    +#: field:crm.helpdesk,date:0
    +msgid "Date"
    +msgstr "日期"
    +
    +#. module: crm_helpdesk
    +#: selection:crm.helpdesk.report,month:0
    +msgid "November"
    +msgstr "11月"
    +
    +#. module: crm_helpdesk
    +#: view:crm.helpdesk:0
    +msgid "History"
    +msgstr "日志"
    +
    +#. module: crm_helpdesk
    +#: view:crm.helpdesk:0
    +msgid "Attachments"
    +msgstr "附件"
    +
    +#. module: crm_helpdesk
    +#: view:crm.helpdesk:0
    +msgid "Misc"
    +msgstr "杂项"
    +
    +#. module: crm_helpdesk
    +#: view:crm.helpdesk:0
    +#: field:crm.helpdesk,state:0
    +#: view:crm.helpdesk.report:0
    +#: field:crm.helpdesk.report,state:0
    +msgid "State"
    +msgstr "州/省"
    +
    +#. module: crm_helpdesk
    +#: view:crm.helpdesk:0
    +msgid "General"
    +msgstr "通用"
    +
    +#. module: crm_helpdesk
    +#: view:crm.helpdesk:0
    +msgid "Send Reminder"
    +msgstr "发送提醒"
    +
    +#. module: crm_helpdesk
    +#: help:crm.helpdesk,section_id:0
    +msgid ""
    +"Sales team to which Case belongs to.                                 Define "
    +"Responsible user and Email account for mail gateway."
    +msgstr "销售团队属于这业务.定义负责用户和电子邮件帐户和网关"
    +
    +#. module: crm_helpdesk
    +#: view:crm.helpdesk:0
    +msgid "Done"
    +msgstr "完成"
    +
    +#. module: crm_helpdesk
    +#: selection:crm.helpdesk.report,month:0
    +msgid "December"
    +msgstr "12月"
    +
    +#. module: crm_helpdesk
    +#: view:crm.helpdesk:0
    +msgid "Cancel"
    +msgstr "取消"
    +
    +#. module: crm_helpdesk
    +#: view:crm.helpdesk:0
    +msgid "Close"
    +msgstr "结束"
    +
    +#. module: crm_helpdesk
    +#: view:crm.helpdesk:0
    +#: selection:crm.helpdesk,state:0
    +#: selection:crm.helpdesk.report,state:0
    +msgid "Open"
    +msgstr "开启"
    +
    +#. module: crm_helpdesk
    +#: view:crm.helpdesk:0
    +msgid "Helpdesk Support Tree"
    +msgstr "服务台支持树"
    +
    +#. module: crm_helpdesk
    +#: view:crm.helpdesk:0
    +msgid "Categorization"
    +msgstr "归类"
    +
    +#. module: crm_helpdesk
    +#: view:crm.helpdesk.report:0
    +#: model:ir.actions.act_window,name:crm_helpdesk.action_report_crm_helpdesk
    +#: model:ir.model,name:crm_helpdesk.model_crm_helpdesk
    +#: model:ir.ui.menu,name:crm_helpdesk.menu_config_helpdesk
    +msgid "Helpdesk"
    +msgstr "服务台"
    +
    +#. module: crm_helpdesk
    +#: view:crm.helpdesk:0
    +#: field:crm.helpdesk,user_id:0
    +msgid "Responsible"
    +msgstr "负责人"
    +
    +#. module: crm_helpdesk
    +#: view:crm.helpdesk.report:0
    +msgid "Current"
    +msgstr "当前的"
    +
    +#. module: crm_helpdesk
    +#: view:crm.helpdesk:0
    +msgid "Details"
    +msgstr "明细行"
    +
    +#. module: crm_helpdesk
    +#: view:crm.helpdesk:0
    +msgid "Reply"
    +msgstr "回复"
    +
    +#. module: crm_helpdesk
    +#: field:crm.helpdesk,description:0
    +msgid "Description"
    +msgstr "说明"
    +
    +#. module: crm_helpdesk
    +#: selection:crm.helpdesk.report,month:0
    +msgid "May"
    +msgstr "5月"
    +
    +#. module: crm_helpdesk
    +#: field:crm.helpdesk,probability:0
    +msgid "Probability (%)"
    +msgstr "概率(%)"
    +
    +#. module: crm_helpdesk
    +#: field:crm.helpdesk.report,email:0
    +msgid "# Emails"
    +msgstr "电子邮件"
    +
    +#. module: crm_helpdesk
    +#: model:ir.actions.act_window,help:crm_helpdesk.action_report_crm_helpdesk
    +msgid ""
    +"Have a general overview of all support requests by sorting them with "
    +"specific criteria such as the processing time, number of requests answered, "
    +"emails sent and costs."
    +msgstr "所有的支持请求都有分类,具体标准都有大致的描述如: 处理时间,请求回复的次数,邮件的发送成本."
    +
    +#. module: crm_helpdesk
    +#: help:crm.helpdesk,canal_id:0
    +msgid ""
    +"The channels represent the different communication  modes available with the "
    +"customer."
    +msgstr "途径代表与客户沟通的不同方式"
    +
    +#. module: crm_helpdesk
    +#: help:crm.helpdesk,state:0
    +msgid ""
    +"The state is set to 'Draft', when a case is created.                         "
    +"         \n"
    +"If the case is in progress the state is set to 'Open'.                       "
    +"           \n"
    +"When the case is over, the state is set to 'Done'.                           "
    +"       \n"
    +"If the case needs to be reviewed then the state is set to 'Pending'."
    +msgstr ""
    +"当一个业务创建时状态设为'草稿'\n"
    +"如果业务正在处理状态设为'开启'\n"
    +"当业务结束状态设为'完成'\n"
    +"如果业务需要审查状态设为'待定'"
    +
    +#. module: crm_helpdesk
    +#: selection:crm.helpdesk.report,month:0
    +msgid "February"
    +msgstr "2月"
    +
    +#. module: crm_helpdesk
    +#: field:crm.helpdesk,name:0
    +msgid "Name"
    +msgstr "名称"
    +
    +#. module: crm_helpdesk
    +#: view:crm.helpdesk.report:0
    +msgid "Lost"
    +msgstr "丢失"
    +
    +#. module: crm_helpdesk
    +#: model:ir.ui.menu,name:crm_helpdesk.menu_help_support_main
    +msgid "Helpdesk and Support"
    +msgstr "服务台和支持"
    +
    +#. module: crm_helpdesk
    +#: selection:crm.helpdesk.report,month:0
    +msgid "April"
    +msgstr "4月"
    +
    +#. module: crm_helpdesk
    +#: view:crm.helpdesk.report:0
    +msgid "My Case(s)"
    +msgstr "我的业务"
    +
    +#. module: crm_helpdesk
    +#: field:crm.helpdesk,id:0
    +msgid "ID"
    +msgstr ""
    +
    +#. module: crm_helpdesk
    +#: model:ir.actions.act_window,help:crm_helpdesk.crm_helpdesk_categ_action
    +msgid ""
    +"Create and manage helpdesk categories to better manage and classify your "
    +"support requests."
    +msgstr "创建和管理服务台类型去更好管理和分类你的支持的请求"
    +
    +#. module: crm_helpdesk
    +#: selection:crm.helpdesk,priority:0
    +#: selection:crm.helpdesk.report,priority:0
    +msgid "High"
    +msgstr "高"
    +
    +#. module: crm_helpdesk
    +#: view:crm.helpdesk:0
    +#: field:crm.helpdesk,section_id:0
    +#: view:crm.helpdesk.report:0
    +msgid "Sales Team"
    +msgstr "销售团队"
    +
    +#. module: crm_helpdesk
    +#: field:crm.helpdesk,date_action_last:0
    +msgid "Last Action"
    +msgstr "最近动作"
    +
    +#. module: crm_helpdesk
    +#: model:ir.actions.act_window,help:crm_helpdesk.crm_case_helpdesk_act111
    +msgid ""
    +"Helpdesk and Support allow you to track your interventions. Select a "
    +"customer, add notes and categorize interventions with partners if necessary. "
    +"You can also assign a priority level. Use the OpenERP Issues system to "
    +"manage your support activities. Issues can be connected to the email "
    +"gateway: new emails may create issues, each of them automatically gets the "
    +"history of the conversation with the customer."
    +msgstr ""
    +"服务台和支持使你可以去跟踪你的介入.如果需要选择一个客户增加备注和类型介入这业务伙伴.你可以分配一优先级用系统问题模块来管理的的支持活动.问题能链接邮件网"
    +"关.新的邮件可能创建新的问题,它们能自动写入与客户沟通的日志."
    +
    +#. module: crm_helpdesk
    +#: view:crm.helpdesk.report:0
    +#: field:crm.helpdesk.report,name:0
    +msgid "Year"
    +msgstr "年"
    +
    +#. module: crm_helpdesk
    +#: field:crm.helpdesk,duration:0
    +msgid "Duration"
    +msgstr "持续时间"
    diff --git a/addons/document/i18n/gl.po b/addons/document/i18n/gl.po
    index 86a4e404b16..79cec54a03c 100644
    --- a/addons/document/i18n/gl.po
    +++ b/addons/document/i18n/gl.po
    @@ -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: 2011-04-08 06:12+0000\n"
    +"X-Launchpad-Export-Date: 2011-04-09 06:16+0000\n"
     "X-Generator: Launchpad (build 12735)\n"
     
     #. module: document
    diff --git a/addons/document_webdav/i18n/ca.po b/addons/document_webdav/i18n/ca.po
    new file mode 100644
    index 00000000000..0d5c5598849
    --- /dev/null
    +++ b/addons/document_webdav/i18n/ca.po
    @@ -0,0 +1,206 @@
    +# Catalan translation for openobject-addons
    +# Copyright (c) 2011 Rosetta Contributors and Canonical Ltd 2011
    +# This file is distributed under the same license as the openobject-addons package.
    +# FIRST AUTHOR , 2011.
    +#
    +msgid ""
    +msgstr ""
    +"Project-Id-Version: openobject-addons\n"
    +"Report-Msgid-Bugs-To: FULL NAME \n"
    +"POT-Creation-Date: 2011-01-11 11:15+0000\n"
    +"PO-Revision-Date: 2011-04-10 16:26+0000\n"
    +"Last-Translator: FULL NAME \n"
    +"Language-Team: Catalan \n"
    +"MIME-Version: 1.0\n"
    +"Content-Type: text/plain; charset=UTF-8\n"
    +"Content-Transfer-Encoding: 8bit\n"
    +"X-Launchpad-Export-Date: 2011-04-11 05:43+0000\n"
    +"X-Generator: Launchpad (build 12735)\n"
    +
    +#. module: document_webdav
    +#: field:document.webdav.dir.property,create_date:0
    +#: field:document.webdav.file.property,create_date:0
    +msgid "Date Created"
    +msgstr ""
    +
    +#. module: document_webdav
    +#: constraint:document.directory:0
    +msgid "Error! You can not create recursive Directories."
    +msgstr ""
    +
    +#. module: document_webdav
    +#: view:document.webdav.dir.property:0
    +#: view:document.webdav.file.property:0
    +msgid "Search Document properties"
    +msgstr ""
    +
    +#. module: document_webdav
    +#: view:document.webdav.dir.property:0
    +#: field:document.webdav.dir.property,namespace:0
    +#: view:document.webdav.file.property:0
    +#: field:document.webdav.file.property,namespace:0
    +msgid "Namespace"
    +msgstr ""
    +
    +#. module: document_webdav
    +#: field:document.directory,dav_prop_ids:0
    +msgid "DAV properties"
    +msgstr ""
    +
    +#. module: document_webdav
    +#: model:ir.model,name:document_webdav.model_document_webdav_file_property
    +msgid "document.webdav.file.property"
    +msgstr ""
    +
    +#. module: document_webdav
    +#: view:document.webdav.dir.property:0
    +#: view:document.webdav.file.property:0
    +msgid "Group By..."
    +msgstr ""
    +
    +#. module: document_webdav
    +#: view:document.directory:0
    +msgid "These properties will be added to WebDAV requests"
    +msgstr ""
    +
    +#. module: document_webdav
    +#: model:ir.ui.menu,name:document_webdav.menu_file_props
    +msgid "DAV properties for documents"
    +msgstr ""
    +
    +#. module: document_webdav
    +#: code:addons/document_webdav/webdav.py:37
    +#, python-format
    +msgid "PyWebDAV Import Error!"
    +msgstr ""
    +
    +#. module: document_webdav
    +#: view:document.webdav.file.property:0
    +#: field:document.webdav.file.property,file_id:0
    +msgid "Document"
    +msgstr ""
    +
    +#. module: document_webdav
    +#: model:ir.module.module,description:document_webdav.module_meta_information
    +msgid ""
    +" With this module, the WebDAV server for the documents is activated.\n"
    +"        You can then use any compatible browser to remotely see the "
    +"attachments of OpenObject.\n"
    +"\n"
    +"        After installation, the webDAV server can be controlled by a "
    +"[webdav] section in the server's config.\n"
    +"        Server Configuration Parameter:\n"
    +"        [webdav]\n"
    +"        ; enable = True ; Serve webdav over the http(s) servers\n"
    +"        ; vdir = webdav ; the directory that webdav will be served at\n"
    +"          ; this default val means that webdav will be\n"
    +"          ; on \"http://localhost:8069/webdav/\n"
    +"        ; verbose = True ; Turn on the verbose messages of webdav\n"
    +"        ; debug = True ; Turn on the debugging messages of webdav\n"
    +"          ; since the messages are routed to the python logging, with\n"
    +"          ; levels \"debug\" and \"debug_rpc\" respectively, you can leave\n"
    +"          ; these options on\n"
    +msgstr ""
    +
    +#. module: document_webdav
    +#: sql_constraint:document.directory:0
    +msgid "Directory cannot be parent of itself!"
    +msgstr ""
    +
    +#. module: document_webdav
    +#: view:document.directory:0
    +msgid "Dynamic context"
    +msgstr ""
    +
    +#. module: document_webdav
    +#: view:document.directory:0
    +msgid "WebDAV properties"
    +msgstr ""
    +
    +#. module: document_webdav
    +#: sql_constraint:document.directory:0
    +msgid "The directory name must be unique !"
    +msgstr ""
    +
    +#. module: document_webdav
    +#: code:addons/document_webdav/webdav.py:37
    +#, python-format
    +msgid ""
    +"Please install PyWebDAV from "
    +"http://code.google.com/p/pywebdav/downloads/detail?name=PyWebDAV-"
    +"0.9.4.tar.gz&can=2&q=/"
    +msgstr ""
    +
    +#. module: document_webdav
    +#: model:ir.ui.menu,name:document_webdav.menu_dir_props
    +msgid "DAV properties for folders"
    +msgstr ""
    +
    +#. module: document_webdav
    +#: view:document.directory:0
    +#: view:document.webdav.dir.property:0
    +#: view:document.webdav.file.property:0
    +msgid "Properties"
    +msgstr ""
    +
    +#. module: document_webdav
    +#: field:document.webdav.dir.property,name:0
    +#: field:document.webdav.file.property,name:0
    +msgid "Name"
    +msgstr ""
    +
    +#. module: document_webdav
    +#: model:ir.model,name:document_webdav.model_document_webdav_dir_property
    +msgid "document.webdav.dir.property"
    +msgstr ""
    +
    +#. module: document_webdav
    +#: field:document.webdav.dir.property,value:0
    +#: field:document.webdav.file.property,value:0
    +msgid "Value"
    +msgstr ""
    +
    +#. module: document_webdav
    +#: field:document.webdav.dir.property,dir_id:0
    +#: model:ir.model,name:document_webdav.model_document_directory
    +msgid "Directory"
    +msgstr ""
    +
    +#. module: document_webdav
    +#: field:document.webdav.dir.property,write_uid:0
    +#: field:document.webdav.file.property,write_uid:0
    +msgid "Last Modification User"
    +msgstr ""
    +
    +#. module: document_webdav
    +#: view:document.webdav.dir.property:0
    +msgid "Dir"
    +msgstr ""
    +
    +#. module: document_webdav
    +#: field:document.webdav.dir.property,write_date:0
    +#: field:document.webdav.file.property,write_date:0
    +msgid "Date Modified"
    +msgstr ""
    +
    +#. module: document_webdav
    +#: field:document.webdav.dir.property,create_uid:0
    +#: field:document.webdav.file.property,create_uid:0
    +msgid "Creator"
    +msgstr ""
    +
    +#. module: document_webdav
    +#: model:ir.module.module,shortdesc:document_webdav.module_meta_information
    +msgid "WebDAV server for Document Management"
    +msgstr ""
    +
    +#. module: document_webdav
    +#: sql_constraint:document.directory:0
    +msgid "Directory must have a parent or a storage"
    +msgstr ""
    +
    +#. module: document_webdav
    +#: field:document.webdav.dir.property,do_subst:0
    +#: field:document.webdav.file.property,do_subst:0
    +msgid "Substitute"
    +msgstr ""
    diff --git a/addons/fetchmail/i18n/ca.po b/addons/fetchmail/i18n/ca.po
    new file mode 100644
    index 00000000000..80dc00c19a2
    --- /dev/null
    +++ b/addons/fetchmail/i18n/ca.po
    @@ -0,0 +1,317 @@
    +# Catalan translation for openobject-addons
    +# Copyright (c) 2011 Rosetta Contributors and Canonical Ltd 2011
    +# This file is distributed under the same license as the openobject-addons package.
    +# FIRST AUTHOR , 2011.
    +#
    +msgid ""
    +msgstr ""
    +"Project-Id-Version: openobject-addons\n"
    +"Report-Msgid-Bugs-To: FULL NAME \n"
    +"POT-Creation-Date: 2011-01-11 11:15+0000\n"
    +"PO-Revision-Date: 2011-04-10 14:58+0000\n"
    +"Last-Translator: jmartin (Zikzakmedia) \n"
    +"Language-Team: Catalan \n"
    +"MIME-Version: 1.0\n"
    +"Content-Type: text/plain; charset=UTF-8\n"
    +"Content-Transfer-Encoding: 8bit\n"
    +"X-Launchpad-Export-Date: 2011-04-11 05:43+0000\n"
    +"X-Generator: Launchpad (build 12735)\n"
    +
    +#. module: fetchmail
    +#: constraint:email.server:0
    +msgid ""
    +"Warning! Record for selected Model can not be created\n"
    +"Please choose valid Model"
    +msgstr ""
    +"Atenció! No es poden crear registres per al model seleccionat\n"
    +"Seleccioneu un model vàlid"
    +
    +#. module: fetchmail
    +#: selection:email.server,state:0
    +msgid "Confirmed"
    +msgstr "Confirmat"
    +
    +#. module: fetchmail
    +#: view:email.server:0
    +msgid "Confirm"
    +msgstr "Confirma"
    +
    +#. module: fetchmail
    +#: view:email.server:0
    +msgid "Group By..."
    +msgstr "Agrupa per..."
    +
    +#. module: fetchmail
    +#: view:email.server:0
    +#: field:email.server,state:0
    +msgid "State"
    +msgstr "Estat"
    +
    +#. module: fetchmail
    +#: view:email.server:0
    +msgid "POP"
    +msgstr "POP"
    +
    +#. module: fetchmail
    +#: selection:email.server,state:0
    +msgid "Not Confirmed"
    +msgstr "No confirmat"
    +
    +#. module: fetchmail
    +#: field:email.server,user:0
    +msgid "User Name"
    +msgstr "Nom de l'usuari"
    +
    +#. module: fetchmail
    +#: view:email.server:0
    +msgid "Type"
    +msgstr "Tipus"
    +
    +#. module: fetchmail
    +#: view:email.server:0
    +msgid "POP/IMAP Servers"
    +msgstr "Servidores POP/IMAP"
    +
    +#. module: fetchmail
    +#: model:ir.module.module,shortdesc:fetchmail.module_meta_information
    +msgid "Fetchmail Server"
    +msgstr "Servidor Fetchmail"
    +
    +#. module: fetchmail
    +#: view:email.server:0
    +#: field:email.server,note:0
    +msgid "Description"
    +msgstr "Descripció"
    +
    +#. module: fetchmail
    +#: help:email.server,object_id:0
    +msgid ""
    +"OpenObject Model. Generates a record of this model.\n"
    +"Select Object with message_new attrbutes."
    +msgstr ""
    +"Model OpenObject. Genera un registre d'aquest model.\n"
    +"Seleccioneu un objecte amb atributs message_new (nou missatge)."
    +
    +#. module: fetchmail
    +#: field:email.server,attach:0
    +msgid "Add Attachments ?"
    +msgstr "Afegeix adjunts?"
    +
    +#. module: fetchmail
    +#: view:email.server:0
    +msgid "# of emails"
    +msgstr "nombre d'emails"
    +
    +#. module: fetchmail
    +#: model:ir.actions.act_window,name:fetchmail.act_server_history
    +msgid "Email History"
    +msgstr "Historial d'emails"
    +
    +#. module: fetchmail
    +#: field:email.server,user_id:0
    +msgid "User"
    +msgstr "Usuari"
    +
    +#. module: fetchmail
    +#: field:email.server,date:0
    +msgid "Date"
    +msgstr "Data"
    +
    +#. module: fetchmail
    +#: selection:email.server,state:0
    +msgid "Waiting for Verification"
    +msgstr "Esperant verificació"
    +
    +#. module: fetchmail
    +#: field:email.server,password:0
    +msgid "Password"
    +msgstr "Contrasenya"
    +
    +#. module: fetchmail
    +#: view:mailgate.message:0
    +msgid "Emails"
    +msgstr "Emails"
    +
    +#. module: fetchmail
    +#: view:email.server:0
    +msgid "Search Email Servers"
    +msgstr "Buscar servidores de correo"
    +
    +#. module: fetchmail
    +#: view:email.server:0
    +msgid "Server & Login"
    +msgstr "Servidor i connexió"
    +
    +#. module: fetchmail
    +#: view:email.server:0
    +msgid "Auto Reply?"
    +msgstr "¿Auto responder?"
    +
    +#. module: fetchmail
    +#: field:email.server,name:0
    +msgid "Name"
    +msgstr "Nom"
    +
    +#. module: fetchmail
    +#: model:ir.model,name:fetchmail.model_mailgate_message
    +msgid "Mailgateway Message"
    +msgstr "Missatge passarel·la de correu"
    +
    +#. module: fetchmail
    +#: model:ir.actions.act_window,name:fetchmail.action_email_server_tree
    +msgid "POP Servers"
    +msgstr "Servidores POP"
    +
    +#. module: fetchmail
    +#: view:email.server:0
    +msgid "Set to Draft"
    +msgstr "Canvia a esborrany"
    +
    +#. module: fetchmail
    +#: field:email.server,message_ids:0
    +#: model:ir.actions.act_window,name:fetchmail.action_view_mail_message_emails
    +msgid "Messages"
    +msgstr "Missatges"
    +
    +#. module: fetchmail
    +#: model:ir.ui.menu,name:fetchmail.menu_action_fetchmail_server_tree
    +msgid "Fetchmail Services"
    +msgstr "Servicios Fetchmail"
    +
    +#. module: fetchmail
    +#: field:email.server,server:0
    +msgid "Server"
    +msgstr "Servidor"
    +
    +#. module: fetchmail
    +#: field:email.server,active:0
    +msgid "Active"
    +msgstr "Actiu"
    +
    +#. module: fetchmail
    +#: view:email.server:0
    +msgid "Process Parameter"
    +msgstr "Paràmetre procés"
    +
    +#. module: fetchmail
    +#: field:email.server,is_ssl:0
    +msgid "SSL ?"
    +msgstr "SSL"
    +
    +#. module: fetchmail
    +#: selection:email.server,type:0
    +#: selection:mailgate.message,server_type:0
    +msgid "IMAP Server"
    +msgstr "Servidor IMAP"
    +
    +#. module: fetchmail
    +#: field:email.server,object_id:0
    +msgid "Model"
    +msgstr "Model"
    +
    +#. module: fetchmail
    +#: view:email.server:0
    +msgid "IMAP"
    +msgstr "IMAP"
    +
    +#. module: fetchmail
    +#: view:email.server:0
    +#: model:ir.model,name:fetchmail.model_email_server
    +msgid "POP/IMAP Server"
    +msgstr "Servidor POP/IMAP"
    +
    +#. module: fetchmail
    +#: constraint:email.server:0
    +msgid "Warning! Can't have duplicate server configuration!"
    +msgstr "¡Aviso! No puede tener la configuración del servidor duplicada."
    +
    +#. module: fetchmail
    +#: field:email.server,type:0
    +#: field:mailgate.message,server_type:0
    +msgid "Server Type"
    +msgstr "Tipus de servidor"
    +
    +#. module: fetchmail
    +#: view:email.server:0
    +msgid "Login Information"
    +msgstr "Informació de connexió"
    +
    +#. module: fetchmail
    +#: view:email.server:0
    +msgid "Server Information"
    +msgstr "Informació del servidor"
    +
    +#. module: fetchmail
    +#: help:email.server,attach:0
    +msgid "Fetches mail with attachments if true."
    +msgstr "Si está marcado, obtiene correo con documentos adjuntos."
    +
    +#. module: fetchmail
    +#: selection:email.server,type:0
    +#: selection:mailgate.message,server_type:0
    +msgid "POP Server"
    +msgstr "Servidor POP"
    +
    +#. module: fetchmail
    +#: field:email.server,port:0
    +msgid "Port"
    +msgstr "Port"
    +
    +#. module: fetchmail
    +#: model:ir.module.module,description:fetchmail.module_meta_information
    +msgid ""
    +"Fetchmail: \n"
    +"    * Fetch email from Pop / IMAP server\n"
    +"    * Support SSL\n"
    +"    * Integrated with all Modules\n"
    +"    * Automatic Email Receive\n"
    +"    * Email based Records (Add, Update)\n"
    +"    "
    +msgstr ""
    +"Fetchmail: \n"
    +"    * Recuperar email des de servidor POP / IMAP\n"
    +"    * Compatibilitat amb SSL\n"
    +"    * Integració amb tots els mòduls\n"
    +"    * Recepció automàtica d'emails\n"
    +"    * Registres basats en email (afegir, actualitzar)\n"
    +"    "
    +
    +#. module: fetchmail
    +#: view:email.server:0
    +msgid "SSL"
    +msgstr "SSL"
    +
    +#. module: fetchmail
    +#: help:email.server,action_id:0
    +msgid ""
    +"An Email Server Action. It will be run whenever an e-mail is fetched from "
    +"server."
    +msgstr ""
    +"Una acció de servidor de correu. S'executarà sempre que s'obtingui un email "
    +"des del servidor."
    +
    +#. module: fetchmail
    +#: help:email.server,priority:0
    +msgid "Priority between 0 to 10, select define the order of Processing"
    +msgstr "Prioritat entre 0 i 10, defineix l'ordre de procés."
    +
    +#. module: fetchmail
    +#: field:email.server,action_id:0
    +msgid "Email Server Action"
    +msgstr "Acción d'email del servidor"
    +
    +#. module: fetchmail
    +#: field:email.server,priority:0
    +msgid "Server Priority"
    +msgstr "Prioridad servidor"
    +
    +#. module: fetchmail
    +#: view:mailgate.message:0
    +#: field:mailgate.message,server_id:0
    +msgid "Mail Server"
    +msgstr "Servidor de correu"
    +
    +#. module: fetchmail
    +#: view:email.server:0
    +msgid "Fetch Emails"
    +msgstr "Recupera emails"
    diff --git a/addons/fetchmail/i18n/es.po b/addons/fetchmail/i18n/es.po
    index 9f7567addd2..e9db1c36778 100644
    --- a/addons/fetchmail/i18n/es.po
    +++ b/addons/fetchmail/i18n/es.po
    @@ -8,14 +8,14 @@ msgstr ""
     "Project-Id-Version: openobject-addons\n"
     "Report-Msgid-Bugs-To: FULL NAME \n"
     "POT-Creation-Date: 2011-01-11 11:15+0000\n"
    -"PO-Revision-Date: 2011-01-19 12:00+0000\n"
    -"Last-Translator: Raimon Esteve (Zikzakmedia) \n"
    +"PO-Revision-Date: 2011-04-10 14:47+0000\n"
    +"Last-Translator: jmartin (Zikzakmedia) \n"
     "Language-Team: Spanish \n"
     "MIME-Version: 1.0\n"
     "Content-Type: text/plain; charset=UTF-8\n"
     "Content-Transfer-Encoding: 8bit\n"
    -"X-Launchpad-Export-Date: 2011-01-25 06:40+0000\n"
    -"X-Generator: Launchpad (build 12177)\n"
    +"X-Launchpad-Export-Date: 2011-04-11 05:43+0000\n"
    +"X-Generator: Launchpad (build 12735)\n"
     
     #. module: fetchmail
     #: constraint:email.server:0
    @@ -100,7 +100,7 @@ msgstr "¿Añadir adjuntos?"
     #. module: fetchmail
     #: view:email.server:0
     msgid "# of emails"
    -msgstr "# de correos"
    +msgstr "número de emails"
     
     #. module: fetchmail
     #: model:ir.actions.act_window,name:fetchmail.act_server_history
    diff --git a/addons/hr_recruitment/i18n/ca.po b/addons/hr_recruitment/i18n/ca.po
    index d8671d7eb20..235db7b449a 100644
    --- a/addons/hr_recruitment/i18n/ca.po
    +++ b/addons/hr_recruitment/i18n/ca.po
    @@ -8,14 +8,14 @@ msgstr ""
     "Project-Id-Version: openobject-addons\n"
     "Report-Msgid-Bugs-To: FULL NAME \n"
     "POT-Creation-Date: 2011-01-11 11:15+0000\n"
    -"PO-Revision-Date: 2011-03-31 21:56+0000\n"
    -"Last-Translator: Esther Xaus (Zikzakmedia) \n"
    +"PO-Revision-Date: 2011-04-10 14:51+0000\n"
    +"Last-Translator: jmartin (Zikzakmedia) \n"
     "Language-Team: Catalan \n"
     "MIME-Version: 1.0\n"
     "Content-Type: text/plain; charset=UTF-8\n"
     "Content-Transfer-Encoding: 8bit\n"
    -"X-Launchpad-Export-Date: 2011-04-01 06:05+0000\n"
    -"X-Generator: Launchpad (build 12559)\n"
    +"X-Launchpad-Export-Date: 2011-04-11 05:43+0000\n"
    +"X-Generator: Launchpad (build 12735)\n"
     
     #. module: hr_recruitment
     #: help:hr.applicant,active:0
    @@ -134,7 +134,7 @@ msgstr "Anotacions"
     #. module: hr_recruitment
     #: field:hr.applicant,message_ids:0
     msgid "Messages"
    -msgstr "Mensatges"
    +msgstr "Missatges"
     
     #. module: hr_recruitment
     #: view:hr.applicant:0
    diff --git a/addons/hr_timesheet_invoice/i18n/it.po b/addons/hr_timesheet_invoice/i18n/it.po
    index c0f44f89b84..ef21949b979 100644
    --- a/addons/hr_timesheet_invoice/i18n/it.po
    +++ b/addons/hr_timesheet_invoice/i18n/it.po
    @@ -7,14 +7,14 @@ msgstr ""
     "Project-Id-Version: OpenERP Server 6.0dev\n"
     "Report-Msgid-Bugs-To: support@openerp.com\n"
     "POT-Creation-Date: 2011-01-11 11:15+0000\n"
    -"PO-Revision-Date: 2011-01-19 12:00+0000\n"
    -"Last-Translator: Nicola Riolini - Micronaet \n"
    +"PO-Revision-Date: 2011-04-10 12:36+0000\n"
    +"Last-Translator: Carlo - didotech.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: 2011-01-25 06:44+0000\n"
    -"X-Generator: Launchpad (build 12177)\n"
    +"X-Launchpad-Export-Date: 2011-04-11 05:43+0000\n"
    +"X-Generator: Launchpad (build 12735)\n"
     
     #. module: hr_timesheet_invoice
     #: view:report.timesheet.line:0
    @@ -145,7 +145,7 @@ msgstr "Importo Fatturato"
     #. module: hr_timesheet_invoice
     #: view:report.timesheet.line:0
     msgid "Uninvoiced line with billing rate"
    -msgstr ""
    +msgstr "Linee non fatturate con tasso di fatturazione"
     
     #. module: hr_timesheet_invoice
     #: field:report_timesheet.invoice,account_id:0
    @@ -165,7 +165,7 @@ msgstr "Importo"
     #. module: hr_timesheet_invoice
     #: view:account.analytic.account:0
     msgid "Reactivate Account"
    -msgstr ""
    +msgstr "Riattiva il Conto"
     
     #. module: hr_timesheet_invoice
     #: help:hr.timesheet.invoice.create,name:0
    @@ -190,7 +190,7 @@ msgstr "Contabilità Analitica da Chiudere"
     #. module: hr_timesheet_invoice
     #: view:board.board:0
     msgid "Uninvoice Lines With Billing Rate"
    -msgstr ""
    +msgstr "Linee non fatturate con tasso di fatturazione"
     
     #. module: hr_timesheet_invoice
     #: view:report.timesheet.line:0
    @@ -524,7 +524,7 @@ msgstr "Timesheet non assegnati a utenti"
     #. module: hr_timesheet_invoice
     #: field:report.timesheet.line,invoice_id:0
     msgid "Invoiced"
    -msgstr ""
    +msgstr "Fatturati"
     
     #. module: hr_timesheet_invoice
     #: field:report.analytic.account.close,quantity_max:0
    @@ -734,17 +734,17 @@ msgstr "Quantità"
     #. module: hr_timesheet_invoice
     #: report:hr.timesheet.invoice.account.analytic.account.cost_ledger:0
     msgid "Date/Code"
    -msgstr ""
    +msgstr "Data/codice"
     
     #. module: hr_timesheet_invoice
     #: field:report.timesheet.line,general_account_id:0
     msgid "General Account"
    -msgstr ""
    +msgstr "Contabilità Generale"
     
     #. module: hr_timesheet_invoice
     #: model:ir.model,name:hr_timesheet_invoice.model_hr_timesheet_analytic_profit
     msgid "Print Timesheet Profit"
    -msgstr ""
    +msgstr "Stampa il profitto del timesheet"
     
     #. module: hr_timesheet_invoice
     #: field:account.analytic.account,to_invoice:0
    @@ -804,7 +804,7 @@ msgstr "Annulla"
     #. module: hr_timesheet_invoice
     #: view:account.analytic.account:0
     msgid "Close"
    -msgstr ""
    +msgstr "Chiudi"
     
     #. module: hr_timesheet_invoice
     #: model:ir.actions.act_window,help:hr_timesheet_invoice.action_hr_timesheet_invoice_factor_form
    @@ -832,7 +832,7 @@ msgstr "Necessario saldo prodotto"
     #. module: hr_timesheet_invoice
     #: view:hr.timesheet.invoice.create:0
     msgid "Billing Data"
    -msgstr ""
    +msgstr "Data fatturazione"
     
     #. module: hr_timesheet_invoice
     #: code:addons/hr_timesheet_invoice/wizard/hr_timesheet_invoice_create.py:77
    @@ -945,6 +945,9 @@ msgid ""
     "This list shows you every task you can invoice to the customer. Select the "
     "lines and click the Action button to generate the invoices automatically."
     msgstr ""
    +"Questo lista vi mostra ogni attività fatturabile al cliente. Selezionare le "
    +"linee d'azione e fare clic sul pulsante per generare automaticamente le "
    +"fatture."
     
     #. module: hr_timesheet_invoice
     #: code:addons/hr_timesheet_invoice/wizard/hr_timesheet_analytic_profit.py:58
    diff --git a/addons/idea/i18n/mn.po b/addons/idea/i18n/mn.po
    index 4f1e1ae51b1..97a53e7d9ce 100644
    --- a/addons/idea/i18n/mn.po
    +++ b/addons/idea/i18n/mn.po
    @@ -8,14 +8,14 @@ msgstr ""
     "Project-Id-Version: openobject-addons\n"
     "Report-Msgid-Bugs-To: FULL NAME \n"
     "POT-Creation-Date: 2011-01-11 11:15+0000\n"
    -"PO-Revision-Date: 2011-01-19 12:00+0000\n"
    -"Last-Translator: badralb \n"
    +"PO-Revision-Date: 2011-04-11 04:22+0000\n"
    +"Last-Translator: Uurtsaikh \n"
     "Language-Team: Mongolian \n"
     "MIME-Version: 1.0\n"
     "Content-Type: text/plain; charset=UTF-8\n"
     "Content-Transfer-Encoding: 8bit\n"
    -"X-Launchpad-Export-Date: 2011-01-25 06:45+0000\n"
    -"X-Generator: Launchpad (build 12177)\n"
    +"X-Launchpad-Export-Date: 2011-04-11 05:43+0000\n"
    +"X-Generator: Launchpad (build 12735)\n"
     
     #. module: idea
     #: help:idea.category,visibility:0
    @@ -76,7 +76,7 @@ msgstr ""
     #. module: idea
     #: model:ir.module.module,shortdesc:idea.module_meta_information
     msgid "Idea Manager"
    -msgstr ""
    +msgstr "Саналын удирдлага"
     
     #. module: idea
     #: selection:report.vote,month:0
    diff --git a/addons/product/i18n/id.po b/addons/product/i18n/id.po
    index c0b29d8ef80..3852f3732da 100644
    --- a/addons/product/i18n/id.po
    +++ b/addons/product/i18n/id.po
    @@ -13,7 +13,7 @@ msgstr ""
     "MIME-Version: 1.0\n"
     "Content-Type: text/plain; charset=UTF-8\n"
     "Content-Transfer-Encoding: 8bit\n"
    -"X-Launchpad-Export-Date: 2011-04-08 06:13+0000\n"
    +"X-Launchpad-Export-Date: 2011-04-09 06:16+0000\n"
     "X-Generator: Launchpad (build 12735)\n"
     
     #. module: product
    diff --git a/addons/thunderbird/i18n/bg.po b/addons/thunderbird/i18n/bg.po
    index 6d3cd5eedf6..f447ab7cd77 100644
    --- a/addons/thunderbird/i18n/bg.po
    +++ b/addons/thunderbird/i18n/bg.po
    @@ -8,14 +8,14 @@ msgstr ""
     "Project-Id-Version: openobject-addons\n"
     "Report-Msgid-Bugs-To: FULL NAME \n"
     "POT-Creation-Date: 2011-01-11 11:16+0000\n"
    -"PO-Revision-Date: 2011-03-30 12:16+0000\n"
    +"PO-Revision-Date: 2011-04-09 08:47+0000\n"
     "Last-Translator: Dimitar Markov \n"
     "Language-Team: Bulgarian \n"
     "MIME-Version: 1.0\n"
     "Content-Type: text/plain; charset=UTF-8\n"
     "Content-Transfer-Encoding: 8bit\n"
    -"X-Launchpad-Export-Date: 2011-03-31 06:35+0000\n"
    -"X-Generator: Launchpad (build 12559)\n"
    +"X-Launchpad-Export-Date: 2011-04-10 06:01+0000\n"
    +"X-Generator: Launchpad (build 12735)\n"
     
     #. module: thunderbird
     #: field:thunderbird.installer,plugin_file:0
    @@ -94,17 +94,17 @@ msgstr ""
     #: field:thunderbird.installer,name:0
     #: field:thunderbird.installer,pdf_name:0
     msgid "File name"
    -msgstr ""
    +msgstr "Име на файл"
     
     #. module: thunderbird
     #: view:thunderbird.installer:0
     msgid "Installation and Configuration Steps"
    -msgstr ""
    +msgstr "Стъпки за инсталиране и настройка"
     
     #. module: thunderbird
     #: field:thunderbird.installer,progress:0
     msgid "Configuration Progress"
    -msgstr ""
    +msgstr "Прогрес на конфигурация"
     
     #. module: thunderbird
     #: model:ir.actions.act_window,name:thunderbird.action_thunderbird_installer
    @@ -121,17 +121,17 @@ msgstr ""
     #. module: thunderbird
     #: view:thunderbird.installer:0
     msgid "Configure"
    -msgstr ""
    +msgstr "Настройване"
     
     #. module: thunderbird
     #: view:thunderbird.installer:0
     msgid "Skip"
    -msgstr ""
    +msgstr "Пропусни"
     
     #. module: thunderbird
     #: field:thunderbird.installer,config_logo:0
     msgid "Image"
    -msgstr ""
    +msgstr "Изображение"
     
     #. module: thunderbird
     #: model:ir.module.module,description:thunderbird.module_meta_information
    diff --git a/addons/web_livechat/i18n/zh_CN.po b/addons/web_livechat/i18n/zh_CN.po
    new file mode 100644
    index 00000000000..6ca859f8b0b
    --- /dev/null
    +++ b/addons/web_livechat/i18n/zh_CN.po
    @@ -0,0 +1,39 @@
    +# Chinese (Simplified) translation for openobject-addons
    +# Copyright (c) 2011 Rosetta Contributors and Canonical Ltd 2011
    +# This file is distributed under the same license as the openobject-addons package.
    +# FIRST AUTHOR , 2011.
    +#
    +msgid ""
    +msgstr ""
    +"Project-Id-Version: openobject-addons\n"
    +"Report-Msgid-Bugs-To: FULL NAME \n"
    +"POT-Creation-Date: 2011-01-11 11:16+0000\n"
    +"PO-Revision-Date: 2011-04-08 07:20+0000\n"
    +"Last-Translator: FULL NAME \n"
    +"Language-Team: Chinese (Simplified) \n"
    +"MIME-Version: 1.0\n"
    +"Content-Type: text/plain; charset=UTF-8\n"
    +"Content-Transfer-Encoding: 8bit\n"
    +"X-Launchpad-Export-Date: 2011-04-09 06:16+0000\n"
    +"X-Generator: Launchpad (build 12735)\n"
    +
    +#. module: web_livechat
    +#: sql_constraint:publisher_warranty.contract:0
    +msgid ""
    +"Your publisher warranty contract is already subscribed in the system !"
    +msgstr ""
    +
    +#. module: web_livechat
    +#: model:ir.module.module,shortdesc:web_livechat.module_meta_information
    +msgid "Live Chat Support"
    +msgstr ""
    +
    +#. module: web_livechat
    +#: model:ir.model,name:web_livechat.model_publisher_warranty_contract
    +msgid "publisher_warranty.contract"
    +msgstr ""
    +
    +#. module: web_livechat
    +#: model:ir.module.module,description:web_livechat.module_meta_information
    +msgid "Enable live chat support for whom have a maintenance contract"
    +msgstr ""
    diff --git a/addons/web_uservoice/i18n/zh_CN.po b/addons/web_uservoice/i18n/zh_CN.po
    new file mode 100644
    index 00000000000..788b3f5045a
    --- /dev/null
    +++ b/addons/web_uservoice/i18n/zh_CN.po
    @@ -0,0 +1,29 @@
    +# Chinese (Simplified) translation for openobject-addons
    +# Copyright (c) 2011 Rosetta Contributors and Canonical Ltd 2011
    +# This file is distributed under the same license as the openobject-addons package.
    +# FIRST AUTHOR , 2011.
    +#
    +msgid ""
    +msgstr ""
    +"Project-Id-Version: openobject-addons\n"
    +"Report-Msgid-Bugs-To: FULL NAME \n"
    +"POT-Creation-Date: 2011-01-12 16:15+0000\n"
    +"PO-Revision-Date: 2011-04-08 07:13+0000\n"
    +"Last-Translator: FULL NAME \n"
    +"Language-Team: Chinese (Simplified) \n"
    +"MIME-Version: 1.0\n"
    +"Content-Type: text/plain; charset=UTF-8\n"
    +"Content-Transfer-Encoding: 8bit\n"
    +"X-Launchpad-Export-Date: 2011-04-09 06:16+0000\n"
    +"X-Generator: Launchpad (build 12735)\n"
    +
    +#. module: web_uservoice
    +#: model:ir.module.module,shortdesc:web_uservoice.module_meta_information
    +msgid "Add uservoice button in header"
    +msgstr ""
    +
    +#. module: web_uservoice
    +#: code:addons/web_uservoice/web/editors.py:72
    +#, python-format
    +msgid "feedback"
    +msgstr ""
    diff --git a/bin/addons/base/i18n/nl.po b/bin/addons/base/i18n/nl.po
    index bd0584512ac..6b2b0d22eb7 100644
    --- a/bin/addons/base/i18n/nl.po
    +++ b/bin/addons/base/i18n/nl.po
    @@ -7,14 +7,14 @@ msgstr ""
     "Project-Id-Version: OpenERP Server 5.0.0\n"
     "Report-Msgid-Bugs-To: support@openerp.com\n"
     "POT-Creation-Date: 2011-01-11 11:14+0000\n"
    -"PO-Revision-Date: 2011-02-21 08:40+0000\n"
    -"Last-Translator: Niels Huylebroeck \n"
    +"PO-Revision-Date: 2011-04-10 19:20+0000\n"
    +"Last-Translator: Mustufa Rangwala (Open ERP) \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: 2011-02-22 14:26+0000\n"
    -"X-Generator: Launchpad (build 12351)\n"
    +"X-Launchpad-Export-Date: 2011-04-11 05:42+0000\n"
    +"X-Generator: Launchpad (build 12735)\n"
     
     #. module: base
     #: view:ir.filters:0
    @@ -918,7 +918,7 @@ msgstr "Toegang verwijderen"
     #. module: base
     #: model:res.country,name:base.ne
     msgid "Niger"
    -msgstr "Nigeria"
    +msgstr "Niger"
     
     #. module: base
     #: selection:base.language.install,lang:0
    
    From 75bf28388b9c2904576aedc43b61620665ee9cd0 Mon Sep 17 00:00:00 2001
    From: Xavier Morel 
    Date: Mon, 11 Apr 2011 08:25:41 +0200
    Subject: [PATCH 125/259] [IMP] improvements to View.normalize_attrs
    
    bzr revid: xmo@openerp.com-20110411062541-mjib0mm8wk7ujlyy
    ---
     addons/base/controllers/main.py | 13 +++++--------
     1 file changed, 5 insertions(+), 8 deletions(-)
    
    diff --git a/addons/base/controllers/main.py b/addons/base/controllers/main.py
    index 96782c1cec4..efc960168c4 100644
    --- a/addons/base/controllers/main.py
    +++ b/addons/base/controllers/main.py
    @@ -424,19 +424,16 @@ class View(openerpweb.Controller):
             :param dict context: evaluation context
             """
             # If @attrs is normalized in json by server, the eval should be replaced by simplejson.loads
    -        attrs = eval(elem.attrib.get('attrs', '{}'))
    +        attrs = openerpweb.ast.literal_eval(elem.get('attrs', '{}'))
             if 'states' in elem.attrib:
    -            if 'invisible' not in attrs:
    -                attrs['invisible'] = []
    -                # This should be done by the server
    -            attrs['invisible'].append(('state', 'not in', elem.attrib['states'].split(',')))
    -            del(elem.attrib['states'])
    +            attrs.setdefault('invisible', [])\
    +                .append(('state', 'not in', elem.attrib.pop('states').split(',')))
             if attrs:
    -            elem.attrib['attrs'] = simplejson.dumps(attrs)
    +            elem.set('attrs', simplejson.dumps(attrs))
             for a in ['invisible', 'readonly', 'required']:
                 if a in elem.attrib:
                     # In the XML we trust
    -                avalue = bool(eval(elem.attrib.get(a, 'False'),
    +                avalue = bool(eval(elem.get(a, 'False'),
                                        {'context': context or {}}))
                     if not avalue:
                         del elem.attrib[a]
    
    From 5a901eef839cf82dae9886c2e5d7929234e9d86d Mon Sep 17 00:00:00 2001
    From: Xavier Morel 
    Date: Mon, 11 Apr 2011 08:27:25 +0200
    Subject: [PATCH 126/259] [FIX] dataset tests
    
    bzr revid: xmo@openerp.com-20110411062725-7eh31m9vtuasmsjz
    ---
     addons/base/test/test_dataset.py | 8 ++++----
     1 file changed, 4 insertions(+), 4 deletions(-)
    
    diff --git a/addons/base/test/test_dataset.py b/addons/base/test/test_dataset.py
    index 80d1e52561b..27d2169bf1b 100644
    --- a/addons/base/test/test_dataset.py
    +++ b/addons/base/test/test_dataset.py
    @@ -14,13 +14,13 @@ class TestDataSetController(unittest2.TestCase):
             self.search.return_value = []
             self.read.return_value = []
     
    -        self.assertFalse(self.dataset.do_find(self.request, 'fake.model'))
    +        self.assertFalse(self.dataset.do_search_read(self.request, 'fake.model'))
             self.read.assert_called_once_with([], False)
     
         def test_regular_find(self):
             self.search.return_value = [1, 2, 3]
     
    -        self.dataset.do_find(self.request, 'fake.model')
    +        self.dataset.do_search_read(self.request, 'fake.model')
             self.read.assert_called_once_with([1, 2, 3], False)
     
         def test_ids_shortcut(self):
    @@ -32,7 +32,7 @@ class TestDataSetController(unittest2.TestCase):
             ]
     
             self.assertEqual(
    -            self.dataset.do_find(self.request, 'fake.model', ['id']),
    +            self.dataset.do_search_read(self.request, 'fake.model', ['id']),
                 [{'id': 1}, {'id': 2}, {'id': 3}])
             self.assertFalse(self.read.called)
     
    @@ -46,7 +46,7 @@ class TestDataSetController(unittest2.TestCase):
             result = self.dataset.do_get(
                 self.request, 'fake.model', [3, 2, 1])
             self.read.assert_called_once_with(
    -            [3, 2, 1])
    +            [3, 2, 1], False)
             self.assertFalse(self.search.called)
     
             self.assertEqual(
    
    From 669b109bde7786c406b6141f2954677f52668852 Mon Sep 17 00:00:00 2001
    From: Xavier Morel 
    Date: Mon, 11 Apr 2011 08:30:54 +0200
    Subject: [PATCH 127/259] [FIX] docstring for DataSet.do_search_read: missing
     'fields' param
    
    bzr revid: xmo@openerp.com-20110411063054-jybr8z734xy3qndp
    ---
     addons/base/controllers/main.py | 3 +++
     1 file changed, 3 insertions(+)
    
    diff --git a/addons/base/controllers/main.py b/addons/base/controllers/main.py
    index efc960168c4..c8614c0f5cb 100644
    --- a/addons/base/controllers/main.py
    +++ b/addons/base/controllers/main.py
    @@ -363,6 +363,9 @@ class DataSet(openerpweb.Controller):
             :type model: str
             :param ids: a list of identifiers
             :type ids: list
    +        :param fields: a list of fields to fetch, ``False`` or empty to fetch
    +                       all fields in the model
    +        :type fields: list | False
             :returns: a list of records, in the same order as the list of ids
             :rtype: list
             """
    
    From 53ea40d8e99e3a8a1505edea9695605f839bc4a7 Mon Sep 17 00:00:00 2001
    From: "ARA (OpenERP)" 
    Date: Mon, 11 Apr 2011 12:30:35 +0530
    Subject: [PATCH 128/259] [FIX] hr_timesheet:an employee shouldn't be able to
     see all timesheet line
    
    lp bug: https://launchpad.net/bugs/755659 fixed
    
    bzr revid: ara@tinyerp.com-20110411070035-rmd3l2a1g3zdfomt
    ---
     addons/hr_timesheet/__openerp__.py                   |  1 +
     .../hr_timesheet/security/hr_timesheet_security.xml  | 12 ++++++++++++
     addons/hr_timesheet/security/ir.model.access.csv     |  1 +
     3 files changed, 14 insertions(+)
     create mode 100644 addons/hr_timesheet/security/hr_timesheet_security.xml
    
    diff --git a/addons/hr_timesheet/__openerp__.py b/addons/hr_timesheet/__openerp__.py
    index 345f9c92df7..e58d09c296d 100644
    --- a/addons/hr_timesheet/__openerp__.py
    +++ b/addons/hr_timesheet/__openerp__.py
    @@ -44,6 +44,7 @@ to set up a management by affair.
         'init_xml': ['hr_timesheet_data.xml'],
         'update_xml': [
             'security/ir.model.access.csv',
    +        'security/hr_timesheet_security.xml',
             'hr_timesheet_view.xml',
             'hr_timesheet_report.xml',
             'hr_timesheet_wizard.xml',
    diff --git a/addons/hr_timesheet/security/hr_timesheet_security.xml b/addons/hr_timesheet/security/hr_timesheet_security.xml
    new file mode 100644
    index 00000000000..6b341e50f4b
    --- /dev/null
    +++ b/addons/hr_timesheet/security/hr_timesheet_security.xml
    @@ -0,0 +1,12 @@
    +
    +
    +    
    +
    +        
    +            HR Analytic Timesheet
    +            
    +            [('user_id', '=', user.id)]
    +        
    +
    +    
    +
    \ No newline at end of file
    diff --git a/addons/hr_timesheet/security/ir.model.access.csv b/addons/hr_timesheet/security/ir.model.access.csv
    index 6e932d4e8f8..ea34aa4ddc4 100644
    --- a/addons/hr_timesheet/security/ir.model.access.csv
    +++ b/addons/hr_timesheet/security/ir.model.access.csv
    @@ -9,3 +9,4 @@
     "access_account_fiscalyear_hr_user","account.account.fiscalyear.user","account.model_account_fiscalyear","base.group_hr_user",1,1,1,1
     "hr.access_account_journal_view_hruser","account.journal.view hruser","account.model_account_journal_view","base.group_hr_user",1,0,0,0
     "hr.access_account_journal_column_hruser","account.journal.column hruser","account.model_account_journal_column","base.group_hr_user",1,0,0,0
    +"access_hr_analytic_timesheet_user","hr.analytic.timesheet.user","model_hr_analytic_timesheet","base.group_user",1,0,0,0
    \ No newline at end of file
    
    From f21bb336d3aca07eb135c891dfcaf20818fcebd4 Mon Sep 17 00:00:00 2001
    From: Xavier Morel 
    Date: Mon, 11 Apr 2011 09:58:46 +0200
    Subject: [PATCH 129/259] [FIX] dataset search, 'context' is popped from kwargs
     into the request object, and should be taken from there for RPC calls
    
    bzr revid: xmo@openerp.com-20110411075846-9qxzabjav0y1l47n
    ---
     addons/base/controllers/main.py  | 5 ++---
     addons/base/test/test_dataset.py | 5 +++--
     2 files changed, 5 insertions(+), 5 deletions(-)
    
    diff --git a/addons/base/controllers/main.py b/addons/base/controllers/main.py
    index c8614c0f5cb..28806083d61 100644
    --- a/addons/base/controllers/main.py
    +++ b/addons/base/controllers/main.py
    @@ -334,18 +334,17 @@ class DataSet(openerpweb.Controller):
             :param int offset: from which index should the results start being returned
             :param int limit: the maximum number of records to return
             :param list domain: the search domain for the query
    -        :param dict context: the context in which the search should be executed
             :param list sort: sorting directives
             :returns: a list of result records
             :rtype: list
             """
             Model = request.session.model(model)
             ids = Model.search(domain or [], offset or 0, limit or False,
    -                           sort or False, context or False)
    +                           sort or False, request.context)
             if fields and fields == ['id']:
                 # shortcut read if we only want the ids
                 return map(lambda id: {'id': id}, ids)
    -        return Model.read(ids, fields or False)
    +        return Model.read(ids, fields or False, request.context)
     
         @openerpweb.jsonrequest
         def get(self, request, model, ids, fields=False):
    diff --git a/addons/base/test/test_dataset.py b/addons/base/test/test_dataset.py
    index 27d2169bf1b..702c63b0899 100644
    --- a/addons/base/test/test_dataset.py
    +++ b/addons/base/test/test_dataset.py
    @@ -15,13 +15,14 @@ class TestDataSetController(unittest2.TestCase):
             self.read.return_value = []
     
             self.assertFalse(self.dataset.do_search_read(self.request, 'fake.model'))
    -        self.read.assert_called_once_with([], False)
    +        self.read.assert_called_once_with([], False, self.request.context)
     
         def test_regular_find(self):
             self.search.return_value = [1, 2, 3]
     
             self.dataset.do_search_read(self.request, 'fake.model')
    -        self.read.assert_called_once_with([1, 2, 3], False)
    +        self.read.assert_called_once_with([1, 2, 3], False,
    +                                          self.request.context)
     
         def test_ids_shortcut(self):
             self.search.return_value = [1, 2, 3]
    
    From bc82a989f2449165f28955e7a11f944dbdf2e036 Mon Sep 17 00:00:00 2001
    From: Fabien Meghazi 
    Date: Mon, 11 Apr 2011 10:30:32 +0200
    Subject: [PATCH 130/259] [IMP] Renamed Notification methods 'default' ->
     notify  ,  'alert' -> warn
    
    bzr revid: fme@openerp.com-20110411083032-zc87gltpnw2z7s0r
    ---
     addons/base/static/src/js/chrome.js |  9 ++-------
     addons/base/static/src/js/data.js   |  2 +-
     addons/base/static/src/js/form.js   | 12 ++++++------
     addons/base/static/src/js/search.js |  2 +-
     4 files changed, 10 insertions(+), 15 deletions(-)
    
    diff --git a/addons/base/static/src/js/chrome.js b/addons/base/static/src/js/chrome.js
    index b26dccffb2e..920973e640a 100644
    --- a/addons/base/static/src/js/chrome.js
    +++ b/addons/base/static/src/js/chrome.js
    @@ -245,12 +245,7 @@ openerp.base.Notification =  openerp.base.BasicController.extend({
                 text: text
             });
         },
    -    // TODO remove to avoid default as attribute
    -    'default': function(title, text) {
    -        this.notify(title,text);
    -    },
    -    // TODO change into warn to avoid alert
    -    alert: function(title, text) {
    +    warn: function(title, text) {
             this.$element.notify('create', 'oe_notification_alert', {
                 title: title,
                 text: text
    @@ -907,7 +902,7 @@ openerp.base.WebClient = openerp.base.Controller.extend({
             this.header.start();
             this.login.start();
             this.menu.start();
    -        this.notification['default']("OpenERP Client", "The openerp client has been initialized.");
    +        this.notification.notify("OpenERP Client", "The openerp client has been initialized.");
         },
         on_logged: function() {
             this.action =  new openerp.base.ActionManager(this.session, "oe_app");
    diff --git a/addons/base/static/src/js/data.js b/addons/base/static/src/js/data.js
    index 8f5d6168e75..c16bf8eb81b 100644
    --- a/addons/base/static/src/js/data.js
    +++ b/addons/base/static/src/js/data.js
    @@ -100,7 +100,7 @@ openerp.base.DataSet =  openerp.base.Controller.extend( /** @lends openerp.base.
             }, callback);
         },
         unlink: function(ids) {
    -        this.notification['default']("Unlink", ids);
    +        this.notification.notify("Unlink", ids);
         },
         call: function (method, ids, args, callback) {
             ids = ids || [];
    diff --git a/addons/base/static/src/js/form.js b/addons/base/static/src/js/form.js
    index bf42fc4fd7f..e31f03510d8 100644
    --- a/addons/base/static/src/js/form.js
    +++ b/addons/base/static/src/js/form.js
    @@ -234,24 +234,24 @@ openerp.base.FormView =  openerp.base.Controller.extend( /** @lends openerp.base
                 }
             });
             msg += "";
    -        this.notification.alert("The following fields are invalid :", msg);
    +        this.notification.warn("The following fields are invalid :", msg);
         },
         on_saved: function(r) {
             if (!r.result) {
                 this.log("Record was not saved");
             } else {
                 // Check response for exceptions, display error
    -            this.notification['default']("Record saved", "The record #" + this.datarecord.id + " has been saved.");
    +            this.notification.notify("Record saved", "The record #" + this.datarecord.id + " has been saved.");
             }
         },
         do_search: function (domains, contexts, groupbys) {
    -        this.notification['default']("Searching form");
    +        this.notification.notify("Searching form");
         },
         on_action: function (action) {
    -        this.notification['default']('Executing action ' + action);
    +        this.notification.notify('Executing action ' + action);
         },
         do_cancel: function () {
    -        this.notification['default']("Cancelling form");
    +        this.notification.notify("Cancelling form");
         }
     });
     
    @@ -720,7 +720,7 @@ openerp.base.form.FieldOne2ManyDatasSet = openerp.base.DataSetStatic.extend({
             this._super(id, data, callback);
         },
         unlink: function() {
    -        this.notification['default']('Unlinking o2m ' + this.ids);
    +        this.notification.notify('Unlinking o2m ' + this.ids);
         }
     });
     
    diff --git a/addons/base/static/src/js/search.js b/addons/base/static/src/js/search.js
    index ef10992d75f..21d1408f087 100644
    --- a/addons/base/static/src/js/search.js
    +++ b/addons/base/static/src/js/search.js
    @@ -215,7 +215,7 @@ openerp.base.SearchView = openerp.base.Controller.extend({
          * @param {Array} errors a never-empty array of error objects
          */
         on_invalid: function (errors) {
    -        this.notification['default']("Invalid Search", "triggered from search view");
    +        this.notification.notify("Invalid Search", "triggered from search view");
         },
         do_clear: function (e) {
             if (e && e.preventDefault) { e.preventDefault(); }
    
    From d99bacbd60615ab9e1a6e18e437d13fc2e949821 Mon Sep 17 00:00:00 2001
    From: Xavier Morel 
    Date: Mon, 11 Apr 2011 10:42:59 +0200
    Subject: [PATCH 131/259] [TEST] add test for normalize_attrs of states
    
    bzr revid: xmo@openerp.com-20110411084259-gpkw2nzpw8ctuhy5
    ---
     addons/base/test/test_view.py | 53 ++++++++++++++++++++++-------------
     1 file changed, 34 insertions(+), 19 deletions(-)
    
    diff --git a/addons/base/test/test_view.py b/addons/base/test/test_view.py
    index e5c6162dae0..f20f9e12f61 100644
    --- a/addons/base/test/test_view.py
    +++ b/addons/base/test/test_view.py
    @@ -2,33 +2,16 @@ import xml.etree.ElementTree
     import mock
     
     import unittest2
    +import simplejson
     
     import base.controllers.main
     import openerpweb.nonliterals
     import openerpweb.openerpweb
     
     #noinspection PyCompatibility
    -class ViewTest(unittest2.TestCase):
    +class DomainsAndContextsTest(unittest2.TestCase):
         def setUp(self):
             self.view = base.controllers.main.View()
    -    def test_identity(self):
    -        base_view = """
    -            
    -                
    -                    
    -                    
    -                
    -                
    -            
    -        """
    -
    -        pristine = xml.etree.ElementTree.fromstring(base_view)
    -        transformed = self.view.transform_view(base_view, None)
    -
    -        self.assertEqual(
    -             xml.etree.ElementTree.tostring(transformed),
    -             xml.etree.ElementTree.tostring(pristine)
    -        )
     
         def test_convert_literal_domain(self):
             e = xml.etree.ElementTree.Element(
    @@ -115,3 +98,35 @@ class ViewTest(unittest2.TestCase):
                 openerpweb.nonliterals.Context(
                     session, key=e.get('context').key).get_context_string(),
                 context_string)
    +
    +class AttrsNormalizationTest(unittest2.TestCase):
    +    def setUp(self):
    +        self.view = base.controllers.main.View()
    +
    +    def test_identity(self):
    +        base_view = """
    +            
    + + + + + + + """ + + pristine = xml.etree.ElementTree.fromstring(base_view) + transformed = self.view.transform_view(base_view, None) + + self.assertEqual( + xml.etree.ElementTree.tostring(transformed), + xml.etree.ElementTree.tostring(pristine) + ) + def test_transform_states(self): + element = xml.etree.ElementTree.Element( + 'field', states="open,closed") + self.view.normalize_attrs(element, {}) + + self.assertIsNone(element.get('states')) + self.assertEqual( + simplejson.loads(element.get('attrs')), + {'invisible': [['state', 'not in', ['open', 'closed']]]}) From 047b10f0ff2c55270a084b3e2eff7455997f9950 Mon Sep 17 00:00:00 2001 From: Thibault Francois Date: Mon, 11 Apr 2011 10:51:20 +0200 Subject: [PATCH 132/259] [FIX] mass convert oldest lead bzr revid: tfr@openerp.com-20110411085120-xdjn8z046ak9enen --- addons/crm/wizard/crm_lead_to_opportunity.py | 7 +++---- addons/crm/wizard/crm_lead_to_partner.py | 1 - addons/crm/wizard/crm_merge_opportunities.py | 6 +++++- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/addons/crm/wizard/crm_lead_to_opportunity.py b/addons/crm/wizard/crm_lead_to_opportunity.py index ea6145f3719..33ec426d7d6 100644 --- a/addons/crm/wizard/crm_lead_to_opportunity.py +++ b/addons/crm/wizard/crm_lead_to_opportunity.py @@ -48,11 +48,10 @@ class crm_lead2opportunity_partner(osv.osv_memory): """ lead_obj = self.pool.get('crm.lead') - res = super(crm_lead2opportunity_partner, self).default_get(cr, uid, fields, context=context) opportunities = res.get('opportunity_ids') or [] - partner_id = False + email = False for lead in lead_obj.browse(cr, uid, opportunities, context=context): partner_id = lead.partner_id and lead.partner_id.id or False email = re.findall(r'([^ ,<@]+@[^> ,]+)', lead.email_from or '') @@ -150,7 +149,7 @@ class crm_lead2opportunity_partner(osv.osv_memory): subject = "lead %s converted into opportunity" % lead.name body = "Info \n Id : %s \n Subject: %s \n Partner: %s \n Description : %s " % (lead.id, lead.name, lead.partner_id.name, lead.description) try : - tools.email_send(email_from, email_to, subject, body) + tools.email_send(email_from, [email_to], subject, body) except: pass @@ -211,7 +210,7 @@ class crm_lead2opportunity_partner(osv.osv_memory): if data.name == 'merge' and (len(data.opportunity_ids) > 1 or not context.get('mass_convert') ): merge_obj = self.pool.get('crm.merge.opportunity') self.write(cr, uid, ids, {'opportunity_ids' : [(6,0, [data.opportunity_ids[0].id])]}, context=context) - context.update({'lead_ids' : record_id}) + context.update({'lead_ids' : record_id, "convert" : True}) return merge_obj.merge(cr, uid, data.opportunity_ids, context=context) return { diff --git a/addons/crm/wizard/crm_lead_to_partner.py b/addons/crm/wizard/crm_lead_to_partner.py index 71b454f18c3..ae9943cb6db 100644 --- a/addons/crm/wizard/crm_lead_to_partner.py +++ b/addons/crm/wizard/crm_lead_to_partner.py @@ -73,7 +73,6 @@ class crm_lead2partner(osv.osv_memory): data = list(context and context.get('active_ids', []) or []) res = super(crm_lead2partner, self).default_get(cr, uid, fields, context=context) - for lead in lead_obj.browse(cr, uid, data, context=context): partner_ids = [] # Find partner address matches the email_from of the lead diff --git a/addons/crm/wizard/crm_merge_opportunities.py b/addons/crm/wizard/crm_merge_opportunities.py index ba066e65c78..8cf1d14ce17 100644 --- a/addons/crm/wizard/crm_merge_opportunities.py +++ b/addons/crm/wizard/crm_merge_opportunities.py @@ -61,7 +61,11 @@ class crm_merge_opportunity(osv.osv_memory): def find_oldest(self, cr, uid, op_ids, context=None): + if not context: + context = {} ids = [op_id.id for op_id in op_ids] + if context.get('convert'): + ids = list(set(ids) - set(context.get('lead_ids', False)) ) lead_obj = self.pool.get('crm.lead') op_id = lead_obj.search(cr, uid, [('id', 'in', ids)], order='create_date' , context=context) opps = lead_obj.browse(cr, uid, [op_id[0]], context=context) @@ -74,7 +78,7 @@ class crm_merge_opportunity(osv.osv_memory): opp_obj = self.pool.get('crm.lead') message_obj = self.pool.get('mailgate.message') - lead_ids = context and context.pop('lead_ids', []) or [] + lead_ids = context and context.get('lead_ids', []) or [] if len(op_ids) <= 1: raise osv.except_osv(_('Warning !'),_('Please select more than one opportunities.')) From 3b7d2dd1c3090b793f14adbc63d034732c1c409c Mon Sep 17 00:00:00 2001 From: "noz (OpenERP)" Date: Mon, 11 Apr 2011 14:38:02 +0530 Subject: [PATCH 133/259] [FIX] Fixed dynamic return for poll method. bzr revid: noz@tinyerp.com-20110411090802-zzrsexmojj6w9zan --- addons/web_chat/controllers/main.py | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/addons/web_chat/controllers/main.py b/addons/web_chat/controllers/main.py index 2beccdcda0c..ff5b95d6579 100644 --- a/addons/web_chat/controllers/main.py +++ b/addons/web_chat/controllers/main.py @@ -132,13 +132,16 @@ class PollServer(openerpweb.Controller): """ - for i in range(60): + msg = [] + + for i in range(5): received_msg = mq.read('Guest1', i); if received_msg: msg = self._pollParseMessages(received_msg) - time.sleep(2) + time.sleep(1) else: - time.sleep(2) + msg = [] + time.sleep(1) # for i in range(60): #r = mq.read(username,timestamp) @@ -148,12 +151,14 @@ class PollServer(openerpweb.Controller): # sleep 2 # else # return emptylist - -# print "==============poll receive...", kw.get('callback') + + msg = '[{"t":"m","s":"Guest130214008855.5","r":"Guest130214013134.26","m":"xxxxxx"}]' + # # it's http://localhost:8002/web_chat/pollserver/poll?method=long?callback=jsonp1302147330483&_1302147330483= - return '%s([{"t":"m","s":"Guest130214008855.5","r":"Guest130214013134.26","m":"xxxxxx"}]);'%kw.get('callback','') - @openerpweb.jsonrequest + return '%s'%kw.get('callback', '') + '(' + msg + ');' + + @openerpweb.httprequest def send(self, req, **kw): print "========= send ========", kw From c2865075b16014ace644d6f0cb17e1ccc2cc4dcf Mon Sep 17 00:00:00 2001 From: Antony Lesuisse Date: Mon, 11 Apr 2011 11:26:46 +0200 Subject: [PATCH 134/259] web_chat im.js eol 0x0d to 0x0a bzr revid: al@openerp.com-20110411092646-dykbpwndmn5gawf1 --- addons/web_chat/static/lib/AjaxIM/js/im.js | 2102 +++++++++++++++++++- 1 file changed, 2101 insertions(+), 1 deletion(-) diff --git a/addons/web_chat/static/lib/AjaxIM/js/im.js b/addons/web_chat/static/lib/AjaxIM/js/im.js index ef80481a246..42c3f743204 100644 --- a/addons/web_chat/static/lib/AjaxIM/js/im.js +++ b/addons/web_chat/static/lib/AjaxIM/js/im.js @@ -1 +1,2101 @@ -// = im.js = // // **Copyright © 2005 – 2010 Joshua Gross**\\ // //MIT Licensed// // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. // // This is the main library for Ajax IM. It encompasses the UI controls, // and connecting with the server. It does //not// handle registration or // account management. (function($, _instance) { AjaxIM = function(options, actions) { if(this instanceof AjaxIM) { var self = this; // === {{{ defaults }}} === // // These are the available settings for Ajax IM, and the associated // defaults: // // * {{{pollType}}} determines the way in which the client will talk to // the server. // ** {{{comet}}} will use http streaming, wherein a connection to the server will be held open indefinitely, and the server will push down new events (messages, status updates) as they occur. // ** {{{long}}} will hold open a connection with the server for as long as possible, or until a new event is received. Upon the server sending an event or closing the connection, the client will automatically—and immediately—reconnect. // ** {{{short}}} will open a connection, and the server (if this method is supported) will //immediately// provide a response as to whether or not there are any new events. Once a response is received, the client will wait 5 seconds, and then reconnect. // * {{{pollServer}}} is the default URL to which all actions refer. It is // possible to specify certain action URLs separately (as is used with the // NodeJS server). // * {{{cookieName}}} is the name of the session cookie used by the server. // If this is not set properly, the IM engine will not be able to automatically // reinitialize sessions. // * {{{theme}}} is the name of the theme folder that defines the HTML and // CSS of the IM bar and chat boxes. Usually, themes are deposited in the // provided "themes" folder and specified by that path, e.g. {{{themes/default}}}. // Theme files within the theme folder must be named {{{theme.html}}} and // {{{theme.css}}}. // * {{{storageMethod}}} defines the way in which data (chat sessions) are // temporarily stored client-side. By default, {{{"flash"}}} is used because // it is the most widely supported method. However, // [[http://eric.garside.name/docs.html?p=jstore#js-engines|other storage engines]] // are available, with their respective up- and down-sides // outlined, on the jStore website. // * {{{storeSession}}} (**not implemented**) sets the number of days to // retain stored chat session data before it should be deleted. // * {{{checkResume}}} is a flag that sets whether or not the client should // make a call to the server before resuming the session (such as on a page // reload). This will ensure that the session has not expired. If set to {{{false}}}, // a call to the server will not be made, and the session will be assumed to // be active. var defaults = { pollType: 'long', pollServer: './ajaxim.php', cookieName: 'ajaxim_session', theme: 'themes/default', storageMethod: 'auto', flashStorage: 'js/jStore.Flash.html', storeSession: 5, // number of days to store chat data (0 for current session only) checkResume: true }; // === {{{AjaxIM.}}}**{{{settings}}}** === // // These are the settings for the IM. If particular options are not specified, // the defaults (see above) will be used. //These options will be defined // upon calling the initialization function, and not set directly.// this.settings = $.extend(defaults, options); // === {{{AjaxIM.}}}**{{{actions}}}** === // // Each individual action that the IM engine can execute is predefined here. // By default, it merely appends the action onto the end of the {{{pollServer}}} url, // however, it is possible to define actions individually. //The alternative actions // will be defined upon calling the initialization function, and not set directly.// // // Should you define an action at a different URL, Ajax IM will determine whether // or not this URL is within the current domain. If it is within a subdomain of // the current domain, it will set the document.domain variable for you, // to match a broader hostname scope; the action will continue to use {{{$.post}}} // (the default AJAX method for Ajax IM). // // On the other hand, should you choose a URL outside the current domain // Ajax IM will switch to {{{$.getJSON}}} (a get request) to avoid // cross-domain scripting issues. This means that a server on a different // port or at a different address will need to be able to handle GET // requests rather than POST requests (such as how the Node.JS Ajax IM // server works). this.actions = $.extend({ login: this.settings.pollServer + '/login', logout: this.settings.pollServer + '/logout', register: this.settings.pollServer + '/register', poll: this.settings.pollServer + '/poll?method=' + this.settings.pollType, send: this.settings.pollServer + '/send', status: this.settings.pollServer + '/status', resume: this.settings.pollServer + '/resume' }, actions); var httpRx = new RegExp('^http://', 'i'), slashslashRx = new RegExp('^//', 'i'), queryStrRx = new RegExp('[?](.+)$'), subdomainRx = new RegExp('((http[s]?:)?//)?(.+?)[.]' + window.location.host, 'i'); $.each(this.actions, function(name, action) { if(name == 'poll' || name == 'send') { if(self.settings.pollType != 'comet') action += (queryStrRx.test(action[1]) ? '&' : '?') + 'callback=?'; action = ['jsonp', action]; } else { action = ['ajax', action]; if(subdomainRx.test(action[1])) { document.domain = '.' + window.location.host; } else if((http = httpRx.test(action[1])) || slashslashRx.test(action[1])) { if(!(new RegExp('//' + window.location.host + '/', 'i')).test(action[1])) { action[1] += (queryStrRx.test(action[1]) ? '&' : '?') + 'callback=?'; action = ['jsonp', action[1]]; } } } self.actions[name] = action; }); // We load the theme dynamically based on the passed // settings. If the theme is set to false, we assume // that the user is going to load it himself. this.themeLoaded = false; if(this.settings.theme) { $('
    ').appendTo('body').load(this.settings.theme + '/theme.html #imjs-bar, .imjs-tooltip', function() { self.themeLoaded = true; setup.apply(self); } ); if(typeof document.createStyleSheet == 'function') document.createStyleSheet(this.settings.theme + '/theme.css'); else $('body').append(''); } else { this.themeLoaded = true; setup.apply(this); } // Client-side storage for keeping track of // conversation states, active tabs, etc. // The default is flash storage, however, other // options are available via the jStore library. if(this.settings.storageMethod) { this.storageBrowserKey = 'unknown'; this.storeKey = ''; $.each($.browser, function(k, v) { if(k == 'version') return true; else if(v == true) { self.storageBrowserKey = k; return false; } }); if(this.settings.storageMethod == 'auto') { $.each(['ie', 'html5', 'local', 'flash'], function() { if($.jStore.Availability[this]()) { self.settings.storageMethod = this; return false; } }); } $.extend($.jStore.defaults, { project: 'im.js', engine: this.settings.storageMethod, flash: this.settings.flashStorage }); this.storageReady = false; if(this.settings.storageMethod == 'flash') { $.jStore.ready(function(engine) { $.jStore.flashReady(function() { self.storageReady = true; setup.apply(self); }); }) } else { $.jStore.ready(function(engine) { self.storageReady = true; setup.apply(self); }); } $.jStore.load(); } else { this.storageReady = true; setup.apply(this); } // Allow a chatbox to me minimized $('.imjs-chatbox').live('click', function(e) { e.preventDefault(); return false; }); $('.imjs-chatbox .imjs-minimize').live('click', function() { $(this).parents('.imjs-chatbox').data('tab').click(); }); // Allow a chatbox to be closed $('.imjs-chatbox .imjs-close').live('click', function() { var chatbox = $(this).parents('.imjs-chatbox'); chatbox.data('tab') .data('state', 'closed').css('display', 'none'); if(self.settings.storageMethod && self.storageReady) { delete self.chatstore[chatbox.data('username')]; if(self.storageReady) { $.jStore.store( self.storageBrowserKey + '-' + self.username + '-chats', self.chatstore); } } }); // Setup message sending for all chatboxes $('.imjs-chatbox .imjs-input').live('keydown', function(event) { var obj = $(this); if(event.keyCode == 13 && !($.browser.msie && $.browser.version < 8)) { self.send(obj.parents('.imjs-chatbox').data('username'), obj.val()); } }).live('keyup', function(event) { if(event.keyCode == 13) { if($.browser.msie && $.browser.version < 8) { var obj = $(this); self.send(obj.parents('.imjs-chatbox').data('username'), obj.val()); } var obj = $(this); obj.val(''); obj.height(obj.data('height')); } }).live('keypress', function(e) { var obj = $(this); if(!($.browser.msie && $.browser.opera)) obj.height(0); if(this.scrollHeight > obj.height() || this.scrollHeight < obj.height()) { obj.height(this.scrollHeight); } }); $('.imjs-msglog').live('click', function() { var chatbox = $(this).parents('.imjs-chatbox'); chatbox.find('.imjs-input').focus(); }); // Create a chatbox when a buddylist item is clicked $('.imjs-friend').live('click', function() { var chatbox = self._createChatbox($(this).data('friend')); if(chatbox.data('tab').data('state') != 'active') chatbox.data('tab').click(); chatbox.find('.imjs-input').focus(); }); // Setup and hide the scrollers $('.imjs-scroll').css('display', 'none'); $('#imjs-scroll-left').live('click', function() { var hiddenTab = $('#imjs-bar li.imjs-tab:visible').slice(-1) .next('#imjs-bar li.imjs-tab:hidden') .filter(function() { return $(this).data('state') != 'closed' }) .not('.imjs-default').slice(-1).css('display', ''); if(hiddenTab.length) { $('#imjs-bar li.imjs-tab:visible').eq(0).css('display', 'none'); $(this).html(parseInt($(this).html()) - 1); $('#imjs-scroll-right').html(parseInt($('#imjs-scroll-right').html()) + 1); } return false; }); $('#imjs-scroll-right').live('click', function() { var hiddenTab = $('#imjs-bar li.imjs-tab:visible').eq(0) .prev('#imjs-bar li.imjs-tab:hidden') .filter(function() { return $(this).data('state') != 'closed' }) .not('.imjs-default').slice(-1).css('display', ''); if(hiddenTab.length) { $('#imjs-bar li.imjs-tab:visible').slice(-1).css('display', 'none'); $(this).html(parseInt($(this).html()) - 1); $('#imjs-scroll-left').html(parseInt($('#imjs-scroll-left').html()) + 1); } return false; }); // Initialize the chatbox hash this.chats = {}; // Try to resume any existing session this.resume(); $(window).resize(function() { self.bar._scrollers(); }); } else return AjaxIM.init(options); }; // We predefine all public functions here... // If they are called before everything (theme, storage engine) has loaded, // then they get put into a "prequeue" and run when everything *does* // finally load. // // This ensures that nothing loads without all of the principal components // being pre-loaded. If that were to occur (without this prequeue), things // would surely break. var prequeue = []; var empty = function() { var func = this; return function() { prequeue.push([func, arguments]) }; }; $.extend(AjaxIM.prototype, { settings: {}, friends: {}, chats: {}, storage: empty.apply('storage'), login: empty.apply('login'), logout: empty.apply('logout'), resume: empty.apply('resume'), form: empty.apply('form'), poll: empty.apply('poll'), incoming: empty.apply('incoming'), send: empty.apply('send'), status: empty.apply('status'), statuses: {}, bar: { initialize: empty.apply('bar.initialize'), activateTab: empty.apply('bar.activateTab'), closeTab: empty.apply('bar.closeTab'), addTab: empty.apply('bar.addTab'), notification: empty.apply('bar.notification'), _scrollers: empty.apply('bar._scrollers') } }); setup = (function() { var self = this; if(!this.storageReady || !this.themeLoaded) return; $(self).trigger('loadComplete'); $(window).resize(); $.extend(AjaxIM.prototype, { // == Cookies == // // The "cookies" functions can be used to set, get, and erase JSON-based cookies. // These functions are primarily used to manage and read the server-set cookie // that handles the user's chat session ID. cookies: { // === {{{AjaxIM.}}}**{{{cookies.set(name, value, days)}}}** === // // Sets a cookie, stringifying the JSON value upon storing it. // // ==== Parameters ==== // * {{{name}}} is the cookie name.\\ // * {{{value}}} is the cookie data that you would like to store.\\ // * {{{days}}} is the number of days that the cookie will be stored for. set: function(name, value, days) { if (days) { var date = new Date(); date.setTime(date.getTime() + (days * 24 * 60 * 60 * 1000)); var expires = "; expires=" + date.toGMTString(); } else var expires = ""; document.cookie = name + "=" + $.compactJSON(value) + expires + "; path=/"; }, // === {{{AjaxIM.}}}**{{{cookies.get(name)}}}** === // // Gets a cookie, decoding the JSON value before returning the data. // // ==== Parameters ==== // * {{{name}}} is the cookie name that you would like to retrieve. get: function(name) { var nameEQ = name + "="; var ca = document.cookie.split(';'); for(var i = 0; i < ca.length; i++) { var c = ca[i]; while (c.charAt(0) == ' ') c = c.substring(1, c.length); if (c.indexOf(nameEQ) == 0) { var cval = decodeURIComponent(c.substring(nameEQ.length, c.length)); return $.secureEvalJSON(cval); } } return null; }, // === {{{AjaxIM.}}}**{{{cookies.erase(name)}}}** === // // Deletes a cookie. // // {{{name}}} is the existing cookie that you would like to delete. erase: function(name) { self.cookies.set(name, '', -1); } }, // == Main == // === {{{AjaxIM.}}}**{{{storage()}}}** === // // Retrieves chat session data from whatever storage engine is enabled // (provided that one is enabled at all). If a page reloads, this function // is called to restore the user's chat state (existing conversations, active tab). // This function is called //automatically//, upon initialization of the IM engine. storage: function() { if(!self.storeKey.length) return; try { var chatstore = $.jStore.store(self.storeKey + 'chats') || {}; } catch(e) { $.jStore.remove(self.storeKey + 'chats'); var chatstore = {}; } if(this.chatstore) { $.each(this.chatstore, function(username, convo) { if(username in chatstore) chatstore[username] = $.merge(chatstore[username], self.chatstore[username]); else chatstore[username] = self.chatstore[username]; }); this.chatstore = chatstore; $.jStore.store(self.storeKey + 'chats', chatstore); } else { this.chatstore = chatstore; } $.each(this.chatstore, function(username, convo) { if(!convo.length) return; var chatbox = self._createChatbox(username, true); chatbox.data('lastDateStamp', null).css('display', 'none'); // Remove the automatic date stamp chatbox.find('.imjs-msglog').empty(); // Restore all messages, date stamps, and errors $.each(convo, function() { switch(this[0]) { case 'error': self._addError(chatbox, decodeURIComponent(this[2]), this[3]); break; case 'datestamp': self._addDateStamp(chatbox, this[3]); break; case 'a': case 'b': self._addMessage(this[0], chatbox, this[1], decodeURIComponent(this[2]), this[3]); break; } }); $(self).trigger('chatRestored', [username, chatbox]); }); var activeTab = $.jStore.store(self.storeKey + 'activeTab') || []; if(activeTab.length && (activeTab = activeTab[0]) && activeTab in this.chats) { this.chats[activeTab].data('tab').click(); var msglog = this.chats[activeTab].find('.imjs-msglog'); msglog[0].scrollTop = msglog[0].scrollHeight; } }, // === {{{AjaxIM.}}}**{{{login(username, password)}}}** === // // Authenticates a user and initializes the IM engine. If the user is // already logged in, [s]he is logged out, the session is cleared, and // the new user is logged in. // // Returns the user's properly formatted username, session ID, and online // friends in JSON, if successful; e.g.:\\ // {{{ {u: 'username', s: 'longsessionid', f: [{u: 'friend', s: 1, g: 'group'}]} }}} // // If unsuccessful, {{{false}}} is returned. // // ==== Parameters ==== // * {{{username}}} is the user's username.\\ // * {{{password}}} is the user's password. This password will be MD5 hashed // before it is sent to the server. login: function(username, password) { if(!username) username = ''; if(!password) password = ''; if(this.username) return true; // Already logged in! // hash password before sending it to the server password = $.md5(password); // authenticate AjaxIM.request( this.actions.login, {'username': username, 'password': password}, function(auth) { if(auth.r == 'logged in') { self.username = ('u' in auth ? auth.u : username); if(self.settings.storageMethod) self.storeKey = [self.storageBrowserKey, self.username, ''].join('-'); var existing = self.cookies.get(self.settings.cookieName); self.storage(); // Begin the session $.each(auth.f, function() { self.friends[this.u] = {status: [this.s, ''], group: this.g}; }); self._session(self.friends); self._storeFriends(); $(self).trigger('loginSuccessful', [auth]); return auth; } else { $(self).trigger('loginError', [auth]); } return false; } ); }, // === {{{AjaxIM.}}}**{{{logout()}}}** === // // Logs the user out and removes his/her session cookie. As well, it // will close all existing chat windows, clear the storage engine, and // remove the IM bar. logout: function() { AjaxIM.request( this.actions.logout, {}, function(done) { if(done) { self.cookies.erase(self.settings.cookieName); self._clearSession(); $(self).trigger('logoutSuccessful'); return true; } else { $(self).trigger('logoutError'); return false; } } ); }, // === {{{AjaxIM.}}}**{{{resume()}}}** === // // Resumes an existing session based on a session ID stored in the // server-set cookie. This function is called //automatically// upon IM // engine (re-)initialization, so the user does not need to re-login // should a session already exist. resume: function() { var session = this.cookies.get(this.settings.cookieName); if(session && session.sid) { this.username = session.user; this.storeKey = [this.storageBrowserKey, this.username, ''].join('-'); var friends = $.jStore.store(this.storeKey + 'friends') || []; if(self.settings.checkResume) { AjaxIM.request( this.actions.resume, {}, function(response) { if(response.r == 'connected') { self._session(friends); self.storage(); } else { var username = this.username; self._clearSession(); $(self).trigger('sessionNotResumed', [username]); } } ); } else { self._session(friends); self.storage(); } } else { $(self).trigger('noSession'); } }, // === //private// {{{AjaxIM.}}}**{{{_session(friends)}}}** === // // Restores session data (username, friends) and begins polling the server. // Called only by {{{AjaxIM.resume()}}}. // // ==== Parameters ==== // * {{{friends}}} is a list of "friend" objects, e.g.:\\ // {{{[{u: 'friend', s: 1, g: 'group'}, ...]}}} // ** {{{u}}} being the friend's username. // ** {{{s}}} being one of the available status codes (see {{{AjaxIM.statuses}}}), depending on the friend's current status. // ** {{{g}}} being the group that the friend is in. _session: function(friends) { $('#imjs-friends-panel .imjs-header span').html(this.username); $('#imjs-friends').removeClass('imjs-not-connected'); $.each(friends, function(friend, info) { self.addFriend.apply(self, [friend, info.status, info.group]); }); self._storeFriends(); $(self).trigger('sessionResumed', [this.username]); setTimeout(function() { self.poll(); }, 0); }, // === //private// {{{AjaxIM.}}}**{{{_clearSession()}}}** === // // Clears all session data from the last known user. _clearSession: function() { if(self.settings.storageMethod && self.storageReady) { $.jStore.remove(self.storeKey + 'chats'); $.jStore.remove(self.storeKey + 'friends'); $.jStore.remove(self.storeKey + 'activeTab'); } self.chats = {}; $('.imjs-tab').not('.imjs-tab.imjs-default').remove(); self.cookies.erase('ajaxim_session'); delete self.username; }, // === {{{AjaxIM.}}}**{{{form(element)}}}** === // // Loads a login and registration form into the specified element // or, if no element is supplied, to the location on the page from // which this function was called. form: function(element) { $(element).load(this.settings.theme + '/theme.html #imjs-lr', function() { $('#imjs-lr .error').hide(); if(self.username) { $('#imjs-register, #imjs-login fieldset').hide(); $('#imjs-logged-in') .show() .html($('#imjs-logged-in').html().replace('{username}', self.username)); } else { $('#imjs-logged-in').hide(); } // Handle logout success $(self).bind('logoutSuccessful', function() { $('#imjs-login fieldset').slideDown(); $('#imjs-register').slideDown(); $('#imjs-logged-in') .html($('#imjs-logged-in strong').html('{username}')) .slideUp(); }); $('#imjs-logged-in a').click(function() { self.logout(); return false; }); // Handle login error or success $(self).bind('loginError', function() { $('#imjs-login .error').html(AjaxIM.i18n.authInvalid).slideDown('fast'); $('#imjs-login input') .addClass('imjs-lr-error') .blur(function() { $(this).removeClass('imjs-lr-error'); }); }).bind('loginSuccessful', function() { $('#imjs-login fieldset').slideUp(); $('#imjs-register').slideUp(); $('#imjs-logged-in') .html($('#imjs-logged-in').html().replace('{username}', self.username)) .slideDown(); }); var login = function() { self.login($('#imjs-login-username').val(), $('#imjs-login-password').val()); return false; }; $('#imjs-login').submit(login); $('#imjs-login-submit').click(login); var regIssues = false; var regError = function(error, fields) { $('#imjs-register .error') .append(AjaxIM.i18n['register' + error] + ' ') .slideDown(); $(fields) .addClass('imjs-lr-error') .blur(function() { $(this).removeClass('imjs-lr-error'); }); regIssues = true; }; var register = function() { $('#imjs-register .error').empty(); regIssues = false; var username = $('#imjs-register-username').val(); var password = $('#imjs-register-password').val(); if(password.length < 4) regError('PasswordLength', '#imjs-register-password'); if(password != $('#imjs-register-cpassword').val()) regError('PasswordMatch', '#imjs-register-password, #imjs-register-cpassword'); if(username.length <= 2 || !$('#imjs-register-username').val().match(/^[A-Za-z0-9_.]+$/)) regError('UsernameLength', '#imjs-register-username'); if(!regIssues) { AjaxIM.request( self.actions.register, {username: username, password: password}, function(response) { if(response.r == 'registered') { self.login(username, password); } else if(response.r == 'error') { switch(response.e) { case 'unknown': regError('Unknown', ''); break; case 'invalid password': regError('PasswordLength', '#imjs-register-password'); break; case 'invalid username': regError('UsernameLength', '#imjs-register-username'); break; case 'username taken': regError('UsernameTaken', '#imjs-register-username'); break; } } }, function(error) { regError('Unknown', ''); } ); } return false; }; $('#imjs-register').submit(register); $('#imjs-register-submit').click(register); }); }, // === {{{AjaxIM.}}}**{{{poll()}}}** === // // Queries the server for new messages. If a 'long' or 'short' poll // type is used, jQuery's {{{$.post}}} or {{{$.getJSON}}} will be // used. If 'comet' is used, the server connection will be deferred // to the comet set of functions. poll: function() { if(/^(short|long)$/.test(this.settings.pollType)) { AjaxIM.request( this.actions.poll, {}, function(response) { if(!response['e']) { if(response.length) self._parseMessages(response); setTimeout(function() { self.poll(); }, 0); } else { switch(response.e) { case 'no session found': self._notConnected(); break; } $(self).trigger('pollFailed', [response.e]); } }, function(error) { self._notConnected(); $(self).trigger('pollFailed', ['not connected']); // try reconnecting? } ); } else if(this.settings.pollType == 'comet') { this.comet.connect(); } }, // === //private// {{{AjaxIM.}}}**{{{_parseMessages(messages)}}}** === // // Handles an incoming message array:\\ // {{{[{t: 'type', s: 'sender', r: 'recipient', m: 'message'}, ...]}}} // // * {{{t}}} (message type) is one of: // ** {{{m}}} — a standard message // ** {{{s}}} — a user's status update // ** {{{b}}} — a broadcasted message (sent to many users simultaneously) // * {{{s}}} is the sender of the message. // * {{{r}}} is the intended recipient of the message. Most of the time, this will // simply be the logged in user, however, a broadcasted message may not specify // a recipient or may specify a different recipient. Also provides future // compatability for chatrooms. // * {{{m}}} is the actual message. For something such as a status update, this can // be a JSON object or parsable string; e.g. {{{"2:I'm away."}}} // // ==== Parameters ==== // * {{{messages}}} is the message array _parseMessages: function(messages) { if($.isArray(messages)) { $.each(messages, function() { $(self).trigger('parseMessage', [this]); switch(this.t) { case 'm': self.incoming(this.s, this.m); break; case 's': var status = this.m.split(':'); if(this['g']) self.addFriend(this.s, status, this.g); self._friendUpdate(this.s, status[0], status.slice(1).join(':')); self._storeFriends(); break; case 'b': break; default: break; } }); } }, // === {{{AjaxIM.}}}**{{{incoming(from, message)}}}** === // // Handles a new message from another user. If a chatbox for that // user does not yet exist, one is created. If it does exist, but // is minimized, the user is notified but the chatbox is not brought // to the front. This function also stores the message, if a storage // method is set. // // ==== Parameters ==== // * {{{from}}} is the username of the sender. // * {{{message}}} is the body. incoming: function(from, message) { // check if IM exists, otherwise create new window // TODO: If friend is not on the buddylist, // should add them to a temp list? var chatbox = this._createChatbox(from); if(!$('#imjs-bar .imjs-selected').length) { chatbox.data('tab').click(); } else if(chatbox.data('tab').data('state') != 'active') { this.bar.notification(chatbox.data('tab')); } var time = this._addMessage('b', chatbox, from, message); this._storeMessage('b', chatbox, from, message, time); }, // === {{{AjaxIM.}}}**{{{addFriend(username, group)}}}** === // // Inserts a new friend into the friends list. If the group specified // doesn't exist, it is created. If the friend is already in this group, // they aren't added again, however, the friend item is returned. // // ==== Parameters ==== // * {{{username}}} is the username of the new friend. // * {{{status}}} is the current status of the friend. // * {{{group}}} is the user group to which the friend should be added. addFriend: function(username, status, group) { var status_name = 'available'; $.each(this.statuses, function(key, val) { if(status[0] == val) { status_name = key; return false; } }); var group_id = 'imjs-group-' + $.md5(group); if(!(group_item = $('#' + group_id)).length) { var group_item = $('.imjs-friend-group.imjs-default').clone() .removeClass('imjs-default') .attr('id', group_id) .data('group', group) .appendTo('#imjs-friends-list'); var group_header = group_item.find('.imjs-friend-group-header'); group_header.html(group_header.html().replace('{group}', group)); } var user_id = 'imjs-friend-' + $.md5(username + group); if(!$('#' + user_id).length) { var user_item = group_item.find('ul li.imjs-default').clone() .removeClass('imjs-default') .addClass('imjs-' + status_name) .attr('id', user_id) .data('friend', username) .appendTo(group_item.find('ul')); if(status[0] == 0) user_item.hide(); user_item.html(user_item.html().replace('{username}', username)); } this.friends[username] = {'status': status, group: group}; this._updateFriendCount(); return this.friends[username]; }, // === //private// {{{AjaxIM.}}}**{{{_updateFriendCount()}}}** === // // Counts the number of online friends and updates the friends count // in the friend tab. _updateFriendCount: function() { var friendsLength = 0; for(var f in this.friends) { if(this.friends[f].status[0] != 0) friendsLength++; } $('#imjs-friends .imjs-tab-text span span').html(friendsLength); }, // === //private// {{{AjaxIM.}}}**{{{_storeFriends()}}}** === // // If a storage method is enabled, the current state of the // user's friends list is stored. _storeFriends: function() { if(this.settings.storageMethod && this.storageReady) $.jStore.store(this.storeKey + 'friends', this.friends); }, // === //private// {{{AjaxIM.}}}**{{{_createChatbox(username)}}}** === // // Builds a chatbox based on the default chatbox HTML and CSS defined // in the current theme. Should a chatbox for this user already exist, // a new one is not created. Instead, it is either given focus (should // no other windows already have focus), or a notification is issued. // // As well, if the chatbox does not exist, an associated tab will be // created. // // ==== Parameters ==== // * {{{username}}} is the name of the user for whom the chatbox is intended // for. // * {{{no_stamp}}} sets whther or not to add a date stamp to the chatbox // upon creation. // // //Note:// New chatboxes are given an automatically generated ID in the // format of {{{#imjs-[md5 of username]}}}. _createChatbox: function(username, no_stamp) { var chatbox_id = 'imjs-' + $.md5(username); if(!(chatbox = $('#' + chatbox_id)).size()) { // add a tab var tab = this.bar.addTab(username, '#' + chatbox_id); var chatbox = tab.find('.imjs-chatbox'); chatbox.attr('id', chatbox_id); chatbox.data('tab', tab); // remove default items from the message log var message_log = chatbox.find('.imjs-msglog').empty(); // setup the chatbox header var cb_header = chatbox.find('.imjs-header'); cb_header.html(cb_header.html().replace('{username}', username)); if(!no_stamp) { // add a date stamp var time = this._addDateStamp(chatbox); this._storeNonMessage('datestamp', username, null, time); } // associate the username with the object and vice-versa this.chats[username] = chatbox; chatbox.data('username', username); // did this chatbox fall down? this.bar._scrollers(); if(username in this.friends) { status = this.friends[username].status; var status_name = 'available'; $.each(this.statuses, function(key, val) { if(status[0] == val) { status_name = key; return false; } }); tab.addClass('imjs-' + status_name); } // store inputbox height //var input = chatbox.find('.imjs-input'); //input.data('height', input.height()); } else if(chatbox.data('tab').data('state') == 'closed') { chatbox.find('.imjs-msglog > *').addClass('imjs-msg-old'); var tab = chatbox.data('tab'); if(tab.css('display') == 'none') tab.css('display', '').removeClass('imjs-selected') .appendTo('#imjs-bar'); if(!no_stamp) { // possibly add a date stamp var time = this._addDateStamp(chatbox); this._storeNonMessage('datestamp', username, null, time); } if(!$('#imjs-bar .imjs-selected').length) { tab.click(); } else { this.bar.notification(tab); } } return chatbox; }, // === //private// {{{AjaxIM.}}}**{{{_addDateStamp(chatbox)}}}** // // // Adds a date/time notifier to a chatbox. These are generally // inserted upon creation of a chatbox, or upon the date changing // since the last time a date stamp was added. If a date stamp for // the current date already exists, a new one will not be added. // // ==== Parameters ==== // * {{{chatbox}}} refers to the jQuery-selected chatbox DOM element. // * {{{time}}} is the date/time the date stamp will show. It is specified // in milliseconds since the Unix Epoch. This is //only// defined when // date stamps are being restored from storage; if not specified, the // current computer time will be used. _addDateStamp: function(chatbox, time) { var message_log = $(chatbox).find('.imjs-msglog'); if(!time) time = (new Date()).getTime(); var date_stamp = $('.imjs-tab.imjs-default .imjs-chatbox .imjs-msglog .imjs-date').clone(); var date_stamp_time = date_stamp.find('.imjs-msg-time'); if(date_stamp_time.length) date_stamp_time.html(AjaxIM.dateFormat(time, date_stamp_time.html())); var date_stamp_date = date_stamp.find('.imjs-date-date'); var formatted_date = AjaxIM.dateFormat(time, date_stamp_date.html()); if(chatbox.data('lastDateStamp') != formatted_date) { if(date_stamp_date.length) date_stamp_date.html(AjaxIM.dateFormat(time, date_stamp_date.html())); chatbox.data('lastDateStamp', formatted_date); date_stamp.appendTo(message_log); } else { //$('
    ').appendTo(message_log); } return time; }, // === //private// {{{AjaxIM.}}}**{{{_addError(chatbox, error)}}}** // // // Adds an error to a chatbox. These are generally inserted after // a user sends a message unsuccessfully. If an error message // was already added, another one will be added anyway. // // ==== Parameters ==== // * {{{chatbox}}} refers to the jQuery-selected chatbox DOM element. // * {{{error}}} is the error message string. // * {{{time}}} is the date/time the error occurred. It is specified in // milliseconds since the Unix Epoch. This is //only// defined when // errors are being restored from storage; if not specified, the current // computer time will be used. _addError: function(chatbox, error, time) { var message_log = $(chatbox).find('.imjs-msglog'); var error_item = $('.imjs-tab.imjs-default .imjs-chatbox .imjs-msglog .imjs-error').clone(); var error_item_time = error_item.find('.imjs-msg-time'); if(error_item_time.length) { if(!time) time = (new Date()).getTime(); error_item_time.html(AjaxIM.dateFormat(time, error_item_time.html())); } error_item.find('.imjs-error-error').html(error); error_item.appendTo(message_log); message_log[0].scrollTop = message_log[0].scrollHeight; }, // === //private// {{{AjaxIM.}}}**{{{_addMessage(ab, chatbox, username, message, time)}}}** // // // Adds a message to a chatbox. Depending on the {{{ab}}} value, // the color of the username may change as a way of visually // identifying users (however, this depends on the theme's CSS). // A timestamp is added to the message, and the chatbox is scrolled // to the bottom, such that the new message is visible. // // Messages will be automatically tag-escaped, so as to prevent // any potential cross-site scripting problems. Additionally, // URLs will be automatically linked. // // ==== Parameters ==== // * {{{ab}}} refers to whether the user is "a" or "b" in a conversation. // For the general case, "you" are "a" and "they" are "b". // * {{{chatbox}}} refers to the jQuery-selected chatbox DOM element. // * {{{username}}} is the username of the user who sent the message. // * {{{time}}} is the time the message was sent in milliseconds since // the Unix Epoch. This is //only// defined when messages are being // restored from storage. For new messages, the current computer // time is automatically used. _addMessage: function(ab, chatbox, username, message, time) { var last_message = chatbox.find('.imjs-msglog > *:last-child'); if(last_message.hasClass('imjs-msg-' + ab)) { // Last message was from the same person, so let's just add another imjs-msg-*-msg var message_container = (last_message.hasClass('imjs-msg-' + ab + '-container') ? last_message : last_message.find('.imjs-msg-' + ab + '-container')); var single_message = $('.imjs-tab.imjs-default .imjs-chatbox .imjs-msglog .imjs-msg-' + ab + '-msg') .clone().appendTo(message_container); single_message.html(single_message.html().replace('{username}', username)); } else if(!last_message.length || !last_message.hasClass('imjs-msg-' + ab)) { var message_group = $('.imjs-tab.imjs-default .imjs-chatbox .imjs-msg-' + ab) .clone().appendTo(chatbox.find('.imjs-msglog')); message_group.html(message_group.html().replace('{username}', username)); var single_message = message_group.find('.imjs-msg-' + ab + '-msg'); } // clean up the message message = message.replace(//g, '>') .replace(/(^|.*)\*([^*]+)\*(.*|$)/, '$1$2$3'); // autolink URLs message = message.replace( new RegExp('([A-Za-z][A-Za-z0-9+.-]{1,120}:[A-Za-z0-9/]' + '(([A-Za-z0-9$_.+!*,;/?:@&~=-])|%[A-Fa-f0-9]{2}){1,333}' + '(#([a-zA-Z0-9][a-zA-Z0-9$_.+!*,;/?:@&~=%-]{0,1000}))?)', 'g'), '$1'); // insert the message single_message.html(single_message.html().replace('{message}', message)); // set the message time var msgtime = single_message.find('.imjs-msg-time'); if(!time) time = new Date(); if(typeof time != 'string') time = AjaxIM.dateFormat(time, msgtime.html()); msgtime.html(time); var msglog = chatbox.find('.imjs-msglog'); msglog[0].scrollTop = msglog[0].scrollHeight; return time; }, // === //private// {{{AjaxIM.}}}**{{{_storeNonMessage(type, username, data, time)}}}** === // // **Redundant?**\\ // Similar to {{{AjaxIM._storeMessage}}}, but stores items that aren't messages, // such as datestamps and errors. // // ==== Parameters ==== // * {{{type}}} is the type of non-message (error, datestamp). // * {{{username}}} is the username of the user being chatted with. // * {{{data}}} is the (optional) data of the non-message to be stored. // * {{{time}}} is the time of the message. _storeNonMessage: function(type, username, data, time) { // If storage is on & ready, store the non-message if(this.settings.storageMethod) { if(!this.chatstore) this.chatstore = {}; if(!(username in this.chatstore)) this.chatstore[username] = []; // If the chat store gets too long, it becomes slow to load. if(this.chatstore[username].length > 300) this.chatstore[username].shift(); // For some reason, if we don't encode and decode the message, it *will* break // (at least) the Flash storage engine's retrieval. Gah! this.chatstore[username].push( [type, username, encodeURIComponent(data), time]); if(this.storageReady) $.jStore.store(self.storeKey + 'chats', this.chatstore); } }, // === //private// {{{AjaxIM.}}}**{{{_storeMessage(ab, chatbox, username, message, time)}}}** === // // Taking the same arguments as {{{AjaxIM._addMessage}}}, {{{_storeMessage}}} pushes a message // into the storage hash, if storage is enabled. // // Messages are added to a message array, by username. The entire chat hash is stored as // a {{{'chats'}}} object in whatever storage engine is enabled. _storeMessage: function(ab, chatbox, username, message, time) { // If storage is on & ready, store the message if(this.settings.storageMethod) { if(!this.chatstore) this.chatstore = {}; message = message.replace(//g, '>'); if(!(username in this.chatstore)) { this.chatstore[username] = []; } else if(this.chatstore[username].length > 300) { // If the chat store gets too long, it becomes slow to load. this.chatstore[username].shift(); } // For some reason, if we don't encode and decode the message, it *will* break // (at least) the Flash storage engine's retrieval. Gah! this.chatstore[chatbox.data('username')].push( [ab, username, encodeURIComponent(message), time]); if(this.storageReady) $.jStore.store(this.storeKey + 'chats', this.chatstore); } }, // === //private// {{{AjaxIM.}}}**{{{_friendUpdate(friend, status, statusMessage)}}}** === // // Called when a friend's status is updated. This function will update all locations // where a status icon is displayed (chat tab, friends list), as well as insert // a notification, should a chatbox be open. // // ==== Parameters ==== // * {{{friend}}} is the username of the friend. // * {{{status}}} is the new status code. See {{{AjaxIM.statuses}}} for a list of available // codes. //Note: If an invalid status is specified, no action will be taken.// // * {{{statusMessage}}} is a message that was, optionally, specified by the user. It will be // used should "you" send the user an IM while they are away, or if their status is viewed // in another way (such as via the friends list [**not yet implemented**]). _friendUpdate: function(friend, status, statusMessage) { // add friend to buddylist, update their status, etc. var status_name = 'available'; $.each(this.statuses, function(key, val) { if(status == val) { status_name = key; return false; } }); if(this.chats[friend]) { var tab = this.chats[friend].data('tab'); var tab_class = 'imjs-tab'; if(tab.data('state') == 'active') tab_class += ' imjs-selected'; tab_class += ' imjs-' + status_name; tab.attr('class', tab_class); // display the status in the chatbox var date_stamp = $('.imjs-tab.imjs-default .imjs-chatbox .imjs-msglog .imjs-date').clone(); var date_stamp_time = date_stamp.find('.imjs-msg-time'); if(date_stamp_time.length) date_stamp_time.html(AjaxIM.dateFormat(date_stamp_time.html())); var date_stamp_date = date_stamp.find('.imjs-date-date').html( AjaxIM.i18n[ 'chat' + status_name[0].toUpperCase() + status_name.slice(1) ].replace(/%s/g, friend)); var msglog = this.chats[friend].find('.imjs-msglog'); date_stamp.appendTo(msglog); msglog[0].scrollTop = msglog[0].scrollHeight; } if(this.friends[friend]) { var friend_id = 'imjs-friend-' + $.md5(friend + this.friends[friend].group); $('#' + friend_id).attr('class', 'imjs-friend imjs-' + status_name); if(status == 0) { $('#' + friend_id + ':visible').slideUp(); $('#' + friend_id + ':hidden').hide(); } else if(!$('#' + friend_id + ':visible').length) { $('#' + friend_id).slideDown(); } this.friends[friend].status = [status, statusMessage]; this._updateFriendCount(); } }, // === //private// {{{AjaxIM.}}}**{{{_notConnected()}}}** === // // Puts the user into a visible state of disconnection. Sets the // friends list to "not connected" and empties it; disallows new messages // to be sent. _notConnected: function() { $('#imjs-friends').addClass('imjs-not-connected').unbind('click', this.activateTab); }, // === {{{AjaxIM.}}}**{{{send(to, message)}}}** === // // Sends a message to another user. The message will be added // to the chatbox before it is actually sent, however, if an // error occurs during sending, that will be indicated immediately // afterward. // // After sending the message, one of three status codes should be // returned as a JSON object, e.g. {{{{r: 'code'}}}}: // * {{{ok}}} — Message was sent successfully. // * {{{offline}}} — The user is offline or unavailable to // receive messages. // * {{{error}}} — a problem occurred, unrelated to the user // being unavailable. // // ==== Parameters ==== // * {{{to}}} is the username of the recipient. // * {{{message}}} is the content to be sent. send: function(to, message) { if(!message) return; if(this.chats[to]) { // REMOVE ME? // possibly add a datestamp var time = self._addDateStamp(this.chats[to]); this._storeNonMessage('datestamp', to, null, time); time = this._addMessage('a', this.chats[to], this.username, message); this._storeMessage('a', this.chats[to], this.username, message, time); } $(self).trigger('sendingMessage', [to, message]); AjaxIM.request( this.actions.send, {'to': to, 'message': message}, function(result) { switch(result.r) { case 'ok': $(self).trigger('sendMessageSuccessful', [to, message]); break; case 'offline': $(self).trigger('sendMessageFailed', ['offline', to, message]); break; case 'error': default: if(result.e == 'no session found') { self._notConnected(); self._addError(self.chats[to], AjaxIM.i18n.notConnected); self._storeNonMessage('error', to, AjaxIM.i18n.notConnected, (new Date()).getTime()); } $(self).trigger('sendMessageFailed', [result.e, to, message]); break; } }, function(error) { self._notConnected(); self._addError(self.chats[to], AjaxIM.i18n.notConnected); self._storeNonMessage('error', to, AjaxIM.i18n.notConnected, (new Date()).getTime()); $(self).trigger('sendMessageFailed', ['not connected', to, message]); } ); }, // === {{{AjaxIM.}}}**{{{status(s, message)}}}** === // // Sets the user's status and status message. It is possible to not // set a status message by setting it to an empty string. The status // will be sent to the server, where upon the server will broadcast // the update to all individuals with "you" on their friends list. // // ==== Parameters ==== // * {{{s}}} is the status code, as defined by {{{AjaxIM.statuses}}}. // * {{{message}}} is the custom status message. status: function(s, message) { // update status icon(s) if(!this.statuses[s]) return; $('#imjs-friends').attr('class', 'imjs-' + s); $(self).trigger('changingStatus', [s, message]); AjaxIM.request( this.actions.status, {'status': this.statuses[s], 'message': message}, function(result) { switch(result.r) { case 'ok': $(self).trigger('changeStatusSuccessful', [s, message]); break; case 'error': default: $(self).trigger('changeStatusFailed', [result.e, s, message]); break; } }, function(error) { $(self).trigger('changeStatusFailed', ['not connected', s, message]); } ); }, // === {{{AjaxIM.}}}**{{{statuses}}}** === // // These are the available status codes and their associated identities: // * {{{offline}}} (0) — Only used when signing out/when another // user has signed out, as once this status is set, the user is removed // from the server and friends will be unable to contact the user. // * {{{available}}} (1) — The user is online and ready to be messaged. // * {{{away}}} (2) — The user is online but is not available. Others // may still contact this user, however, the user may not respond. Anyone // contacting an away user will receive a notice stating that the user is away, // and (if one is set) their custom status message. // * {{{invisible}}} (3; **not yet implemented**) — The user is online, // but other users are made unaware, and the user will be represented // as being offline. It is still possible to contact this user, and for this // user to contact others; no status message or notice will be sent to others // messaging this user. statuses: {offline: 0, available: 1, away: 2, invisible: 3}, // == Footer bar == // // The footer bar is the bar that sits at the bottom of the page, in a fixed // position. It contains a tab for the friends list, and tabs for any open // chat boxes. It is also possible to add custom tabs for other functionality. bar: { // === {{{AjaxIM.}}}**{{{bar.initialize()}}}** === // // Setup the footer bar and enable tab actions. This function // uses {{{jQuery.live}}} to set hooks on any bar tabs created // in the future. initialize: function() { // Set up your standard tab actions $('.imjs-tab') .live('click', this.activateTab); $('.imjs-tab .imjs-close') .live('click', this.closeTab); // Set up the friends list actions var self = this; $(document).click(function(e) { if(e.target.id == 'imjs-friends' || $(e.target).parents('#imjs-friends').length) { return; } if($('#imjs-friends').data('state') == 'active') self.activateTab.call($('#imjs-friends')); }); $('#imjs-friends') .data('state', 'minimized') .click(function(e) { if(!$(this).hasClass('imjs-not-connected') && e.target.id != 'imjs-friends-panel' && !$(e.target).parents('#imjs-friends-panel').length) self.activateTab.call(this); }) .mouseenter(function() { if($(this).hasClass('imjs-not-connected')) { $('.imjs-tooltip').css('display', 'block'); $('.imjs-tooltip p').html(AjaxIM.i18n.notConnectedTip); var tip_left = $(this).offset().left - $('.imjs-tooltip').outerWidth() + ($(this).outerWidth() / 2); var tip_top = $(this).offset().top - $('.imjs-tooltip').outerHeight(true); $('.imjs-tooltip').css({ left: tip_left, top: tip_top }); } }) .mouseleave(function() { if($(this).hasClass('imjs-not-connected')) { $('.imjs-tooltip').css('display', ''); } }); $('#imjs-friends-panel') .data('tab', $('#imjs-friends')) .css('display', 'none'); }, // === {{{AjaxIM.}}}**{{{bar.activateTab()}}}** === // // Activate a tab by setting it to the 'active' state and // showing any related chatbox. If a chatbox is available // for this tab, also focus the input box. // // //Note:// {{{this}}}, here, refers to the tab DOM element. activateTab: function() { var chatbox = $(this).find('.imjs-chatbox') || false; if($(this).data('state') != 'active') { if($(this).attr('id') != 'imjs-friends') { $('#imjs-bar > li') .not($(this)) .not('#imjs-friends') .removeClass('imjs-selected') .each(function() { if($(this).data('state') != 'closed') { $(this).data('state', 'minimized'); var chatbox = $(this).find('.imjs-chatbox'); if(chatbox.length) chatbox.css('display', 'none'); } }); } if(chatbox && chatbox.css('display') == 'none') chatbox.css('display', ''); // set the tab to active... var tab = $(this).addClass('imjs-selected').data('state', 'active'); // ...and hide and reset the notification icon tab.find('.imjs-notification').css('display', 'none') .data('count', 0); if(self.settings.storageMethod && self.storageReady && chatbox && (username = chatbox.data('username'))) { $.jStore.store(self.storeKey + 'activeTab', [username]); } $(self).trigger('tabToggled', ['activated', tab]); } else { var tab = $(this).removeClass('imjs-selected').data('state', 'minimized'); if(chatbox && chatbox.css('display') != 'none') chatbox.css('display', 'none'); if(self.settings.storageMethod && self.storageReady) { $.jStore.store(self.storeKey + 'activeTab', ['*']); } $(self).trigger('tabToggled', ['minimized', tab]); } if(chatbox) { if(!(input = chatbox.find('.imjs-input')).data('height')) { // store the height for resizing later input.data('height', input.height()); } try { var msglog = chatbox.find('.imjs-msglog'); msglog[0].scrollTop = msglog[0].scrollHeight; } catch(e) {} try { chatbox.find('.imjs-input').focus(); } catch(e) {} } }, // === {{{AjaxIM.}}}**{{{bar.closeTab()}}}** === // // Close a tab and hide any related chatbox, such that // the chatbox can not be reopened without reinitializing // the tab. // // //Note:// {{{this}}}, here, refers to the tab DOM element. closeTab: function() { var tab = $(this).parents('.imjs-tab'); tab.css('display', 'none').data('state', 'closed'); if(self.settings.storageMethod && self.storageReady) { delete self.chatstore[tab.find('.imjs-chatbox').data('username')]; if(self.storageReady) $.jStore.store(self.storeKey + 'chats', self.chatstore); } $(self).trigger('tabToggled', ['closed', tab]); self.bar._scrollers(); return false; }, // === {{{AjaxIM.}}}**{{{bar.addTab(label, action, closable)}}}** === // // Adds a tab to the tab bar, with the label {{{label}}}. When // clicked, it will call a callback function, {{{action}}}. If // {{{action}}} is a string, it is assumed that the string is // referring to a chatbox ID. // // ==== Parameters ==== // * {{{label}}} is the text that will be displayed on the tab.\\ // * {{{action}}} is the callback function, if it is a non-chatbox // tab, or a string if it //is// a chatbox tab.\\ // * {{{closable}}} is a boolean value that determines whether or not // it is possible for a user to close this tab. // // //Note:// New tabs are given an automatically generated ID // in the format of {{{#imjs-tab-[md5 of label]}}}. addTab: function(label, action, closable) { var tab = $('.imjs-tab.imjs-default').clone().insertAfter('#imjs-scroll-right'); tab.removeClass('imjs-default') .attr('id', 'imjs-tab-' + $.md5(label)) .html(tab.html().replace('{label}', label)) .data('state', 'minimized'); var notification = tab.find('.imjs-notification'); notification.css('display', 'none') .data('count', 0) .data('default-text', notification.html()) .html(notification.html().replace('{count}', '0')); if(closable === false) tab.find('.imjs-close').eq(0).remove(); if(typeof action == 'string') { //tab.data('chatbox', action); } else { tab.find('.imjs-chatbox').remove(); tab.click(action); } return tab; }, // === {{{AjaxIM.}}}**{{{bar.notification(tab)}}}** === // // Displays a notification on a tab. Generally, this is called when // a tab is minimized to let the user know that there is an update // for them. The way the notification is displayed depends on the // theme CSS. // // ==== Parameters ==== // * {{{tab}}} is the jQuery-selected tab DOM element. notification: function(tab) { var notify = tab.find('.imjs-notification'); var notify_count = notify.data('count') + 1; notify.data('count', notify_count) .html(notify.data('default-text').replace('{count}', notify_count)) .css('display', ''); }, // === //private// {{{AjaxIM.}}}**{{{bar._scrollers()}}}** === // // Document me! _scrollers: function() { var needScrollers = false; $('.imjs-tab').filter(function() { return $(this).data('state') != 'closed' }).css('display', ''); $.each(self.chats, function(username, chatbox) { var tab = chatbox.data('tab'); if(tab.data('state') == 'closed') return true; if(tab.position().top > $('#imjs-bar').height()) { $('.imjs-scroll').css('display', ''); tab.css('display', 'none'); needScrollers = true; } else { tab.css('display', ''); } }); if(!needScrollers) { $('.imjs-scroll').css('display', 'none'); } if($('#imjs-scroll-left').css('display') != 'none' && $('#imjs-scroll-left').position().top > $('#imjs-bar').height()) { $('#imjs-bar li.imjs-tab:visible').slice(-1).css('display', 'none'); } var hiddenLeft = $('#imjs-bar li.imjs-tab:visible').slice(-1) .nextAll('#imjs-bar li.imjs-tab:hidden') .not('.imjs-default') .filter(function() { return $(this).data('state') != 'closed' }).length; var hiddenRight = $('#imjs-bar li.imjs-tab:visible').eq(0) .prevAll('#imjs-bar li.imjs-tab:hidden') .not('.imjs-default') .filter(function() { return $(this).data('state') != 'closed' }).length; $('#imjs-scroll-left').html(hiddenLeft); $('#imjs-scroll-right').html(hiddenRight); } }, // == Comet == // // Comet, or HTTP streaming, holds open a connection between the client and // the server indefinitely. As the server receives new messages or events, // they are passed down to the client in a {{{<script>}}} // tag which calls the {{{AjaxIM.incoming()}}} function. The connection is // opened using either an {{{iframe}}} (in Opera or Internet Explorer) or // an {{{XMLHTTPRequest}}} object. Due to the extra flexibility necessary // with the {{{XMLHTTPRequest}}} object, jQuery's {{{$.ajax}}} is not used. comet: { type: '', obj: null, onbeforeunload: null, onreadystatechange: null, iframe: function() { if(/loaded|complete/i.test(this.obj.readyState)) throw new Error("IM server not available!"); }, // === {{{AjaxIM.}}}**{{{comet.connect()}}}** === // // Creates and initializes the object and connection between the server // and the client. For Internet Explorer and Opera, we use an // {{{<iframe>}}} element; for all other browsers, we create an // {{{XMLHTTPRequest}}} object. The server connects to the URI defined // as the "poll" action. This function is called automatically, when // the IM engine is initialized and the {{{AjaxIM.poll()}}} function // is called. connect: function() { var self = _instance; if($.browser.opera || $.browser.msie) { var iframe = $(''); with(iframe) { css({ position: 'absolute', visibility: 'visible', display: 'block', left: '-10000px', top: '-10000px', width: '1px', height: '1px' }); attr('src', self.actions.poll[1]); appendTo('body'); bind('readystatechange', self.comet.onreadystatechange = function() { self.comet.iframe() }); bind('beforeunload', self.comet.onbeforeunload = function() { self.comet.disconnect() }); } self.comet.type = 'iframe'; self.comet.obj = iframe; } else { var xhr = new XMLHttpRequest; var length = 1029; var code = /^\s*]*>parent\.(.+);<\/script>$/; xhr.open('get', self.actions.poll[1], true); xhr.onreadystatechange = function(){ if(xhr.readyState > 2) { if(xhr.status == 200) { responseText = xhr.responseText.substring(length); length = xhr.responseText.length; if(responseText != ' ') eval(responseText.replace(code, "$1")); } // We need an "else" here. If the state changes to // "loaded", the user needs to know they're // disconnected. } }; self.comet.type = 'xhr'; self.comet.obj = xhr; addEventListener('beforeunload', self.comet.beforeunload = function() { self.comet.disconnect(); }, false); setTimeout(function() { xhr.send(null) }, 10); } }, // === {{{AjaxIM.}}}**{{{comet.disconnect()}}}** === // // Disconnect from the server and destroy the connection object. This // function is called before the page unloads, so that we plug up and // potential leaks and free memory. disconnect: function() { var self = _instance.comet; if(!this.type || !this.obj) return; if(this.type == 'iframe') { detachEvent('onreadystatechange', this.onreadystatechange); detachEvent('onbeforeunload', this.onbeforeunload); this.obj.src = '.'; $(this.obj).remove(); } else { removeEventListener('beforeunload', this.onbeforeunload, false); this.obj.onreadystatechange = function(){}; this.obj.abort(); } delete this.obj; } } }) self.bar.initialize(); if(prequeue.length) { $.each(prequeue, function() { var func = this[0].split('.'); if(func.length > 1) self[func[0]][func[1]].apply(self, this[1]); else self[func[0]].apply(self, this[1]); }); } }); // == Static functions and variables == // // The following functions and variables are available outside of an initialized // {{{AjaxIM}}} object. // === {{{AjaxIM.}}}**{{{client}}}** === // // Once {{{AjaxIM.init()}}} is called, this will be set to the active AjaxIM // object. Only one AjaxIM object instance can exist at a time. This variable // can and should be accessed directly. AjaxIM.client = null; // === {{{AjaxIM.}}}**{{{init(options, actions)}}}** === // // Initialize the AjaxIM client object and engine. Here, you can define your // options and actions as outlined at the top of this documentation. // // ==== Parameters ==== // * {{{options}}} is the hash of custom settings to initialize Ajax IM with. // * {{{actions}}} is the hash of any custom action URLs. AjaxIM.init = function(options, actions) { if(!_instance) { _instance = new AjaxIM(options, actions); AjaxIM.client = _instance; } return _instance; } // === {{{AjaxIM.}}}**{{{request(url, data, successFunc, failureFunc)}}}** === // // Wrapper around {{{$.jsonp}}}, the JSON-P library for jQuery, and {{{$.ajax}}}, // jQuery's ajax library. Allows either function to be called, automatically, // depending on the request's URL array (see {{{AjaxIM.actions}}}). // // ==== Parameters ==== // {{{url}}} is the URL of the request. // {{{data}}} are any arguments that go along with the request. // {{{success}}} is a callback function called when a request has completed // without issue. // {{{_ignore_}}} is simply to provide compatability with {{{$.post}}}. // {{{failure}}} is a callback function called when a request hasn't not // completed successfully. AjaxIM.request = function(url, data, successFunc, failureFunc) { if(typeof failureFunc != 'function'); failureFunc = function(){}; $[url[0]]({ 'url': url[1], 'data': data, dataType: (url[0] == 'ajax' ? 'json' : 'jsonp'), type: 'POST', cache: false, timeout: 60000, callback: 'jsonp' + (new Date()).getTime(), success: function(json, textStatus) { successFunc(json); }, error: function(xOptions, error) { failureFunc(error); } }); // This prevents Firefox from spinning indefinitely // while it waits for a response. Why? Fuck if I know. if(url[0] == 'jsonp' && $.browser.mozilla) { $.jsonp({ 'url': 'about:', timeout: 0 }); } }; // === {{{AjaxIM.}}}**{{{incoming(data)}}}** === // // Never call this directly. It is used as a connecting function between // client and server for Comet. // // //Note:// There are two {{{AjaxIM.incoming()}}} functions. This one is a // static function called outside of the initialized AjaxIM object; the other // is only called within the initalized AjaxIM object. AjaxIM.incoming = function(data) { if(!_instance) return false; if(data.length) _instance._parseMessages(data); } // === {{{AjaxIM.}}}**{{{loaded}}}** === // // If Ajax IM has been loaded with the im.load.js file, this function will be // called when the library is finally loaded and ready for use. Similar to // jQuery's $(document).ready(), but for Ajax IM. AjaxIM.loaded = function() { if(typeof AjaxIMLoadedFunction == 'function') { AjaxIMLoadedFunction(); delete AjaxIMLoadedFunction; // clean up the global namespace } }; // === {{{AjaxIM.}}}**{{{dateFormat([date,] [mask,] utc)}}}** === // // Date Format 1.2.3\\ // © 2007-2009 Steven Levithan ([[http://blog.stevenlevithan.com/archives/date-time-format|stevenlevithan.com]])\\ // MIT license // // Includes enhancements by Scott Trenda // and Kris Kowal ([[http://cixar.com/~kris.kowal/|cixar.com/~kris.kowal/]]) // // Accepts a date, a mask, or a date and a mask and returns a formatted version // of the given date. // // ==== Parameters ==== // * {{{date}}} is a {{{Date()}}} object. If not specified, the date defaults to the // current date/time. // * {{{mask}}} is a string that defines the formatting of the date. Formatting // options can be found in the // [[http://blog.stevenlevithan.com/archives/date-time-format|Date Format]] // documentation. If not specified, the mask defaults to {{{dateFormat.masks.default}}}. AjaxIM.dateFormat = function () { var token = /d{1,4}|m{1,4}|yy(?:yy)?|([HhMsTt])\1?|[LloSZ]|"[^"]*"|'[^']*'/g, timezone = new RegExp('\b(?:[PMCEA][SDP]T|(?:Pacific|Mountain|Central|Eastern|Atlantic) ' + '(?:Standard|Daylight|Prevailing) Time|(?:GMT|UTC)(?:[-+]\d{4})?)\b', 'g'), timezoneClip = /[^-+\dA-Z]/g, pad = function (val, len) { val = String(val); len = len || 2; while (val.length < len) val = "0" + val; return val; }; // Regexes and supporting functions are cached through closure return function (date, mask, utc) { var dF = AjaxIM.dateFormat; // You can't provide utc if you skip other args (use the "UTC:" mask prefix) if (arguments.length == 1 && Object.prototype.toString.call(date) == "[object String]" && !/\d/.test(date)) { mask = date; date = undefined; } // Passing date through Date applies Date.parse, if necessary date = date ? new Date(date) : new Date; if (isNaN(date)) throw SyntaxError("invalid date"); mask = String(dF.masks[mask] || mask || dF.masks["default"]); // Allow setting the utc argument via the mask if (mask.slice(0, 4) == "UTC:") { mask = mask.slice(4); utc = true; } var _ = utc ? "getUTC" : "get", d = date[_ + "Date"](), D = date[_ + "Day"](), m = date[_ + "Month"](), y = date[_ + "FullYear"](), H = date[_ + "Hours"](), M = date[_ + "Minutes"](), s = date[_ + "Seconds"](), L = date[_ + "Milliseconds"](), o = utc ? 0 : date.getTimezoneOffset(), flags = { d: d, dd: pad(d), ddd: AjaxIM.i18n.dayNames[D], dddd: AjaxIM.i18n.dayNames[D + 7], m: m + 1, mm: pad(m + 1), mmm: AjaxIM.i18n.monthNames[m], mmmm: AjaxIM.i18n.monthNames[m + 12], yy: String(y).slice(2), yyyy: y, h: H % 12 || 12, hh: pad(H % 12 || 12), H: H, HH: pad(H), M: M, MM: pad(M), s: s, ss: pad(s), l: pad(L, 3), L: pad(L > 99 ? Math.round(L / 10) : L), t: H < 12 ? "a" : "p", tt: H < 12 ? "am" : "pm", T: H < 12 ? "A" : "P", TT: H < 12 ? "AM" : "PM", Z: utc ? "UTC" : (String(date).match(timezone) || [""]) .pop().replace(timezoneClip, ""), o: (o > 0 ? "-" : "+") + pad(Math.floor(Math.abs(o) / 60) * 100 + Math.abs(o) % 60, 4), S: ["th", "st", "nd", "rd"][d % 10 > 3 ? 0 : (d % 100 - d % 10 != 10) * d % 10] }; return mask.replace(token, function ($0) { return $0 in flags ? flags[$0] : $0.slice(1, $0.length - 1); }); }; }(); // Some common format strings AjaxIM.dateFormat.masks = { "default": "ddd mmm dd yyyy HH:MM:ss", shortDate: "m/d/yy", mediumDate: "mmm d, yyyy", longDate: "mmmm d, yyyy", fullDate: "dddd, mmmm d, yyyy", shortTime: "h:MM TT", mediumTime: "h:MM:ss TT", longTime: "h:MM:ss TT Z", isoDate: "yyyy-mm-dd", isoTime: "HH:MM:ss", isoDateTime: "yyyy-mm-dd'T'HH:MM:ss", isoUtcDateTime: "UTC:yyyy-mm-dd'T'HH:MM:ss'Z'" }; // === {{{AjaxIM.}}}**{{{i18n}}}** === // // Text strings used by Ajax IM. Should you want to translate Ajax IM into // another language, merely change these strings. // // {{{%s}}} denotes text that will be automatically replaced when the string is // used. AjaxIM.i18n = { dayNames: [ "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday" ], monthNames: [ "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December" ], chatOffline: '%s signed off.', chatAvailable: '%s became available.', chatAway: '%s went away.', notConnected: 'You are currently not connected or the server is not available. ' + 'Please ensure that you are signed in and try again.', notConnectedTip: 'You are currently not connected.', authInvalid: 'Invalid username or password.', registerPasswordLength: 'Passwords must be more than 4 characters in length.', registerUsernameLength: 'Usernames must be more than 2 characters in length and ' + ' contain only A-Z, a-z, 0-9, underscores (_) and periods (.).', registerPasswordMatch: 'Entered passwords do not match.', registerUsernameTaken: 'The chosen username is already in use; please choose another.', registerUnknown: 'An unknown error occurred. Please try again.' } })(jQuery, false); \ No newline at end of file +// = im.js = +// +// **Copyright © 2005 – 2010 Joshua Gross**\\ +// //MIT Licensed// +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// +// This is the main library for Ajax IM. It encompasses the UI controls, +// and connecting with the server. It does //not// handle registration or +// account management. + +(function($, _instance) { + AjaxIM = function(options, actions) { + if(this instanceof AjaxIM) { + var self = this; + + // === {{{ defaults }}} === + // + // These are the available settings for Ajax IM, and the associated + // defaults: + // + // * {{{pollType}}} determines the way in which the client will talk to + // the server. + // ** {{{comet}}} will use http streaming, wherein a connection to the server will be held open indefinitely, and the server will push down new events (messages, status updates) as they occur. + // ** {{{long}}} will hold open a connection with the server for as long as possible, or until a new event is received. Upon the server sending an event or closing the connection, the client will automatically—and immediately—reconnect. + // ** {{{short}}} will open a connection, and the server (if this method is supported) will //immediately// provide a response as to whether or not there are any new events. Once a response is received, the client will wait 5 seconds, and then reconnect. + // * {{{pollServer}}} is the default URL to which all actions refer. It is + // possible to specify certain action URLs separately (as is used with the + // NodeJS server). + // * {{{cookieName}}} is the name of the session cookie used by the server. + // If this is not set properly, the IM engine will not be able to automatically + // reinitialize sessions. + // * {{{theme}}} is the name of the theme folder that defines the HTML and + // CSS of the IM bar and chat boxes. Usually, themes are deposited in the + // provided "themes" folder and specified by that path, e.g. {{{themes/default}}}. + // Theme files within the theme folder must be named {{{theme.html}}} and + // {{{theme.css}}}. + // * {{{storageMethod}}} defines the way in which data (chat sessions) are + // temporarily stored client-side. By default, {{{"flash"}}} is used because + // it is the most widely supported method. However, + // [[http://eric.garside.name/docs.html?p=jstore#js-engines|other storage engines]] + // are available, with their respective up- and down-sides + // outlined, on the jStore website. + // * {{{storeSession}}} (**not implemented**) sets the number of days to + // retain stored chat session data before it should be deleted. + // * {{{checkResume}}} is a flag that sets whether or not the client should + // make a call to the server before resuming the session (such as on a page + // reload). This will ensure that the session has not expired. If set to {{{false}}}, + // a call to the server will not be made, and the session will be assumed to + // be active. + var defaults = { + pollType: 'long', + pollServer: './ajaxim.php', + cookieName: 'ajaxim_session', + theme: 'themes/default', + storageMethod: 'auto', + flashStorage: 'js/jStore.Flash.html', + storeSession: 5, // number of days to store chat data (0 for current session only) + checkResume: true + }; + + // === {{{AjaxIM.}}}**{{{settings}}}** === + // + // These are the settings for the IM. If particular options are not specified, + // the defaults (see above) will be used. //These options will be defined + // upon calling the initialization function, and not set directly.// + this.settings = $.extend(defaults, options); + + // === {{{AjaxIM.}}}**{{{actions}}}** === + // + // Each individual action that the IM engine can execute is predefined here. + // By default, it merely appends the action onto the end of the {{{pollServer}}} url, + // however, it is possible to define actions individually. //The alternative actions + // will be defined upon calling the initialization function, and not set directly.// + // + // Should you define an action at a different URL, Ajax IM will determine whether + // or not this URL is within the current domain. If it is within a subdomain of + // the current domain, it will set the document.domain variable for you, + // to match a broader hostname scope; the action will continue to use {{{$.post}}} + // (the default AJAX method for Ajax IM). + // + // On the other hand, should you choose a URL outside the current domain + // Ajax IM will switch to {{{$.getJSON}}} (a get request) to avoid + // cross-domain scripting issues. This means that a server on a different + // port or at a different address will need to be able to handle GET + // requests rather than POST requests (such as how the Node.JS Ajax IM + // server works). + this.actions = $.extend({ + login: this.settings.pollServer + '/login', + logout: this.settings.pollServer + '/logout', + register: this.settings.pollServer + '/register', + poll: this.settings.pollServer + '/poll?method=' + this.settings.pollType, + send: this.settings.pollServer + '/send', + status: this.settings.pollServer + '/status', + resume: this.settings.pollServer + '/resume' + }, actions); + + var httpRx = new RegExp('^http://', 'i'), + slashslashRx = new RegExp('^//', 'i'), + queryStrRx = new RegExp('[?](.+)$'), + subdomainRx = new RegExp('((http[s]?:)?//)?(.+?)[.]' + window.location.host, 'i'); + $.each(this.actions, function(name, action) { + if(name == 'poll') { + if(self.settings.pollType != 'comet') + action += (queryStrRx.test(action[1]) ? '&' : '?') + 'callback=?'; + + action = ['jsonp', action]; + } else { + action = ['ajax', action]; + if(subdomainRx.test(action[1])) { + document.domain = '.' + window.location.host; + } else if((http = httpRx.test(action[1])) || slashslashRx.test(action[1])) { + if(!(new RegExp('//' + window.location.host + '/', 'i')).test(action[1])) { + action[1] += (queryStrRx.test(action[1]) ? '&' : '?') + 'callback=?'; + action = ['jsonp', action[1]]; + } + } + } + + self.actions[name] = action; + }); + + // We load the theme dynamically based on the passed + // settings. If the theme is set to false, we assume + // that the user is going to load it himself. + this.themeLoaded = false; + if(this.settings.theme) { + $('
    ').appendTo('body').load(this.settings.theme + '/theme.html #imjs-bar, .imjs-tooltip', + function() { + self.themeLoaded = true; + setup.apply(self); + } + ); + if(typeof document.createStyleSheet == 'function') + document.createStyleSheet(this.settings.theme + '/theme.css'); + else + $('body').append(''); + } else { + this.themeLoaded = true; + setup.apply(this); + } + + // Client-side storage for keeping track of + // conversation states, active tabs, etc. + // The default is flash storage, however, other + // options are available via the jStore library. + if(this.settings.storageMethod) { + this.storageBrowserKey = 'unknown'; + this.storeKey = ''; + + $.each($.browser, function(k, v) { + if(k == 'version') return true; + else if(v == true) { + self.storageBrowserKey = k; + return false; + } + }); + + if(this.settings.storageMethod == 'auto') { + $.each(['ie', 'html5', 'local', 'flash'], function() { + if($.jStore.Availability[this]()) { + self.settings.storageMethod = this; + return false; + } + }); + } + + $.extend($.jStore.defaults, { + project: 'im.js', + engine: this.settings.storageMethod, + flash: this.settings.flashStorage + }); + + this.storageReady = false; + + if(this.settings.storageMethod == 'flash') { + $.jStore.ready(function(engine) { + $.jStore.flashReady(function() { + self.storageReady = true; + setup.apply(self); + }); + }) + } else { + $.jStore.ready(function(engine) { + self.storageReady = true; + setup.apply(self); + }); + } + + $.jStore.load(); + } else { + this.storageReady = true; + setup.apply(this); + } + + // Allow a chatbox to me minimized + $('.imjs-chatbox').live('click', function(e) { + e.preventDefault(); + return false; + }); + + $('.imjs-chatbox .imjs-minimize').live('click', function() { + $(this).parents('.imjs-chatbox').data('tab').click(); + }); + + // Allow a chatbox to be closed + $('.imjs-chatbox .imjs-close').live('click', function() { + var chatbox = $(this).parents('.imjs-chatbox'); + chatbox.data('tab') + .data('state', 'closed').css('display', 'none'); + + if(self.settings.storageMethod && self.storageReady) { + delete self.chatstore[chatbox.data('username')]; + if(self.storageReady) { + $.jStore.store( + self.storageBrowserKey + '-' + + self.username + '-chats', + self.chatstore); + } + } + }); + + // Setup message sending for all chatboxes + $('.imjs-chatbox .imjs-input').live('keydown', function(event) { + var obj = $(this); + if(event.keyCode == 13 && !($.browser.msie && $.browser.version < 8)) { + self.send(obj.parents('.imjs-chatbox').data('username'), obj.val()); + } + }).live('keyup', function(event) { + if(event.keyCode == 13) { + if($.browser.msie && $.browser.version < 8) { + var obj = $(this); + self.send(obj.parents('.imjs-chatbox').data('username'), obj.val()); + } + + var obj = $(this); + obj.val(''); + obj.height(obj.data('height')); + } + }).live('keypress', function(e) { + var obj = $(this); + if(!($.browser.msie && $.browser.opera)) obj.height(0); + if(this.scrollHeight > obj.height() || this.scrollHeight < obj.height()) { + obj.height(this.scrollHeight); + } + }); + + $('.imjs-msglog').live('click', function() { + var chatbox = $(this).parents('.imjs-chatbox'); + chatbox.find('.imjs-input').focus(); + }); + + // Create a chatbox when a buddylist item is clicked + $('.imjs-friend').live('click', function() { + var chatbox = self._createChatbox($(this).data('friend')); + + if(chatbox.data('tab').data('state') != 'active') + chatbox.data('tab').click(); + + chatbox.find('.imjs-input').focus(); + }); + + // Setup and hide the scrollers + $('.imjs-scroll').css('display', 'none'); + $('#imjs-scroll-left').live('click', function() { + var hiddenTab = $('#imjs-bar li.imjs-tab:visible').slice(-1) + .next('#imjs-bar li.imjs-tab:hidden') + .filter(function() { + return $(this).data('state') != 'closed' + }) + .not('.imjs-default').slice(-1).css('display', ''); + + if(hiddenTab.length) { + $('#imjs-bar li.imjs-tab:visible').eq(0).css('display', 'none'); + $(this).html(parseInt($(this).html()) - 1); + $('#imjs-scroll-right').html(parseInt($('#imjs-scroll-right').html()) + 1); + } + + return false; + }); + $('#imjs-scroll-right').live('click', function() { + var hiddenTab = $('#imjs-bar li.imjs-tab:visible').eq(0) + .prev('#imjs-bar li.imjs-tab:hidden') + .filter(function() { + return $(this).data('state') != 'closed' + }) + .not('.imjs-default').slice(-1).css('display', ''); + + if(hiddenTab.length) { + $('#imjs-bar li.imjs-tab:visible').slice(-1).css('display', 'none'); + $(this).html(parseInt($(this).html()) - 1); + $('#imjs-scroll-left').html(parseInt($('#imjs-scroll-left').html()) + 1); + } + + return false; + }); + + // Initialize the chatbox hash + this.chats = {}; + + // Try to resume any existing session + this.resume(); + + $(window).resize(function() { + self.bar._scrollers(); + }); + } else + return AjaxIM.init(options); + }; + + // We predefine all public functions here... + // If they are called before everything (theme, storage engine) has loaded, + // then they get put into a "prequeue" and run when everything *does* + // finally load. + // + // This ensures that nothing loads without all of the principal components + // being pre-loaded. If that were to occur (without this prequeue), things + // would surely break. + var prequeue = []; + var empty = function() { + var func = this; + return function() { prequeue.push([func, arguments]) }; + }; + $.extend(AjaxIM.prototype, { + settings: {}, + friends: {}, + chats: {}, + + storage: empty.apply('storage'), + login: empty.apply('login'), + logout: empty.apply('logout'), + resume: empty.apply('resume'), + form: empty.apply('form'), + poll: empty.apply('poll'), + incoming: empty.apply('incoming'), + send: empty.apply('send'), + status: empty.apply('status'), + statuses: {}, + bar: { + initialize: empty.apply('bar.initialize'), + activateTab: empty.apply('bar.activateTab'), + closeTab: empty.apply('bar.closeTab'), + addTab: empty.apply('bar.addTab'), + notification: empty.apply('bar.notification'), + _scrollers: empty.apply('bar._scrollers') + } + }); + + setup = (function() { + var self = this; + if(!this.storageReady || !this.themeLoaded) return; + + $(self).trigger('loadComplete'); + $(window).resize(); + + $.extend(AjaxIM.prototype, { + // == Cookies == + // + // The "cookies" functions can be used to set, get, and erase JSON-based cookies. + // These functions are primarily used to manage and read the server-set cookie + // that handles the user's chat session ID. + cookies: { + // === {{{AjaxIM.}}}**{{{cookies.set(name, value, days)}}}** === + // + // Sets a cookie, stringifying the JSON value upon storing it. + // + // ==== Parameters ==== + // * {{{name}}} is the cookie name.\\ + // * {{{value}}} is the cookie data that you would like to store.\\ + // * {{{days}}} is the number of days that the cookie will be stored for. + set: function(name, value, days) { + if (days) { + var date = new Date(); + date.setTime(date.getTime() + (days * 24 * 60 * 60 * 1000)); + var expires = "; expires=" + date.toGMTString(); + } else var expires = ""; + document.cookie = name + "=" + $.compactJSON(value) + expires + "; path=/"; + }, + + // === {{{AjaxIM.}}}**{{{cookies.get(name)}}}** === + // + // Gets a cookie, decoding the JSON value before returning the data. + // + // ==== Parameters ==== + // * {{{name}}} is the cookie name that you would like to retrieve. + get: function(name) { + var nameEQ = name + "="; + var ca = document.cookie.split(';'); + for(var i = 0; i < ca.length; i++) { + var c = ca[i]; + while (c.charAt(0) == ' ') c = c.substring(1, c.length); + if (c.indexOf(nameEQ) == 0) { + var cval = decodeURIComponent(c.substring(nameEQ.length, c.length)); + return $.secureEvalJSON(cval); + } + } + return null; + }, + + // === {{{AjaxIM.}}}**{{{cookies.erase(name)}}}** === + // + // Deletes a cookie. + // + // {{{name}}} is the existing cookie that you would like to delete. + erase: function(name) { + self.cookies.set(name, '', -1); + } + }, + + // == Main == + + // === {{{AjaxIM.}}}**{{{storage()}}}** === + // + // Retrieves chat session data from whatever storage engine is enabled + // (provided that one is enabled at all). If a page reloads, this function + // is called to restore the user's chat state (existing conversations, active tab). + // This function is called //automatically//, upon initialization of the IM engine. + storage: function() { + if(!self.storeKey.length) return; + + try { + var chatstore = $.jStore.store(self.storeKey + 'chats') || {}; + } catch(e) { + $.jStore.remove(self.storeKey + 'chats'); + var chatstore = {}; + } + + if(this.chatstore) { + $.each(this.chatstore, function(username, convo) { + if(username in chatstore) + chatstore[username] = $.merge(chatstore[username], self.chatstore[username]); + else + chatstore[username] = self.chatstore[username]; + }); + + this.chatstore = chatstore; + $.jStore.store(self.storeKey + 'chats', chatstore); + } else { + this.chatstore = chatstore; + } + + $.each(this.chatstore, function(username, convo) { + if(!convo.length) return; + + var chatbox = self._createChatbox(username, true); + chatbox.data('lastDateStamp', null).css('display', 'none'); + + // Remove the automatic date stamp + chatbox.find('.imjs-msglog').empty(); + + // Restore all messages, date stamps, and errors + $.each(convo, function() { + switch(this[0]) { + case 'error': + self._addError(chatbox, decodeURIComponent(this[2]), this[3]); + break; + + case 'datestamp': + self._addDateStamp(chatbox, this[3]); + break; + + case 'a': + case 'b': + self._addMessage(this[0], chatbox, this[1], + decodeURIComponent(this[2]), this[3]); + break; + } + }); + + $(self).trigger('chatRestored', [username, chatbox]); + }); + + var activeTab = $.jStore.store(self.storeKey + 'activeTab') || []; + if(activeTab.length && (activeTab = activeTab[0]) && activeTab in this.chats) { + this.chats[activeTab].data('tab').click(); + var msglog = this.chats[activeTab].find('.imjs-msglog'); + msglog[0].scrollTop = msglog[0].scrollHeight; + } + }, + + // === {{{AjaxIM.}}}**{{{login(username, password)}}}** === + // + // Authenticates a user and initializes the IM engine. If the user is + // already logged in, [s]he is logged out, the session is cleared, and + // the new user is logged in. + // + // Returns the user's properly formatted username, session ID, and online + // friends in JSON, if successful; e.g.:\\ + // {{{ {u: 'username', s: 'longsessionid', f: [{u: 'friend', s: 1, g: 'group'}]} }}} + // + // If unsuccessful, {{{false}}} is returned. + // + // ==== Parameters ==== + // * {{{username}}} is the user's username.\\ + // * {{{password}}} is the user's password. This password will be MD5 hashed + // before it is sent to the server. + login: function(username, password) { + if(!username) username = ''; + if(!password) password = ''; + + if(this.username) + return true; // Already logged in! + + // hash password before sending it to the server + password = $.md5(password); + + // authenticate + AjaxIM.request( + this.actions.login, + {'username': username, 'password': password}, + function(auth) { + if(auth.r == 'logged in') { + self.username = ('u' in auth ? auth.u : username); + + if(self.settings.storageMethod) + self.storeKey = [self.storageBrowserKey, self.username, ''].join('-'); + + var existing = self.cookies.get(self.settings.cookieName); + self.storage(); + + // Begin the session + $.each(auth.f, function() { + self.friends[this.u] = {status: [this.s, ''], group: this.g}; + }); + self._session(self.friends); + self._storeFriends(); + + $(self).trigger('loginSuccessful', [auth]); + + return auth; + } else { + $(self).trigger('loginError', [auth]); + } + + return false; + } + ); + }, + + // === {{{AjaxIM.}}}**{{{logout()}}}** === + // + // Logs the user out and removes his/her session cookie. As well, it + // will close all existing chat windows, clear the storage engine, and + // remove the IM bar. + logout: function() { + AjaxIM.request( + this.actions.logout, + {}, + function(done) { + if(done) { + self.cookies.erase(self.settings.cookieName); + self._clearSession(); + $(self).trigger('logoutSuccessful'); + return true; + } else { + $(self).trigger('logoutError'); + return false; + } + } + ); + }, + + // === {{{AjaxIM.}}}**{{{resume()}}}** === + // + // Resumes an existing session based on a session ID stored in the + // server-set cookie. This function is called //automatically// upon IM + // engine (re-)initialization, so the user does not need to re-login + // should a session already exist. + resume: function() { + var session = this.cookies.get(this.settings.cookieName); + + if(session && session.sid) { + this.username = session.user; + + this.storeKey = [this.storageBrowserKey, this.username, ''].join('-'); + + var friends = $.jStore.store(this.storeKey + 'friends') || []; + if(self.settings.checkResume) { + AjaxIM.request( + this.actions.resume, + {}, + function(response) { + if(response.r == 'connected') { + self._session(friends); + self.storage(); + } else { + var username = this.username; + self._clearSession(); + $(self).trigger('sessionNotResumed', [username]); + } + } + ); + } else { + self._session(friends); + self.storage(); + } + } else { + $(self).trigger('noSession'); + } + }, + + // === //private// {{{AjaxIM.}}}**{{{_session(friends)}}}** === + // + // Restores session data (username, friends) and begins polling the server. + // Called only by {{{AjaxIM.resume()}}}. + // + // ==== Parameters ==== + // * {{{friends}}} is a list of "friend" objects, e.g.:\\ + // {{{[{u: 'friend', s: 1, g: 'group'}, ...]}}} + // ** {{{u}}} being the friend's username. + // ** {{{s}}} being one of the available status codes (see {{{AjaxIM.statuses}}}), depending on the friend's current status. + // ** {{{g}}} being the group that the friend is in. + _session: function(friends) { + $('#imjs-friends-panel .imjs-header span').html(this.username); + $('#imjs-friends').removeClass('imjs-not-connected'); + + $.each(friends, function(friend, info) { + self.addFriend.apply(self, [friend, info.status, info.group]); + }); + self._storeFriends(); + + $(self).trigger('sessionResumed', [this.username]); + + setTimeout(function() { self.poll(); }, 0); + }, + + // === //private// {{{AjaxIM.}}}**{{{_clearSession()}}}** === + // + // Clears all session data from the last known user. + _clearSession: function() { + if(self.settings.storageMethod && self.storageReady) { + $.jStore.remove(self.storeKey + 'chats'); + $.jStore.remove(self.storeKey + 'friends'); + $.jStore.remove(self.storeKey + 'activeTab'); + } + + self.chats = {}; + $('.imjs-tab').not('.imjs-tab.imjs-default').remove(); + + self.cookies.erase('ajaxim_session'); + delete self.username; + }, + + // === {{{AjaxIM.}}}**{{{form(element)}}}** === + // + // Loads a login and registration form into the specified element + // or, if no element is supplied, to the location on the page from + // which this function was called. + form: function(element) { + $(element).load(this.settings.theme + '/theme.html #imjs-lr', function() { + $('#imjs-lr .error').hide(); + + if(self.username) { + $('#imjs-register, #imjs-login fieldset').hide(); + $('#imjs-logged-in') + .show() + .html($('#imjs-logged-in').html().replace('{username}', self.username)); + } else { + $('#imjs-logged-in').hide(); + } + + // Handle logout success + $(self).bind('logoutSuccessful', function() { + $('#imjs-login fieldset').slideDown(); + $('#imjs-register').slideDown(); + + $('#imjs-logged-in') + .html($('#imjs-logged-in strong').html('{username}')) + .slideUp(); + }); + $('#imjs-logged-in a').click(function() { + self.logout(); + return false; + }); + + // Handle login error or success + $(self).bind('loginError', function() { + $('#imjs-login .error').html(AjaxIM.i18n.authInvalid).slideDown('fast'); + $('#imjs-login input') + .addClass('imjs-lr-error') + .blur(function() { $(this).removeClass('imjs-lr-error'); }); + }).bind('loginSuccessful', function() { + $('#imjs-login fieldset').slideUp(); + $('#imjs-register').slideUp(); + + $('#imjs-logged-in') + .html($('#imjs-logged-in').html().replace('{username}', self.username)) + .slideDown(); + }); + var login = function() { + self.login($('#imjs-login-username').val(), $('#imjs-login-password').val()); + return false; + }; + $('#imjs-login').submit(login); + $('#imjs-login-submit').click(login); + + var regIssues = false; + var regError = function(error, fields) { + $('#imjs-register .error') + .append(AjaxIM.i18n['register' + error] + ' ') + .slideDown(); + $(fields) + .addClass('imjs-lr-error') + .blur(function() { $(this).removeClass('imjs-lr-error'); }); + regIssues = true; + }; + + var register = function() { + $('#imjs-register .error').empty(); + + regIssues = false; + + var username = $('#imjs-register-username').val(); + var password = $('#imjs-register-password').val(); + + if(password.length < 4) + regError('PasswordLength', '#imjs-register-password'); + + if(password != $('#imjs-register-cpassword').val()) + regError('PasswordMatch', '#imjs-register-password, #imjs-register-cpassword'); + + if(username.length <= 2 || + !$('#imjs-register-username').val().match(/^[A-Za-z0-9_.]+$/)) + regError('UsernameLength', '#imjs-register-username'); + + if(!regIssues) { + AjaxIM.request( + self.actions.register, + {username: username, password: password}, + function(response) { + if(response.r == 'registered') { + self.login(username, password); + } else if(response.r == 'error') { + switch(response.e) { + case 'unknown': + regError('Unknown', ''); + break; + + case 'invalid password': + regError('PasswordLength', '#imjs-register-password'); + break; + + case 'invalid username': + regError('UsernameLength', '#imjs-register-username'); + break; + + case 'username taken': + regError('UsernameTaken', '#imjs-register-username'); + break; + } + } + }, + function(error) { + regError('Unknown', ''); + } + ); + } + + return false; + }; + $('#imjs-register').submit(register); + $('#imjs-register-submit').click(register); + }); + }, + + // === {{{AjaxIM.}}}**{{{poll()}}}** === + // + // Queries the server for new messages. If a 'long' or 'short' poll + // type is used, jQuery's {{{$.post}}} or {{{$.getJSON}}} will be + // used. If 'comet' is used, the server connection will be deferred + // to the comet set of functions. + poll: function() { + if(/^(short|long)$/.test(this.settings.pollType)) { + AjaxIM.request( + this.actions.poll, + {}, + function(response) { + if(!response['e']) { + if(response.length) + self._parseMessages(response); + + setTimeout(function() { self.poll(); }, 0); + } else { + switch(response.e) { + case 'no session found': + self._notConnected(); + break; + } + + $(self).trigger('pollFailed', [response.e]); + } + }, + function(error) { + self._notConnected(); + $(self).trigger('pollFailed', ['not connected']); + // try reconnecting? + } + ); + } else if(this.settings.pollType == 'comet') { + this.comet.connect(); + } + }, + + // === //private// {{{AjaxIM.}}}**{{{_parseMessages(messages)}}}** === + // + // Handles an incoming message array:\\ + // {{{[{t: 'type', s: 'sender', r: 'recipient', m: 'message'}, ...]}}} + // + // * {{{t}}} (message type) is one of: + // ** {{{m}}} — a standard message + // ** {{{s}}} — a user's status update + // ** {{{b}}} — a broadcasted message (sent to many users simultaneously) + // * {{{s}}} is the sender of the message. + // * {{{r}}} is the intended recipient of the message. Most of the time, this will + // simply be the logged in user, however, a broadcasted message may not specify + // a recipient or may specify a different recipient. Also provides future + // compatability for chatrooms. + // * {{{m}}} is the actual message. For something such as a status update, this can + // be a JSON object or parsable string; e.g. {{{"2:I'm away."}}} + // + // ==== Parameters ==== + // * {{{messages}}} is the message array + _parseMessages: function(messages) { + if($.isArray(messages)) { + $.each(messages, function() { + $(self).trigger('parseMessage', [this]); + + switch(this.t) { + case 'm': + self.incoming(this.s, this.m); + break; + + case 's': + var status = this.m.split(':'); + if(this['g']) + self.addFriend(this.s, status, this.g); + self._friendUpdate(this.s, status[0], status.slice(1).join(':')); + self._storeFriends(); + break; + + case 'b': + break; + + default: + break; + } + }); + } + }, + + // === {{{AjaxIM.}}}**{{{incoming(from, message)}}}** === + // + // Handles a new message from another user. If a chatbox for that + // user does not yet exist, one is created. If it does exist, but + // is minimized, the user is notified but the chatbox is not brought + // to the front. This function also stores the message, if a storage + // method is set. + // + // ==== Parameters ==== + // * {{{from}}} is the username of the sender. + // * {{{message}}} is the body. + incoming: function(from, message) { + // check if IM exists, otherwise create new window + // TODO: If friend is not on the buddylist, + // should add them to a temp list? + var chatbox = this._createChatbox(from); + + if(!$('#imjs-bar .imjs-selected').length) { + chatbox.data('tab').click(); + } else if(chatbox.data('tab').data('state') != 'active') { + this.bar.notification(chatbox.data('tab')); + } + + var time = this._addMessage('b', chatbox, from, message); + this._storeMessage('b', chatbox, from, message, time); + }, + + // === {{{AjaxIM.}}}**{{{addFriend(username, group)}}}** === + // + // Inserts a new friend into the friends list. If the group specified + // doesn't exist, it is created. If the friend is already in this group, + // they aren't added again, however, the friend item is returned. + // + // ==== Parameters ==== + // * {{{username}}} is the username of the new friend. + // * {{{status}}} is the current status of the friend. + // * {{{group}}} is the user group to which the friend should be added. + addFriend: function(username, status, group) { + var status_name = 'available'; + $.each(this.statuses, + function(key, val) { if(status[0] == val) { status_name = key; return false; } }); + + var group_id = 'imjs-group-' + $.md5(group); + + if(!(group_item = $('#' + group_id)).length) { + var group_item = $('.imjs-friend-group.imjs-default').clone() + .removeClass('imjs-default') + .attr('id', group_id) + .data('group', group) + .appendTo('#imjs-friends-list'); + + var group_header = group_item.find('.imjs-friend-group-header'); + group_header.html(group_header.html().replace('{group}', group)); + } + + var user_id = 'imjs-friend-' + $.md5(username + group); + + if(!$('#' + user_id).length) { + var user_item = group_item.find('ul li.imjs-default').clone() + .removeClass('imjs-default') + .addClass('imjs-' + status_name) + .attr('id', user_id) + .data('friend', username) + .appendTo(group_item.find('ul')); + if(status[0] == 0) user_item.hide(); + user_item.html(user_item.html().replace('{username}', username)); + } + + this.friends[username] = {'status': status, group: group}; + + this._updateFriendCount(); + + return this.friends[username]; + }, + + // === //private// {{{AjaxIM.}}}**{{{_updateFriendCount()}}}** === + // + // Counts the number of online friends and updates the friends count + // in the friend tab. + _updateFriendCount: function() { + var friendsLength = 0; + for(var f in this.friends) { + if(this.friends[f].status[0] != 0) + friendsLength++; + } + $('#imjs-friends .imjs-tab-text span span').html(friendsLength); + }, + + // === //private// {{{AjaxIM.}}}**{{{_storeFriends()}}}** === + // + // If a storage method is enabled, the current state of the + // user's friends list is stored. + _storeFriends: function() { + if(this.settings.storageMethod && this.storageReady) + $.jStore.store(this.storeKey + 'friends', this.friends); + }, + + // === //private// {{{AjaxIM.}}}**{{{_createChatbox(username)}}}** === + // + // Builds a chatbox based on the default chatbox HTML and CSS defined + // in the current theme. Should a chatbox for this user already exist, + // a new one is not created. Instead, it is either given focus (should + // no other windows already have focus), or a notification is issued. + // + // As well, if the chatbox does not exist, an associated tab will be + // created. + // + // ==== Parameters ==== + // * {{{username}}} is the name of the user for whom the chatbox is intended + // for. + // * {{{no_stamp}}} sets whther or not to add a date stamp to the chatbox + // upon creation. + // + // //Note:// New chatboxes are given an automatically generated ID in the + // format of {{{#imjs-[md5 of username]}}}. + _createChatbox: function(username, no_stamp) { + var chatbox_id = 'imjs-' + $.md5(username); + if(!(chatbox = $('#' + chatbox_id)).size()) { + // add a tab + var tab = this.bar.addTab(username, '#' + chatbox_id); + var chatbox = tab.find('.imjs-chatbox'); + chatbox.attr('id', chatbox_id); + + chatbox.data('tab', tab); + + // remove default items from the message log + var message_log = chatbox.find('.imjs-msglog').empty(); + + // setup the chatbox header + var cb_header = chatbox.find('.imjs-header'); + cb_header.html(cb_header.html().replace('{username}', username)); + + if(!no_stamp) { + // add a date stamp + var time = this._addDateStamp(chatbox); + this._storeNonMessage('datestamp', username, null, time); + } + + // associate the username with the object and vice-versa + this.chats[username] = chatbox; + chatbox.data('username', username); + + // did this chatbox fall down? + this.bar._scrollers(); + + if(username in this.friends) { + status = this.friends[username].status; + var status_name = 'available'; + $.each(this.statuses, + function(key, val) { if(status[0] == val) { status_name = key; return false; } }); + tab.addClass('imjs-' + status_name); + } + + // store inputbox height + //var input = chatbox.find('.imjs-input'); + //input.data('height', input.height()); + } else if(chatbox.data('tab').data('state') == 'closed') { + chatbox.find('.imjs-msglog > *').addClass('imjs-msg-old'); + + var tab = chatbox.data('tab'); + if(tab.css('display') == 'none') + tab.css('display', '').removeClass('imjs-selected') + .appendTo('#imjs-bar'); + + if(!no_stamp) { + // possibly add a date stamp + var time = this._addDateStamp(chatbox); + this._storeNonMessage('datestamp', username, null, time); + } + + if(!$('#imjs-bar .imjs-selected').length) { + tab.click(); + } else { + this.bar.notification(tab); + } + } + + return chatbox; + }, + + // === //private// {{{AjaxIM.}}}**{{{_addDateStamp(chatbox)}}}** // + // + // Adds a date/time notifier to a chatbox. These are generally + // inserted upon creation of a chatbox, or upon the date changing + // since the last time a date stamp was added. If a date stamp for + // the current date already exists, a new one will not be added. + // + // ==== Parameters ==== + // * {{{chatbox}}} refers to the jQuery-selected chatbox DOM element. + // * {{{time}}} is the date/time the date stamp will show. It is specified + // in milliseconds since the Unix Epoch. This is //only// defined when + // date stamps are being restored from storage; if not specified, the + // current computer time will be used. + _addDateStamp: function(chatbox, time) { + var message_log = $(chatbox).find('.imjs-msglog'); + if(!time) + time = (new Date()).getTime(); + + var date_stamp = $('.imjs-tab.imjs-default .imjs-chatbox .imjs-msglog .imjs-date').clone(); + var date_stamp_time = date_stamp.find('.imjs-msg-time'); + if(date_stamp_time.length) + date_stamp_time.html(AjaxIM.dateFormat(time, date_stamp_time.html())); + + var date_stamp_date = date_stamp.find('.imjs-date-date'); + var formatted_date = AjaxIM.dateFormat(time, date_stamp_date.html()); + if(chatbox.data('lastDateStamp') != formatted_date) { + if(date_stamp_date.length) + date_stamp_date.html(AjaxIM.dateFormat(time, date_stamp_date.html())); + + chatbox.data('lastDateStamp', formatted_date); + date_stamp.appendTo(message_log); + } else { + //$('
    ').appendTo(message_log); + } + + return time; + }, + + // === //private// {{{AjaxIM.}}}**{{{_addError(chatbox, error)}}}** // + // + // Adds an error to a chatbox. These are generally inserted after + // a user sends a message unsuccessfully. If an error message + // was already added, another one will be added anyway. + // + // ==== Parameters ==== + // * {{{chatbox}}} refers to the jQuery-selected chatbox DOM element. + // * {{{error}}} is the error message string. + // * {{{time}}} is the date/time the error occurred. It is specified in + // milliseconds since the Unix Epoch. This is //only// defined when + // errors are being restored from storage; if not specified, the current + // computer time will be used. + _addError: function(chatbox, error, time) { + var message_log = $(chatbox).find('.imjs-msglog'); + + var error_item = + $('.imjs-tab.imjs-default .imjs-chatbox .imjs-msglog .imjs-error').clone(); + + var error_item_time = error_item.find('.imjs-msg-time'); + if(error_item_time.length) { + if(!time) + time = (new Date()).getTime(); + error_item_time.html(AjaxIM.dateFormat(time, error_item_time.html())); + } + + error_item.find('.imjs-error-error').html(error); + error_item.appendTo(message_log); + + message_log[0].scrollTop = message_log[0].scrollHeight; + }, + + // === //private// {{{AjaxIM.}}}**{{{_addMessage(ab, chatbox, username, message, time)}}}** // + // + // Adds a message to a chatbox. Depending on the {{{ab}}} value, + // the color of the username may change as a way of visually + // identifying users (however, this depends on the theme's CSS). + // A timestamp is added to the message, and the chatbox is scrolled + // to the bottom, such that the new message is visible. + // + // Messages will be automatically tag-escaped, so as to prevent + // any potential cross-site scripting problems. Additionally, + // URLs will be automatically linked. + // + // ==== Parameters ==== + // * {{{ab}}} refers to whether the user is "a" or "b" in a conversation. + // For the general case, "you" are "a" and "they" are "b". + // * {{{chatbox}}} refers to the jQuery-selected chatbox DOM element. + // * {{{username}}} is the username of the user who sent the message. + // * {{{time}}} is the time the message was sent in milliseconds since + // the Unix Epoch. This is //only// defined when messages are being + // restored from storage. For new messages, the current computer + // time is automatically used. + _addMessage: function(ab, chatbox, username, message, time) { + var last_message = chatbox.find('.imjs-msglog > *:last-child'); + if(last_message.hasClass('imjs-msg-' + ab)) { + // Last message was from the same person, so let's just add another imjs-msg-*-msg + var message_container = (last_message.hasClass('imjs-msg-' + ab + '-container') ? + last_message : + last_message.find('.imjs-msg-' + ab + '-container')); + + var single_message = + $('.imjs-tab.imjs-default .imjs-chatbox .imjs-msglog .imjs-msg-' + ab + '-msg') + .clone().appendTo(message_container); + + single_message.html(single_message.html().replace('{username}', username)); + } else if(!last_message.length || !last_message.hasClass('imjs-msg-' + ab)) { + var message_group = $('.imjs-tab.imjs-default .imjs-chatbox .imjs-msg-' + ab) + .clone().appendTo(chatbox.find('.imjs-msglog')); + message_group.html(message_group.html().replace('{username}', username)); + + var single_message = message_group.find('.imjs-msg-' + ab + '-msg'); + } + + // clean up the message + message = message.replace(//g, '>') + .replace(/(^|.*)\*([^*]+)\*(.*|$)/, '$1$2$3'); + + // autolink URLs + message = message.replace( + new RegExp('([A-Za-z][A-Za-z0-9+.-]{1,120}:[A-Za-z0-9/]' + + '(([A-Za-z0-9$_.+!*,;/?:@&~=-])|%[A-Fa-f0-9]{2}){1,333}' + + '(#([a-zA-Z0-9][a-zA-Z0-9$_.+!*,;/?:@&~=%-]{0,1000}))?)', 'g'), + '$1'); + + // insert the message + single_message.html(single_message.html().replace('{message}', message)); + + // set the message time + var msgtime = single_message.find('.imjs-msg-time'); + if(!time) + time = new Date(); + + if(typeof time != 'string') + time = AjaxIM.dateFormat(time, msgtime.html()); + + msgtime.html(time); + + var msglog = chatbox.find('.imjs-msglog'); + msglog[0].scrollTop = msglog[0].scrollHeight; + + return time; + }, + + // === //private// {{{AjaxIM.}}}**{{{_storeNonMessage(type, username, data, time)}}}** === + // + // **Redundant?**\\ + // Similar to {{{AjaxIM._storeMessage}}}, but stores items that aren't messages, + // such as datestamps and errors. + // + // ==== Parameters ==== + // * {{{type}}} is the type of non-message (error, datestamp). + // * {{{username}}} is the username of the user being chatted with. + // * {{{data}}} is the (optional) data of the non-message to be stored. + // * {{{time}}} is the time of the message. + _storeNonMessage: function(type, username, data, time) { + // If storage is on & ready, store the non-message + if(this.settings.storageMethod) { + if(!this.chatstore) this.chatstore = {}; + if(!(username in this.chatstore)) this.chatstore[username] = []; + + // If the chat store gets too long, it becomes slow to load. + if(this.chatstore[username].length > 300) + this.chatstore[username].shift(); + + // For some reason, if we don't encode and decode the message, it *will* break + // (at least) the Flash storage engine's retrieval. Gah! + this.chatstore[username].push( + [type, username, encodeURIComponent(data), time]); + + if(this.storageReady) $.jStore.store(self.storeKey + 'chats', this.chatstore); + } + }, + + // === //private// {{{AjaxIM.}}}**{{{_storeMessage(ab, chatbox, username, message, time)}}}** === + // + // Taking the same arguments as {{{AjaxIM._addMessage}}}, {{{_storeMessage}}} pushes a message + // into the storage hash, if storage is enabled. + // + // Messages are added to a message array, by username. The entire chat hash is stored as + // a {{{'chats'}}} object in whatever storage engine is enabled. + _storeMessage: function(ab, chatbox, username, message, time) { + // If storage is on & ready, store the message + if(this.settings.storageMethod) { + if(!this.chatstore) this.chatstore = {}; + + message = message.replace(//g, '>'); + + if(!(username in this.chatstore)) { + this.chatstore[username] = []; + } else if(this.chatstore[username].length > 300) { + // If the chat store gets too long, it becomes slow to load. + this.chatstore[username].shift(); + } + + // For some reason, if we don't encode and decode the message, it *will* break + // (at least) the Flash storage engine's retrieval. Gah! + this.chatstore[chatbox.data('username')].push( + [ab, username, encodeURIComponent(message), time]); + + if(this.storageReady) $.jStore.store(this.storeKey + 'chats', this.chatstore); + } + }, + + // === //private// {{{AjaxIM.}}}**{{{_friendUpdate(friend, status, statusMessage)}}}** === + // + // Called when a friend's status is updated. This function will update all locations + // where a status icon is displayed (chat tab, friends list), as well as insert + // a notification, should a chatbox be open. + // + // ==== Parameters ==== + // * {{{friend}}} is the username of the friend. + // * {{{status}}} is the new status code. See {{{AjaxIM.statuses}}} for a list of available + // codes. //Note: If an invalid status is specified, no action will be taken.// + // * {{{statusMessage}}} is a message that was, optionally, specified by the user. It will be + // used should "you" send the user an IM while they are away, or if their status is viewed + // in another way (such as via the friends list [**not yet implemented**]). + _friendUpdate: function(friend, status, statusMessage) { + // add friend to buddylist, update their status, etc. + var status_name = 'available'; + $.each(this.statuses, + function(key, val) { if(status == val) { status_name = key; return false; } }); + + if(this.chats[friend]) { + var tab = this.chats[friend].data('tab'); + var tab_class = 'imjs-tab'; + if(tab.data('state') == 'active') tab_class += ' imjs-selected'; + tab_class += ' imjs-' + status_name; + + tab.attr('class', tab_class); + + // display the status in the chatbox + var date_stamp = + $('.imjs-tab.imjs-default .imjs-chatbox .imjs-msglog .imjs-date').clone(); + + var date_stamp_time = date_stamp.find('.imjs-msg-time'); + if(date_stamp_time.length) + date_stamp_time.html(AjaxIM.dateFormat(date_stamp_time.html())); + + var date_stamp_date = date_stamp.find('.imjs-date-date').html( + AjaxIM.i18n[ + 'chat' + status_name[0].toUpperCase() + status_name.slice(1) + ].replace(/%s/g, friend)); + + var msglog = this.chats[friend].find('.imjs-msglog'); + date_stamp.appendTo(msglog); + msglog[0].scrollTop = msglog[0].scrollHeight; + } + + if(this.friends[friend]) { + var friend_id = 'imjs-friend-' + $.md5(friend + this.friends[friend].group); + $('#' + friend_id).attr('class', 'imjs-friend imjs-' + status_name); + + if(status == 0) { + $('#' + friend_id + ':visible').slideUp(); + $('#' + friend_id + ':hidden').hide(); + } else if(!$('#' + friend_id + ':visible').length) { + $('#' + friend_id).slideDown(); + } + + this.friends[friend].status = [status, statusMessage]; + this._updateFriendCount(); + } + }, + + // === //private// {{{AjaxIM.}}}**{{{_notConnected()}}}** === + // + // Puts the user into a visible state of disconnection. Sets the + // friends list to "not connected" and empties it; disallows new messages + // to be sent. + _notConnected: function() { + $('#imjs-friends').addClass('imjs-not-connected').unbind('click', this.activateTab); + }, + + // === {{{AjaxIM.}}}**{{{send(to, message)}}}** === + // + // Sends a message to another user. The message will be added + // to the chatbox before it is actually sent, however, if an + // error occurs during sending, that will be indicated immediately + // afterward. + // + // After sending the message, one of three status codes should be + // returned as a JSON object, e.g. {{{{r: 'code'}}}}: + // * {{{ok}}} — Message was sent successfully. + // * {{{offline}}} — The user is offline or unavailable to + // receive messages. + // * {{{error}}} — a problem occurred, unrelated to the user + // being unavailable. + // + // ==== Parameters ==== + // * {{{to}}} is the username of the recipient. + // * {{{message}}} is the content to be sent. + send: function(to, message) { + if(!message) return; + + if(this.chats[to]) { // REMOVE ME? + // possibly add a datestamp + var time = self._addDateStamp(this.chats[to]); + this._storeNonMessage('datestamp', to, null, time); + + time = this._addMessage('a', this.chats[to], this.username, message); + this._storeMessage('a', this.chats[to], this.username, message, time); + } + + $(self).trigger('sendingMessage', [to, message]); + + AjaxIM.request( + this.actions.send, + {'to': to, 'message': message}, + function(result) { + switch(result.r) { + case 'ok': + $(self).trigger('sendMessageSuccessful', [to, message]); + break; + + case 'offline': + $(self).trigger('sendMessageFailed', ['offline', to, message]); + break; + + case 'error': + default: + if(result.e == 'no session found') { + self._notConnected(); + self._addError(self.chats[to], AjaxIM.i18n.notConnected); + self._storeNonMessage('error', to, + AjaxIM.i18n.notConnected, (new Date()).getTime()); + } + + $(self).trigger('sendMessageFailed', [result.e, to, message]); + break; + } + }, + function(error) { + self._notConnected(); + self._addError(self.chats[to], AjaxIM.i18n.notConnected); + self._storeNonMessage('error', to, + AjaxIM.i18n.notConnected, (new Date()).getTime()); + + $(self).trigger('sendMessageFailed', ['not connected', to, message]); + } + ); + }, + + // === {{{AjaxIM.}}}**{{{status(s, message)}}}** === + // + // Sets the user's status and status message. It is possible to not + // set a status message by setting it to an empty string. The status + // will be sent to the server, where upon the server will broadcast + // the update to all individuals with "you" on their friends list. + // + // ==== Parameters ==== + // * {{{s}}} is the status code, as defined by {{{AjaxIM.statuses}}}. + // * {{{message}}} is the custom status message. + status: function(s, message) { + // update status icon(s) + if(!this.statuses[s]) + return; + + $('#imjs-friends').attr('class', 'imjs-' + s); + + $(self).trigger('changingStatus', [s, message]); + + AjaxIM.request( + this.actions.status, + {'status': this.statuses[s], 'message': message}, + function(result) { + switch(result.r) { + case 'ok': + $(self).trigger('changeStatusSuccessful', [s, message]); + break; + + case 'error': + default: + $(self).trigger('changeStatusFailed', [result.e, s, message]); + break; + } + }, + function(error) { + $(self).trigger('changeStatusFailed', ['not connected', s, message]); + } + ); + }, + + // === {{{AjaxIM.}}}**{{{statuses}}}** === + // + // These are the available status codes and their associated identities: + // * {{{offline}}} (0) — Only used when signing out/when another + // user has signed out, as once this status is set, the user is removed + // from the server and friends will be unable to contact the user. + // * {{{available}}} (1) — The user is online and ready to be messaged. + // * {{{away}}} (2) — The user is online but is not available. Others + // may still contact this user, however, the user may not respond. Anyone + // contacting an away user will receive a notice stating that the user is away, + // and (if one is set) their custom status message. + // * {{{invisible}}} (3; **not yet implemented**) — The user is online, + // but other users are made unaware, and the user will be represented + // as being offline. It is still possible to contact this user, and for this + // user to contact others; no status message or notice will be sent to others + // messaging this user. + statuses: {offline: 0, available: 1, away: 2, invisible: 3}, + + // == Footer bar == + // + // The footer bar is the bar that sits at the bottom of the page, in a fixed + // position. It contains a tab for the friends list, and tabs for any open + // chat boxes. It is also possible to add custom tabs for other functionality. + bar: { + // === {{{AjaxIM.}}}**{{{bar.initialize()}}}** === + // + // Setup the footer bar and enable tab actions. This function + // uses {{{jQuery.live}}} to set hooks on any bar tabs created + // in the future. + initialize: function() { + // Set up your standard tab actions + $('.imjs-tab') + .live('click', this.activateTab); + + $('.imjs-tab .imjs-close') + .live('click', this.closeTab); + + // Set up the friends list actions + var self = this; + $(document).click(function(e) { + if(e.target.id == 'imjs-friends' || + $(e.target).parents('#imjs-friends').length) { + return; + } + + if($('#imjs-friends').data('state') == 'active') + self.activateTab.call($('#imjs-friends')); + }); + $('#imjs-friends') + .data('state', 'minimized') + .click(function(e) { + if(!$(this).hasClass('imjs-not-connected') && + e.target.id != 'imjs-friends-panel' && + !$(e.target).parents('#imjs-friends-panel').length) + self.activateTab.call(this); + }) + .mouseenter(function() { + if($(this).hasClass('imjs-not-connected')) { + $('.imjs-tooltip').css('display', 'block'); + $('.imjs-tooltip p').html(AjaxIM.i18n.notConnectedTip); + + var tip_left = $(this).offset().left - + $('.imjs-tooltip').outerWidth() + + ($(this).outerWidth() / 2); + var tip_top = $(this).offset().top - + $('.imjs-tooltip').outerHeight(true); + + $('.imjs-tooltip').css({ + left: tip_left, + top: tip_top + }); + } + }) + .mouseleave(function() { + if($(this).hasClass('imjs-not-connected')) { + $('.imjs-tooltip').css('display', ''); + } + }); + $('#imjs-friends-panel') + .data('tab', $('#imjs-friends')) + .css('display', 'none'); + }, + + // === {{{AjaxIM.}}}**{{{bar.activateTab()}}}** === + // + // Activate a tab by setting it to the 'active' state and + // showing any related chatbox. If a chatbox is available + // for this tab, also focus the input box. + // + // //Note:// {{{this}}}, here, refers to the tab DOM element. + activateTab: function() { + var chatbox = $(this).find('.imjs-chatbox') || false; + + if($(this).data('state') != 'active') { + if($(this).attr('id') != 'imjs-friends') { + $('#imjs-bar > li') + .not($(this)) + .not('#imjs-friends') + .removeClass('imjs-selected') + .each(function() { + if($(this).data('state') != 'closed') { + $(this).data('state', 'minimized'); + var chatbox = $(this).find('.imjs-chatbox'); + if(chatbox.length) + chatbox.css('display', 'none'); + } + }); + } + + if(chatbox && chatbox.css('display') == 'none') + chatbox.css('display', ''); + + // set the tab to active... + var tab = $(this).addClass('imjs-selected').data('state', 'active'); + + // ...and hide and reset the notification icon + tab.find('.imjs-notification').css('display', 'none') + .data('count', 0); + + if(self.settings.storageMethod && self.storageReady && + chatbox && (username = chatbox.data('username'))) { + $.jStore.store(self.storeKey + 'activeTab', [username]); + } + + $(self).trigger('tabToggled', ['activated', tab]); + } else { + var tab = $(this).removeClass('imjs-selected').data('state', 'minimized'); + + if(chatbox && chatbox.css('display') != 'none') + chatbox.css('display', 'none'); + + if(self.settings.storageMethod && self.storageReady) { + $.jStore.store(self.storeKey + 'activeTab', ['*']); + } + + $(self).trigger('tabToggled', ['minimized', tab]); + } + + if(chatbox) { + if(!(input = chatbox.find('.imjs-input')).data('height')) { + // store the height for resizing later + input.data('height', input.height()); + } + + try { + var msglog = chatbox.find('.imjs-msglog'); + msglog[0].scrollTop = msglog[0].scrollHeight; + } catch(e) {} + + try { chatbox.find('.imjs-input').focus(); } catch(e) {} + } + }, + + // === {{{AjaxIM.}}}**{{{bar.closeTab()}}}** === + // + // Close a tab and hide any related chatbox, such that + // the chatbox can not be reopened without reinitializing + // the tab. + // + // //Note:// {{{this}}}, here, refers to the tab DOM element. + closeTab: function() { + var tab = $(this).parents('.imjs-tab'); + tab.css('display', 'none').data('state', 'closed'); + + if(self.settings.storageMethod && self.storageReady) { + delete self.chatstore[tab.find('.imjs-chatbox').data('username')]; + if(self.storageReady) $.jStore.store(self.storeKey + 'chats', self.chatstore); + } + + $(self).trigger('tabToggled', ['closed', tab]); + + self.bar._scrollers(); + + return false; + }, + + // === {{{AjaxIM.}}}**{{{bar.addTab(label, action, closable)}}}** === + // + // Adds a tab to the tab bar, with the label {{{label}}}. When + // clicked, it will call a callback function, {{{action}}}. If + // {{{action}}} is a string, it is assumed that the string is + // referring to a chatbox ID. + // + // ==== Parameters ==== + // * {{{label}}} is the text that will be displayed on the tab.\\ + // * {{{action}}} is the callback function, if it is a non-chatbox + // tab, or a string if it //is// a chatbox tab.\\ + // * {{{closable}}} is a boolean value that determines whether or not + // it is possible for a user to close this tab. + // + // //Note:// New tabs are given an automatically generated ID + // in the format of {{{#imjs-tab-[md5 of label]}}}. + addTab: function(label, action, closable) { + var tab = $('.imjs-tab.imjs-default').clone().insertAfter('#imjs-scroll-right'); + tab.removeClass('imjs-default') + .attr('id', 'imjs-tab-' + $.md5(label)) + .html(tab.html().replace('{label}', label)) + .data('state', 'minimized'); + + var notification = tab.find('.imjs-notification'); + notification.css('display', 'none') + .data('count', 0) + .data('default-text', notification.html()) + .html(notification.html().replace('{count}', '0')); + + if(closable === false) + tab.find('.imjs-close').eq(0).remove(); + + if(typeof action == 'string') { + //tab.data('chatbox', action); + } else { + tab.find('.imjs-chatbox').remove(); + tab.click(action); + } + + return tab; + }, + + // === {{{AjaxIM.}}}**{{{bar.notification(tab)}}}** === + // + // Displays a notification on a tab. Generally, this is called when + // a tab is minimized to let the user know that there is an update + // for them. The way the notification is displayed depends on the + // theme CSS. + // + // ==== Parameters ==== + // * {{{tab}}} is the jQuery-selected tab DOM element. + notification: function(tab) { + var notify = tab.find('.imjs-notification'); + var notify_count = notify.data('count') + 1; + + notify.data('count', notify_count) + .html(notify.data('default-text').replace('{count}', notify_count)) + .css('display', ''); + }, + + // === //private// {{{AjaxIM.}}}**{{{bar._scrollers()}}}** === + // + // Document me! + _scrollers: function() { + var needScrollers = false; + $('.imjs-tab').filter(function() { + return $(this).data('state') != 'closed' + }).css('display', ''); + + $.each(self.chats, function(username, chatbox) { + var tab = chatbox.data('tab'); + if(tab.data('state') == 'closed') return true; + + if(tab.position().top > $('#imjs-bar').height()) { + $('.imjs-scroll').css('display', ''); + tab.css('display', 'none'); + needScrollers = true; + } else { + tab.css('display', ''); + } + }); + + if(!needScrollers) { + $('.imjs-scroll').css('display', 'none'); + } + + if($('#imjs-scroll-left').css('display') != 'none' && + $('#imjs-scroll-left').position().top > $('#imjs-bar').height()) { + $('#imjs-bar li.imjs-tab:visible').slice(-1).css('display', 'none'); + } + + var hiddenLeft = $('#imjs-bar li.imjs-tab:visible').slice(-1) + .nextAll('#imjs-bar li.imjs-tab:hidden') + .not('.imjs-default') + .filter(function() { + return $(this).data('state') != 'closed' + }).length; + + var hiddenRight = $('#imjs-bar li.imjs-tab:visible').eq(0) + .prevAll('#imjs-bar li.imjs-tab:hidden') + .not('.imjs-default') + .filter(function() { + return $(this).data('state') != 'closed' + }).length; + + $('#imjs-scroll-left').html(hiddenLeft); + $('#imjs-scroll-right').html(hiddenRight); + } + }, + + // == Comet == + // + // Comet, or HTTP streaming, holds open a connection between the client and + // the server indefinitely. As the server receives new messages or events, + // they are passed down to the client in a {{{<script>}}} + // tag which calls the {{{AjaxIM.incoming()}}} function. The connection is + // opened using either an {{{iframe}}} (in Opera or Internet Explorer) or + // an {{{XMLHTTPRequest}}} object. Due to the extra flexibility necessary + // with the {{{XMLHTTPRequest}}} object, jQuery's {{{$.ajax}}} is not used. + comet: { + type: '', + obj: null, + + onbeforeunload: null, + onreadystatechange: null, + + iframe: function() { + if(/loaded|complete/i.test(this.obj.readyState)) + throw new Error("IM server not available!"); + }, + + // === {{{AjaxIM.}}}**{{{comet.connect()}}}** === + // + // Creates and initializes the object and connection between the server + // and the client. For Internet Explorer and Opera, we use an + // {{{<iframe>}}} element; for all other browsers, we create an + // {{{XMLHTTPRequest}}} object. The server connects to the URI defined + // as the "poll" action. This function is called automatically, when + // the IM engine is initialized and the {{{AjaxIM.poll()}}} function + // is called. + connect: function() { + var self = _instance; + + if($.browser.opera || $.browser.msie) { + var iframe = $(''); + with(iframe) { + css({ + position: 'absolute', + visibility: 'visible', + display: 'block', + left: '-10000px', + top: '-10000px', + width: '1px', + height: '1px' + }); + + attr('src', self.actions.poll[1]); + appendTo('body'); + + bind('readystatechange', + self.comet.onreadystatechange = function() { self.comet.iframe() }); + bind('beforeunload', + self.comet.onbeforeunload = function() { self.comet.disconnect() }); + } + + self.comet.type = 'iframe'; + self.comet.obj = iframe; + } else { + var xhr = new XMLHttpRequest; + var length = 1029; + var code = /^\s*]*>parent\.(.+);<\/script>$/; + + xhr.open('get', self.actions.poll[1], true); + xhr.onreadystatechange = function(){ + if(xhr.readyState > 2) { + if(xhr.status == 200) { + responseText = xhr.responseText.substring(length); + length = xhr.responseText.length; + if(responseText != ' ') + eval(responseText.replace(code, "$1")); + } + // We need an "else" here. If the state changes to + // "loaded", the user needs to know they're + // disconnected. + } + }; + + self.comet.type = 'xhr'; + self.comet.obj = xhr; + + addEventListener('beforeunload', + self.comet.beforeunload = function() { self.comet.disconnect(); }, false); + setTimeout(function() { xhr.send(null) }, 10); + } + }, + + // === {{{AjaxIM.}}}**{{{comet.disconnect()}}}** === + // + // Disconnect from the server and destroy the connection object. This + // function is called before the page unloads, so that we plug up and + // potential leaks and free memory. + disconnect: function() { + var self = _instance.comet; + + if(!this.type || !this.obj) + return; + + if(this.type == 'iframe') { + detachEvent('onreadystatechange', this.onreadystatechange); + detachEvent('onbeforeunload', this.onbeforeunload); + this.obj.src = '.'; + $(this.obj).remove(); + } else { + removeEventListener('beforeunload', this.onbeforeunload, false); + this.obj.onreadystatechange = function(){}; + this.obj.abort(); + } + + delete this.obj; + } + } + }) + + self.bar.initialize(); + + if(prequeue.length) { + $.each(prequeue, function() { + var func = this[0].split('.'); + if(func.length > 1) + self[func[0]][func[1]].apply(self, this[1]); + else + self[func[0]].apply(self, this[1]); + }); + } + }); + + // == Static functions and variables == + // + // The following functions and variables are available outside of an initialized + // {{{AjaxIM}}} object. + + // === {{{AjaxIM.}}}**{{{client}}}** === + // + // Once {{{AjaxIM.init()}}} is called, this will be set to the active AjaxIM + // object. Only one AjaxIM object instance can exist at a time. This variable + // can and should be accessed directly. + AjaxIM.client = null; + + // === {{{AjaxIM.}}}**{{{init(options, actions)}}}** === + // + // Initialize the AjaxIM client object and engine. Here, you can define your + // options and actions as outlined at the top of this documentation. + // + // ==== Parameters ==== + // * {{{options}}} is the hash of custom settings to initialize Ajax IM with. + // * {{{actions}}} is the hash of any custom action URLs. + AjaxIM.init = function(options, actions) { + if(!_instance) { + _instance = new AjaxIM(options, actions); + AjaxIM.client = _instance; + } + + return _instance; + } + + + // === {{{AjaxIM.}}}**{{{request(url, data, successFunc, failureFunc)}}}** === + // + // Wrapper around {{{$.jsonp}}}, the JSON-P library for jQuery, and {{{$.ajax}}}, + // jQuery's ajax library. Allows either function to be called, automatically, + // depending on the request's URL array (see {{{AjaxIM.actions}}}). + // + // ==== Parameters ==== + // {{{url}}} is the URL of the request. + // {{{data}}} are any arguments that go along with the request. + // {{{success}}} is a callback function called when a request has completed + // without issue. + // {{{_ignore_}}} is simply to provide compatability with {{{$.post}}}. + // {{{failure}}} is a callback function called when a request hasn't not + // completed successfully. + AjaxIM.request = function(url, data, successFunc, failureFunc) { + if(typeof failureFunc != 'function'); + failureFunc = function(){}; + + $[url[0]]({ + 'url': url[1], + 'data': data, + dataType: (url[0] == 'ajax' ? 'json' : 'jsonp'), + type: 'POST', + cache: false, + timeout: 60000, + callback: 'jsonp' + (new Date()).getTime(), + success: function(json, textStatus) { + successFunc(json); + }, + error: function(xOptions, error) { + failureFunc(error); + } + }); + + // This prevents Firefox from spinning indefinitely + // while it waits for a response. Why? Fuck if I know. + if(url[0] == 'jsonp' && $.browser.mozilla) { + $.jsonp({ + 'url': 'about:', + timeout: 0 + }); + } + }; + + // === {{{AjaxIM.}}}**{{{incoming(data)}}}** === + // + // Never call this directly. It is used as a connecting function between + // client and server for Comet. + // + // //Note:// There are two {{{AjaxIM.incoming()}}} functions. This one is a + // static function called outside of the initialized AjaxIM object; the other + // is only called within the initalized AjaxIM object. + AjaxIM.incoming = function(data) { + if(!_instance) + return false; + + if(data.length) + _instance._parseMessages(data); + } + + // === {{{AjaxIM.}}}**{{{loaded}}}** === + // + // If Ajax IM has been loaded with the im.load.js file, this function will be + // called when the library is finally loaded and ready for use. Similar to + // jQuery's $(document).ready(), but for Ajax IM. + AjaxIM.loaded = function() { + if(typeof AjaxIMLoadedFunction == 'function') { + AjaxIMLoadedFunction(); + delete AjaxIMLoadedFunction; // clean up the global namespace + } + }; + + // === {{{AjaxIM.}}}**{{{dateFormat([date,] [mask,] utc)}}}** === + // + // Date Format 1.2.3\\ + // © 2007-2009 Steven Levithan ([[http://blog.stevenlevithan.com/archives/date-time-format|stevenlevithan.com]])\\ + // MIT license + // + // Includes enhancements by Scott Trenda + // and Kris Kowal ([[http://cixar.com/~kris.kowal/|cixar.com/~kris.kowal/]]) + // + // Accepts a date, a mask, or a date and a mask and returns a formatted version + // of the given date. + // + // ==== Parameters ==== + // * {{{date}}} is a {{{Date()}}} object. If not specified, the date defaults to the + // current date/time. + // * {{{mask}}} is a string that defines the formatting of the date. Formatting + // options can be found in the + // [[http://blog.stevenlevithan.com/archives/date-time-format|Date Format]] + // documentation. If not specified, the mask defaults to {{{dateFormat.masks.default}}}. + + AjaxIM.dateFormat = function () { + var token = /d{1,4}|m{1,4}|yy(?:yy)?|([HhMsTt])\1?|[LloSZ]|"[^"]*"|'[^']*'/g, + timezone = new RegExp('\b(?:[PMCEA][SDP]T|(?:Pacific|Mountain|Central|Eastern|Atlantic) ' + + '(?:Standard|Daylight|Prevailing) Time|(?:GMT|UTC)(?:[-+]\d{4})?)\b', + 'g'), + timezoneClip = /[^-+\dA-Z]/g, + pad = function (val, len) { + val = String(val); + len = len || 2; + while (val.length < len) val = "0" + val; + return val; + }; + + // Regexes and supporting functions are cached through closure + return function (date, mask, utc) { + var dF = AjaxIM.dateFormat; + + // You can't provide utc if you skip other args (use the "UTC:" mask prefix) + if (arguments.length == 1 && Object.prototype.toString.call(date) == + "[object String]" && !/\d/.test(date)) { + mask = date; + date = undefined; + } + + // Passing date through Date applies Date.parse, if necessary + date = date ? new Date(date) : new Date; + if (isNaN(date)) throw SyntaxError("invalid date"); + + mask = String(dF.masks[mask] || mask || dF.masks["default"]); + + // Allow setting the utc argument via the mask + if (mask.slice(0, 4) == "UTC:") { + mask = mask.slice(4); + utc = true; + } + + var _ = utc ? "getUTC" : "get", + d = date[_ + "Date"](), + D = date[_ + "Day"](), + m = date[_ + "Month"](), + y = date[_ + "FullYear"](), + H = date[_ + "Hours"](), + M = date[_ + "Minutes"](), + s = date[_ + "Seconds"](), + L = date[_ + "Milliseconds"](), + o = utc ? 0 : date.getTimezoneOffset(), + flags = { + d: d, + dd: pad(d), + ddd: AjaxIM.i18n.dayNames[D], + dddd: AjaxIM.i18n.dayNames[D + 7], + m: m + 1, + mm: pad(m + 1), + mmm: AjaxIM.i18n.monthNames[m], + mmmm: AjaxIM.i18n.monthNames[m + 12], + yy: String(y).slice(2), + yyyy: y, + h: H % 12 || 12, + hh: pad(H % 12 || 12), + H: H, + HH: pad(H), + M: M, + MM: pad(M), + s: s, + ss: pad(s), + l: pad(L, 3), + L: pad(L > 99 ? Math.round(L / 10) : L), + t: H < 12 ? "a" : "p", + tt: H < 12 ? "am" : "pm", + T: H < 12 ? "A" : "P", + TT: H < 12 ? "AM" : "PM", + Z: utc ? "UTC" : + (String(date).match(timezone) || [""]) + .pop().replace(timezoneClip, ""), + o: (o > 0 ? "-" : "+") + + pad(Math.floor(Math.abs(o) / 60) * 100 + Math.abs(o) % 60, 4), + S: ["th", "st", "nd", "rd"][d % 10 > 3 ? + 0 : + (d % 100 - d % 10 != 10) * d % 10] + }; + + return mask.replace(token, function ($0) { + return $0 in flags ? flags[$0] : $0.slice(1, $0.length - 1); + }); + }; + }(); + + // Some common format strings + AjaxIM.dateFormat.masks = { + "default": "ddd mmm dd yyyy HH:MM:ss", + shortDate: "m/d/yy", + mediumDate: "mmm d, yyyy", + longDate: "mmmm d, yyyy", + fullDate: "dddd, mmmm d, yyyy", + shortTime: "h:MM TT", + mediumTime: "h:MM:ss TT", + longTime: "h:MM:ss TT Z", + isoDate: "yyyy-mm-dd", + isoTime: "HH:MM:ss", + isoDateTime: "yyyy-mm-dd'T'HH:MM:ss", + isoUtcDateTime: "UTC:yyyy-mm-dd'T'HH:MM:ss'Z'" + }; + + // === {{{AjaxIM.}}}**{{{i18n}}}** === + // + // Text strings used by Ajax IM. Should you want to translate Ajax IM into + // another language, merely change these strings. + // + // {{{%s}}} denotes text that will be automatically replaced when the string is + // used. + AjaxIM.i18n = { + dayNames: [ + "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", + "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday" + ], + monthNames: [ + "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", + "January", "February", "March", "April", "May", "June", "July", "August", "September", + "October", "November", "December" + ], + + chatOffline: '%s signed off.', + chatAvailable: '%s became available.', + chatAway: '%s went away.', + + notConnected: 'You are currently not connected or the server is not available. ' + + 'Please ensure that you are signed in and try again.', + notConnectedTip: 'You are currently not connected.', + + authInvalid: 'Invalid username or password.', + + registerPasswordLength: 'Passwords must be more than 4 characters in length.', + registerUsernameLength: 'Usernames must be more than 2 characters in length and ' + + ' contain only A-Z, a-z, 0-9, underscores (_) and periods (.).', + registerPasswordMatch: 'Entered passwords do not match.', + registerUsernameTaken: 'The chosen username is already in use; please choose another.', + registerUnknown: 'An unknown error occurred. Please try again.' + } +})(jQuery, false); From c8e48449b32255e4f7803a1573982a42fbf3d491 Mon Sep 17 00:00:00 2001 From: Olivier Dony Date: Mon, 11 Apr 2011 12:08:47 +0200 Subject: [PATCH 135/259] [FIX] orm.read_group: fix group_by for date[time]s, currently showing duplicate groups bzr revid: odo@openerp.com-20110411100847-va4ok35jx3tohor6 --- bin/osv/orm.py | 1 + 1 file changed, 1 insertion(+) diff --git a/bin/osv/orm.py b/bin/osv/orm.py index 7fc8744737b..91574e7fa6a 100644 --- a/bin/osv/orm.py +++ b/bin/osv/orm.py @@ -2175,6 +2175,7 @@ class orm(orm_template): if fget[groupby]['type'] in ('date', 'datetime'): flist = "to_char(%s,'yyyy-mm') as %s " % (qualified_groupby_field, groupby) groupby = "to_char(%s,'yyyy-mm')" % (qualified_groupby_field) + qualified_groupby_field = groupby else: flist = qualified_groupby_field else: From 3412b89d95c1febe139e5184ba0295c85bf3a785 Mon Sep 17 00:00:00 2001 From: Xavier Morel Date: Mon, 11 Apr 2011 12:31:18 +0200 Subject: [PATCH 136/259] [IMP] add a bunch of tests for transformation of invisible fields, make View.fields_view_get take a request so it can use the request context for its evaluations bzr revid: xmo@openerp.com-20110411103118-msx5plh2lnz5obps --- addons/base/controllers/main.py | 26 +++++++------ addons/base/test/test_view.py | 48 ++++++++++++++++++++++++ addons/base_calendar/controllers/main.py | 3 +- 3 files changed, 64 insertions(+), 13 deletions(-) diff --git a/addons/base/controllers/main.py b/addons/base/controllers/main.py index 28806083d61..a8dc58625fa 100644 --- a/addons/base/controllers/main.py +++ b/addons/base/controllers/main.py @@ -403,16 +403,20 @@ class DataSet(openerpweb.Controller): return {'result': r} class View(openerpweb.Controller): - def fields_view_get(self, session, model, view_id, view_type, transform=True, toolbar=False, submenu=False): - Model = session.model(model) - r = Model.fields_view_get(view_id, view_type, {}, toolbar, submenu) + def fields_view_get(self, request, model, view_id, view_type, + transform=True, toolbar=False, submenu=False): + Model = request.session.model(model) + fvg = Model.fields_view_get(view_id, view_type, request.context, + toolbar, submenu) if transform: - context = {} # TODO: dict(ctx_sesssion, **ctx_action) - xml = self.transform_view(r['arch'], session, context) + evaluation_context = request.session.evaluation_context( + request.context or {}) + xml = self.transform_view( + fvg['arch'], request.session, evaluation_context) else: - xml = ElementTree.fromstring(r['arch']) - r['arch'] = Xml2Json.convert_element(xml) - return r + xml = ElementTree.fromstring(fvg['arch']) + fvg['arch'] = Xml2Json.convert_element(xml) + return fvg def normalize_attrs(self, elem, context): """ Normalize @attrs, @invisible, @required, @readonly and @states, so @@ -507,7 +511,7 @@ class FormView(View): @openerpweb.jsonrequest def load(self, req, model, view_id, toolbar=False): - fields_view = self.fields_view_get(req.session, model, view_id, 'form', toolbar=toolbar) + fields_view = self.fields_view_get(req, model, view_id, 'form', toolbar=toolbar) return {'fields_view': fields_view} class ListView(View): @@ -515,7 +519,7 @@ class ListView(View): @openerpweb.jsonrequest def load(self, req, model, view_id, toolbar=False): - fields_view = self.fields_view_get(req.session, model, view_id, 'tree', toolbar=toolbar) + fields_view = self.fields_view_get(req, model, view_id, 'tree', toolbar=toolbar) return {'fields_view': fields_view} class SearchView(View): @@ -523,7 +527,7 @@ class SearchView(View): @openerpweb.jsonrequest def load(self, req, model, view_id): - fields_view = self.fields_view_get(req.session, model, view_id, 'search') + fields_view = self.fields_view_get(req, model, view_id, 'search') return {'fields_view': fields_view} class Action(openerpweb.Controller): diff --git a/addons/base/test/test_view.py b/addons/base/test/test_view.py index f20f9e12f61..d8f65ccff99 100644 --- a/addons/base/test/test_view.py +++ b/addons/base/test/test_view.py @@ -1,3 +1,4 @@ +import copy import xml.etree.ElementTree import mock @@ -8,6 +9,11 @@ import base.controllers.main import openerpweb.nonliterals import openerpweb.openerpweb +def field_attrs(fields_view_get, fieldname): + (field,) = filter(lambda f: f['attrs'].get('name') == fieldname, + fields_view_get['arch']['children']) + return field['attrs'] + #noinspection PyCompatibility class DomainsAndContextsTest(unittest2.TestCase): def setUp(self): @@ -130,3 +136,45 @@ class AttrsNormalizationTest(unittest2.TestCase): self.assertEqual( simplejson.loads(element.get('attrs')), {'invisible': [['state', 'not in', ['open', 'closed']]]}) + + def test_transform_invisible(self): + element = xml.etree.ElementTree.Element( + 'field', invisible="context.get('invisible_country', False)") + + empty_context = copy.deepcopy(element) + self.view.normalize_attrs(empty_context, {}) + self.assertEqual(empty_context.get('invisible'), None) + + full_context = copy.deepcopy(element) + self.view.normalize_attrs(full_context, {'invisible_country': True}) + self.assertEqual(full_context.get('invisible'), '1') + + def test_transform_invisible_list_column(self): + req = mock.Mock() + req.context = {'set_editable':True, 'set_visible':True, + 'gtd_visible':True, 'user_invisible':True} + req.session.evaluation_context = \ + openerpweb.openerpweb.OpenERPSession().evaluation_context + req.session.model('project.task').fields_view_get.return_value = { + 'arch': ''' + + + + + + + + + '''} + parsed_view = base.controllers.main.View().fields_view_get( + req, 'project.task', 42, 'tree') + + self.assertTrue(field_attrs(parsed_view, 'sequence')['invisible']) + self.assertTrue(field_attrs(parsed_view, 'user_id')['invisible']) + self.assertTrue( + field_attrs(parsed_view, 'delegated_user_id')['invisible']) + self.assertTrue(field_attrs(parsed_view, 'total_hours')['invisible']) + self.assertTrue( + field_attrs(parsed_view, 'date_deadline')['invisible']) + self.assertTrue(field_attrs(parsed_view, 'type_id')['invisible']) + diff --git a/addons/base_calendar/controllers/main.py b/addons/base_calendar/controllers/main.py index 41081bc7cae..a54d75c5b9b 100644 --- a/addons/base_calendar/controllers/main.py +++ b/addons/base_calendar/controllers/main.py @@ -57,7 +57,7 @@ class CalendarView(View): @openerpweb.jsonrequest def load(self, req, model, view_id): - fields_view = self.fields_view_get(req.session, model, view_id, 'calendar') + fields_view = self.fields_view_get(req, model, view_id, 'calendar') return {'fields_view':fields_view} def convert(self, event): @@ -354,4 +354,3 @@ class CalendarView(View): title = title.strip() description = ', '.join(description).strip() return {'id': event['id'], 'start_date': str(DT.datetime(*starts[:6])), 'end_date': str(DT.datetime(*ends[:6])), 'text': title, 'title': description, 'color': self.colors[event[self.color_field]][-1]} - \ No newline at end of file From 911369822abb9779193137301326e61242b9daa7 Mon Sep 17 00:00:00 2001 From: Xavier Morel Date: Mon, 11 Apr 2011 13:14:51 +0200 Subject: [PATCH 137/259] [ADD] processing of context['set_editable'] on list view bzr revid: xmo@openerp.com-20110411111451-5j6ve9f1wjiuzjfx --- addons/base/controllers/main.py | 49 +++++++++++++++++++++++++++++++ addons/base/static/src/js/list.js | 11 ++++++- addons/base/test/test_view.py | 27 +++++++++++++++++ 3 files changed, 86 insertions(+), 1 deletion(-) diff --git a/addons/base/controllers/main.py b/addons/base/controllers/main.py index a8dc58625fa..36e9b0feaee 100644 --- a/addons/base/controllers/main.py +++ b/addons/base/controllers/main.py @@ -1,5 +1,6 @@ # -*- coding: utf-8 -*- import glob, os +import pprint from xml.etree import ElementTree from cStringIO import StringIO @@ -522,6 +523,54 @@ class ListView(View): fields_view = self.fields_view_get(req, model, view_id, 'tree', toolbar=toolbar) return {'fields_view': fields_view} + def fields_view_get(self, request, model, view_id, view_type="tree", + transform=True, toolbar=False, submenu=False): + """ Sets @editable on the view's arch if it isn't already set and + ``set_editable`` is present in the request context + """ + view = super(ListView, self).fields_view_get( + request, model, view_id, view_type, transform, toolbar, submenu) + + view_attributes = view['arch']['attrs'] + if request.context.get('set_editable')\ + and 'editable' not in view_attributes: + view_attributes['editable'] = 'bottom' + return view + + @openerpweb.jsonrequest + def fill(self, request, model, id, domain, + offset=0, limit=False): + return self.do_fill(request, model, id, domain, offset, limit) + + def do_fill(self, request, model, id, domain, + offset=0, limit=False): + """ Returns all information needed to fill a table: + + * view with processed ``editable`` flag + * fields (columns) with processed ``invisible`` flag + * rows with processed ``attrs`` and ``colors`` + + .. note:: context is passed through ``request`` parameter + + :param request: OpenERP request + :type request: openerpweb.openerpweb.JsonRequest + :type str model: OpenERP model for this list view + :type int id: view_id, or False if none provided + :param list domain: the search domain to search for + :param int offset: search offset, for pagination + :param int limit: search limit, for pagination + :returns: hell if I have any idea yet + """ + view = self.fields_view_get(request, model, id) + + rows = DataSet().do_search_read(request, model, + offset=offset, limit=limit, + domain=domain) + # rows pipe + # process_attrs + # process_colors + return rows + class SearchView(View): _cp_path = "/base/searchview" diff --git a/addons/base/static/src/js/list.js b/addons/base/static/src/js/list.js index 4fc3ef07720..247b2d535d9 100644 --- a/addons/base/static/src/js/list.js +++ b/addons/base/static/src/js/list.js @@ -160,7 +160,16 @@ openerp.base.ListView = openerp.base.Controller.extend( // TODO: handle non-empty results.group_by with read_group self.dataset.context = results.context; self.dataset.domain = results.domain; - self.dataset.read_slice(self.dataset.fields, 0, self.limit, self.do_fill_table); + // TODO: need to do 5 billion tons of pre-processing, bypass + // DataSet for now + //self.dataset.read_slice(self.dataset.fields, 0, self.limit, + // self.do_fill_table); + self.rpc('/base/listview/fill', { + 'model': self.dataset.model, + 'id': self.view_id, + 'context': results.context, + 'domain': results.domain + }, self.do_fill_table); }); }, do_update: function () { diff --git a/addons/base/test/test_view.py b/addons/base/test/test_view.py index d8f65ccff99..141bbd5e0db 100644 --- a/addons/base/test/test_view.py +++ b/addons/base/test/test_view.py @@ -178,3 +178,30 @@ class AttrsNormalizationTest(unittest2.TestCase): field_attrs(parsed_view, 'date_deadline')['invisible']) self.assertTrue(field_attrs(parsed_view, 'type_id')['invisible']) +class ListViewTest(unittest2.TestCase): + def setUp(self): + self.view = base.controllers.main.ListView() + self.request = mock.Mock() + self.request.context = {'set_editable': True} + def test_no_editable_editable_context(self): + self.request.session.model('fake').fields_view_get.return_value = \ + {'arch': ''} + view = self.view.fields_view_get(self.request, 'fake', False) + + self.assertEqual(view['arch']['attrs']['editable'], + 'bottom') + def test_editable_top_editable_context(self): + self.request.session.model('fake').fields_view_get.return_value = \ + {'arch': ''} + view = self.view.fields_view_get(self.request, 'fake', False) + + self.assertEqual(view['arch']['attrs']['editable'], + 'top') + + def test_editable_bottom_editable_context(self): + self.request.session.model('fake').fields_view_get.return_value = \ + {'arch': ''} + view = self.view.fields_view_get(self.request, 'fake', False) + + self.assertEqual(view['arch']['attrs']['editable'], + 'bottom') From 8ca75e0b11eb712d549d91064358bb816aeef0ec Mon Sep 17 00:00:00 2001 From: "noz (OpenERP)" Date: Mon, 11 Apr 2011 16:45:38 +0530 Subject: [PATCH 138/259] [FIX] Sent first chat message to self. bzr revid: noz@tinyerp.com-20110411111538-yxvexkoyldb5xrid --- addons/web_chat/controllers/main.py | 33 ++++++++-------------- addons/web_chat/static/lib/AjaxIM/js/im.js | 4 +-- 2 files changed, 13 insertions(+), 24 deletions(-) diff --git a/addons/web_chat/controllers/main.py b/addons/web_chat/controllers/main.py index ff5b95d6579..adb32c3a7a3 100644 --- a/addons/web_chat/controllers/main.py +++ b/addons/web_chat/controllers/main.py @@ -67,6 +67,7 @@ class PollServer(openerpweb.Controller): } """ mq = req.applicationsession.setdefault("web_chat", PollServerMessageQueue()) + mq.messages = [] #r = 'logged in' #u = generate random.randint(0,2**32) @@ -106,9 +107,9 @@ class PollServer(openerpweb.Controller): def poll(self, req, **kw): mq = req.applicationsession.setdefault("web_chat", PollServerMessageQueue()) - print "================ poll ======= ", kw - # Long Polling - method = kw.get('method') + + # Method: Long Poll + """ --> GET http://im.ajaxim.com/poll?callback=jsonp1302138663582&_1302138663582= <-- 200 OK @@ -132,7 +133,7 @@ class PollServer(openerpweb.Controller): """ - msg = [] + msg = '[]' for i in range(5): received_msg = mq.read('Guest1', i); @@ -140,27 +141,14 @@ class PollServer(openerpweb.Controller): msg = self._pollParseMessages(received_msg) time.sleep(1) else: - msg = [] + msg = '[]' time.sleep(1) - - # for i in range(60): - #r = mq.read(username,timestamp) - # if messages - # return r - # if no message sleep 2s and retry - # sleep 2 - # else - # return emptylist - msg = '[{"t":"m","s":"Guest130214008855.5","r":"Guest130214013134.26","m":"xxxxxx"}]' - -# # it's http://localhost:8002/web_chat/pollserver/poll?method=long?callback=jsonp1302147330483&_1302147330483= - - return '%s'%kw.get('callback', '') + '(' + msg + ');' + # it's http://localhost:8002/web_chat/pollserver/poll?callback=jsonp1302147330483&_1302147330483= + return '%s'%kw.get('callback', '') + '(' + str(msg) + ');' @openerpweb.httprequest def send(self, req, **kw): - print "========= send ========", kw to = kw.get('to') message = kw.get('message') @@ -192,7 +180,7 @@ class PollServer(openerpweb.Controller): if message: mq.write(m_type="m", m_from=req.applicationsession['current_user'], m_to=to, m_message=message, m_group="Users") - return {'r': 'sent'} + return '%s'%kw.get('callback', '') + '(' + simplejson.dumps({'r': 'sent'}) + ')' else: return {'r': 'error', 'e': 'send error'} @@ -221,7 +209,8 @@ class PollServer(openerpweb.Controller): def _pollParseMessages(self, messages): msg_arr = [] for msg in messages: - msg_arr.append({'t': msg['type'], 's': msg['from'], 'r': msg['to'], 'm': msg['message']}) + msg_arr.append({"t": str(msg['type']), "s": str(msg['from']), "r": str(msg['to']), "m": str(msg['message'])}) + return msg_arr def _sanitize(self, message): diff --git a/addons/web_chat/static/lib/AjaxIM/js/im.js b/addons/web_chat/static/lib/AjaxIM/js/im.js index 42c3f743204..9ab195fd6b6 100644 --- a/addons/web_chat/static/lib/AjaxIM/js/im.js +++ b/addons/web_chat/static/lib/AjaxIM/js/im.js @@ -105,7 +105,7 @@ login: this.settings.pollServer + '/login', logout: this.settings.pollServer + '/logout', register: this.settings.pollServer + '/register', - poll: this.settings.pollServer + '/poll?method=' + this.settings.pollType, + poll: this.settings.pollServer + '/poll', send: this.settings.pollServer + '/send', status: this.settings.pollServer + '/status', resume: this.settings.pollServer + '/resume' @@ -116,7 +116,7 @@ queryStrRx = new RegExp('[?](.+)$'), subdomainRx = new RegExp('((http[s]?:)?//)?(.+?)[.]' + window.location.host, 'i'); $.each(this.actions, function(name, action) { - if(name == 'poll') { + if(name == 'poll' || name == 'send') { if(self.settings.pollType != 'comet') action += (queryStrRx.test(action[1]) ? '&' : '?') + 'callback=?'; From 86c1b252e69224c39851598d68acc5a6ead6b5c9 Mon Sep 17 00:00:00 2001 From: Fabien Meghazi Date: Mon, 11 Apr 2011 13:35:16 +0200 Subject: [PATCH 139/259] [ADD] Added record creation. Refactored form view. bzr revid: fme@openerp.com-20110411113516-s8ydhmknehgbwp2n --- addons/base/controllers/main.py | 6 ++ addons/base/static/src/js/data.js | 7 +- addons/base/static/src/js/form.js | 135 +++++++++++++++++------------- 3 files changed, 89 insertions(+), 59 deletions(-) diff --git a/addons/base/controllers/main.py b/addons/base/controllers/main.py index 96782c1cec4..83dae67b2ba 100644 --- a/addons/base/controllers/main.py +++ b/addons/base/controllers/main.py @@ -382,6 +382,12 @@ class DataSet(openerpweb.Controller): value = r[0] return {'value': value} + @openerpweb.jsonrequest + def create(self, req, model, data, context={}): + m = req.session.model(model) + r = m.create(data, context) + return {'result': r} + @openerpweb.jsonrequest def save(self, req, model, id, data, context={}): m = req.session.model(model) diff --git a/addons/base/static/src/js/data.js b/addons/base/static/src/js/data.js index c16bf8eb81b..7b1a930c88f 100644 --- a/addons/base/static/src/js/data.js +++ b/addons/base/static/src/js/data.js @@ -89,7 +89,12 @@ openerp.base.DataSet = openerp.base.Controller.extend( /** @lends openerp.base. context: this.context }, callback); }, - create: function() { + create: function(data, callback) { + return this.rpc('/base/dataset/create', { + model: this.model, + data: data, + context: this.context + }, callback); }, write: function (id, data, callback) { return this.rpc('/base/dataset/save', { diff --git a/addons/base/static/src/js/form.js b/addons/base/static/src/js/form.js index e31f03510d8..3de0bbfd32a 100644 --- a/addons/base/static/src/js/form.js +++ b/addons/base/static/src/js/form.js @@ -27,6 +27,7 @@ openerp.base.FormView = openerp.base.Controller.extend( /** @lends openerp.base this.fields = {}; this.datarecord = {}; this.ready = false; + this.show_invalid = true; }, start: function() { //this.log('Starting FormView '+this.model+this.view_id) @@ -69,16 +70,18 @@ openerp.base.FormView = openerp.base.Controller.extend( /** @lends openerp.base if (record) { this.datarecord = record; for (var f in this.fields) { - this.fields[f].set_value(this.datarecord[f]); + this.fields[f].set_value(this.datarecord[f] || false); + this.fields[f].validate(); } if (!record.id) { + this.show_invalid = false; // Second pass in order to trigger the onchanges in case of new record for (var f in record) { - this.fields[f].on_ui_change(); + this.on_form_changed(this.fields[f]); } } this.on_form_changed(); - this.ready = true; + this.show_invalid = this.ready = true; } else { this.log("No record received"); } @@ -197,6 +200,7 @@ openerp.base.FormView = openerp.base.Controller.extend( /** @lends openerp.base }); }, do_save: function() { + var self = this; if (!this.ready) { return false; } @@ -206,6 +210,7 @@ openerp.base.FormView = openerp.base.Controller.extend( /** @lends openerp.base f = this.fields[f]; if (f.invalid) { invalid = true; + f.update_dom(); } else if (f.touched) { values[f.name] = f.get_value(); } @@ -214,13 +219,19 @@ openerp.base.FormView = openerp.base.Controller.extend( /** @lends openerp.base this.on_invalid(); } else { this.log("About to save", values); - this.dataset.write(this.datarecord.id, values, this.on_saved); + if (!this.datarecord.id) { + this.dataset.create(values, function() { + self.datarecord.id = arguments[0].result; + self.on_saved.apply(self, arguments); + }); + } else { + this.dataset.write(this.datarecord.id, values, this.on_saved); + } } }, do_save_edit: function() { - if (this.do_save()) { - this.switch_readonly(); - } + this.do_save(); + //this.switch_readonly(); Use promises }, switch_readonly: function() { }, @@ -499,6 +510,9 @@ openerp.base.form.Field = openerp.base.form.Widget.extend({ this.invalid = false; this.update_dom(); }, + set_value_from_ui: function() { + this.value = undefined; + }, get_value: function() { return this.value; }, @@ -506,10 +520,17 @@ openerp.base.form.Field = openerp.base.form.Widget.extend({ this._super.apply(this, arguments); this.$element.toggleClass('disabled', this.readonly); this.$element.toggleClass('required', this.required); - this.$element.toggleClass('invalid', this.invalid); + if (this.view.show_invalid) { + this.$element.toggleClass('invalid', this.invalid); + } }, on_ui_change: function() { this.touched = true; + this.set_value_from_ui(); + this.validate(); + this.view.on_form_changed(this); + }, + validate: function() { } }); @@ -531,31 +552,41 @@ openerp.base.form.FieldChar = openerp.base.form.Field.extend({ this._super.apply(this, arguments); this.$element.find('input').attr('disabled', this.readonly); }, - on_ui_change: function() { - this._super.apply(this, arguments); + set_value_from_ui: function() { this.value = this.$element.find('input').val(); - this.invalid = this.required && this.value == ""; - this.view.on_form_changed(this); + }, + validate: function() { + this.invalid = false; + if (this.value === false || this.value === "") { + this.invalid = this.required; + } else if (this.validation_regex) { + this.invalid = !this.validation_regex.test(this.value); + } } }); openerp.base.form.FieldEmail = openerp.base.form.FieldChar.extend({ + init: function(view, node) { + this._super(view, node); + this.validation_regex = /@/; + } }); openerp.base.form.FieldUrl = openerp.base.form.FieldChar.extend({ }); openerp.base.form.FieldFloat = openerp.base.form.FieldChar.extend({ + init: function(view, node) { + this._super(view, node); + this.validation_regex = /^\d+(\.\d+)?$/; + }, set_value: function(value) { this._super.apply(this, arguments); var show_value = (value != null && value !== false) ? value.toFixed(2) : ''; - this.$element.find('input').val(value); + this.$element.find('input').val(show_value); }, - on_ui_change: function() { - this._super.apply(this, arguments); + set_value_from_ui: function() { this.value = this.$element.find('input').val().replace(/,/g, '.'); - this.invalid = (this.required && this.value == "") || !this.value.match(/^\d+(\.\d+)?$/) ; - this.view.on_form_changed(this); } }); @@ -563,23 +594,13 @@ openerp.base.form.FieldDate = openerp.base.form.FieldChar.extend({ init: function(view, node) { this._super(view, node); this.template = "FieldDate"; + this.validation_regex = /^\d+-\d+-\d+$/; }, start: function() { this._super.apply(this, arguments); this.$element.find('input').change(this.on_ui_change).datepicker({ dateFormat: 'yy-mm-dd' }); - }, - set_value: function(value) { - this._super.apply(this, arguments); - var show_value = (value != null && value !== false) ? value : ''; - this.$element.find('input').val(show_value); - }, - on_ui_change: function() { - this._super.apply(this, arguments); - this.value = this.$element.find('input').val(); - this.invalid = this.required && this.value == ""; - this.view.on_form_changed(this); } }); @@ -587,6 +608,7 @@ openerp.base.form.FieldDatetime = openerp.base.form.FieldChar.extend({ init: function(view, node) { this._super(view, node); this.template = "FieldDatetime"; + this.validation_regex = /^\d+-\d+-\d+( \d+:\d+(:\d+)?)?$/; }, start: function() { this._super.apply(this, arguments); @@ -594,17 +616,6 @@ openerp.base.form.FieldDatetime = openerp.base.form.FieldChar.extend({ dateFormat: 'yy-mm-dd', timeFormat: 'hh:mm:ss' }); - }, - set_value: function(value) { - this._super.apply(this, arguments); - var show_value = (value != null && value !== false) ? value : ''; - this.$element.find('input').val(show_value); - }, - on_ui_change: function() { - this._super.apply(this, arguments); - this.value = this.$element.find('input').val(); - this.invalid = this.required && this.value == ""; - this.view.on_form_changed(this); } }); @@ -612,6 +623,7 @@ openerp.base.form.FieldText = openerp.base.form.Field.extend({ init: function(view, node) { this._super(view, node); this.template = "FieldText"; + this.validation_regex = null; }, start: function() { this._super.apply(this, arguments); @@ -626,11 +638,16 @@ openerp.base.form.FieldText = openerp.base.form.Field.extend({ this._super.apply(this, arguments); this.$element.find('textarea').attr('disabled', this.readonly); }, - on_ui_change: function() { - this._super.apply(this, arguments); + set_value_from_ui: function() { this.value = this.$element.find('textarea').val(); - this.invalid = this.required && this.value == ""; - this.view.on_form_changed(this); + }, + validate: function() { + this.invalid = false; + if (this.value === false || this.value === "") { + this.invalid = this.required; + } else if (this.validation_regex) { + this.invalid = !this.validation_regex.test(this.value); + } } }); @@ -652,15 +669,15 @@ openerp.base.form.FieldBoolean = openerp.base.form.Field.extend({ this._super.apply(this, arguments); this.$element.find('input')[0].checked = value; }, + set_value_from_ui: function() { + this.value = this.$element.find('input').is(':checked'); + }, update_dom: function() { this._super.apply(this, arguments); - this.$element.find('textarea').attr('disabled', this.readonly); + this.$element.find('input').attr('disabled', this.readonly); }, - on_ui_change: function() { - this._super.apply(this, arguments); - this.value = this.$element.find('input').is(':checked'); + validate: function() { this.invalid = this.required && !this.value; - this.view.on_form_changed(this); } }); @@ -685,15 +702,15 @@ openerp.base.form.FieldSelection = openerp.base.form.Field.extend({ this.$element.find('select')[0].selectedIndex = 0; } }, + set_value_from_ui: function() { + this.value = this.$element.find('select').val(); + }, update_dom: function() { this._super.apply(this, arguments); this.$element.find('select').attr('disabled', this.readonly); }, - on_ui_change: function() { - this._super.apply(this, arguments); - this.value = this.$element.find('select').val(); - this.invalid = this.required && this.value == ""; - this.view.on_form_changed(this); + validate: function() { + this.invalid = this.required && this.value === ""; } }); @@ -744,12 +761,14 @@ openerp.base.form.FieldOne2Many = openerp.base.form.Field.extend({ this.viewmanager = new openerp.base.form.FieldOne2ManyViewManager(this.view.session, this.element_id, this.dataset, views); this.viewmanager.start(); }, - set_value_CASSEEEEEEEEEEEEEEEEE: function(value) { + set_value: function(value) { this.value = value; - this.log("o2m.set_value",value); - this.viewmanager.dataset.ids = value; - this.viewmanager.dataset.ids.count = value.length; - this.viewmanager.views.list.controller.do_update(); + if (value != false) { + this.log("o2m.set_value",value); + this.viewmanager.dataset.ids = value; + this.viewmanager.dataset.count = value.length; + this.viewmanager.views.list.controller.do_update(); + } }, get_value: function(value) { return this.operations; From bfacf53e04731b039c79e1c442e6843f6e12b629 Mon Sep 17 00:00:00 2001 From: niv-openerp Date: Mon, 11 Apr 2011 13:45:29 +0200 Subject: [PATCH 140/259] [IMP] Open new window. bzr revid: nicolas.vanhoren@openerp.com-20110411114529-332vb6wtrocrwjm0 --- .../static/lib/jquery.ba-bbq/jquery.ba-bbq.js | 1137 +++++++++++++++++ .../lib/jquery.ba-bbq/jquery.ba-bbq.min.js | 18 + addons/base/static/src/base.html | 1 + addons/base/static/src/js/views.js | 5 +- 4 files changed, 1159 insertions(+), 2 deletions(-) create mode 100644 addons/base/static/lib/jquery.ba-bbq/jquery.ba-bbq.js create mode 100644 addons/base/static/lib/jquery.ba-bbq/jquery.ba-bbq.min.js diff --git a/addons/base/static/lib/jquery.ba-bbq/jquery.ba-bbq.js b/addons/base/static/lib/jquery.ba-bbq/jquery.ba-bbq.js new file mode 100644 index 00000000000..f251123acd7 --- /dev/null +++ b/addons/base/static/lib/jquery.ba-bbq/jquery.ba-bbq.js @@ -0,0 +1,1137 @@ +/*! + * jQuery BBQ: Back Button & Query Library - v1.2.1 - 2/17/2010 + * http://benalman.com/projects/jquery-bbq-plugin/ + * + * Copyright (c) 2010 "Cowboy" Ben Alman + * Dual licensed under the MIT and GPL licenses. + * http://benalman.com/about/license/ + */ + +// Script: jQuery BBQ: Back Button & Query Library +// +// *Version: 1.2.1, Last updated: 2/17/2010* +// +// Project Home - http://benalman.com/projects/jquery-bbq-plugin/ +// GitHub - http://github.com/cowboy/jquery-bbq/ +// Source - http://github.com/cowboy/jquery-bbq/raw/master/jquery.ba-bbq.js +// (Minified) - http://github.com/cowboy/jquery-bbq/raw/master/jquery.ba-bbq.min.js (4.0kb) +// +// About: License +// +// Copyright (c) 2010 "Cowboy" Ben Alman, +// Dual licensed under the MIT and GPL licenses. +// http://benalman.com/about/license/ +// +// About: Examples +// +// These working examples, complete with fully commented code, illustrate a few +// ways in which this plugin can be used. +// +// Basic AJAX - http://benalman.com/code/projects/jquery-bbq/examples/fragment-basic/ +// Advanced AJAX - http://benalman.com/code/projects/jquery-bbq/examples/fragment-advanced/ +// jQuery UI Tabs - http://benalman.com/code/projects/jquery-bbq/examples/fragment-jquery-ui-tabs/ +// Deparam - http://benalman.com/code/projects/jquery-bbq/examples/deparam/ +// +// About: Support and Testing +// +// Information about what version or versions of jQuery this plugin has been +// tested with, what browsers it has been tested in, and where the unit tests +// reside (so you can test it yourself). +// +// jQuery Versions - 1.3.2, 1.4.1, 1.4.2 +// Browsers Tested - Internet Explorer 6-8, Firefox 2-3.7, Safari 3-4, +// Chrome 4-5, Opera 9.6-10.1. +// Unit Tests - http://benalman.com/code/projects/jquery-bbq/unit/ +// +// About: Release History +// +// 1.2.1 - (2/17/2010) Actually fixed the stale window.location Safari bug from +// in BBQ, which was the main reason for the +// previous release! +// 1.2 - (2/16/2010) Integrated v1.2, which fixes a +// Safari bug, the event can now be bound before DOM ready, and IE6/7 +// page should no longer scroll when the event is first bound. Also +// added the method, and reworked the +// internal "add" method to be compatible with +// changes made to the jQuery 1.4.2 special events API. +// 1.1.1 - (1/22/2010) Integrated v1.1, which fixes an +// obscure IE8 EmulateIE7 meta tag compatibility mode bug. +// 1.1 - (1/9/2010) Broke out the jQuery BBQ event.special +// functionality into a separate plugin for users who want just the +// basic event & back button support, without all the extra awesomeness +// that BBQ provides. This plugin will be included as part of jQuery BBQ, +// but also be available separately. See +// plugin for more information. Also added the +// method and added additional examples. +// 1.0.3 - (12/2/2009) Fixed an issue in IE 6 where location.search and +// location.hash would report incorrectly if the hash contained the ? +// character. Also and +// will no longer parse params out of a URL that doesn't contain ? or #, +// respectively. +// 1.0.2 - (10/10/2009) Fixed an issue in IE 6/7 where the hidden IFRAME caused +// a "This page contains both secure and nonsecure items." warning when +// used on an https:// page. +// 1.0.1 - (10/7/2009) Fixed an issue in IE 8. Since both "IE7" and "IE8 +// Compatibility View" modes erroneously report that the browser +// supports the native window.onhashchange event, a slightly more +// robust test needed to be added. +// 1.0 - (10/2/2009) Initial release + +(function($,window){ + '$:nomunge'; // Used by YUI compressor. + + // Some convenient shortcuts. + var undefined, + aps = Array.prototype.slice, + decode = decodeURIComponent, + + // Method / object references. + jq_param = $.param, + jq_param_fragment, + jq_deparam, + jq_deparam_fragment, + jq_bbq = $.bbq = $.bbq || {}, + jq_bbq_pushState, + jq_bbq_getState, + jq_elemUrlAttr, + jq_event_special = $.event.special, + + // Reused strings. + str_hashchange = 'hashchange', + str_querystring = 'querystring', + str_fragment = 'fragment', + str_elemUrlAttr = 'elemUrlAttr', + str_location = 'location', + str_href = 'href', + str_src = 'src', + + // Reused RegExp. + re_trim_querystring = /^.*\?|#.*$/g, + re_trim_fragment = /^.*\#/, + re_no_escape, + + // Used by jQuery.elemUrlAttr. + elemUrlAttr_cache = {}; + + // A few commonly used bits, broken out to help reduce minified file size. + + function is_string( arg ) { + return typeof arg === 'string'; + }; + + // Why write the same function twice? Let's curry! Mmmm, curry.. + + function curry( func ) { + var args = aps.call( arguments, 1 ); + + return function() { + return func.apply( this, args.concat( aps.call( arguments ) ) ); + }; + }; + + // Get location.hash (or what you'd expect location.hash to be) sans any + // leading #. Thanks for making this necessary, Firefox! + function get_fragment( url ) { + return url.replace( /^[^#]*#?(.*)$/, '$1' ); + }; + + // Get location.search (or what you'd expect location.search to be) sans any + // leading #. Thanks for making this necessary, IE6! + function get_querystring( url ) { + return url.replace( /(?:^[^?#]*\?([^#]*).*$)?.*/, '$1' ); + }; + + // Section: Param (to string) + // + // Method: jQuery.param.querystring + // + // Retrieve the query string from a URL or if no arguments are passed, the + // current window.location. + // + // Usage: + // + // > jQuery.param.querystring( [ url ] ); + // + // Arguments: + // + // url - (String) A URL containing query string params to be parsed. If url + // is not passed, the current window.location is used. + // + // Returns: + // + // (String) The parsed query string, with any leading "?" removed. + // + + // Method: jQuery.param.querystring (build url) + // + // Merge a URL, with or without pre-existing query string params, plus any + // object, params string or URL containing query string params into a new URL. + // + // Usage: + // + // > jQuery.param.querystring( url, params [, merge_mode ] ); + // + // Arguments: + // + // url - (String) A valid URL for params to be merged into. This URL may + // contain a query string and/or fragment (hash). + // params - (String) A params string or URL containing query string params to + // be merged into url. + // params - (Object) A params object to be merged into url. + // merge_mode - (Number) Merge behavior defaults to 0 if merge_mode is not + // specified, and is as-follows: + // + // * 0: params in the params argument will override any query string + // params in url. + // * 1: any query string params in url will override params in the params + // argument. + // * 2: params argument will completely replace any query string in url. + // + // Returns: + // + // (String) Either a params string with urlencoded data or a URL with a + // urlencoded query string in the format 'a=b&c=d&e=f'. + + // Method: jQuery.param.fragment + // + // Retrieve the fragment (hash) from a URL or if no arguments are passed, the + // current window.location. + // + // Usage: + // + // > jQuery.param.fragment( [ url ] ); + // + // Arguments: + // + // url - (String) A URL containing fragment (hash) params to be parsed. If + // url is not passed, the current window.location is used. + // + // Returns: + // + // (String) The parsed fragment (hash) string, with any leading "#" removed. + + // Method: jQuery.param.fragment (build url) + // + // Merge a URL, with or without pre-existing fragment (hash) params, plus any + // object, params string or URL containing fragment (hash) params into a new + // URL. + // + // Usage: + // + // > jQuery.param.fragment( url, params [, merge_mode ] ); + // + // Arguments: + // + // url - (String) A valid URL for params to be merged into. This URL may + // contain a query string and/or fragment (hash). + // params - (String) A params string or URL containing fragment (hash) params + // to be merged into url. + // params - (Object) A params object to be merged into url. + // merge_mode - (Number) Merge behavior defaults to 0 if merge_mode is not + // specified, and is as-follows: + // + // * 0: params in the params argument will override any fragment (hash) + // params in url. + // * 1: any fragment (hash) params in url will override params in the + // params argument. + // * 2: params argument will completely replace any query string in url. + // + // Returns: + // + // (String) Either a params string with urlencoded data or a URL with a + // urlencoded fragment (hash) in the format 'a=b&c=d&e=f'. + + function jq_param_sub( is_fragment, get_func, url, params, merge_mode ) { + var result, + qs, + matches, + url_params, + hash; + + if ( params !== undefined ) { + // Build URL by merging params into url string. + + // matches[1] = url part that precedes params, not including trailing ?/# + // matches[2] = params, not including leading ?/# + // matches[3] = if in 'querystring' mode, hash including leading #, otherwise '' + matches = url.match( is_fragment ? /^([^#]*)\#?(.*)$/ : /^([^#?]*)\??([^#]*)(#?.*)/ ); + + // Get the hash if in 'querystring' mode, and it exists. + hash = matches[3] || ''; + + if ( merge_mode === 2 && is_string( params ) ) { + // If merge_mode is 2 and params is a string, merge the fragment / query + // string into the URL wholesale, without converting it into an object. + qs = params.replace( is_fragment ? re_trim_fragment : re_trim_querystring, '' ); + + } else { + // Convert relevant params in url to object. + url_params = jq_deparam( matches[2] ); + + params = is_string( params ) + + // Convert passed params string into object. + ? jq_deparam[ is_fragment ? str_fragment : str_querystring ]( params ) + + // Passed params object. + : params; + + qs = merge_mode === 2 ? params // passed params replace url params + : merge_mode === 1 ? $.extend( {}, params, url_params ) // url params override passed params + : $.extend( {}, url_params, params ); // passed params override url params + + // Convert params object to a string. + qs = jq_param( qs ); + + // Unescape characters specified via $.param.noEscape. Since only hash- + // history users have requested this feature, it's only enabled for + // fragment-related params strings. + if ( is_fragment ) { + qs = qs.replace( re_no_escape, decode ); + } + } + + // Build URL from the base url, querystring and hash. In 'querystring' + // mode, ? is only added if a query string exists. In 'fragment' mode, # + // is always added. + result = matches[1] + ( is_fragment ? '#' : qs || !matches[1] ? '?' : '' ) + qs + hash; + + } else { + // If URL was passed in, parse params from URL string, otherwise parse + // params from window.location. + result = get_func( url !== undefined ? url : window[ str_location ][ str_href ] ); + } + + return result; + }; + + jq_param[ str_querystring ] = curry( jq_param_sub, 0, get_querystring ); + jq_param[ str_fragment ] = jq_param_fragment = curry( jq_param_sub, 1, get_fragment ); + + // Method: jQuery.param.fragment.noEscape + // + // Specify characters that will be left unescaped when fragments are created + // or merged using , or when the fragment is modified + // using . This option only applies to serialized data + // object fragments, and not set-as-string fragments. Does not affect the + // query string. Defaults to ",/" (comma, forward slash). + // + // Note that this is considered a purely aesthetic option, and will help to + // create URLs that "look pretty" in the address bar or bookmarks, without + // affecting functionality in any way. That being said, be careful to not + // unescape characters that are used as delimiters or serve a special + // purpose, such as the "#?&=+" (octothorpe, question mark, ampersand, + // equals, plus) characters. + // + // Usage: + // + // > jQuery.param.fragment.noEscape( [ chars ] ); + // + // Arguments: + // + // chars - (String) The characters to not escape in the fragment. If + // unspecified, defaults to empty string (escape all characters). + // + // Returns: + // + // Nothing. + + jq_param_fragment.noEscape = function( chars ) { + chars = chars || ''; + var arr = $.map( chars.split(''), encodeURIComponent ); + re_no_escape = new RegExp( arr.join('|'), 'g' ); + }; + + // A sensible default. These are the characters people seem to complain about + // "uglifying up the URL" the most. + jq_param_fragment.noEscape( ',/' ); + + // Section: Deparam (from string) + // + // Method: jQuery.deparam + // + // Deserialize a params string into an object, optionally coercing numbers, + // booleans, null and undefined values; this method is the counterpart to the + // internal jQuery.param method. + // + // Usage: + // + // > jQuery.deparam( params [, coerce ] ); + // + // Arguments: + // + // params - (String) A params string to be parsed. + // coerce - (Boolean) If true, coerces any numbers or true, false, null, and + // undefined to their actual value. Defaults to false if omitted. + // + // Returns: + // + // (Object) An object representing the deserialized params string. + + $.deparam = jq_deparam = function( params, coerce ) { + var obj = {}, + coerce_types = { 'true': !0, 'false': !1, 'null': null }; + + // Iterate over all name=value pairs. + $.each( params.replace( /\+/g, ' ' ).split( '&' ), function(j,v){ + var param = v.split( '=' ), + key = decode( param[0] ), + val, + cur = obj, + i = 0, + + // If key is more complex than 'foo', like 'a[]' or 'a[b][c]', split it + // into its component parts. + keys = key.split( '][' ), + keys_last = keys.length - 1; + + // If the first keys part contains [ and the last ends with ], then [] + // are correctly balanced. + if ( /\[/.test( keys[0] ) && /\]$/.test( keys[ keys_last ] ) ) { + // Remove the trailing ] from the last keys part. + keys[ keys_last ] = keys[ keys_last ].replace( /\]$/, '' ); + + // Split first keys part into two parts on the [ and add them back onto + // the beginning of the keys array. + keys = keys.shift().split('[').concat( keys ); + + keys_last = keys.length - 1; + } else { + // Basic 'foo' style key. + keys_last = 0; + } + + // Are we dealing with a name=value pair, or just a name? + if ( param.length === 2 ) { + val = decode( param[1] ); + + // Coerce values. + if ( coerce ) { + val = val && !isNaN(val) ? +val // number + : val === 'undefined' ? undefined // undefined + : coerce_types[val] !== undefined ? coerce_types[val] // true, false, null + : val; // string + } + + if ( keys_last ) { + // Complex key, build deep object structure based on a few rules: + // * The 'cur' pointer starts at the object top-level. + // * [] = array push (n is set to array length), [n] = array if n is + // numeric, otherwise object. + // * If at the last keys part, set the value. + // * For each keys part, if the current level is undefined create an + // object or array based on the type of the next keys part. + // * Move the 'cur' pointer to the next level. + // * Rinse & repeat. + for ( ; i <= keys_last; i++ ) { + key = keys[i] === '' ? cur.length : keys[i]; + cur = cur[key] = i < keys_last + ? cur[key] || ( keys[i+1] && isNaN( keys[i+1] ) ? {} : [] ) + : val; + } + + } else { + // Simple key, even simpler rules, since only scalars and shallow + // arrays are allowed. + + if ( $.isArray( obj[key] ) ) { + // val is already an array, so push on the next value. + obj[key].push( val ); + + } else if ( obj[key] !== undefined ) { + // val isn't an array, but since a second value has been specified, + // convert val into an array. + obj[key] = [ obj[key], val ]; + + } else { + // val is a scalar. + obj[key] = val; + } + } + + } else if ( key ) { + // No value was defined, so set something meaningful. + obj[key] = coerce + ? undefined + : ''; + } + }); + + return obj; + }; + + // Method: jQuery.deparam.querystring + // + // Parse the query string from a URL or the current window.location, + // deserializing it into an object, optionally coercing numbers, booleans, + // null and undefined values. + // + // Usage: + // + // > jQuery.deparam.querystring( [ url ] [, coerce ] ); + // + // Arguments: + // + // url - (String) An optional params string or URL containing query string + // params to be parsed. If url is omitted, the current window.location + // is used. + // coerce - (Boolean) If true, coerces any numbers or true, false, null, and + // undefined to their actual value. Defaults to false if omitted. + // + // Returns: + // + // (Object) An object representing the deserialized params string. + + // Method: jQuery.deparam.fragment + // + // Parse the fragment (hash) from a URL or the current window.location, + // deserializing it into an object, optionally coercing numbers, booleans, + // null and undefined values. + // + // Usage: + // + // > jQuery.deparam.fragment( [ url ] [, coerce ] ); + // + // Arguments: + // + // url - (String) An optional params string or URL containing fragment (hash) + // params to be parsed. If url is omitted, the current window.location + // is used. + // coerce - (Boolean) If true, coerces any numbers or true, false, null, and + // undefined to their actual value. Defaults to false if omitted. + // + // Returns: + // + // (Object) An object representing the deserialized params string. + + function jq_deparam_sub( is_fragment, url_or_params, coerce ) { + if ( url_or_params === undefined || typeof url_or_params === 'boolean' ) { + // url_or_params not specified. + coerce = url_or_params; + url_or_params = jq_param[ is_fragment ? str_fragment : str_querystring ](); + } else { + url_or_params = is_string( url_or_params ) + ? url_or_params.replace( is_fragment ? re_trim_fragment : re_trim_querystring, '' ) + : url_or_params; + } + + return jq_deparam( url_or_params, coerce ); + }; + + jq_deparam[ str_querystring ] = curry( jq_deparam_sub, 0 ); + jq_deparam[ str_fragment ] = jq_deparam_fragment = curry( jq_deparam_sub, 1 ); + + // Section: Element manipulation + // + // Method: jQuery.elemUrlAttr + // + // Get the internal "Default URL attribute per tag" list, or augment the list + // with additional tag-attribute pairs, in case the defaults are insufficient. + // + // In the and methods, this list + // is used to determine which attribute contains the URL to be modified, if + // an "attr" param is not specified. + // + // Default Tag-Attribute List: + // + // a - href + // base - href + // iframe - src + // img - src + // input - src + // form - action + // link - href + // script - src + // + // Usage: + // + // > jQuery.elemUrlAttr( [ tag_attr ] ); + // + // Arguments: + // + // tag_attr - (Object) An object containing a list of tag names and their + // associated default attribute names in the format { tag: 'attr', ... } to + // be merged into the internal tag-attribute list. + // + // Returns: + // + // (Object) An object containing all stored tag-attribute values. + + // Only define function and set defaults if function doesn't already exist, as + // the urlInternal plugin will provide this method as well. + $[ str_elemUrlAttr ] || ($[ str_elemUrlAttr ] = function( obj ) { + return $.extend( elemUrlAttr_cache, obj ); + })({ + a: str_href, + base: str_href, + iframe: str_src, + img: str_src, + input: str_src, + form: 'action', + link: str_href, + script: str_src + }); + + jq_elemUrlAttr = $[ str_elemUrlAttr ]; + + // Method: jQuery.fn.querystring + // + // Update URL attribute in one or more elements, merging the current URL (with + // or without pre-existing query string params) plus any params object or + // string into a new URL, which is then set into that attribute. Like + // , but for all elements in a jQuery + // collection. + // + // Usage: + // + // > jQuery('selector').querystring( [ attr, ] params [, merge_mode ] ); + // + // Arguments: + // + // attr - (String) Optional name of an attribute that will contain a URL to + // merge params or url into. See for a list of default + // attributes. + // params - (Object) A params object to be merged into the URL attribute. + // params - (String) A URL containing query string params, or params string + // to be merged into the URL attribute. + // merge_mode - (Number) Merge behavior defaults to 0 if merge_mode is not + // specified, and is as-follows: + // + // * 0: params in the params argument will override any params in attr URL. + // * 1: any params in attr URL will override params in the params argument. + // * 2: params argument will completely replace any query string in attr + // URL. + // + // Returns: + // + // (jQuery) The initial jQuery collection of elements, but with modified URL + // attribute values. + + // Method: jQuery.fn.fragment + // + // Update URL attribute in one or more elements, merging the current URL (with + // or without pre-existing fragment/hash params) plus any params object or + // string into a new URL, which is then set into that attribute. Like + // , but for all elements in a jQuery + // collection. + // + // Usage: + // + // > jQuery('selector').fragment( [ attr, ] params [, merge_mode ] ); + // + // Arguments: + // + // attr - (String) Optional name of an attribute that will contain a URL to + // merge params into. See for a list of default + // attributes. + // params - (Object) A params object to be merged into the URL attribute. + // params - (String) A URL containing fragment (hash) params, or params + // string to be merged into the URL attribute. + // merge_mode - (Number) Merge behavior defaults to 0 if merge_mode is not + // specified, and is as-follows: + // + // * 0: params in the params argument will override any params in attr URL. + // * 1: any params in attr URL will override params in the params argument. + // * 2: params argument will completely replace any fragment (hash) in attr + // URL. + // + // Returns: + // + // (jQuery) The initial jQuery collection of elements, but with modified URL + // attribute values. + + function jq_fn_sub( mode, force_attr, params, merge_mode ) { + if ( !is_string( params ) && typeof params !== 'object' ) { + // force_attr not specified. + merge_mode = params; + params = force_attr; + force_attr = undefined; + } + + return this.each(function(){ + var that = $(this), + + // Get attribute specified, or default specified via $.elemUrlAttr. + attr = force_attr || jq_elemUrlAttr()[ ( this.nodeName || '' ).toLowerCase() ] || '', + + // Get URL value. + url = attr && that.attr( attr ) || ''; + + // Update attribute with new URL. + that.attr( attr, jq_param[ mode ]( url, params, merge_mode ) ); + }); + + }; + + $.fn[ str_querystring ] = curry( jq_fn_sub, str_querystring ); + $.fn[ str_fragment ] = curry( jq_fn_sub, str_fragment ); + + // Section: History, hashchange event + // + // Method: jQuery.bbq.pushState + // + // Adds a 'state' into the browser history at the current position, setting + // location.hash and triggering any bound callbacks + // (provided the new state is different than the previous state). + // + // If no arguments are passed, an empty state is created, which is just a + // shortcut for jQuery.bbq.pushState( {}, 2 ). + // + // Usage: + // + // > jQuery.bbq.pushState( [ params [, merge_mode ] ] ); + // + // Arguments: + // + // params - (String) A serialized params string or a hash string beginning + // with # to merge into location.hash. + // params - (Object) A params object to merge into location.hash. + // merge_mode - (Number) Merge behavior defaults to 0 if merge_mode is not + // specified (unless a hash string beginning with # is specified, in which + // case merge behavior defaults to 2), and is as-follows: + // + // * 0: params in the params argument will override any params in the + // current state. + // * 1: any params in the current state will override params in the params + // argument. + // * 2: params argument will completely replace current state. + // + // Returns: + // + // Nothing. + // + // Additional Notes: + // + // * Setting an empty state may cause the browser to scroll. + // * Unlike the fragment and querystring methods, if a hash string beginning + // with # is specified as the params agrument, merge_mode defaults to 2. + + jq_bbq.pushState = jq_bbq_pushState = function( params, merge_mode ) { + if ( is_string( params ) && /^#/.test( params ) && merge_mode === undefined ) { + // Params string begins with # and merge_mode not specified, so completely + // overwrite window.location.hash. + merge_mode = 2; + } + + var has_args = params !== undefined, + // Merge params into window.location using $.param.fragment. + url = jq_param_fragment( window[ str_location ][ str_href ], + has_args ? params : {}, has_args ? merge_mode : 2 ); + + // Set new window.location.href. If hash is empty, use just # to prevent + // browser from reloading the page. Note that Safari 3 & Chrome barf on + // location.hash = '#'. + window[ str_location ][ str_href ] = url + ( /#/.test( url ) ? '' : '#' ); + }; + + // Method: jQuery.bbq.getState + // + // Retrieves the current 'state' from the browser history, parsing + // location.hash for a specific key or returning an object containing the + // entire state, optionally coercing numbers, booleans, null and undefined + // values. + // + // Usage: + // + // > jQuery.bbq.getState( [ key ] [, coerce ] ); + // + // Arguments: + // + // key - (String) An optional state key for which to return a value. + // coerce - (Boolean) If true, coerces any numbers or true, false, null, and + // undefined to their actual value. Defaults to false. + // + // Returns: + // + // (Anything) If key is passed, returns the value corresponding with that key + // in the location.hash 'state', or undefined. If not, an object + // representing the entire 'state' is returned. + + jq_bbq.getState = jq_bbq_getState = function( key, coerce ) { + return key === undefined || typeof key === 'boolean' + ? jq_deparam_fragment( key ) // 'key' really means 'coerce' here + : jq_deparam_fragment( coerce )[ key ]; + }; + + // Method: jQuery.bbq.removeState + // + // Remove one or more keys from the current browser history 'state', creating + // a new state, setting location.hash and triggering any bound + // callbacks (provided the new state is different than + // the previous state). + // + // If no arguments are passed, an empty state is created, which is just a + // shortcut for jQuery.bbq.pushState( {}, 2 ). + // + // Usage: + // + // > jQuery.bbq.removeState( [ key [, key ... ] ] ); + // + // Arguments: + // + // key - (String) One or more key values to remove from the current state, + // passed as individual arguments. + // key - (Array) A single array argument that contains a list of key values + // to remove from the current state. + // + // Returns: + // + // Nothing. + // + // Additional Notes: + // + // * Setting an empty state may cause the browser to scroll. + + jq_bbq.removeState = function( arr ) { + var state = {}; + + // If one or more arguments is passed.. + if ( arr !== undefined ) { + + // Get the current state. + state = jq_bbq_getState(); + + // For each passed key, delete the corresponding property from the current + // state. + $.each( $.isArray( arr ) ? arr : arguments, function(i,v){ + delete state[ v ]; + }); + } + + // Set the state, completely overriding any existing state. + jq_bbq_pushState( state, 2 ); + }; + + // Event: hashchange event (BBQ) + // + // Usage in jQuery 1.4 and newer: + // + // In jQuery 1.4 and newer, the event object passed into any hashchange event + // callback is augmented with a copy of the location.hash fragment at the time + // the event was triggered as its event.fragment property. In addition, the + // event.getState method operates on this property (instead of location.hash) + // which allows this fragment-as-a-state to be referenced later, even after + // window.location may have changed. + // + // Note that event.fragment and event.getState are not defined according to + // W3C (or any other) specification, but will still be available whether or + // not the hashchange event exists natively in the browser, because of the + // utility they provide. + // + // The event.fragment property contains the output of + // and the event.getState method is equivalent to the + // method. + // + // > $(window).bind( 'hashchange', function( event ) { + // > var hash_str = event.fragment, + // > param_obj = event.getState(), + // > param_val = event.getState( 'param_name' ), + // > param_val_coerced = event.getState( 'param_name', true ); + // > ... + // > }); + // + // Usage in jQuery 1.3.2: + // + // In jQuery 1.3.2, the event object cannot to be augmented as in jQuery 1.4+, + // so the fragment state isn't bound to the event object and must instead be + // parsed using the and methods. + // + // > $(window).bind( 'hashchange', function( event ) { + // > var hash_str = $.param.fragment(), + // > param_obj = $.bbq.getState(), + // > param_val = $.bbq.getState( 'param_name' ), + // > param_val_coerced = $.bbq.getState( 'param_name', true ); + // > ... + // > }); + // + // Additional Notes: + // + // * Due to changes in the special events API, jQuery BBQ v1.2 or newer is + // required to enable the augmented event object in jQuery 1.4.2 and newer. + // * See for more detailed information. + + jq_event_special[ str_hashchange ] = $.extend( jq_event_special[ str_hashchange ], { + + // Augmenting the event object with the .fragment property and .getState + // method requires jQuery 1.4 or newer. Note: with 1.3.2, everything will + // work, but the event won't be augmented) + add: function( handleObj ) { + var old_handler; + + function new_handler(e) { + // e.fragment is set to the value of location.hash (with any leading # + // removed) at the time the event is triggered. + var hash = e[ str_fragment ] = jq_param_fragment(); + + // e.getState() works just like $.bbq.getState(), but uses the + // e.fragment property stored on the event object. + e.getState = function( key, coerce ) { + return key === undefined || typeof key === 'boolean' + ? jq_deparam( hash, key ) // 'key' really means 'coerce' here + : jq_deparam( hash, coerce )[ key ]; + }; + + old_handler.apply( this, arguments ); + }; + + // This may seem a little complicated, but it normalizes the special event + // .add method between jQuery 1.4/1.4.1 and 1.4.2+ + if ( $.isFunction( handleObj ) ) { + // 1.4, 1.4.1 + old_handler = handleObj; + return new_handler; + } else { + // 1.4.2+ + old_handler = handleObj.handler; + handleObj.handler = new_handler; + } + } + + }); + +})(jQuery,this); + +/*! + * jQuery hashchange event - v1.2 - 2/11/2010 + * http://benalman.com/projects/jquery-hashchange-plugin/ + * + * Copyright (c) 2010 "Cowboy" Ben Alman + * Dual licensed under the MIT and GPL licenses. + * http://benalman.com/about/license/ + */ + +// Script: jQuery hashchange event +// +// *Version: 1.2, Last updated: 2/11/2010* +// +// Project Home - http://benalman.com/projects/jquery-hashchange-plugin/ +// GitHub - http://github.com/cowboy/jquery-hashchange/ +// Source - http://github.com/cowboy/jquery-hashchange/raw/master/jquery.ba-hashchange.js +// (Minified) - http://github.com/cowboy/jquery-hashchange/raw/master/jquery.ba-hashchange.min.js (1.1kb) +// +// About: License +// +// Copyright (c) 2010 "Cowboy" Ben Alman, +// Dual licensed under the MIT and GPL licenses. +// http://benalman.com/about/license/ +// +// About: Examples +// +// This working example, complete with fully commented code, illustrate one way +// in which this plugin can be used. +// +// hashchange event - http://benalman.com/code/projects/jquery-hashchange/examples/hashchange/ +// +// About: Support and Testing +// +// Information about what version or versions of jQuery this plugin has been +// tested with, what browsers it has been tested in, and where the unit tests +// reside (so you can test it yourself). +// +// jQuery Versions - 1.3.2, 1.4.1, 1.4.2 +// Browsers Tested - Internet Explorer 6-8, Firefox 2-3.7, Safari 3-4, Chrome, Opera 9.6-10.1. +// Unit Tests - http://benalman.com/code/projects/jquery-hashchange/unit/ +// +// About: Known issues +// +// While this jQuery hashchange event implementation is quite stable and robust, +// there are a few unfortunate browser bugs surrounding expected hashchange +// event-based behaviors, independent of any JavaScript window.onhashchange +// abstraction. See the following examples for more information: +// +// Chrome: Back Button - http://benalman.com/code/projects/jquery-hashchange/examples/bug-chrome-back-button/ +// Firefox: Remote XMLHttpRequest - http://benalman.com/code/projects/jquery-hashchange/examples/bug-firefox-remote-xhr/ +// WebKit: Back Button in an Iframe - http://benalman.com/code/projects/jquery-hashchange/examples/bug-webkit-hash-iframe/ +// Safari: Back Button from a different domain - http://benalman.com/code/projects/jquery-hashchange/examples/bug-safari-back-from-diff-domain/ +// +// About: Release History +// +// 1.2 - (2/11/2010) Fixed a bug where coming back to a page using this plugin +// from a page on another domain would cause an error in Safari 4. Also, +// IE6/7 Iframe is now inserted after the body (this actually works), +// which prevents the page from scrolling when the event is first bound. +// Event can also now be bound before DOM ready, but it won't be usable +// before then in IE6/7. +// 1.1 - (1/21/2010) Incorporated document.documentMode test to fix IE8 bug +// where browser version is incorrectly reported as 8.0, despite +// inclusion of the X-UA-Compatible IE=EmulateIE7 meta tag. +// 1.0 - (1/9/2010) Initial Release. Broke out the jQuery BBQ event.special +// window.onhashchange functionality into a separate plugin for users +// who want just the basic event & back button support, without all the +// extra awesomeness that BBQ provides. This plugin will be included as +// part of jQuery BBQ, but also be available separately. + +(function($,window,undefined){ + '$:nomunge'; // Used by YUI compressor. + + // Method / object references. + var fake_onhashchange, + jq_event_special = $.event.special, + + // Reused strings. + str_location = 'location', + str_hashchange = 'hashchange', + str_href = 'href', + + // IE6/7 specifically need some special love when it comes to back-button + // support, so let's do a little browser sniffing.. + browser = $.browser, + mode = document.documentMode, + is_old_ie = browser.msie && ( mode === undefined || mode < 8 ), + + // Does the browser support window.onhashchange? Test for IE version, since + // IE8 incorrectly reports this when in "IE7" or "IE8 Compatibility View"! + supports_onhashchange = 'on' + str_hashchange in window && !is_old_ie; + + // Get location.hash (or what you'd expect location.hash to be) sans any + // leading #. Thanks for making this necessary, Firefox! + function get_fragment( url ) { + url = url || window[ str_location ][ str_href ]; + return url.replace( /^[^#]*#?(.*)$/, '$1' ); + }; + + // Property: jQuery.hashchangeDelay + // + // The numeric interval (in milliseconds) at which the + // polling loop executes. Defaults to 100. + + $[ str_hashchange + 'Delay' ] = 100; + + // Event: hashchange event + // + // Fired when location.hash changes. In browsers that support it, the native + // window.onhashchange event is used (IE8, FF3.6), otherwise a polling loop is + // initialized, running every milliseconds to see if + // the hash has changed. In IE 6 and 7, a hidden Iframe is created to allow + // the back button and hash-based history to work. + // + // Usage: + // + // > $(window).bind( 'hashchange', function(e) { + // > var hash = location.hash; + // > ... + // > }); + // + // Additional Notes: + // + // * The polling loop and Iframe are not created until at least one callback + // is actually bound to 'hashchange'. + // * If you need the bound callback(s) to execute immediately, in cases where + // the page 'state' exists on page load (via bookmark or page refresh, for + // example) use $(window).trigger( 'hashchange' ); + // * The event can be bound before DOM ready, but since it won't be usable + // before then in IE6/7 (due to the necessary Iframe), recommended usage is + // to bind it inside a $(document).ready() callback. + + jq_event_special[ str_hashchange ] = $.extend( jq_event_special[ str_hashchange ], { + + // Called only when the first 'hashchange' event is bound to window. + setup: function() { + // If window.onhashchange is supported natively, there's nothing to do.. + if ( supports_onhashchange ) { return false; } + + // Otherwise, we need to create our own. And we don't want to call this + // until the user binds to the event, just in case they never do, since it + // will create a polling loop and possibly even a hidden Iframe. + $( fake_onhashchange.start ); + }, + + // Called only when the last 'hashchange' event is unbound from window. + teardown: function() { + // If window.onhashchange is supported natively, there's nothing to do.. + if ( supports_onhashchange ) { return false; } + + // Otherwise, we need to stop ours (if possible). + $( fake_onhashchange.stop ); + } + + }); + + // fake_onhashchange does all the work of triggering the window.onhashchange + // event for browsers that don't natively support it, including creating a + // polling loop to watch for hash changes and in IE 6/7 creating a hidden + // Iframe to enable back and forward. + fake_onhashchange = (function(){ + var self = {}, + timeout_id, + iframe, + set_history, + get_history; + + // Initialize. In IE 6/7, creates a hidden Iframe for history handling. + function init(){ + // Most browsers don't need special methods here.. + set_history = get_history = function(val){ return val; }; + + // But IE6/7 do! + if ( is_old_ie ) { + + // Create hidden Iframe after the end of the body to prevent initial + // page load from scrolling unnecessarily. + iframe = $('