*** planner-gantt-print.c	2011-11-03 23:30:21.987851412 +1030
--- planner-gantt-print-408929fix.c	2011-11-03 23:19:56.059141967 +1030
***************
*** 37,42 ****
--- 37,54 ----
  #define d(x)
  #define GET_PAGE(d,r,c) (&d->pages[r*d->cols_of_pages+c])
  #define INDENT_FACTOR 4
+ #define PRINT_COL(o)  ((PrintColumn *) o)
+ typedef struct {
+ 	GtkTreeViewColumn   *tree_column;
+ 	gchar               *name;
+ 
+ 	gdouble              width;
+ 
+ 	gboolean             expander_column;
+ 
+ 	GtkTreeCellDataFunc  data_func;
+ 	gpointer             user_data;
+ } PrintColumn;
  
  typedef struct {
  	mrptime  first_time;
***************
*** 80,90 ****
  	gdouble            tree_x1;
  	gdouble            tree_x2;
  
! 	gdouble            name_x1;
! 	gdouble            name_x2;
! 
! 	gdouble            work_x1;
! 	gdouble            work_x2;
  
  	gdouble            row_height;
  
--- 92,99 ----
  	gdouble            tree_x1;
  	gdouble            tree_x2;
  
! 	gdouble			   columns_x1;
! 	gdouble			   columns_x2;
  
  	gdouble            row_height;
  
***************
*** 94,103 ****
  	PangoFontDescription         *font;
  	PangoFontDescription         *font_bold;
  
- 	GList             *tasks;
- 
  	gdouble            f;
  
  	/* Summary drawing. */
  	gdouble            summary_height;
  	gdouble            summary_thick;
--- 103,113 ----
  	PangoFontDescription         *font;
  	PangoFontDescription         *font_bold;
  
  	gdouble            f;
  
+ 	GSList            *columns;
+ 	GSList 			  *print_tasks;
+ 
  	/* Summary drawing. */
  	gdouble            summary_height;
  	gdouble            summary_thick;
***************
*** 130,135 ****
--- 140,146 ----
  typedef struct {
  	MrpTask *task;
  	gint     depth;
+ 	GtkTreePath *path;
  } PrintTask;
  
  typedef enum {
***************
*** 173,178 ****
--- 184,193 ----
  print_table_header (PlannerGanttPrintData *data)
  {
  	gdouble x, y;
+ 	x = 0;
+ 	y = 0;
+ 	GSList *c;
+ 	PrintColumn *column;
  
  	cairo_set_line_width (data->job->cr, THIN_LINE_WIDTH);
  	planner_print_job_set_font_bold (data->job);
***************
*** 183,240 ****
  	planner_print_job_lineto (data->job, data->tree_x2, y);
  	cairo_stroke (data->job->cr);
  
! 	x = data->name_x1 + data->job->x_pad;
  	y = data->row_height;
  
! 	planner_print_job_show_clipped (data->job,
! 					x, y,
! 					_("Name"),
! 					data->name_x1 + data->job->x_pad, y - data->row_height,
! 					data->name_x2 - data->job->x_pad, y + data->row_height);
! 
! 	x = data->work_x1 + data->job->x_pad;
! 
! 	planner_print_job_show_clipped (data->job,
! 					x, y,
! 					_("Work"),
! 					data->work_x1 + data->job->x_pad, 0,
! 					data->work_x2 - data->job->x_pad, y + data->row_height);
! 
  	planner_print_job_set_font_regular (data->job);
  }
  
  static void
  print_table_tasks (PlannerGanttPrintData *data,
  		   gboolean               header,
- 		   GList                 *tasks,
  		   gint                   first)
  {
  	gchar     *str;
- 	gint       work;
  	gdouble    x, y;
! 	GList     *l, *to;
  	PrintTask *ptask;
  	gint       last, i;
! 
  	if (header) {
  		last = first + data->tasks_per_page_with_header;
  	} else {
  		last = first + data->tasks_per_page_without_header;
  	}
  
! 	l = g_list_nth (tasks, first);
! 	to = g_list_nth (tasks, last);
  	i = 1;
  
  	cairo_set_line_width (data->job->cr, THIN_LINE_WIDTH);
  
! 	while (l && l != to) {
! 		ptask = l->data;
  
! 		g_object_get (ptask->task,
! 			      "name", &str,
! 			      "work", &work,
! 			      NULL);
  
  		if (mrp_task_get_n_children (ptask->task) > 0) {
  			planner_print_job_set_font_bold (data->job);
--- 198,250 ----
  	planner_print_job_lineto (data->job, data->tree_x2, y);
  	cairo_stroke (data->job->cr);
  
! 	x = data->columns_x1;
  	y = data->row_height;
  
! 	for (c = data->columns; c; c = c->next) {
! 		column = PRINT_COL (c->data);
! 		planner_print_job_show_clipped (data->job,
! 						x + data->job->x_pad, y,
! 						column->name,
! 						x + data->job->x_pad, y - data->row_height,
! 						x + column->width - data->job->x_pad, y + data->row_height);
! 		x += column->width;
! 	}
  	planner_print_job_set_font_regular (data->job);
  }
  
  static void
  print_table_tasks (PlannerGanttPrintData *data,
  		   gboolean               header,
  		   gint                   first)
  {
  	gchar     *str;
  	gdouble    x, y;
! 	GSList     *r, *c, *to;
  	PrintTask *ptask;
  	gint       last, i;
! 	gint             depth = 0; /* This is to record depth only for "expander columns" */
! 	GtkTreeModel    *model;
! 	GtkTreeIter      iter;
! 	GtkCellRenderer *cell;
  	if (header) {
  		last = first + data->tasks_per_page_with_header;
  	} else {
  		last = first + data->tasks_per_page_without_header;
  	}
  
! 	r = g_slist_nth (data->print_tasks, first);
! 	to = g_slist_nth (data->print_tasks, last);
! 
  	i = 1;
  
  	cairo_set_line_width (data->job->cr, THIN_LINE_WIDTH);
  
! 	cell  = gtk_cell_renderer_text_new ();
  
! 	/* Process all "rows" i.e. visible tasks */
! 	while (r && r != to) {
! 		ptask = r->data;
  
  		if (mrp_task_get_n_children (ptask->task) > 0) {
  			planner_print_job_set_font_bold (data->job);
***************
*** 242,279 ****
  			planner_print_job_set_font_regular (data->job);
  		}
  
! 		x = data->name_x1 + data->job->x_pad + ptask->depth * INDENT_FACTOR * data->job->x_pad;
  		y = i * data->row_height;
  
  		if (header) {
  			y += data->header_height;
  		}
  
! 		planner_print_job_show_clipped (data->job,
! 						x, y - data->row_height / 4,
! 						str,
! 						data->name_x1 + data->job->x_pad, y - data->row_height,
! 						data->name_x2 - data->job->x_pad, y);
! 
! 		g_free (str);
  
! 		x = data->work_x1 + data->job->x_pad;
  
! 		str = planner_format_duration (data->project, work);
! 		planner_print_job_show_clipped (data->job,
! 						x, y - data->row_height / 4,
! 						str,
! 						data->work_x1 + data->job->x_pad, y - data->row_height,
! 						data->work_x2 - data->job->x_pad, y);
! 		g_free (str);
  
  		planner_print_job_moveto (data->job, 0, y);
  		planner_print_job_lineto (data->job, data->tree_x2, y);
  		cairo_stroke (data->job->cr);
  
  		i++;
! 		l = l->next;
  	}
  
  	cairo_set_line_width (data->job->cr, 1);
  }
--- 252,304 ----
  			planner_print_job_set_font_regular (data->job);
  		}
  
! 		x = 0;
  		y = i * data->row_height;
  
  		if (header) {
  			y += data->header_height;
  		}
  
! 		/* Process all visible columns within each row */
! 		for (c = data->columns; c; c = c->next) {
! 			PrintColumn *column = PRINT_COL (c->data);
! 
! 			model = gtk_tree_view_get_model (data->tree_view);
! 			gtk_tree_model_get_iter (model, &iter, ptask->path);
! 
! 			(* column->data_func) (column->tree_column,
! 						       cell,
! 						       model,
! 						       &iter,
! 						       column->user_data);
! 
! 			g_object_get (cell,
! 					      "text", &str,
! 					      NULL);
! 
! 			if (str) {
! 				planner_print_job_show_clipped(
! 						data->job,
! 						x + data->job->x_pad + depth * INDENT_FACTOR
! 								* data->job->x_pad, y - data->row_height / 4,
! 						str, x + data->job->x_pad, y - data->row_height,
! 						x + column->width - data->job->x_pad, y);
! 			}
  
! 			x += column->width;
  
! 			g_free (str);
  
+ 		}
  		planner_print_job_moveto (data->job, 0, y);
  		planner_print_job_lineto (data->job, data->tree_x2, y);
  		cairo_stroke (data->job->cr);
  
  		i++;
! 		r = r->next;
  	}
+ 	g_object_ref_sink (cell);
+ 	g_object_unref (cell);
  
  	cairo_set_line_width (data->job->cr, 1);
  }
***************
*** 370,379 ****
  	}
  }
  
- typedef struct {
- 	GtkTreeView *tree_view;
- 	GList       *list;
- } ForeachVisibleData;
  
  static gboolean
  foreach_visible_task (GtkTreeModel *model,
--- 395,400 ----
***************
*** 381,387 ****
  		      GtkTreeIter  *iter,
  		      gpointer      data)
  {
! 	ForeachVisibleData *fvd = data;
  	MrpTask            *task;
  	GtkTreeIter         parent_iter;
  	GtkTreePath        *parent_path;
--- 402,411 ----
  		      GtkTreeIter  *iter,
  		      gpointer      data)
  {
! 	PlannerGanttPrintData *print_data = data;
! 	GSList                 *l;
! 	GtkCellRenderer        *cell;
! 	gdouble             sum_column_widths = 0;
  	MrpTask            *task;
  	GtkTreeIter         parent_iter;
  	GtkTreePath        *parent_path;
***************
*** 390,396 ****
  	gtk_tree_model_iter_parent (model, &parent_iter, iter);
  	parent_path = gtk_tree_model_get_path (model, &parent_iter);
  	if (gtk_tree_path_get_depth (path) == 1 ||
! 	    gtk_tree_view_row_expanded (fvd->tree_view, parent_path)) {
  		gtk_tree_model_get (model,
  				    iter,
  				    COL_TASK, &task,
--- 414,420 ----
  	gtk_tree_model_iter_parent (model, &parent_iter, iter);
  	parent_path = gtk_tree_model_get_path (model, &parent_iter);
  	if (gtk_tree_path_get_depth (path) == 1 ||
! 			gtk_tree_view_row_expanded (print_data->tree_view, parent_path)) {
  		gtk_tree_model_get (model,
  				    iter,
  				    COL_TASK, &task,
***************
*** 399,453 ****
  		ptask = g_new0 (PrintTask, 1);
  		ptask->task = task;
  		ptask->depth = gtk_tree_path_get_depth (path);
  
! 		fvd->list = g_list_prepend (fvd->list, ptask);
  	}
  	gtk_tree_path_free (parent_path);
  
  	return FALSE;
  }
  
! static GList *
  gantt_print_get_visible_tasks (PlannerGanttPrintData *data)
  {
! 	ForeachVisibleData  fvd;
  	GtkTreeModel       *model;
  
  	model = gtk_tree_view_get_model (data->tree_view);
  
! 	fvd.list = NULL;
! 	fvd.tree_view = data->tree_view;
  
  	gtk_tree_model_foreach (model,
  				foreach_visible_task,
! 				&fvd);
  
! 	return g_list_reverse (fvd.list);
  }
  
  static void
! gantt_print_free_print_tasks (GList *tasks)
  {
! 	GList *l;
  
  	for (l = tasks; l; l = l->next) {
  		g_free (l->data);
  	}
  }
  
! static GList *
  gantt_print_get_relations (PlannerGanttPrintData *data)
  {
  	GList   *tasks, *l;
  	GList   *predecessors, *p;
! 	GList  *relations = NULL;
  
  	tasks = mrp_project_get_all_tasks (data->project);
  	for (l = tasks; l; l = l->next) {
  		predecessors = mrp_task_get_predecessor_relations (l->data);
  
  		for (p = predecessors; p; p = p->next) {
! 			relations = g_list_prepend (relations, p->data);
  		}
  	}
  
--- 423,572 ----
  		ptask = g_new0 (PrintTask, 1);
  		ptask->task = task;
  		ptask->depth = gtk_tree_path_get_depth (path);
+ 		ptask->path = gtk_tree_path_copy (path);
+ 
+ 		cell  = gtk_cell_renderer_text_new ();
+ 
+ 		/* Loop through the columns to update widths */
+ 		for (l = print_data->columns; l; l = l->next) {
+ 			PrintColumn *column = PRINT_COL (l->data);
+ 			gchar       *str;
+ 			gdouble      extra = 3 * print_data->job->x_pad;
+ 			gdouble      ext;
+ 
+ 			(* column->data_func) (column->tree_column,
+ 					cell,
+ 					model,
+ 					iter,
+ 					column->user_data);
+ 			g_object_get (cell,
+ 					"text", &str,
+ 					NULL);
+ 
+ 			if (column->expander_column) {
+ 				extra += INDENT_FACTOR * print_data->job->x_pad;
+ 			}
  
! 			ext = 0;
! 			if(str) {
! 				ext = planner_print_job_get_extents (print_data->job, str);
! 			}
! 			column->width = MAX (column->width,
! 					ext
! 					+ extra);
! 
! 			/* Sum of all column widths */
! 			sum_column_widths += column->width;
! 
! 			g_free (str);
! 		}
! 		/* Determine max size of all columns calculated so far */
! 		print_data->columns_x2 = MAX (print_data->columns_x2, sum_column_widths);
! 
! 		print_data->print_tasks = g_slist_prepend (print_data->print_tasks, ptask);
! 
! 		g_object_ref_sink (cell);
! 		g_object_unref (cell);
  	}
  	gtk_tree_path_free (parent_path);
  
  	return FALSE;
  }
  
! /* PP  BEGIN */
! static PrintColumn *
! gantt_print_table_create_column (PlannerGanttPrintData *data,
! 				 GtkTreeViewColumn      *tree_column,
! 				 gboolean                expander_column)
! {
! 	PrintColumn *column;
! 	gdouble ext;
! 
! 	column = g_new0 (PrintColumn, 1);
! 
! 	column->tree_column = tree_column;
! 	column->expander_column = expander_column;
! 	column->name = g_strdup (gtk_tree_view_column_get_title (tree_column));
! 	planner_print_job_set_font_bold (data->job);
! 	ext = planner_print_job_get_extents (data->job, column->name);
! 	column->width = ext + 3 * data->job->x_pad;
! 
! 	column->data_func = g_object_get_data (G_OBJECT (tree_column),
! 					       "data-func");
! 	column->user_data = g_object_get_data (G_OBJECT (tree_column),
! 					       "user-data");
! 
! 	return column;
! }
! 
! static void
  gantt_print_get_visible_tasks (PlannerGanttPrintData *data)
  {
! 	gboolean                expander_column;
  	GtkTreeModel       *model;
  
  	model = gtk_tree_view_get_model (data->tree_view);
  
! 	data->print_tasks = NULL;
! 
! 	GList	   *tree_columns, *l;
! 	tree_columns = gtk_tree_view_get_columns (data->tree_view);
! 	for (l = tree_columns; l; l = l->next) {
! 		PrintColumn       *column;
! 		GtkTreeViewColumn *tree_column;
! 
! 		tree_column = GTK_TREE_VIEW_COLUMN (l->data);
! 		if (!gtk_tree_view_column_get_visible (tree_column)) {
! 			continue;
! 		}
! 
! 		if (tree_column == gtk_tree_view_get_expander_column (data->tree_view)) {
! 			expander_column = TRUE;
! 		} else {
! 			expander_column = FALSE;
! 		}
! 
! 		column = gantt_print_table_create_column (data,
! 							  tree_column,
! 							  expander_column);
  
+ 		data->columns = g_slist_prepend (data->columns, column);
+ 	}
+ 	g_list_free (tree_columns);
+ 	data->columns = g_slist_reverse (data->columns);
+ 
+ 	/* Generate rows */
  	gtk_tree_model_foreach (model,
  				foreach_visible_task,
! 				data);
  
! 	data->print_tasks = g_slist_reverse (data->print_tasks);
  }
  
  static void
! gantt_print_free_print_tasks (GSList *tasks)
  {
! 	GSList *l;
  
  	for (l = tasks; l; l = l->next) {
  		g_free (l->data);
  	}
  }
  
! 
! static GSList *
  gantt_print_get_relations (PlannerGanttPrintData *data)
  {
  	GList   *tasks, *l;
  	GList   *predecessors, *p;
! 	GSList  *relations = NULL;
  
  	tasks = mrp_project_get_all_tasks (data->project);
  	for (l = tasks; l; l = l->next) {
  		predecessors = mrp_task_get_predecessor_relations (l->data);
  
  		for (p = predecessors; p; p = p->next) {
! 			relations = g_slist_prepend (relations, p->data);
  		}
  	}
  
***************
*** 582,588 ****
  	}
  
  	return text != NULL;
! }
  
  void
  planner_gantt_print_do (PlannerGanttPrintData *data, gint page_nr)
--- 701,709 ----
  	}
  
  	return text != NULL;
! } /* gantt_print_get_allocated_resources_string */
! 
! 
  
  void
  planner_gantt_print_do (PlannerGanttPrintData *data, gint page_nr)
***************
*** 625,640 ****
  		cairo_stroke (data->job->cr);
  
  		planner_print_job_moveto (data->job,
! 					  data->name_x2,
! 					  0);
  		planner_print_job_lineto (data->job,
! 					  data->name_x2,
! 					  data->job->height);
  		cairo_stroke (data->job->cr);
  
  		print_table_tasks (data,
  				   row == 0,
- 				   data->tasks,
  				   first_task);
  	} else {
  		x1 = 0;
--- 746,760 ----
  		cairo_stroke (data->job->cr);
  
  		planner_print_job_moveto (data->job,
! 				data->columns_x2,
! 				0);
  		planner_print_job_lineto (data->job,
! 				data->columns_x2,
! 				data->job->height);
  		cairo_stroke (data->job->cr);
  
  		print_table_tasks (data,
  				   row == 0,
  				   first_task);
  	} else {
  		x1 = 0;
***************
*** 895,905 ****
  			      gboolean         show_critical)
  {
  	PlannerGanttPrintData *data;
! 	GList                 *tasks = NULL, *l;
  	gint                   num_tasks;
! 	gdouble                max_name_width = 0.0;
! 	gdouble                ext;
! 	GList       *relations;
  	gdouble      x1;
  	gdouble      y1, y2;
  	mrptime      t1, t2, t0;
--- 1015,1023 ----
  			      gboolean         show_critical)
  {
  	PlannerGanttPrintData *data;
! 	GSList                *l;
  	gint                   num_tasks;
! 	GSList       *relations;
  	gdouble      x1;
  	gdouble      y1, y2;
  	mrptime      t1, t2, t0;
***************
*** 951,1003 ****
  	/* Start and finish of the project. */
  	data->start = mrp_project_get_project_start (data->project);
  
! 	tasks = gantt_print_get_visible_tasks (data);
! 	data->tasks = tasks;
! 	num_tasks = g_list_length (tasks);
  
  	data->finish = data->start;
  
  	/* Go through the tasks and get the end time by checking the right-most
  	 * resource label we will print.
  	 */
! 	for (l = tasks; l; l = l->next) {
  		PrintTask *ptask = l->data;
  		MrpTask   *task  = ptask->task;
- 		gchar     *name;
  		mrptime    finish;
  		gdouble    width;
- 		gdouble    name_width;
  
  		g_object_get (task,
! 			      "name", &name,
! 			      "finish", &finish,
! 			      NULL);
! 
! 		ext = planner_print_job_get_extents(data->job, name);
! 		name_width = ext + ptask->depth * INDENT_FACTOR * data->job->x_pad;
! 
! 		if (max_name_width < name_width) {
! 			max_name_width = name_width;
! 		}
  
  		gantt_print_get_allocated_resources_string (data, task, NULL, &width);
  
! 		data->finish = MAX (data->finish, finish);/* + width * data->f);*/
! 
! 		g_free (name);
  	}
  
! 	/* TODO: figure out why the width of WW and WORKWO is significant */
! 	data->name_x1 = 0;
! 	ext = planner_print_job_get_extents (data->job, "WW");
! 	data->name_x2 = data->name_x1 + max_name_width + ext;
! 
! 	data->work_x1 = data->name_x2;
! 	ext = planner_print_job_get_extents (data->job, "WORKWO");
! 	data->work_x2 = data->work_x1 + ext;
! 
  	data->tree_x1 = 0;
! 	data->tree_x2 = data->work_x2;
  
  	data->second_column_start = data->start + (data->job->width - (data->tree_x2 - data->tree_x1)) * data->f;
  
--- 1069,1100 ----
  	/* Start and finish of the project. */
  	data->start = mrp_project_get_project_start (data->project);
  
! 	gantt_print_get_visible_tasks (data);
! 	num_tasks = g_slist_length (data->print_tasks);
  
  	data->finish = data->start;
  
  	/* Go through the tasks and get the end time by checking the right-most
  	 * resource label we will print.
  	 */
! 	for (l = data->print_tasks; l; l = l->next) {
  		PrintTask *ptask = l->data;
  		MrpTask   *task  = ptask->task;
  		mrptime    finish;
  		gdouble    width;
  
  		g_object_get (task,
! 				"finish", &finish,
! 				NULL);
  
  		gantt_print_get_allocated_resources_string (data, task, NULL, &width);
  
! 		data->finish = MAX (data->finish, finish);
  	}
  
! 	data->columns_x1 = 0;
  	data->tree_x1 = 0;
! 	data->tree_x2 = data->columns_x2;
  
  	data->second_column_start = data->start + (data->job->width - (data->tree_x2 - data->tree_x1)) * data->f;
  
***************
*** 1040,1046 ****
  
  	calendar = mrp_project_get_calendar (data->project);
  
! 	num_tasks = g_list_length (data->tasks);
  
  	current_time = mrp_time_current_time();
  
--- 1137,1143 ----
  
  	calendar = mrp_project_get_calendar (data->project);
  
! 	num_tasks = g_slist_length (data->print_tasks);
  
  	current_time = mrp_time_current_time();
  
***************
*** 1048,1054 ****
  	 * where to draw relation arrows.
  	 */
  
! 	l = data->tasks;
  	row = 0;
  	col = 0;
  	while (l) {
--- 1145,1151 ----
  	 * where to draw relation arrows.
  	 */
  
! 	l = data->print_tasks;
  	row = 0;
  	col = 0;
  	while (l) {
***************
*** 1392,1398 ****
  		}
  	}
  
! 	g_list_free (relations);
  
  	/* Third pass, add background shading for non-work intervals. */
  	for (row = 0; row < data->rows_of_pages; row++) {
--- 1489,1495 ----
  		}
  	}
  
! 	g_slist_free (relations);
  
  	/* Third pass, add background shading for non-work intervals. */
  	for (row = 0; row < data->rows_of_pages; row++) {
***************
*** 1521,1528 ****
  	g_hash_table_destroy (data->task_start_coords);
  	g_hash_table_destroy (data->task_finish_coords);
  
! 	gantt_print_free_print_tasks (data->tasks);
! 	data->tasks = NULL;
  
  	num_pages = data->cols_of_pages * data->rows_of_pages;
  
--- 1618,1625 ----
  	g_hash_table_destroy (data->task_start_coords);
  	g_hash_table_destroy (data->task_finish_coords);
  
! 	gantt_print_free_print_tasks (data->print_tasks);
! 	data->print_tasks = NULL;
  
  	num_pages = data->cols_of_pages * data->rows_of_pages;
  
