1 /*---------------------------------------------------------
3 *---------------------------------------------------------*/
4 openerp.web_gantt = function (openerp) {
5 var _t = openerp.web._t,
7 var QWeb = openerp.web.qweb;
8 openerp.web.views.add('gantt', 'openerp.web_gantt.GanttView');
9 openerp.web_gantt.GanttView = openerp.web.View.extend({
10 display_name: _lt('Gantt'),
12 init: function(parent, dataset, view_id) {
14 this.view_manager = parent || new openerp.web.NullViewManager();
15 this.dataset = dataset;
16 this.model = dataset.model;
17 this.view_id = view_id;
18 this.domain = this.dataset.domain || [];
19 this.context = this.dataset.context || {};
20 this.has_been_loaded = $.Deferred();
25 return this.rpc("/web/view/load", {"model": this.model, "view_id": this.view_id, "view_type": "gantt"}, this.on_loaded);
28 on_loaded: function(data) {
30 this.fields_view = data,
31 this.name = this.fields_view.arch.attrs.string,
32 this.view_id = this.fields_view.view_id,
33 this.fields = this.fields_view.fields;
35 this.date_start = this.fields_view.arch.attrs.date_start,
36 this.date_delay = this.fields_view.arch.attrs.date_delay,
37 this.date_stop = this.fields_view.arch.attrs.date_stop,
38 this.day_length = this.fields_view.arch.attrs.day_length || 8;
40 this.color_field = this.fields_view.arch.attrs.color,
41 this.colors = this.fields_view.arch.attrs.colors;
43 if (this.fields_view.arch.children.length) {
44 var level = this.fields_view.arch.children[0];
45 this.parent = level.attrs.link, this.text = level.children.length ? level.children[0].attrs.name : level.attrs.name;
50 if (!this.date_start) {
51 console.error("date_start is not defined in the definition of this gantt view");
55 this.$element.html(QWeb.render("GanttView", {'height': $('.oe-application-container').height(), 'width': $('.oe-application-container').width()}));
56 this.has_been_loaded.resolve();
59 init_gantt_view: function() {
61 ganttChartControl = this.ganttChartControl = new GanttChart(this.day_length);
62 ganttChartControl.setImagePath("/web_gantt/static/lib/dhtmlxGantt/codebase/imgs/");
63 ganttChartControl.setEditable(true);
64 ganttChartControl.showTreePanel(true);
65 ganttChartControl.showContextMenu(false);
66 ganttChartControl.showDescTask(true,'d,s-f');
67 ganttChartControl.showDescProject(true,'n,d');
71 project_starting_date : function() {
73 projects = this.database_projects,
74 min_date = _.min(projects, function(prj) {
75 return self.format_date(prj[self.date_start]);
77 if (min_date) this.project_start_date = this.format_date(min_date[self.date_start]);
79 this.project_start_date = Date.today();
80 return $.Deferred().resolve().promise();
83 format_date : function(date) {
84 var datetime_regex = /^(\d\d\d\d-\d\d-\d\d \d\d:\d\d:\d\d)(?:\.\d+)?$/,
85 date_regex = /^\d\d\d\d-\d\d-\d\d$/,
86 time_regex = /^(\d\d:\d\d:\d\d)(?:\.\d+)?$/,
88 if(date_regex.exec(date)) {
89 this.date_format = "yyyy-MM-dd";
90 } else if(time_regex.exec(date)) {
91 this.date_format = "HH:mm:ss";
93 this.date_format = "yyyy-MM-dd HH:mm:ss";
95 if(typeof date === 'string')
96 return openerp.web.auto_str_to_date(date);
100 on_project_loaded: function(events) {
102 if(!events.length) return;
104 var started_projects = _.filter(events, function(res) {
105 return !!res[self.date_start];
108 this.database_projects = started_projects;
110 if(!self.name && started_projects.length > 0) {
111 var name = started_projects[0][self.parent];
112 self.name = name instanceof Array? name[name.length - 1] : name;
114 this.$element.find('#add_task').click(function(){
118 $.when(this.project_starting_date())
120 if(self.ganttChartControl) {
121 self.ganttChartControl.clearAll();
122 self.$element.find('#GanttView').empty();
125 .done(this.init_gantt_view());
128 var show_event = started_projects;
129 _.each(show_event, function(evt) {evt[self.date_start] = self.format_date(evt[self.date_start])});
130 this.project = new GanttProjectInfo("_1", self.name, this.project_start_date);
131 self.ganttChartControl.addProject(this.project);
137 var child_event = {};
139 var final_events = [];
140 for (var i in show_event) {
142 var res = show_event[i];
145 var text = res[this.text];
146 var start_date = res[this.date_start];
148 if (this.date_stop != undefined){
149 if (res[this.date_stop] != false){
150 var stop_date = this.convert_str_date(res[this.date_stop]);
151 var duration= self.hours_between(start_date, stop_date);
158 var duration = res[this.date_delay];
163 if (this.group_by.length){
164 for (var j in self.group_by){
165 var grp_key = res[self.group_by[j]];
166 if (typeof(grp_key) == "object"){
167 grp_key = res[self.group_by[j]][1];
170 grp_key = res[self.group_by[j]];
174 grp_key = "Undefined";
178 if (parents[grp_key] == undefined){
179 var mod_id = i+ "_" +j;
180 parents[grp_key] = mod_id;
181 child_event[mod_id] = {};
182 all_events[mod_id] = {'parent': "", 'evt':[mod_id , grp_key, start_date, start_date, 100, ""]};
185 mod_id = parents[grp_key];
189 if (child_event[mod_id][grp_key] == undefined){
190 var ch_mod_id = i+ "_" +j;
191 child_event[mod_id][grp_key] = ch_mod_id;
192 child_event[ch_mod_id] = {};
194 all_events[ch_mod_id] = {'parent': mod_id, 'evt':[ch_mod_id , grp_key, start_date, start_date, 100, ""]};
198 mod_id = child_event[mod_id][grp_key];
203 all_events[id] = {'parent': temp_id, 'evt':[id , text, start_date, duration, 100, ""]};
204 final_events.push(id);
208 var mod_id = "_" + i;
209 all_events[mod_id] = {'parent': "", 'evt': [mod_id, this.name, start_date, start_date, 100, ""]};
211 all_events[id] = {'parent': mod_id, 'evt':[id , text, start_date, duration, 100, ""]};
212 final_events.push(id);
216 for (var i in final_events){
217 var evt_id = final_events[i];
218 var evt_date = all_events[evt_id]['evt'][2];
219 while (all_events[evt_id]['parent'] != "") {
220 var parent_id =all_events[evt_id]['parent'];
221 if (all_events[parent_id]['evt'][2] > evt_date){
222 all_events[parent_id]['evt'][2] = evt_date;
229 var evt_duration = "";
230 var evt_end_date = "";
231 var project_tree_field = [];
232 for (var i in final_events){
233 evt_id = final_events[i];
234 evt_date = all_events[evt_id]['evt'][2];
235 evt_duration = all_events[evt_id]['evt'][3];
237 var evt_str_date = this.convert_date_str(evt_date);
238 evt_end_date = this.end_date(evt_str_date, evt_duration);
240 while (all_events[evt_id]['parent'] != "") {
241 var parent_id =all_events[evt_id]['parent'];
242 if (all_events[parent_id]['evt'][3] < evt_end_date){
243 all_events[parent_id]['evt'][3] = evt_end_date;
249 for (var j in self.group_by) {
250 self.render_events(all_events, j);
253 if (!self.group_by.length) {
254 self.render_events(all_events, 0);
257 for (var i in final_events) {
258 evt_id = final_events[i];
259 res = all_events[evt_id];
260 task=new GanttTaskInfo(res['evt'][0], res['evt'][1], res['evt'][2], res['evt'][3], res['evt'][4], "");
261 prt = self.project.getTaskById(res['parent']);
262 prt.addChildTask(task);
267 var name_min_wdt = 150;
268 var gantt_hgt = $(window).height() - oth_hgt;
269 var search_wdt = $("#oe_app_search").width();
271 if (gantt_hgt > min_hgt) {
272 $('#GanttView').height(gantt_hgt).width(search_wdt);
274 $('#GanttView').height(min_hgt).width(search_wdt);
277 self.ganttChartControl.create("GanttView");
280 self.ganttChartControl.attachEvent("onTaskStartDrag", function(task) {
281 if (task.parentTask) {
282 var task_date = task.getEST();
283 if (task_date.getHours()) {
285 hour: task_date.getHours(),
286 minute: task_date.getMinutes(),
292 self.ganttChartControl.attachEvent("onTaskEndResize", function(task) {return self.resizeTask(task);});
293 self.ganttChartControl.attachEvent("onTaskEndDrag", function(task) {return self.resizeTask(task);});
295 var taskdiv = $("div.taskPanel").parent();
296 taskdiv.addClass('ganttTaskPanel');
297 taskdiv.prev().addClass('ganttDayPanel');
298 var $gantt_panel = $(".ganttTaskPanel , .ganttDayPanel");
300 var ganttrow = $('.taskPanel').closest('tr');
301 var gtd = ganttrow.children(':first-child');
302 gtd.children().addClass('task-name');
304 $(".toggle-sidebar").click(function(e) {
308 $(window).bind('resize',function() {
309 window.clearTimeout(self.ganttChartControl._resize_timer);
310 self.ganttChartControl._resize_timer = window.setTimeout(function(){
315 var project = self.ganttChartControl.getProjectById("_1");
317 $(project.projectItem[0]).hide();
318 $(project.projectNameItem).hide();
319 $(project.descrProject).hide();
321 _.each(final_events, function(id) {
322 var Task = project.getTaskById(id);
323 $(Task.cTaskNameItem[0]).click(function() {
330 resizeTask: function(task) {
332 event_id = task.getId();
333 if(task.childTask.length)
337 data[this.date_start] = task.getEST().toString(this.date_format);
340 var diff = task.getDuration() % this.day_length,
341 finished_date = task.getFinishDate().add({hours: diff});
342 data[this.date_stop] = finished_date.toString(this.date_format);
344 data[this.date_delay] = task.getDuration();
347 .write(event_id, data, {})
349 var get_project = _.find(self.database_projects, function(project){ return project.id == event_id});
350 _.extend(get_project,data);
355 editTask: function(task) {
361 event_id = task.getId();
362 if(!event_id || !task.parentTask)
365 if(event_id) event_id = parseInt(event_id, 10);
367 var pop = new openerp.web.form.FormOpenPopup(this);
369 pop.show_element(this.model, event_id, this.context || this.dataset.context, {});
371 pop.on_write.add(function(id, data) {
372 var get_project = _.find(self.database_projects, function(project){ return project.id == id});
374 _.extend(get_project, data);
376 _.extend(self.database_projects, _.extend(data, {'id': id}));
382 set_width: function() {
383 $gantt_panel.width(1);
384 jQuery(".ganttTaskPanel").parent().width(1);
386 var search_wdt = jQuery("#oe_app_search").width();
387 var day_wdt = jQuery(".ganttDayPanel").children().children().width();
388 jQuery('#GanttView').css('width','100%');
390 if (search_wdt - day_wdt <= name_min_wdt){
391 jQuery(".ganttTaskPanel").parent().width(search_wdt - name_min_wdt);
392 jQuery(".ganttTaskPanel").width(search_wdt - name_min_wdt);
393 jQuery(".ganttDayPanel").width(search_wdt - name_min_wdt - 14);
394 jQuery('.task-name').width(name_min_wdt);
395 jQuery('.task-name').children().width(name_min_wdt);
397 jQuery(".ganttTaskPanel").parent().width(day_wdt);
398 jQuery(".ganttTaskPanel").width(day_wdt);
399 jQuery(".taskPanel").width(day_wdt - 16);
400 jQuery(".ganttDayPanel").width(day_wdt -16);
401 jQuery('.task-name').width(search_wdt - day_wdt);
402 jQuery('.task-name').children().width(search_wdt - day_wdt);
407 end_date: function(dat, duration) {
411 var dat = this.convert_str_date(dat);
413 var day = Math.floor(duration/self.day_length);
414 var hrs = duration % self.day_length;
422 hours_between: function(date1, date2, parent_task) {
424 var ONE_DAY = 1000 * 60 * 60 * 24;
425 var date1_ms = date1.getTime();
426 var date2_ms = date2.getTime();
427 var difference_ms = Math.abs(date1_ms - date2_ms);
429 var d = parent_task? Math.ceil(difference_ms / ONE_DAY) : Math.floor(difference_ms / ONE_DAY);
430 var h = (difference_ms % ONE_DAY)/(1000 * 60 * 60);
431 var num = (d * this.day_length) + h;
432 return parseFloat(num.toFixed(2));
436 render_events : function(all_events, j) {
439 for (var i in all_events){
440 var res = all_events[i];
441 if ((typeof(res['evt'][3])) == "object"){
442 res['evt'][3] = self.hours_between(res['evt'][2],res['evt'][3], true);
445 k = res['evt'][0].toString().indexOf('_');
448 if (res['evt'][0].substring(k) == "_"+j){
450 task = new GanttTaskInfo(res['evt'][0], res['evt'][1], res['evt'][2], res['evt'][3], res['evt'][4], "");
451 self.project.addTask(task);
453 task = new GanttTaskInfo(res['evt'][0], res['evt'][1], res['evt'][2], res['evt'][3], res['evt'][4], "");
454 prt = self.project.getTaskById(res['parent']);
455 prt.addChildTask(task);
462 convert_str_date: function (str) {
463 if (typeof str == 'string') {
464 if (str.length == 19) {
465 this.date_format = "yyyy-MM-dd HH:mm:ss";
466 return openerp.web.str_to_datetime(str);
469 if (str.length == 10) {
470 this.date_format = "yyyy-MM-dd";
471 return openerp.web.str_to_date(str);
474 if (str.length == 8) {
475 this.date_format = "HH:mm:ss";
476 return openerp.web.str_to_time(str);
478 throw "Unrecognized date/time format";
484 convert_date_str: function(full_date) {
485 if (this.date_format == "yyyy-MM-dd HH:mm:ss"){
486 return openerp.web.datetime_to_str(full_date);
487 } else if (this.date_format == "yyyy-MM-dd"){
488 return openerp.web.date_to_str(full_date);
489 } else if (this.date_format == "HH:mm:ss"){
490 return openerp.web.time_to_str(full_date);
492 throw "Unrecognized date/time format";
495 reloadView: function() {
496 return this.on_project_loaded(this.database_projects);
499 do_search: function (domains, contexts, groupbys) {
502 if (this.fields_view.arch.attrs.default_group_by) {
503 this.group_by = this.fields_view.arch.attrs.default_group_by.split(',');
506 if (groupbys.length) {
507 this.group_by = groupbys;
510 $.when(this.has_been_loaded).then(function() {
511 self.dataset.read_slice([], {
514 }).done(function(projects){
515 self.on_project_loaded(projects);
520 do_show: function() {
521 this.do_push_state({});
522 return this._super();
527 // here you may tweak globals object, if any, and play with on_* or do_* callbacks on them
530 // vim:et fdc=0 fdl=0: