1 
2 /*
3  * dao.c:
4  *
5  * Authors:
6  *   Jukka-Pekka Iivonen <jiivonen@hutcs.cs.hut.fi>
7  *   Andreas J. Guelzow  <aguelzow@taliesin.ca>
8  *
9  * (C) Copyright 2000, 2001 by Jukka-Pekka Iivonen <jiivonen@hutcs.cs.hut.fi>
10  * (C) Copyright 2001, 2002 by Andreas J. Guelzow  <aguelzow@taliesin.ca>
11  *
12  * This program is free software; you can redistribute it and/or modify
13  * it under the terms of the GNU General Public License as published by
14  * the Free Software Foundation; either version 2 of the License, or
15  * (at your option) any later version.
16  *
17  * This program is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20  * GNU General Public License for more details.
21  *
22  * You should have received a copy of the GNU General Public License
23  * along with this program; if not, see <https://www.gnu.org/licenses/>.
24  */
25 
26 #include <gnumeric-config.h>
27 #include <tools/dao.h>
28 
29 #include <expr.h>
30 #include <value.h>
31 #include <cell.h>
32 #include <sheet.h>
33 #include <ranges.h>
34 #include <style.h>
35 #include <sheet-style.h>
36 #include <workbook.h>
37 #include <workbook-view.h>
38 #include <workbook-control.h>
39 #include <command-context.h>
40 #include <gnm-format.h>
41 #include <sheet-merge.h>
42 #include <sheet-object-cell-comment.h>
43 #include <style-color.h>
44 #include <style-border.h>
45 #include <graph.h>
46 #include <goffice/goffice.h>
47 
48 #include <glib.h>
49 #include <glib/gi18n-lib.h>
50 #include <string.h>
51 #include <time.h>
52 #include <parse-util.h>
53 
54 /**
55  * dao_init: (skip)
56  * @dao:
57  * @type:
58  *
59  * Initialize dao to given type.
60  *
61  **/
62 
63 data_analysis_output_t *
dao_init(data_analysis_output_t * dao,data_analysis_output_type_t type)64 dao_init (data_analysis_output_t *dao,
65 	  data_analysis_output_type_t type)
66 {
67 	if (dao == NULL) {
68 		dao = g_new (data_analysis_output_t, 1);
69 		dao->use_gfree = TRUE;
70 	} else
71 		dao->use_gfree = FALSE;
72 
73 	dao->type              = type;
74 	dao->start_col         = 0;
75 	dao->start_row         = 0;
76 	dao->offset_col        = 0;
77 	dao->offset_row        = 0;
78 	dao->cols              = 1;  /* Fixed in dao_prepare_output */
79 	dao->rows              = 1;
80 	dao->sheet             = NULL;
81 	dao->autofit_flag      = TRUE;
82 	dao->autofit_noshrink  = TRUE;
83 	dao->clear_outputrange = TRUE;
84 	dao->retain_format     = FALSE;
85 	dao->retain_comments   = FALSE;
86 	dao->put_formulas      = FALSE;
87 	dao->wbc               = NULL;
88 	dao->sos               = NULL;
89         dao->omit_so           = FALSE;
90 
91 	return dao;
92 }
93 
94 /**
95  * dao_init_new_sheet: (skip)
96  * @dao:
97  *
98  **/
99 data_analysis_output_t *
dao_init_new_sheet(data_analysis_output_t * dao)100 dao_init_new_sheet (data_analysis_output_t *dao)
101 {
102 	return dao_init (dao, NewSheetOutput);
103 }
104 
dao_free(data_analysis_output_t * dao)105 void dao_free (data_analysis_output_t *dao)
106 {
107 	g_slist_free_full (dao->sos, g_object_unref);
108 	dao->sos = NULL;
109 
110 	if (dao->use_gfree)
111 		g_free (dao);
112 }
113 
114 /**
115  * dao_load_from_value: (skip)
116  * @dao:
117  * @output_range:
118  *
119  **/
120 data_analysis_output_t *
dao_load_from_value(data_analysis_output_t * dao,GnmValue * output_range)121 dao_load_from_value (data_analysis_output_t *dao,
122 		     GnmValue *output_range)
123 {
124 	g_return_val_if_fail (output_range != NULL, dao);
125 	g_return_val_if_fail (VALUE_IS_CELLRANGE (output_range), dao);
126 
127 	dao->start_col = output_range->v_range.cell.a.col;
128 	dao->start_row = output_range->v_range.cell.a.row;
129 	dao->cols = output_range->v_range.cell.b.col
130 		- output_range->v_range.cell.a.col + 1;
131 	dao->rows = output_range->v_range.cell.b.row
132 		- output_range->v_range.cell.a.row + 1;
133 	dao->sheet = output_range->v_range.cell.a.sheet;
134 
135 	return dao;
136 }
137 
138 /**
139  * dao_range_name:
140  * @dao:
141  *
142  * Provides the name of the output range
143  * The caller has to dispose of the name
144  *
145  **/
146 
147 static char *
dao_range_name(data_analysis_output_t * dao)148 dao_range_name (data_analysis_output_t *dao)
149 {
150 	GnmRange range;
151 	range_init (&range, dao->start_col, dao->start_row,
152 		    dao->start_col + dao->cols - 1,
153 		    dao->start_row + dao->rows - 1);
154 
155 	return undo_range_name (dao->sheet, &range);
156 }
157 
158 /**
159  * dao_command_descriptor:
160  * @dao:
161  * @format:
162  * @result:
163  *
164  * Uses format to provide a string to be used as command descriptor for
165  * undo/redo
166  *
167  **/
168 
169 char *
dao_command_descriptor(data_analysis_output_t * dao,char const * format,gpointer result)170 dao_command_descriptor (data_analysis_output_t *dao, char const *format,
171 			gpointer result)
172 {
173 	char *rangename = NULL;
174 	char **text = result;
175 
176 	g_return_val_if_fail (result != NULL, NULL);
177 
178 	g_free (*text);
179 	switch (dao->type) {
180 	case NewSheetOutput:
181 		*text = g_strdup_printf (format, _("New Sheet"));
182 		break;
183 	case NewWorkbookOutput:
184 		*text = g_strdup_printf (format, _("New Workbook"));
185 		break;
186 	case RangeOutput:
187 	default:
188 		rangename = dao_range_name (dao);
189 		*text = g_strdup_printf (format, rangename);
190 		g_free (rangename);
191 		break;
192 	}
193 	return *text;
194 }
195 
196 /**
197  * dao_adjust:
198  * @dao:
199  * @cols:
200  * @rows:
201  *
202  * shrinks the dao to the given cols/rows
203  * (or enlarges it if dao was a singleton)
204  *
205  **/
206 
207 void
dao_adjust(data_analysis_output_t * dao,gint cols,gint rows)208 dao_adjust (data_analysis_output_t *dao, gint cols, gint rows)
209 {
210 	int max_rows, max_cols;
211 
212 	if (dao->cols == 1 && dao->rows == 1) {
213 		if (cols != -1)
214 			dao->cols = cols;
215 		if (rows != -1)
216 			dao->rows = rows;
217 	} else {
218 		if (cols != -1)
219 			dao->cols = MIN (cols, dao->cols);
220 		if (rows != -1)
221 			dao->rows = MIN (rows, dao->rows);
222 	}
223 
224 	if (dao->sheet) {
225 		max_rows = gnm_sheet_get_max_rows (dao->sheet) - dao->start_row;
226 		max_cols = gnm_sheet_get_max_cols (dao->sheet) - dao->start_col;
227 	} else {
228 		/* In case of NewSheetOutput and NewWorkbookOutput */
229 		/* this is called before we actually create the    */
230 		/* new sheet and/or workbook                       */
231 		Sheet *old_sheet = wb_control_cur_sheet (dao->wbc);
232 		max_rows = gnm_sheet_get_max_rows (old_sheet) - dao->start_row;
233 		max_cols = gnm_sheet_get_max_cols (old_sheet) - dao->start_col;
234 	}
235 
236 	if (dao->cols > max_cols)
237 		dao->cols = max_cols;
238 	if (dao->rows > max_rows)
239 		dao->rows = max_rows;
240 }
241 
242 /**
243  * dao_prepare_output:
244  * @dao:
245  * @name:
246  *
247  * prepares the output by creating a new sheet or workbook as appropriate
248  *
249  **/
250 
251 void
dao_prepare_output(WorkbookControl * wbc,data_analysis_output_t * dao,const char * name)252 dao_prepare_output (WorkbookControl *wbc, data_analysis_output_t *dao,
253 		    const char *name)
254 {
255 	char *unique_name;
256 
257 	if (wbc)
258 		dao->wbc = wbc;
259 
260 	if (dao->type == NewSheetOutput) {
261 		Sheet *old_sheet = dao->wbc
262 			? wb_control_cur_sheet (dao->wbc)
263 			: dao->sheet;
264 		Workbook *wb = old_sheet->workbook;
265 		char *name_with_counter = g_strdup_printf ("%s (1)", name);
266 		unique_name = workbook_sheet_get_free_name
267 			(wb, name_with_counter, FALSE, TRUE);
268 		g_free (name_with_counter);
269 		dao->rows = gnm_sheet_get_max_rows (old_sheet);
270 		dao->cols = gnm_sheet_get_max_cols (old_sheet);
271 	        dao->sheet = sheet_new (wb, unique_name, dao->cols, dao->rows);
272 		g_free (unique_name);
273 		dao->start_col = dao->start_row = 0;
274 		workbook_sheet_attach (wb, dao->sheet);
275 	} else if (dao->type == NewWorkbookOutput) {
276 		Sheet *old_sheet = wb_control_cur_sheet (dao->wbc);
277 		Workbook *wb = workbook_new ();
278 		dao->rows = gnm_sheet_get_max_rows (old_sheet);
279 		dao->cols = gnm_sheet_get_max_cols (old_sheet);
280 		dao->sheet = sheet_new (wb, name, dao->cols, dao->rows);
281 		dao->start_col = dao->start_row = 0;
282 		workbook_sheet_attach (wb, dao->sheet);
283 		dao->wbc = workbook_control_new_wrapper (dao->wbc, NULL, wb, NULL);
284 	}
285 
286 	if (dao->wbc)
287 		wb_view_sheet_focus (wb_control_view (dao->wbc), dao->sheet);
288 
289 	if (dao->rows == 0 || (dao->rows == 1 && dao->cols == 1))
290 		dao->rows = gnm_sheet_get_max_rows (dao->sheet) - dao->start_row;
291 	if (dao->cols == 0 || (dao->rows == 1 && dao->cols == 1))
292 		dao->cols = gnm_sheet_get_max_cols (dao->sheet) - dao->start_col;
293 	dao->offset_col = 0;
294 	dao->offset_row = 0;
295 }
296 
297 /**
298  * dao_format_output:
299  * @dao:
300  * @cmd:
301  *
302  * Formats the output range according to the settings
303  *
304  *
305  **/
306 gboolean
dao_format_output(data_analysis_output_t * dao,char const * cmd)307 dao_format_output (data_analysis_output_t *dao, char const *cmd)
308 {
309 	int clear_flags = 0;
310 	GnmRange range;
311 
312 	range_init (&range, dao->start_col, dao->start_row,
313 		    dao->start_col + dao->cols - 1,
314 		    dao->start_row + dao->rows - 1);
315 
316 	if (dao->type == RangeOutput
317 	    && sheet_range_splits_region (dao->sheet, &range, NULL,
318 					  GO_CMD_CONTEXT (dao->wbc), cmd))
319 		return TRUE;
320 
321 	if (dao->clear_outputrange)
322 		clear_flags = CLEAR_VALUES | CLEAR_RECALC_DEPS;
323 	if (!dao->retain_format)
324 		clear_flags |= CLEAR_FORMATS;
325 	if (!dao->retain_comments)
326 		clear_flags |= CLEAR_COMMENTS;
327 
328 	sheet_clear_region (dao->sheet,
329 			    range.start.col, range.start.row,
330 			    range.end.col, range.end.row,
331 			    clear_flags | CLEAR_NOCHECKARRAY | CLEAR_MERGES,
332 			    GO_CMD_CONTEXT (dao->wbc));
333 	return FALSE;
334 }
335 
336 
337 static gboolean
adjust_range(data_analysis_output_t * dao,GnmRange * r)338 adjust_range (data_analysis_output_t *dao, GnmRange *r)
339 {
340 	range_normalize (r);
341 
342 	r->start.col += dao->offset_col + dao->start_col;
343 	r->end.col   += dao->offset_col + dao->start_col;
344 	r->start.row += dao->offset_row + dao->start_row;
345 	r->end.row   += dao->offset_row + dao->start_row;
346 
347 	if (dao->type == RangeOutput && (dao->cols > 1 || dao->rows > 1)) {
348 		if (r->end.col >= dao->start_col + dao->cols)
349 			r->end.col = dao->start_col + dao->cols - 1;
350 		if (r->end.row >= dao->start_row + dao->rows)
351 			r->end.row = dao->start_row + dao->rows - 1;
352 	}
353 
354 	range_ensure_sanity (r, dao->sheet);
355 
356 	return ((r->start.col <= r->end.col) && (r->start.row <= r->end.row));
357 
358 }
359 
360 gboolean
dao_cell_is_visible(data_analysis_output_t * dao,int col,int row)361 dao_cell_is_visible (data_analysis_output_t *dao, int col, int row)
362 {
363 	col += dao->offset_col;
364 	row += dao->offset_row;
365 
366 	if (dao->type == RangeOutput &&
367 	    (dao->cols > 1 || dao->rows > 1) &&
368 	    (col >= dao->cols || row >= dao->rows))
369 	        return FALSE;
370 
371 	col += dao->start_col;
372 	row += dao->start_row;
373 
374 	return (!(col >= gnm_sheet_get_max_cols (dao->sheet) || row >= gnm_sheet_get_max_rows (dao->sheet)));
375 }
376 
377 
378 /**
379  * dao_set_array_expr: (skip)
380  * @dao:
381  * @col: starting column
382  * @row: starting row
383  * @cols: number of columns
384  * @rows: number of rows
385  * @expr: (transfer full): expression to set
386  *
387  */
388 void
dao_set_array_expr(data_analysis_output_t * dao,int col,int row,int cols,int rows,GnmExpr const * expr)389 dao_set_array_expr (data_analysis_output_t *dao,
390 		    int col, int row, int cols, int rows,
391 		    GnmExpr const *expr)
392 {
393 	GnmExprTop const *texpr;
394 	GnmRange r;
395 
396 	range_init (&r, col, row, col + cols - 1, row + rows -1);
397 
398 	if (!adjust_range (dao, &r)) {
399 		gnm_expr_free (expr);
400 		return;
401 	}
402 
403 	texpr = gnm_expr_top_new (expr);
404 	gnm_cell_set_array_formula (dao->sheet,
405 				    r.start.col, r.start.row,
406 				    r.end.col, r.end.row,
407 				    texpr);
408 }
409 
410 /**
411  * dao_set_cell_array_expr: (skip)
412  * @dao:
413  * @col: column
414  * @row: row
415  * @expr: (transfer full): expression to set
416  *
417  * Sets a singleton array expression.
418  */
419 void
dao_set_cell_array_expr(data_analysis_output_t * dao,int col,int row,GnmExpr const * expr)420 dao_set_cell_array_expr (data_analysis_output_t *dao, int col, int row,
421 			 GnmExpr const *expr)
422 {
423 	dao_set_array_expr (dao, col, row, 1, 1, expr);
424 }
425 
426 /**
427  * dao_set_cell_expr: (skip)
428  * @dao:
429  * @col: column
430  * @row: row
431  * @expr: (transfer full): expression to set
432  *
433  * Sets a singleton array expression.
434  */
435 void
dao_set_cell_expr(data_analysis_output_t * dao,int col,int row,GnmExpr const * expr)436 dao_set_cell_expr (data_analysis_output_t *dao, int col, int row,
437 		   GnmExpr const *expr)
438 {
439         GnmCell *cell;
440 	GnmExprTop const *texpr;
441 	GnmRange r;
442 
443 	range_init (&r, col, row, col, row);
444 
445 	if (!adjust_range (dao, &r)) {
446 		gnm_expr_free (expr);
447 	        return;
448 	}
449 
450 	cell = sheet_cell_fetch (dao->sheet, r.start.col, r.start.row);
451 	texpr = gnm_expr_top_new (expr);
452 	gnm_cell_set_expr (cell, texpr);
453 	gnm_expr_top_unref (texpr);
454 }
455 
456 
457 /**
458  * dao_set_cell_value:
459  * @dao:
460  * @col:
461  * @row:
462  * @v: (transfer full):
463  *
464  * set cell to a value
465  *
466  * Note: the rows/cols specification for all dao_set_cell_...
467  *       commands are relative to the location of the output
468  **/
469 void
dao_set_cell_value(data_analysis_output_t * dao,int col,int row,GnmValue * v)470 dao_set_cell_value (data_analysis_output_t *dao, int col, int row, GnmValue *v)
471 {
472         GnmCell *cell;
473 	GnmRange r;
474 
475 	range_init (&r, col, row, col, row);
476 
477 	if (!adjust_range (dao, &r)) {
478 		value_release (v);
479 	        return;
480 	}
481 
482 	cell = sheet_cell_fetch (dao->sheet, r.start.col, r.start.row);
483 
484 	sheet_cell_set_value (cell, v);
485 }
486 
487 /**
488  * dao_set_cell:
489  * @dao:
490  * @col:
491  * @row:
492  * @text:
493  *
494  * set cell to a string
495  *
496  *
497  **/
498 void
dao_set_cell(data_analysis_output_t * dao,int col,int row,const char * text)499 dao_set_cell (data_analysis_output_t *dao, int col, int row, const char *text)
500 {
501 	if (text == NULL) {
502 		/* FIXME: should we erase instead?  */
503 		dao_set_cell_value (dao, col, row, value_new_empty ());
504 	} else {
505 		dao_set_cell_value (dao, col, row, value_new_string (text));
506 	}
507 }
508 
509 
510 /**
511  * dao_set_cell_printf:
512  * @dao:
513  * @col:
514  * @row:
515  * @fmt:
516  * @...:
517  *
518  * create format string and set cell.
519  *
520  **/
521 void
dao_set_cell_printf(data_analysis_output_t * dao,int col,int row,const char * fmt,...)522 dao_set_cell_printf (data_analysis_output_t *dao, int col, int row,
523 		     const char *fmt, ...)
524 {
525 	char *buffer;
526 	va_list args;
527 
528 	va_start (args, fmt);
529 	buffer = g_strdup_vprintf (fmt, args);
530 	va_end (args);
531 
532 	dao_set_cell_value (dao, col, row, value_new_string (buffer));
533 	g_free (buffer);
534 }
535 
536 
537 /**
538  * set_cell_float:
539  * @dao:
540  * @col:
541  * @row:
542  * @v:
543  *
544  * set cell to a gnm_float
545  *
546  *
547  **/
548 void
dao_set_cell_float(data_analysis_output_t * dao,int col,int row,gnm_float v)549 dao_set_cell_float (data_analysis_output_t *dao, int col, int row, gnm_float v)
550 {
551 	dao_set_cell_value (dao, col, row, value_new_float (v));
552 }
553 
554 
555 /**
556  * set_cell_int:
557  * @dao:
558  * @col:
559  * @row:
560  * @v:
561  *
562  * set cell to an int
563  *
564  *
565  **/
566 void
dao_set_cell_int(data_analysis_output_t * dao,int col,int row,int v)567 dao_set_cell_int (data_analysis_output_t *dao, int col, int row, int v)
568 {
569 	dao_set_cell_value (dao, col, row, value_new_int (v));
570 }
571 
572 
573 /**
574  * dao_set_cell_na:
575  * @dao:
576  * @col:
577  * @row:
578  *
579  * set cell to NA
580  *
581  *
582  **/
583 void
dao_set_cell_na(data_analysis_output_t * dao,int col,int row)584 dao_set_cell_na (data_analysis_output_t *dao, int col, int row)
585 {
586 	dao_set_cell_value (dao, col, row, value_new_error_NA (NULL));
587 }
588 
589 /**
590  * dao_set_cell_float_na:
591  * @dao:
592  * @col:
593  * @row:
594  * @v:
595  * @is_valid:
596  *
597  * set cell to a gnm_float or NA as appropriate
598  *
599  *
600  **/
601 void
dao_set_cell_float_na(data_analysis_output_t * dao,int col,int row,gnm_float v,gboolean is_valid)602 dao_set_cell_float_na (data_analysis_output_t *dao, int col, int row,
603 		       gnm_float v, gboolean is_valid)
604 {
605 	if (is_valid) {
606 		dao_set_cell_float (dao, col, row, v);
607 	} else {
608 		dao_set_cell_na (dao, col, row);
609 	}
610 }
611 
612 /**
613  * dao_set_cell_comment:
614  * @dao:
615  * @col:
616  * @row:
617  * @comment:
618  *
619  * set a cell comment
620  *
621  **/
622 void
dao_set_cell_comment(data_analysis_output_t * dao,int col,int row,const char * comment)623 dao_set_cell_comment (data_analysis_output_t *dao, int col, int row,
624 		      const char *comment)
625 {
626 	char const *author = NULL;
627 	GnmRange r;
628 
629 	range_init (&r, col, row, col, row);
630 
631 	if (adjust_range (dao, &r))
632 		cell_set_comment (dao->sheet, &r.start, author, comment, NULL);
633 }
634 
635 
636 /**
637  * dao_autofit_these_columns:
638  * @dao:
639  * @from_col:
640  * @to_col:
641  *
642  * Fits the specified columns to their content
643  **/
644 void
dao_autofit_these_columns(data_analysis_output_t * dao,int from_col,int to_col)645 dao_autofit_these_columns (data_analysis_output_t *dao, int from_col, int to_col)
646 {
647 	GnmRange r;
648 
649 	if (!dao->autofit_flag)
650 		return;
651 
652 	range_init_cols (&r, dao->sheet,
653 			 from_col + dao->start_col,
654 			 to_col + dao->start_col);
655 
656 	colrow_autofit (dao->sheet, &r, TRUE,
657 			FALSE, dao->autofit_noshrink, FALSE,
658 			NULL, NULL);
659 }
660 
661 /**
662  * dao_autofit_columns:
663  * @dao:
664  *
665  * fits all columns to their content
666  **/
667 void
dao_autofit_columns(data_analysis_output_t * dao)668 dao_autofit_columns (data_analysis_output_t *dao)
669 {
670 	dao_autofit_these_columns (dao, 0, dao->cols - 1);
671 }
672 
673 void
dao_autofit_these_rows(data_analysis_output_t * dao,int from_row,int to_row)674 dao_autofit_these_rows (data_analysis_output_t *dao, int from_row, int to_row)
675 {
676 	GnmRange r;
677 
678 	if (!dao->autofit_flag)
679 		return;
680 
681 	range_init_rows (&r, dao->sheet,
682 			 from_row + dao->start_row,
683 			 to_row + dao->start_row);
684 
685 	colrow_autofit (dao->sheet, &r, FALSE,
686 			FALSE, dao->autofit_noshrink, FALSE,
687 			NULL, NULL);
688 }
689 
690 void
dao_autofit_rows(data_analysis_output_t * dao)691 dao_autofit_rows (data_analysis_output_t *dao)
692 {
693 	dao_autofit_these_rows (dao, 0, dao->rows - 1);
694 }
695 
696 
697 /**
698  * dao_set_style:
699  * @dao:
700  * @col1:
701  * @row1:
702  * @col2:
703  * @row2:
704  * @style: (transfer full):
705  *
706  * Applies a partial style to the given region.
707  *
708  **/
709 static void
dao_set_style(data_analysis_output_t * dao,int col1,int row1,int col2,int row2,GnmStyle * mstyle)710 dao_set_style (data_analysis_output_t *dao, int col1, int row1,
711 	      int col2, int row2, GnmStyle *mstyle)
712 {
713 	GnmRange r;
714 
715 	range_init (&r, col1, row1, col2, row2);
716 
717 	if (!adjust_range (dao, &r)) {
718 		gnm_style_unref (mstyle);
719 	        return;
720 	}
721 
722 	sheet_style_apply_range (dao->sheet, &r, mstyle);
723 }
724 
725 /**
726  * dao_set_bold:
727  * @dao:
728  * @col1:
729  * @row1:
730  * @col2:
731  * @row2:
732  *
733  * sets the given cell range to bold
734  *
735  *
736  **/
737 void
dao_set_bold(data_analysis_output_t * dao,int col1,int row1,int col2,int row2)738 dao_set_bold (data_analysis_output_t *dao, int col1, int row1,
739 	      int col2, int row2)
740 {
741 	GnmStyle *mstyle = gnm_style_new ();
742 
743 	gnm_style_set_font_bold (mstyle, TRUE);
744 
745 	dao_set_style (dao, col1, row1, col2, row2, mstyle);
746 }
747 
748 /**
749  * dao_set_italic:
750  * @dao:
751  * @col1:
752  * @row1:
753  * @col2:
754  * @row2:
755  *
756  * sets the given cell range to italic
757  *
758  *
759  **/
760 void
dao_set_italic(data_analysis_output_t * dao,int col1,int row1,int col2,int row2)761 dao_set_italic (data_analysis_output_t *dao, int col1, int row1,
762 		int col2, int row2)
763 {
764 	GnmStyle *mstyle = gnm_style_new ();
765 
766 	gnm_style_set_font_italic (mstyle, TRUE);
767 	dao_set_style (dao, col1, row1, col2, row2, mstyle);
768 }
769 
770 /**
771  * dao_set_percent:
772  * @dao:
773  * @col1:
774  * @row1:
775  * @col2:
776  * @row2:
777  *
778  * set the given cell range to percent format
779  *
780  *
781  **/
782 void
dao_set_percent(data_analysis_output_t * dao,int col1,int row1,int col2,int row2)783 dao_set_percent (data_analysis_output_t *dao, int col1, int row1,
784 		 int col2, int row2)
785 {
786 	GnmStyle *mstyle = gnm_style_new ();
787 	gnm_style_set_format (mstyle, go_format_default_percentage ());
788 	dao_set_style (dao, col1, row1, col2, row2, mstyle);
789 }
790 
791 /**
792  * dao_set_date:
793  * @dao:
794  * @col1:
795  * @row1:
796  * @col2:
797  * @row2:
798  *
799  * set the given cell range to date format
800  *
801  *
802  **/
803 void
dao_set_date(data_analysis_output_t * dao,int col1,int row1,int col2,int row2)804 dao_set_date (data_analysis_output_t *dao, int col1, int row1,
805 		 int col2, int row2)
806 {
807 	GnmStyle *mstyle = gnm_style_new ();
808 	gnm_style_set_format (mstyle, go_format_default_date ());
809 	dao_set_style (dao, col1, row1, col2, row2, mstyle);
810 }
811 
812 /**
813  * dao_set_format:
814  * @dao:
815  * @col1:
816  * @row1:
817  * @col2:
818  * @row2:
819  * @format:
820  *
821  * set the given cell range to given format
822  *
823  *
824  **/
825 void
dao_set_format(data_analysis_output_t * dao,int col1,int row1,int col2,int row2,char const * format)826 dao_set_format (data_analysis_output_t *dao, int col1, int row1,
827 		int col2, int row2,
828 		char const * format)
829 {
830 	GOFormat *fmt;
831 
832 	fmt = go_format_new_from_XL (format);
833 	if (go_format_is_invalid (fmt)) {
834 		g_warning ("Ignoring invalid format [%s]", format);
835 	} else {
836 		GnmStyle *mstyle = gnm_style_new ();
837 		gnm_style_set_format (mstyle, fmt);
838 		dao_set_style (dao, col1, row1, col2, row2, mstyle);
839 	}
840 	go_format_unref (fmt);
841 }
842 
843 
844 /**
845  * dao_set_colors:
846  * @dao:
847  * @col1:
848  * @row1:
849  * @col2:
850  * @row2:
851  *
852  * set the given cell range to given background and text colors
853  *
854  *
855  **/
856 void
dao_set_colors(data_analysis_output_t * dao,int col1,int row1,int col2,int row2,GnmColor * fore,GnmColor * back)857 dao_set_colors (data_analysis_output_t *dao, int col1, int row1,
858 		int col2, int row2,
859 		GnmColor *fore, GnmColor *back)
860 {
861 	GnmStyle *mstyle;
862 
863 	mstyle = gnm_style_new ();
864 	if (fore)
865 		gnm_style_set_font_color (mstyle, fore);
866 	if (back) {
867 		gnm_style_set_back_color (mstyle, back);
868 		gnm_style_set_pattern (mstyle, 1);
869 	}
870 	dao_set_style (dao, col1, row1, col2, row2, mstyle);
871 }
872 
873 /**
874  * dao_set_align:
875  * @dao:
876  * @col1:
877  * @row1:
878  * @col2:
879  * @row2:
880  *
881  * set the given horizontal and vertical alignment to a cell range
882  *
883  *
884  **/
885 void
dao_set_align(data_analysis_output_t * dao,int col1,int row1,int col2,int row2,GnmHAlign align_h,GnmVAlign align_v)886 dao_set_align (data_analysis_output_t *dao, int col1, int row1,
887 	       int col2, int row2,
888 	       GnmHAlign align_h, GnmVAlign align_v)
889 {
890 	GnmStyle *mstyle;
891 
892 	mstyle = gnm_style_new ();
893 	gnm_style_set_align_h (mstyle, align_h);
894 	gnm_style_set_align_v (mstyle, align_v);
895 	dao_set_style (dao, col1, row1, col2, row2, mstyle);
896 }
897 
898 /**
899  * dao_set_border:
900  * @dao:
901  * @col1:
902  * @row1:
903  * @col2:
904  * @row2:
905  *
906  *
907  *
908  **/
909 void
dao_set_border(data_analysis_output_t * dao,int col1,int row1,int col2,int row2,GnmStyleElement elem,GnmStyleBorderType border,GnmColor * color,GnmStyleBorderOrientation orientation)910 dao_set_border (data_analysis_output_t *dao, int col1, int row1,
911 	       int col2, int row2,
912 		GnmStyleElement elem, GnmStyleBorderType border,
913 		GnmColor *color,
914 		GnmStyleBorderOrientation orientation)
915 {
916 	GnmStyle *mstyle;
917 
918 	mstyle = gnm_style_new ();
919 	gnm_style_set_border (mstyle, elem,
920 			      gnm_style_border_fetch (border,
921 						      color,
922 						      orientation));
923 	dao_set_style (dao, col1, row1, col2, row2, mstyle);
924 }
925 
926 
927 
928 /**
929  * dao_get_colrow_state_list:
930  * @dao:
931  * @is_cols: %TRUE for columns, %FALSE for rows.
932  *
933  *
934  * Returns: (transfer full):
935  **/
936 ColRowStateList *
dao_get_colrow_state_list(data_analysis_output_t * dao,gboolean is_cols)937 dao_get_colrow_state_list (data_analysis_output_t *dao, gboolean is_cols)
938 {
939 	switch (dao->type) {
940 	case NewSheetOutput:
941 	case NewWorkbookOutput:
942 		return NULL;
943 	case RangeOutput:
944 		if (is_cols)
945 			return colrow_get_states
946 				(dao->sheet, is_cols, dao->start_col,
947 				 dao->start_col + dao->cols - 1);
948 		else
949 			return colrow_get_states
950 				(dao->sheet, is_cols, dao->start_row,
951 				 dao->start_row + dao->rows - 1);
952 	default:
953 		return NULL;
954 	}
955 }
956 
957 /**
958  * dao_set_colrow_state_list:
959  * @dao:
960  * @is_cols: %TRUE for columns, %FALSE for rows.
961  * @list:
962  *
963  **/
964 void
dao_set_colrow_state_list(data_analysis_output_t * dao,gboolean is_cols,ColRowStateList * list)965 dao_set_colrow_state_list (data_analysis_output_t *dao, gboolean is_cols,
966 			   ColRowStateList *list)
967 {
968 	g_return_if_fail (list);
969 
970 	if (dao->type == RangeOutput)
971 		colrow_set_states (dao->sheet, is_cols,
972 				   is_cols ? dao->start_col : dao->start_row,
973 				   list);
974 }
975 
976 void
dao_append_date(GString * buf)977 dao_append_date (GString *buf)
978 {
979 	GDate     date;
980 	struct tm tm_s;
981 	gchar     *tmp;
982 	time_t    now;
983 
984 	now = time (NULL);
985 	g_date_set_time_t (&date, now);
986 	g_date_to_struct_tm (&date, &tm_s);
987 	tm_s.tm_sec  = now % 60;
988 	tm_s.tm_min  = (now / 60) % 60;
989 	tm_s.tm_hour = (now / 3600) % 24;
990 	tmp = asctime (&tm_s);
991 	g_string_append (buf, tmp);
992 }
993 
994 /**
995  * dao_write_header:
996  * @dao:
997  * @toolname: name of the tool, like Solver or Risk simulation
998  * @title:
999  * @sheet:
1000  *
1001  * Writes the titles of a report.
1002  *
1003  **/
1004 void
dao_write_header(data_analysis_output_t * dao,const gchar * toolname,const gchar * title,Sheet * sheet)1005 dao_write_header (data_analysis_output_t *dao, const gchar *toolname,
1006 		  const gchar *title, Sheet *sheet)
1007 {
1008 	GString *buf;
1009 	const char *uri;
1010 
1011 	buf = g_string_new (NULL);
1012 	g_string_append_printf (buf, "%s %s %s %s",
1013 		_("Gnumeric "), toolname, VERSION, title);
1014 	dao_set_cell (dao, 0, 0, buf->str);
1015 	g_string_free (buf, FALSE);
1016 
1017 	buf = g_string_new (NULL);
1018 	uri = go_doc_get_uri (GO_DOC (sheet->workbook));
1019 	g_string_append_printf (buf, "%s [%s]%s", _("Worksheet:"),
1020 				uri,
1021 				sheet->name_quoted);
1022 	dao_set_cell (dao, 0, 1, buf->str);
1023 	g_string_free (buf, FALSE);
1024 
1025 	buf = g_string_new (NULL);
1026 	g_string_append (buf, _("Report Created: "));
1027 	dao_append_date (buf);
1028 	dao_set_cell (dao, 0, 2, buf->str);
1029 	g_string_free (buf, FALSE);
1030 
1031 	dao_set_bold (dao, 0, 0, 0, 2);
1032 }
1033 
1034 
1035 char *
dao_find_name(Sheet * sheet,int col,int row)1036 dao_find_name (Sheet *sheet, int col, int row)
1037 {
1038         static char *str     = NULL;
1039 	const char  *col_str = "";
1040 	const char  *row_str = "";
1041         int         col_n, row_n;
1042 
1043 	for (col_n = col - 1; col_n >= 0; col_n--) {
1044 	        GnmCell *cell = sheet_cell_get (sheet, col_n, row);
1045 		if (cell && !VALUE_IS_NUMBER (cell->value)) {
1046 			col_str = value_peek_string (cell->value);
1047 		        break;
1048 		}
1049 	}
1050 
1051 	for (row_n = row - 1; row_n >= 0; row_n--) {
1052 	        GnmCell *cell = sheet_cell_get (sheet, col, row_n);
1053 		if (cell && !VALUE_IS_NUMBER (cell->value)) {
1054 			row_str = value_peek_string (cell->value);
1055 		        break;
1056 		}
1057 	}
1058 
1059 	if (*col_str || *row_str) {
1060 		str = g_new (char, strlen (col_str) + strlen (row_str) + 2);
1061 
1062 		if (*col_str)
1063 			sprintf (str, "%s %s", col_str, row_str);
1064 		else
1065 			sprintf (str, "%s", row_str);
1066 	} else {
1067 		const char *tmp = cell_coord_name (col, row);
1068 
1069 		str = g_new (char, strlen (tmp) + 1);
1070 		strcpy (str, tmp);
1071 	}
1072 
1073 	return str;
1074 }
1075 
1076 gboolean
dao_put_formulas(data_analysis_output_t * dao)1077 dao_put_formulas (data_analysis_output_t *dao)
1078 {
1079 	g_return_val_if_fail (dao != NULL, FALSE);
1080 	return dao->put_formulas;
1081 }
1082 
1083 static GnmValue *
cb_convert_to_value(GnmCellIter const * iter,G_GNUC_UNUSED gpointer user)1084 cb_convert_to_value (GnmCellIter const *iter, G_GNUC_UNUSED gpointer user)
1085 {
1086 	GnmCell *cell = iter->cell;
1087 	if (!cell || !gnm_cell_has_expr (cell))
1088 		return NULL;
1089 
1090 	gnm_cell_eval (cell);
1091 
1092 	if (gnm_expr_top_is_array_elem (cell->base.texpr, NULL, NULL))
1093 		return NULL;
1094 
1095 	gnm_cell_convert_expr_to_value (cell);
1096 	return NULL;
1097 }
1098 
1099 
1100 static void
dao_convert_to_values(data_analysis_output_t * dao)1101 dao_convert_to_values (data_analysis_output_t *dao)
1102 {
1103 	if (dao->put_formulas)
1104 		return;
1105 
1106 	sheet_foreach_cell_in_region (dao->sheet, CELL_ITER_IGNORE_BLANK,
1107 				      dao->start_col, dao->start_row,
1108 				      dao->start_col + dao->cols - 1,
1109 				      dao->start_row + dao->rows - 1,
1110 				      cb_convert_to_value,
1111 				      NULL);
1112 }
1113 
1114 void
dao_redraw_respan(data_analysis_output_t * dao)1115 dao_redraw_respan (data_analysis_output_t *dao)
1116 {
1117 	GnmRange r;
1118 
1119 	range_init (&r, dao->start_col, dao->start_row,
1120 		    dao->start_col + dao->cols - 1,
1121 		    dao->start_row + dao->rows - 1);
1122 	sheet_range_calc_spans (dao->sheet, &r,
1123 				GNM_SPANCALC_RESIZE | GNM_SPANCALC_RE_RENDER);
1124 	sheet_region_queue_recalc (dao->sheet, &r);
1125 	dao_convert_to_values (dao);
1126 	sheet_redraw_range (dao->sheet, &r);
1127 }
1128 
1129 
1130 static GnmExpr const  *
dao_get_cellref_full(data_analysis_output_t * dao,int x,int y,Sheet * sheet)1131 dao_get_cellref_full (data_analysis_output_t *dao, int x, int y, Sheet *sheet)
1132 {
1133 	GnmCellRef r;
1134 	r.sheet = sheet;
1135 	r.col = x + dao->start_col + dao->offset_col;
1136 	r.col_relative = FALSE;
1137 	r.row = y + dao->start_row + dao->offset_row;
1138 	r.row_relative = FALSE;
1139 	return gnm_expr_new_cellref (&r);
1140 }
1141 
1142 GnmExpr const  *
dao_get_cellref(data_analysis_output_t * dao,int x,int y)1143 dao_get_cellref (data_analysis_output_t *dao, int x, int y)
1144 {
1145 	return dao_get_cellref_full (dao, x, y, NULL);
1146 }
1147 
1148 static GnmExpr const  *
dao_get_rangeref_full(data_analysis_output_t * dao,int ax,int ay,int bx,int by,Sheet * sheet)1149 dao_get_rangeref_full (data_analysis_output_t *dao, int ax, int ay,  int bx, int by, Sheet *sheet)
1150 {
1151 	GnmValue *v;
1152 	GnmCellRef ar;
1153 	GnmCellRef br;
1154 
1155 	ar.sheet = sheet;
1156 	ar.col = ax + dao->start_col + dao->offset_col;
1157 	ar.col_relative = FALSE;
1158 	ar.row = ay + dao->start_row + dao->offset_row;
1159 	ar.row_relative = FALSE;
1160 
1161 	br.sheet = sheet;
1162 	br.col = bx + dao->start_col + dao->offset_col;
1163 	br.col_relative = FALSE;
1164 	br.row = by + dao->start_row + dao->offset_row;
1165 	br.row_relative = FALSE;
1166 
1167 	v = value_new_cellrange (&ar, &br, 0, 0);
1168 	return gnm_expr_new_constant (v);
1169 }
1170 
1171 GnmExpr const  *
dao_get_rangeref(data_analysis_output_t * dao,int ax,int ay,int bx,int by)1172 dao_get_rangeref (data_analysis_output_t *dao, int ax, int ay,  int bx, int by)
1173 {
1174 	return dao_get_rangeref_full (dao, ax, ay, bx, by, NULL);
1175 }
1176 
1177 void
dao_set_sheet_object(data_analysis_output_t * dao,int col,int row,SheetObject * so)1178 dao_set_sheet_object (data_analysis_output_t *dao, int col, int row, SheetObject* so)
1179 {
1180 	SheetObjectAnchor anchor;
1181 	GnmRange	  anchor_r;
1182 
1183 	g_return_if_fail (so != NULL);
1184 
1185 	if (dao->omit_so) {
1186 		g_object_unref (so);
1187 		return;
1188 	}
1189 
1190 	range_init (&anchor_r, dao->start_col + col, dao->start_row + row,
1191 		    dao->start_col + ((dao->cols < 5) ? dao->cols : 5),
1192 		    dao->start_row + ((dao->rows < 20) ? dao->rows : 20));
1193 
1194 	sheet_object_anchor_init (&anchor, &anchor_r, NULL, GOD_ANCHOR_DIR_UNKNOWN,
1195 	                          GNM_SO_ANCHOR_TWO_CELLS);
1196 	sheet_object_set_anchor (so, &anchor);
1197 	sheet_object_set_sheet (so, dao->sheet);
1198 
1199 	dao->sos = g_slist_prepend (dao->sos, so);
1200 }
1201 
1202 /**
1203  * dao_go_data_vector:
1204  * @dao:
1205  * @ax:
1206  * @ay:
1207  * @bx:
1208  * @by:
1209  *
1210  * Returns: (transfer full):
1211  **/
1212 GOData	*
dao_go_data_vector(data_analysis_output_t * dao,int ax,int ay,int bx,int by)1213 dao_go_data_vector (data_analysis_output_t *dao, int ax, int ay,  int bx, int by)
1214 {
1215 	return gnm_go_data_vector_new_expr (dao->sheet, gnm_expr_top_new (dao_get_rangeref_full (dao, ax, ay, bx, by, dao->sheet)));
1216 }
1217 
1218 /**
1219  * dao_surrender_so:
1220  * @dao:
1221  *
1222  * Returns: (element-type GObject) (transfer full):
1223  **/
1224 GSList *
dao_surrender_so(data_analysis_output_t * dao)1225 dao_surrender_so (data_analysis_output_t *dao)
1226 {
1227 	GSList *l = dao->sos;
1228 	dao->sos = NULL;
1229 
1230 	return l;
1231 }
1232 
1233 void
dao_set_omit_so(data_analysis_output_t * dao,gboolean omit)1234 dao_set_omit_so (data_analysis_output_t *dao, gboolean omit)
1235 {
1236 	dao->omit_so = omit;
1237 }
1238 
1239 
1240 
1241 void
dao_set_merge(data_analysis_output_t * dao,int col1,int row1,int col2,int row2)1242 dao_set_merge (data_analysis_output_t *dao, int col1, int row1,
1243 	       int col2, int row2)
1244 {
1245 	GnmRange r;
1246 
1247 	range_init (&r, col1, row1, col2, row2);
1248 	if (adjust_range (dao, &r))
1249 		gnm_sheet_merge_add (dao->sheet, &r, TRUE, NULL);
1250 }
1251