Undo: fix problem with col widths after paste undo.
[gnumeric.git] / plugins / html / latex.c
blob0afc47b8c5d18ae190b0c3bdfb233215872275ca
1 /* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 /*
3 * latex.c
5 * Copyright (C) 1999, 2000 Rasca, Berlin
6 * EMail: thron@gmx.de
8 * Copyright (C) 2001 Adrian Custer, Berkeley
9 * email: acuster@nature.berkeley.edu
11 * Copyright (C) 2001-2014 Andreas J. Guelzow, Edmonton
12 * email: aguelzow@pyrshep.ca
14 * This program is free software; you can redistribute it and/or modify
15 * it under the terms of the GNU General Public License as published by
16 * the Free Software Foundation; either version 2 of the License, or
17 * (at your option) any later version.
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, see <https://www.gnu.org/licenses/>.
30 * This file contains the LaTeX2e plugin functions.
33 * The LaTeX2e functions are named:
34 * latex_file_save()
35 * latex_table_visible_file_save()
36 * latex_table_file_save
41 #include <gnumeric-config.h>
42 #include <gnumeric.h>
43 #include <gnumeric-conf.h>
44 #include "latex.h"
45 #include <goffice/goffice.h>
46 #include <workbook-view.h>
47 #include <workbook.h>
48 #include <sheet.h>
49 #include <sheet-merge.h>
50 #include <style.h>
51 #include <style-color.h>
52 #include <font.h>
53 #include <cell.h>
54 #include <gnm-format.h>
55 #include <style-border.h>
56 #include <sheet-style.h>
57 #include <parse-util.h>
58 #include <rendered-value.h>
59 #include <cellspan.h>
60 #include <print-info.h>
62 #include <locale.h>
63 #include <gsf/gsf-output.h>
64 #include <string.h>
66 typedef enum {
67 LATEX_NO_BORDER = 0,
68 LATEX_SINGLE_BORDER = 1,
69 LATEX_DOUBLE_BORDER = 2,
70 LATEX_MAX_BORDER
71 } latex_border_t;
73 typedef struct {
74 latex_border_t latex;
75 char const *vertical;
76 char const *horizontal;
77 } latex_border_translator_t;
79 /* the index into the following array is GnmStyleBorderType */
80 static latex_border_translator_t const border_styles[] = {
81 {LATEX_NO_BORDER, "", "~"},
82 {LATEX_SINGLE_BORDER, "|", "-"},
83 {LATEX_SINGLE_BORDER, "|", "-"},
84 {LATEX_SINGLE_BORDER, "|", "-"},
85 {LATEX_SINGLE_BORDER, "|", "-"},
86 {LATEX_DOUBLE_BORDER, "||","="},
87 {LATEX_DOUBLE_BORDER, "||","="},
88 {LATEX_SINGLE_BORDER, "|", "-"},
89 {LATEX_SINGLE_BORDER, "|", "-"},
90 {LATEX_SINGLE_BORDER, "|", "-"},
91 {LATEX_SINGLE_BORDER, "|", "-"},
92 {LATEX_SINGLE_BORDER, "|", "-"},
93 {LATEX_SINGLE_BORDER, "|", "-"},
94 {LATEX_NO_BORDER, "", ""}
97 typedef struct {
98 char const *p_1;
99 char const *p_2;
100 } latex_border_connectors_t;
103 static latex_border_connectors_t const conn_styles[LATEX_MAX_BORDER]
104 [LATEX_MAX_BORDER][LATEX_MAX_BORDER][LATEX_MAX_BORDER] = {
105 /* FIXME: once we are sure that none of the numbered */
106 /*entries are in fact needed we should removed the digits */
107 {{{{"",""}, { "",""}, { "",""}},
108 {{"",""}, { "|",""}, { "32",""}},
109 {{"",""}, { "11",""}, { "","|t:"}}},
110 {{{"",""}, { "",""}, { "",""}},
111 {{"","|"}, { "|",""}, { "33",""}},
112 {{"1",""}, { "13",""}, { "34",""}}},
113 {{{"",""}, { "",""}, { "|","|"}},
114 {{"","|b|"}, { "14",""}, { "|","|"}},
115 {{"","|b:"}, { "|b:",""}, { "|",":"}}}},
116 {{{{"",""}, { "",""}, { "",""}},
117 {{"",""}, { "|",""}, { "35",""}},
118 {{"","|"}, { "17",""}, { "36",""}}},
119 {{{"","|"}, { "|",""}, { "37",""}},
120 {{"|",""}, { "",""}, { "38",""}},
121 {{"4",""}, { "19",""}, { "39",""}}},
122 {{{"","|b|"}, { "20",""}, { "|","|"}},
123 {{"5",""}, { "21",""}, { "|","|"}},
124 {{"|b:",""}, { "22",""}, { "40",""}}}},
125 {{{{"",""}, { "23",""}, { ":t|",""}},
126 {{"|",""}, { "24",""}, { ":t|",""}},
127 {{"",""}, { "",""}, { ":t:",""}}},
128 {{{"7",""}, { "26",""}, { ":t|",""}},
129 {{"8",""}, { "27",""}, { "43",""}},
130 {{"",""}, { "",""}, { ":t:",""}}},
131 {{{":b|",""}, { "29",""}, { ":","|"}},
132 {{":b|",""}, { "30",""}, { ":|",""}},
133 {{":b:",""}, { ":b:",""}, { ":",":"}}}}
137 * latex_raw_str :
138 * @p: a pointer to a char, start of the string to be processed
139 * @output: output stream where the processed characters are written.
140 * @utf8: is this a utf8 string?
142 * @return:
143 * If @p is in form of \L{foo}, return the char pointer pointing to '}' of \L{foo}
144 * else return @p untouched;
146 * Check if @p is in form of \L{foo}.
147 * If it is, the exact "foo" will be put into @output, without any esacaping.
150 static char const *
151 latex_raw_str(char const *p, GsfOutput *output, gboolean utf8)
153 char const *p_begin, *p_orig = p;
154 int depth = 1;
155 if(strncasecmp(p, "\\L{", 3) == 0){
156 p += 3;
157 p_begin = p;
158 /* find the matching close bracket */
159 for(; *p; p = utf8 ? g_utf8_next_char(p) : p + 1){
160 switch(*p){ /* FIXME: how to put in unmatched brackets? */
161 case '{':
162 depth ++;
163 break;
164 case '}':
165 depth--;
166 if(depth == 0){
167 /* put the string beginning from p_begin to p to output */
168 gsf_output_write(output, p - p_begin, p_begin);
169 return p;
174 return p_orig;
179 * latex_fputs_utf :
181 * @p: a pointer to a char, start of the string to be processed.
182 * @output: output stream where the processed characters are written.
184 * This escapes any special LaTeX characters from the LaTeX engine,
185 * except the ones enclosed in "\L{" and "}".
186 * Re-ordered from Rasca's code to have most common first.
188 static void
189 latex_fputs_utf (char const *p, GsfOutput *output)
191 char const *rlt;
192 for (; *p; p = g_utf8_next_char (p)) {
193 switch (g_utf8_get_char (p)) {
195 /* These are the classic TeX symbols $ & % # _ { } (see Lamport, p.15) */
196 case '$': case '&': case '%': case '#':
197 case '_': case '{': case '}':
198 gsf_output_printf (output, "\\%c", *p);
199 break;
200 /* These are the other special characters ~ ^ \ (see Lamport, p.15) */
201 case '^': case '~':
202 gsf_output_printf (output, "\\%c{ }", *p);
203 break;
204 case '\\':
205 rlt = latex_raw_str(p, output, TRUE);
206 if(rlt == p)
207 gsf_output_puts (output, "$\\backslash$");
208 else
209 p = rlt;
210 break;
211 /* Are these available only in LaTeX through mathmode? */
212 case '>': case '<':
213 gsf_output_printf (output, "$%c$", *p);
214 break;
216 default:
217 gsf_output_write (output,
218 (g_utf8_next_char (p)) - p, p);
219 break;
225 * latex_math_fputs_utf :
227 * @p: a pointer to a char, start of the string to be processed.
228 * @output: output stream where the processed characters are written.
230 * This escapes any special LaTeX characters from the LaTeX engine,
231 * except the ones enclosed in "\L{" and "}".
233 * We assume that htis will be set in Mathematics mode.
235 static void
236 latex_math_fputs_utf (char const *p, GsfOutput *output)
238 char const *rlt;
239 for (; *p; p = g_utf8_next_char (p)) {
240 switch (g_utf8_get_char (p)) {
242 /* These are the classic TeX symbols $ & % # (see Lamport, p.15) */
243 case '$': case '&': case '%': case '#':
244 gsf_output_printf (output, "\\%c", *p);
245 break;
246 /* These are the other special characters ~ (see Lamport, p.15) */
247 case '~':
248 gsf_output_printf (output, "\\%c{ }", *p);
249 break;
250 case '\\':
251 rlt = latex_raw_str(p, output, TRUE);
252 if(rlt == p)
253 gsf_output_puts (output, "$\\backslash$");
254 else
255 p = rlt;
256 break;
257 default:
258 gsf_output_write (output,
259 (g_utf8_next_char (p)) - p, p);
260 break;
266 * latex_convert_latin_to_utf
268 * @text: string to convert
270 * return value needs to be freed with g_free
272 * call g_convert_with_fallback and also handle utf minus.
275 static char *
276 latex_convert_latin_to_utf (char const *text)
278 char * encoded_text = NULL;
280 gsize bytes_read;
281 gsize bytes_written;
283 if (g_utf8_strchr (text,-1, 0x2212) == NULL) {
284 encoded_text = g_convert_with_fallback
285 (text, strlen (text),
286 "ISO-8859-1", "UTF-8", (gchar *)"?",
287 &bytes_read, &bytes_written, NULL);
288 } else {
289 gunichar* ucs_string = NULL;
290 gunichar* this_unichar;
291 char *new_text;
292 glong items_read;
293 glong items_written;
295 ucs_string = g_utf8_to_ucs4_fast (text, -1, &items_written);
296 for (this_unichar = ucs_string; *this_unichar != '\0'; this_unichar++) {
297 if (*this_unichar == 0x2212)
298 *this_unichar = 0x002d;
300 new_text = g_ucs4_to_utf8 (ucs_string, -1, &items_read, &items_written, NULL);
301 g_free (ucs_string);
302 encoded_text = g_convert_with_fallback
303 (new_text, strlen (new_text),
304 "ISO-8859-1", "UTF-8", (gchar *)"?",
305 &bytes_read, &bytes_written, NULL);
306 g_free (new_text);
309 return encoded_text;
313 * latex_fputs_latin :
315 * @p: a pointer to a char, start of the string to be processed.
316 * @output: output stream where the processed characters are written.
318 * This escapes any special LaTeX characters from the LaTeX engine,
319 * except the ones enclosed in "\L{" and "}".
320 * Re-ordered from Rasca's code to have most common first.
322 static void
323 latex_fputs_latin (char const *text, GsfOutput *output)
325 char * encoded_text = NULL;
326 char const *p;
327 char const *rlt;
329 encoded_text = latex_convert_latin_to_utf (text);
331 for (p = encoded_text; *p; p++) {
332 switch (*p) {
334 /* These are the classic TeX symbols $ & % # _ { } (see Lamport, p.15) */
335 case '$': case '&': case '%': case '#':
336 case '_': case '{': case '}':
337 gsf_output_printf (output, "\\%c", *p);
338 break;
339 /* These are the other special characters ~ ^ \ (see Lamport, p.15) */
340 case '^': case '~':
341 gsf_output_printf (output, "\\%c{ }", *p);
342 break;
343 case '\\':
344 rlt = latex_raw_str(p, output, FALSE);
345 if(rlt == p)
346 gsf_output_puts (output, "$\\backslash$");
347 else
348 p = rlt;
349 break;
350 /* Are these available only in LaTeX through mathmode? */
351 case '>': case '<': case 'µ':
352 gsf_output_printf (output, "$%c$", *p);
353 break;
355 default:
356 gsf_output_write (output, 1, p);
357 break;
360 g_free (encoded_text);
364 * latex_math_fputs_latin :
366 * @p: a pointer to a char, start of the string to be processed.
367 * @output: output stream where the processed characters are written.
369 * This escapes any special LaTeX characters from the LaTeX engine,
370 * except the ones enclosed in "\L{" and "}".
372 * We assume that htis will be set in Mathematics mode.
374 static void
375 latex_math_fputs_latin (char const *text, GsfOutput *output)
377 char * encoded_text = NULL;
378 char const *p;
379 char const *rlt;
381 encoded_text = latex_convert_latin_to_utf (text);
383 for (p = encoded_text; *p; p++) {
384 switch (*p) {
386 /* These are the classic TeX symbols $ & % # (see Lamport, p.15) */
387 case '$': case '&': case '%': case '#':
388 gsf_output_printf (output, "\\%c", *p);
389 break;
390 /* These are the other special characters ~ (see Lamport, p.15) */
391 case '~':
392 gsf_output_printf (output, "\\%c{ }", *p);
393 break;
394 case '\\':
395 rlt = latex_raw_str(p, output, FALSE);
396 if(rlt == p)
397 gsf_output_puts (output, "$\\backslash$");
398 else
399 p = rlt;
400 break;
402 default:
403 gsf_output_write (output, 1, p);
404 break;
407 g_free (encoded_text);
410 static void
411 latex_fputs (char const *text, GsfOutput *output)
413 if (gnm_conf_get_plugin_latex_use_utf8 ())
414 latex_fputs_utf (text, output);
415 else
416 latex_fputs_latin (text, output);
419 static void
420 latex_math_fputs (char const *text, GsfOutput *output)
422 if (gnm_conf_get_plugin_latex_use_utf8 ())
423 latex_math_fputs_utf (text, output);
424 else
425 latex_math_fputs_latin (text, output);
428 static GnmValue *
429 cb_find_font_encodings (GnmCellIter const *iter, gboolean *fonts)
431 GnmCell *cell = iter->cell;
432 if (cell) {
433 char const *rs =
434 gnm_rendered_value_get_text
435 (gnm_cell_fetch_rendered_value (cell, TRUE));
436 while (*rs) {
437 gunichar ch = g_utf8_get_char (rs);
438 GUnicodeScript script = g_unichar_get_script (ch);
439 if (script > 0 && script <= G_UNICODE_SCRIPT_MANDAIC)
440 fonts [script] = 1;
441 rs = g_utf8_next_char (rs);
444 return NULL;
448 * latex2e_write_font_encodings writes
449 * \usepackage[T2A]{fontenc}
450 * in the presence of cyrillic text
453 static void
454 latex2e_write_font_encodings (GsfOutput *output, Sheet *sheet, GnmRange const *range)
456 gboolean *fonts = g_new0 (gboolean, G_UNICODE_SCRIPT_MANDAIC + 1);
458 sheet_foreach_cell_in_range
459 (sheet, CELL_ITER_IGNORE_BLANK | CELL_ITER_IGNORE_HIDDEN, range,
460 (CellIterFunc)&cb_find_font_encodings, fonts);
462 if (fonts[G_UNICODE_SCRIPT_CYRILLIC])
463 gsf_output_puts (output,
464 " \\usepackage[T2A]{fontenc}\n"
469 * latex2e_write_file_header:
471 * @output: Output stream where the cell contents will be written.
473 * This ouputs the LaTeX header. Kept separate for esthetics.
476 static void
477 latex2e_write_file_header(GsfOutput *output, Sheet *sheet, GnmRange const *range)
479 gboolean is_landscape = FALSE, use_utf8;
480 GtkPageOrientation orient = print_info_get_paper_orientation (sheet->print_info);
482 is_landscape = (orient == GTK_PAGE_ORIENTATION_LANDSCAPE ||
483 orient == GTK_PAGE_ORIENTATION_REVERSE_LANDSCAPE);
484 use_utf8 = gnm_conf_get_plugin_latex_use_utf8 ();
486 gsf_output_puts (output,
487 "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n"
488 "%% %%\n"
489 "%% This is the header of a LaTeX2e file exported from Gnumeric. %%\n"
490 "%% %%\n"
491 "%% This file can be compiled as it stands or included in another %%\n"
492 "%% LaTeX document. The table is based on the longtable package so %%\n"
493 "%% the longtable options (headers, footers...) can be set in the %%\n"
494 "%% preamble section below (see PRAMBLE). %%\n"
495 "%% %%\n"
496 "%% To include the file in another, the following two lines must be %%\n"
497 "%% in the including file: %%\n"
498 "%% \\def\\inputGnumericTable{} %%\n"
499 "%% at the beginning of the file and: %%\n"
500 "%% \\input{name-of-this-file.tex} %%\n"
501 "%% where the table is to be placed. Note also that the including %%\n"
502 "%% file must use the following packages for the table to be %%\n"
503 "%% rendered correctly: %%\n"
506 if (use_utf8)
507 gsf_output_puts (output,
508 "%% \\usepackage{ucs} %%\n"
509 "%% \\usepackage[utf8x]{inputenc} %%\n"
510 "%% \\usepackage[T2A]{fontenc} % if cyrillic is used %%\n"
512 else
513 gsf_output_puts (output,
514 "%% \\usepackage[latin1]{inputenc} %%\n"
517 gsf_output_puts (output,
518 "%% \\usepackage{color} %%\n"
519 "%% \\usepackage{array} %%\n"
520 "%% \\usepackage{longtable} %%\n"
521 "%% \\usepackage{calc} %%\n"
522 "%% \\usepackage{multirow} %%\n"
523 "%% \\usepackage{hhline} %%\n"
524 "%% \\usepackage{ifthen} %%\n"
525 "%% optionally (for landscape tables embedded in another document): %%\n"
526 "%% \\usepackage{lscape} %%\n"
527 "%% %%\n"
528 "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n"
529 "\n"
530 "\n"
531 "\n"
532 "%% This section checks if we are begin input into another file or %%\n"
533 "%% the file will be compiled alone. First use a macro taken from %%\n"
534 "%% the TeXbook ex 7.7 (suggestion of Han-Wen Nienhuys). %%\n"
535 "\\def\\ifundefined#1{\\expandafter\\ifx\\csname#1\\endcsname\\relax}\n"
536 "\n"
537 "\n"
538 "%% Check for the \\def token for inputed files. If it is not %%\n"
539 "%% defined, the file will be processed as a standalone and the %%\n"
540 "%% preamble will be used. %%\n"
541 "\\ifundefined{inputGnumericTable}\n"
542 "\n"
543 "%% We must be able to close or not the document at the end. %%\n"
544 " \\def\\gnumericTableEnd{\\end{document}}\n"
545 "\n"
546 "\n"
547 "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n"
548 "%% %%\n"
549 "%% This is the PREAMBLE. Change these values to get the right %%\n"
550 "%% paper size and other niceties. %%\n"
551 "%% %%\n"
552 "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n"
553 "\n"
555 if (is_landscape)
556 gsf_output_puts (output,
557 " \\documentclass[12pt%\n"
558 " ,landscape%\n"
559 " ]{report}\n"
561 else
562 gsf_output_puts (output,
563 " \\documentclass[12pt%\n"
564 " %,landscape%\n"
565 " ]{report}\n"
570 if (gnm_conf_get_plugin_latex_use_utf8 ()) {
571 gsf_output_puts (output,
572 " \\usepackage{ucs}\n"
573 " \\usepackage[utf8x]{inputenc}\n"
575 latex2e_write_font_encodings (output, sheet, range);
576 } else
577 gsf_output_puts (output,
578 " \\usepackage[latin1]{inputenc}\n"
581 gsf_output_puts (output,
582 " \\usepackage{fullpage}\n"
583 " \\usepackage{color}\n"
584 " \\usepackage{array}\n"
585 " \\usepackage{longtable}\n"
586 " \\usepackage{calc}\n"
587 " \\usepackage{multirow}\n"
588 " \\usepackage{hhline}\n"
589 " \\usepackage{ifthen}\n"
590 "\n"
591 " \\begin{document}\n"
592 "\n"
593 "\n"
594 "%% End of the preamble for the standalone. The next section is for %%\n"
595 "%% documents which are included into other LaTeX2e files. %%\n"
596 "\\else\n"
597 "\n"
598 "%% We are not a stand alone document. For a regular table, we will %%\n"
599 "%% have no preamble and only define the closing to mean nothing. %%\n"
600 " \\def\\gnumericTableEnd{}\n"
601 "\n"
602 "%% If we want landscape mode in an embedded document, comment out %%\n"
603 "%% the line above and uncomment the two below. The table will %%\n"
604 "%% begin on a new page and run in landscape mode. %%\n"
605 "% \\def\\gnumericTableEnd{\\end{landscape}}\n"
606 "% \\begin{landscape}\n"
607 "\n"
608 "\n"
609 "%% End of the else clause for this file being \\input. %%\n"
610 "\\fi\n"
611 "\n"
612 "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n"
613 "%% %%\n"
614 "%% The rest is the gnumeric table, except for the closing %%\n"
615 "%% statement. Changes below will alter the table\'s appearance. %%\n"
616 "%% %%\n"
617 "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n"
618 "\n"
619 "\\providecommand{\\gnumericmathit}[1]{#1} \n"
620 "%% Uncomment the next line if you would like your numbers to be in %%\n"
621 "%% italics if they are italizised in the gnumeric table. %%\n"
622 "%\\renewcommand{\\gnumericmathit}[1]{\\mathit{#1}}\n"
623 "\\providecommand{\\gnumericPB}[1]%\n"
624 "{\\let\\gnumericTemp=\\\\#1\\let\\\\=\\gnumericTemp\\hspace{0pt}}\n"
625 " \\ifundefined{gnumericTableWidthDefined}\n"
626 " \\newlength{\\gnumericTableWidth}\n"
627 " \\newlength{\\gnumericTableWidthComplete}\n"
628 " \\newlength{\\gnumericMultiRowLength}\n"
629 " \\global\\def\\gnumericTableWidthDefined{}\n"
630 " \\fi\n"
631 "%% The following setting protects this code from babel shorthands. %%\n"
632 " \\ifthenelse{\\isundefined{\\languageshorthands}}{}{\\languageshorthands{english}}"
633 "\n"
634 "%% The default table format retains the relative column widths of %%\n"
635 "%% gnumeric. They can easily be changed to c, r or l. In that case %%\n"
636 "%% you may want to comment out the next line and uncomment the one %%\n"
637 "%% thereafter %%\n"
638 "\\providecommand\\gnumbox{\\makebox[0pt]}\n"
639 "%%\\providecommand\\gnumbox[1][]{\\makebox}\n"
640 "\n"
641 "%% to adjust positions in multirow situations %%\n"
642 "\\setlength{\\bigstrutjot}{\\jot}\n"
643 "\\setlength{\\extrarowheight}{\\doublerulesep}\n"
644 "\n"
645 "%% The \\setlongtables command keeps column widths the same across %%\n"
646 "%% pages. Simply comment out next line for varying column widths. %%\n"
647 "\\setlongtables\n"
648 "\n"
654 * latex2e_write_table_header:
656 * @output: Output stream where the cell contents will be written.
657 * @num_cols: The number of columns in the table
659 * A convenience function that also helps make nicer code.
661 static void
662 latex2e_write_table_header(GsfOutput *output, int num_cols)
664 int col;
667 gsf_output_puts (output,
668 "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n"
669 "%% The longtable options. (Caption, headers... see Goosens, p.124) %%\n"
670 "%\t\\caption{The Table Caption.} \\\\ %\n"
671 "% \\hline % Across the top of the table.\n"
672 "%% The rest of these options are table rows which are placed on %%\n"
673 "%% the first, last or every page. Use \\multicolumn if you want. %%\n"
674 "\n"
675 "%% Header for the first page. %%\n"
678 gsf_output_printf (output, "%%\t\\multicolumn{%d}{c}{The First Header} \\\\ \\hline \n", num_cols);
679 gsf_output_printf (output, "%%\t\\multicolumn{1}{c}{colTag}\t%%Column 1\n");
680 for (col = 2 ; col < num_cols; col++)
681 gsf_output_printf (output, "%%\t&\\multicolumn{1}{c}{colTag}\t%%Column %d\n",col);
682 gsf_output_printf (output, "%%\t&\\multicolumn{1}{c}{colTag}\t\\\\ \\hline %%Last column\n");
683 gsf_output_printf (output, "%%\t\\endfirsthead\n\n");
685 gsf_output_printf (output, "%%%% The running header definition. %%%%\n");
686 gsf_output_printf (output, "%%\t\\hline\n");
687 gsf_output_printf (output, "%%\t\\multicolumn{%d}{l}{\\ldots\\small\\slshape continued} \\\\ \\hline\n", num_cols);
688 gsf_output_printf (output, "%%\t\\multicolumn{1}{c}{colTag}\t%%Column 1\n");
689 for (col = 2 ; col < num_cols; col++)
690 gsf_output_printf (output, "%%\t&\\multicolumn{1}{c}{colTag}\t%%Column %d\n",col);
691 gsf_output_printf (output, "%%\t&\\multicolumn{1}{c}{colTag}\t\\\\ \\hline %%Last column\n");
692 gsf_output_printf (output, "%%\t\\endhead\n\n");
694 gsf_output_printf (output, "%%%% The running footer definition. %%%%\n");
695 gsf_output_printf (output, "%%\t\\hline\n");
696 gsf_output_printf (output, "%%\t\\multicolumn{%d}{r}{\\small\\slshape continued\\ldots}", num_cols);
697 gsf_output_printf (output, " \\\\\n");
698 gsf_output_printf (output, "%%\t\\endfoot\n\n");
700 gsf_output_printf (output, "%%%% The ending footer definition. %%%%\n");
701 gsf_output_printf (output, "%%\t\\multicolumn{%d}{c}{That's all folks} \\\\ \\hline \n", num_cols);
702 gsf_output_printf (output, "%%\t\\endlastfoot\n");
703 gsf_output_puts (output, "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n\n");
708 * latex2e_find_vline:
710 * @col:
711 * @row:
712 * @sheet:
713 * @which_border: GnmStyleElement (MSTYLE_BORDER_LEFT or MSTYLE_BORDER_RIGHT)
715 * Determine the border style
718 static GnmStyleBorderType
719 latex2e_find_this_vline (int col, int row, Sheet *sheet, GnmStyleElement which_border)
721 GnmBorder const *border;
722 GnmStyle const *style;
724 if (col < 0 || row < 0)
725 return GNM_STYLE_BORDER_NONE;
727 style = sheet_style_get (sheet, col, row);
728 border = gnm_style_get_border (style, which_border);
730 if (!gnm_style_border_is_blank (border))
731 return border->line_type;
733 if (which_border == MSTYLE_BORDER_LEFT) {
734 if (col <= 0)
735 return GNM_STYLE_BORDER_NONE;
736 style = sheet_style_get (sheet, col - 1, row);
737 border = gnm_style_get_border (style, MSTYLE_BORDER_RIGHT);
738 return ((border == NULL) ? GNM_STYLE_BORDER_NONE : border->line_type);
739 } else {
740 if ((col+1) >= colrow_max (TRUE, sheet))
741 return GNM_STYLE_BORDER_NONE;
742 style = sheet_style_get (sheet, col + 1, row);
743 border = gnm_style_get_border (style, MSTYLE_BORDER_LEFT);
744 return ((border == NULL) ? GNM_STYLE_BORDER_NONE : border->line_type);
747 return GNM_STYLE_BORDER_NONE;
750 static GnmStyleBorderType
751 latex2e_find_vline (int col, int row, Sheet *sheet, GnmStyleElement which_border)
753 /* We are checking for NONE boreders first since there should only be a few merged ranges */
754 GnmStyleBorderType result = latex2e_find_this_vline (col, row, sheet, which_border);
755 GnmCellPos pos;
756 GnmRange const * range;
758 if (result == GNM_STYLE_BORDER_NONE)
759 return GNM_STYLE_BORDER_NONE;
761 pos.col = col;
762 pos.row = row;
763 range = gnm_sheet_merge_contains_pos (sheet, &pos);
765 if (range) {
766 if ((which_border == MSTYLE_BORDER_LEFT && col == range->start.col)
767 || (which_border == MSTYLE_BORDER_RIGHT&& col == range->end.col))
768 return result;
769 else
770 return GNM_STYLE_BORDER_NONE;
772 return result;
776 * latex2e_print_vert_border:
778 * @output: Output stream where the cell contents will be written.
779 * @clines: GnmStyleBorderType indicating the type of border
782 static void
783 latex2e_print_vert_border (GsfOutput *output, GnmStyleBorderType style)
785 g_return_if_fail (/* style >= 0 && */ style < G_N_ELEMENTS (border_styles));
787 gsf_output_printf (output, "%s", border_styles[style].vertical);
791 * latex2e_write_blank_multicolumn_cell:
793 * @output: output stream where the cell contents will be written.
794 * @star_col:
795 * @start_row:
796 * @num_merged_cols: an integer value of the number of columns to merge.
797 * @num_merged_rows: an integer value of the number of rows to merge.
798 * @sheet: the current sheet.
800 * This function creates all the LaTeX code for the cell of a table (i.e. all
801 * the code that might fall between two ampersands (&)), assuming that
802 * the cell is in fact NULL. We therefore have only to worry about a few
803 * formatting issues.
806 static void
807 latex2e_write_blank_multicolumn_cell (GsfOutput *output, int start_col,
808 G_GNUC_UNUSED int start_row,
809 int num_merged_cols, int num_merged_rows,
810 gint index,
811 GnmStyleBorderType *borders, Sheet *sheet)
813 int merge_width = 0;
814 GnmStyleBorderType left_border = GNM_STYLE_BORDER_NONE;
815 GnmStyleBorderType right_border = GNM_STYLE_BORDER_NONE;
817 if (num_merged_cols > 1 || num_merged_rows > 1) {
818 ColRowInfo const * ci;
819 int i;
821 for (i = 0; i < num_merged_cols; i++) {
822 ci = sheet_col_get_info (sheet, start_col + i);
823 merge_width += ci->size_pixels;
827 if (index == 0) {
828 left_border = *borders;
830 right_border = borders[index + num_merged_cols];
832 /* We only set up a multicolumn command if necessary */
833 if (num_merged_cols > 1) {
834 int i;
836 /* Open the multicolumn statement. */
837 gsf_output_printf (output, "\\multicolumn{%d}{", num_merged_cols);
839 if (left_border != GNM_STYLE_BORDER_NONE)
840 latex2e_print_vert_border (output, left_border);
842 if (num_merged_rows > 1) {
843 gsf_output_printf (output, "c");
844 } else {
845 gsf_output_printf (output, "p{");
846 for (i = 0; i < num_merged_cols; i++) {
847 gsf_output_printf (output, "\t\\gnumericCol%s+%%\n",
848 col_name (start_col + i));
850 gsf_output_printf (output, "\t\\tabcolsep*2*%i}", num_merged_cols - 1);
853 if (right_border != GNM_STYLE_BORDER_NONE)
854 latex2e_print_vert_border (output, right_border);
856 /*Close the right delimiter, as above. Also open the text delimiter.*/
857 gsf_output_printf (output,"}%%\n\t{");
858 } else if (left_border != GNM_STYLE_BORDER_NONE || right_border != GNM_STYLE_BORDER_NONE) {
860 /* Open the multicolumn statement. */
861 gsf_output_printf (output, "\\multicolumn{1}{");
863 if (left_border != GNM_STYLE_BORDER_NONE)
864 latex2e_print_vert_border (output, left_border);
866 /* Drop in the left hand format delimiter. */
867 gsf_output_printf (output, "p{\\gnumericCol%s}", col_name(start_col));
869 if (right_border != GNM_STYLE_BORDER_NONE)
870 latex2e_print_vert_border (output, right_border);
872 /*Close the right delimiter, as above. Also open the text delimiter.*/
873 gsf_output_printf (output,"}%%\n\t{");
877 if (num_merged_rows > 1) {
878 int i;
879 /* Open the multirow statement. */
880 gsf_output_printf (output, "\\setlength{\\gnumericMultiRowLength}{0pt}%%\n");
881 for (i = 0; i < num_merged_cols; i++) {
882 gsf_output_printf (output, "\t \\addtolength{\\gnumericMultiRowLength}{\\gnumericCol%s}%%\n", col_name (start_col + i));
883 if (i>0)
884 gsf_output_printf (output, "\t \\addtolength{\\gnumericMultiRowLength}{\\tabcolsep}%%\n");
886 gsf_output_printf (output, "\t \\multirow{%i}[%i]{\\gnumericMultiRowLength}{%%\n\t ", num_merged_rows, num_merged_rows/2);
888 /* Close the multirowtext. */
889 gsf_output_printf (output, "}");
892 /* Close the multicolumn text bracket. */
893 if (num_merged_cols > 1 || left_border != GNM_STYLE_BORDER_NONE
894 || right_border != GNM_STYLE_BORDER_NONE)
895 gsf_output_printf (output, "}");
897 /* And we are done. */
898 gsf_output_printf (output, "\n");
904 * latex2e_write_multicolumn_cell:
906 * @output: output stream where the cell contents will be written.
907 * @cell: the cell whose contents are to be written.
908 * @star_col:
909 * @num_merged_cols: an integer value of the number of columns to merge.
910 * @num_merged_rows: an integer value of the number of rows to merge.
911 * @sheet: the current sheet.
913 * This function creates all the LaTeX code for the cell of a table (i.e. all
914 * the code that might fall between two ampersands (&)).
916 * Note: we are _not_ putting single cell into \multicolumns since this
917 * makes it much more difficult to change column widths later on.
919 static void
920 latex2e_write_multicolumn_cell (GsfOutput *output, GnmCell *cell, int start_col,
921 int num_merged_cols, int num_merged_rows,
922 gint index,
923 GnmStyleBorderType *borders, Sheet *sheet)
925 char * rendered_string;
926 gushort r,g,b;
927 gboolean wrap = FALSE;
928 GOFormatFamily cell_format_family;
929 int merge_width = 0;
930 GnmStyleBorderType left_border = GNM_STYLE_BORDER_NONE;
931 GnmStyleBorderType right_border = GNM_STYLE_BORDER_NONE;
933 /* Print the cell according to its style. */
934 GnmStyle const *style = gnm_cell_get_style (cell);
935 gboolean hidden = gnm_style_get_contents_hidden (style);
937 g_return_if_fail (style != NULL);
939 if (num_merged_cols > 1 || num_merged_rows > 1) {
940 ColRowInfo const * ci;
941 int i;
943 for (i = 0; i < num_merged_cols; i++) {
944 ci = sheet_col_get_info (sheet, start_col + i);
945 merge_width += ci->size_pixels;
949 if (index == 0) {
950 left_border = *borders;
952 right_border = borders[index + num_merged_cols];
954 /* We only set up a multicolumn command if necessary */
955 if (num_merged_cols > 1) {
956 int i;
958 /* Open the multicolumn statement. */
959 gsf_output_printf (output, "\\multicolumn{%d}{", num_merged_cols);
961 if (left_border != GNM_STYLE_BORDER_NONE)
962 latex2e_print_vert_border (output, left_border);
964 if (num_merged_rows > 1) {
965 gsf_output_printf (output, "c");
966 } else {
967 gsf_output_printf (output, "p{");
968 for (i = 0; i < num_merged_cols; i++) {
969 gsf_output_printf (output, "\t\\gnumericCol%s+%%\n",
970 col_name (start_col + i));
972 gsf_output_printf (output, "\t\\tabcolsep*2*%i}", num_merged_cols - 1);
975 if (right_border != GNM_STYLE_BORDER_NONE)
976 latex2e_print_vert_border (output, right_border);
978 /*Close the right delimiter, as above. Also open the text delimiter.*/
979 gsf_output_printf (output,"}%%\n\t{");
980 } else if (left_border != GNM_STYLE_BORDER_NONE || right_border != GNM_STYLE_BORDER_NONE) {
982 /* Open the multicolumn statement. */
983 gsf_output_printf (output, "\\multicolumn{1}{");
985 if (left_border != GNM_STYLE_BORDER_NONE)
986 latex2e_print_vert_border (output, left_border);
988 /* Drop in the left hand format delimiter. */
989 gsf_output_printf (output, "p{\\gnumericCol%s}", col_name(start_col));
991 if (right_border != GNM_STYLE_BORDER_NONE)
992 latex2e_print_vert_border (output, right_border);
994 /*Close the right delimiter, as above. Also open the text delimiter.*/
995 gsf_output_printf (output,"}%%\n\t{");
999 if (num_merged_rows > 1) {
1000 int i;
1001 /* Open the multirow statement. */
1002 gsf_output_printf (output, "\\setlength{\\gnumericMultiRowLength}{0pt}%%\n");
1003 for (i = 0; i < num_merged_cols; i++) {
1004 gsf_output_printf (output, "\t \\addtolength{\\gnumericMultiRowLength}{\\gnumericCol%s}%%\n", col_name (start_col + i));
1005 if (i>0)
1006 gsf_output_printf (output, "\t \\addtolength{\\gnumericMultiRowLength}{\\tabcolsep}%%\n");
1008 gsf_output_printf (output,
1009 "\t \\multirow{%i}[%i]{\\gnumericMultiRowLength}"
1010 "{\\parbox{\\gnumericMultiRowLength}{%%\n\t ",
1011 num_merged_rows, num_merged_rows/2);
1015 /* Send the alignment of the cell through a routine to deal with
1016 * GNM_HALIGN_GENERAL and then deal with the three cases. */
1017 switch (gnm_style_default_halign (style, cell)) {
1018 case GNM_HALIGN_RIGHT:
1019 gsf_output_printf (output, "\\gnumericPB{\\raggedleft}");
1020 break;
1021 case GNM_HALIGN_DISTRIBUTED:
1022 case GNM_HALIGN_CENTER:
1023 case GNM_HALIGN_CENTER_ACROSS_SELECTION:
1024 gsf_output_printf (output, "\\gnumericPB{\\centering}");
1025 break;
1026 case GNM_HALIGN_LEFT:
1027 gsf_output_printf (output, "\\gnumericPB{\\raggedright}");
1028 break;
1029 case GNM_HALIGN_JUSTIFY:
1030 break;
1031 default:
1032 break;
1035 /* Check whether we should do word wrapping */
1036 wrap = gnm_style_get_wrap_text (style);
1038 /* if we don't wrap put it into an mbox, adjusted to width 0 to avoid moving */
1039 /* it to the second line of the parbox */
1040 if (!wrap)
1041 switch (gnm_style_default_halign (style, cell)) {
1042 case GNM_HALIGN_RIGHT:
1043 gsf_output_printf (output, "\\gnumbox[r]{");
1044 break;
1045 case GNM_HALIGN_DISTRIBUTED:
1046 case GNM_HALIGN_CENTER:
1047 case GNM_HALIGN_CENTER_ACROSS_SELECTION:
1048 gsf_output_printf (output, "\\gnumbox{");
1049 break;
1050 case GNM_HALIGN_LEFT:
1051 gsf_output_printf (output, "\\gnumbox[l]{");
1052 break;
1053 case GNM_HALIGN_JUSTIFY:
1054 gsf_output_printf (output, "\\gnumbox[s]{");
1055 break;
1056 default:
1057 gsf_output_printf (output, "\\makebox{");
1058 break;
1061 if (!gnm_cell_is_empty (cell)) {
1062 /* Check the foreground (text) colour. */
1063 GOColor fore = gnm_cell_get_render_color (cell);
1064 if (fore == 0)
1065 r = g = b = 0;
1066 else {
1067 r = GO_COLOR_UINT_R (fore);
1068 g = GO_COLOR_UINT_G (fore);
1069 b = GO_COLOR_UINT_B (fore);
1071 if (r != 0 || g != 0 || b != 0) {
1072 gchar buffer[7] = {0};
1073 gsf_output_printf (output, "{\\color[rgb]{");
1074 g_ascii_formatd (buffer, 7, "%.2f",r/255.0);
1075 gsf_output_printf (output, "%s,", buffer);
1076 g_ascii_formatd (buffer, 7, "%.2f",g/255.0);
1077 gsf_output_printf (output, "%s,", buffer);
1078 g_ascii_formatd (buffer, 7, "%.2f",b/255.0);
1079 gsf_output_printf (output, "%s", buffer);
1080 gsf_output_printf (output, "} ");
1083 /* Establish the font's style for the styles that can be addressed by LaTeX.
1084 * More complicated efforts (like changing fonts) are left to the user.
1087 if (hidden)
1088 gsf_output_printf (output, "\\phantom{");
1090 if (font_is_monospaced (style))
1091 gsf_output_printf (output, "\\texttt{");
1092 else if (font_is_sansserif (style))
1093 gsf_output_printf (output, "\\textsf{");
1094 if (gnm_style_get_font_bold (style))
1095 gsf_output_printf (output, "\\textbf{");
1096 if (gnm_style_get_font_italic (style))
1097 gsf_output_printf (output, "\\textit{");
1100 cell_format_family = go_format_get_family (gnm_cell_get_format (cell));
1101 if (cell_format_family == GO_FORMAT_NUMBER ||
1102 cell_format_family == GO_FORMAT_CURRENCY ||
1103 cell_format_family == GO_FORMAT_PERCENTAGE ||
1104 cell_format_family == GO_FORMAT_FRACTION ||
1105 cell_format_family == GO_FORMAT_SCIENTIFIC){
1106 gsf_output_printf (output, "$");
1107 if (gnm_style_get_font_italic(style))
1108 gsf_output_printf (output, "\\gnumericmathit{");
1110 /* Print the cell contents. */
1111 rendered_string = gnm_cell_get_rendered_text (cell);
1112 latex_math_fputs (rendered_string, output);
1113 g_free (rendered_string);
1115 if (gnm_style_get_font_italic(style))
1116 gsf_output_printf (output, "}");
1117 gsf_output_printf (output, "$");
1118 } else {
1119 /* Print the cell contents. */
1120 rendered_string = gnm_cell_get_rendered_text (cell);
1121 latex_fputs (rendered_string, output);
1122 g_free (rendered_string);
1125 /* Close the styles for the cell. */
1126 if (gnm_style_get_font_italic (style))
1127 gsf_output_printf (output, "}");
1128 if (gnm_style_get_font_bold (style))
1129 gsf_output_printf (output, "}");
1130 if (font_is_monospaced (style))
1131 gsf_output_printf (output, "}");
1132 else if (font_is_sansserif (style))
1133 gsf_output_printf (output, "}");
1134 if (hidden)
1135 gsf_output_printf (output, "}");
1136 if (r != 0 || g != 0 || b != 0)
1137 gsf_output_printf (output, "}");
1140 /* if we don't wrap close the mbox */
1141 if (!wrap)
1142 gsf_output_printf (output, "}");
1144 /* Close the multirowtext. */
1145 if (num_merged_rows > 1)
1146 gsf_output_printf (output, "}}");
1148 /* Close the multicolumn text bracket. */
1149 if (num_merged_cols > 1 || left_border != GNM_STYLE_BORDER_NONE
1150 || right_border != GNM_STYLE_BORDER_NONE)
1151 gsf_output_printf (output, "}");
1153 /* And we are done. */
1154 gsf_output_printf (output, "\n");
1159 * latex2e_find_hhlines :
1161 * @clines: array of GnmStyleBorderType* indicating the type of border
1162 * @length: (remaining) positions in clines
1163 * @col:
1164 * @row:
1165 * @sheet:
1167 * Determine the border style
1171 static gboolean
1172 latex2e_find_hhlines (GnmStyleBorderType *clines, G_GNUC_UNUSED int length, int col, int row,
1173 Sheet *sheet, GnmStyleElement type)
1175 GnmStyle const *style;
1176 GnmBorder const *border;
1177 GnmRange const *range;
1178 GnmCellPos pos;
1180 style = sheet_style_get (sheet, col, row);
1181 border = gnm_style_get_border (style, type);
1182 if (gnm_style_border_is_blank (border))
1183 return FALSE;
1184 clines[0] = border->line_type;
1186 pos.col = col;
1187 pos.row = row;
1188 range = gnm_sheet_merge_contains_pos (sheet, &pos);
1189 if (range) {
1190 if ((type == MSTYLE_BORDER_TOP && row > range->start.row)
1191 || (type == MSTYLE_BORDER_BOTTOM&& row < range->end.row)) {
1192 clines[0] = GNM_STYLE_BORDER_NONE;
1193 return FALSE;
1197 return TRUE;
1202 * latex2e_print_hhline :
1204 * @output: output stream where the cell contents will be written.
1205 * @clines: an array of GnmStyleBorderType* indicating the type of border
1206 * @n: the number of elements in clines
1208 * This procedure prints an hhline command according to the content
1209 * of clines.
1212 static void
1213 latex2e_print_hhline (GsfOutput *output, GnmStyleBorderType *clines, int n, GnmStyleBorderType *prev_vert,
1214 GnmStyleBorderType *next_vert)
1216 int col;
1217 gsf_output_printf (output, "\\hhline{");
1218 gsf_output_printf (output, "%s", conn_styles[LATEX_NO_BORDER]
1219 [prev_vert ? border_styles[prev_vert[0]].latex : LATEX_NO_BORDER]
1220 [border_styles[clines[0]].latex]
1221 [next_vert ? border_styles[next_vert[0]].latex : LATEX_NO_BORDER].p_1);
1222 gsf_output_printf (output, "%s", conn_styles[LATEX_NO_BORDER]
1223 [prev_vert ? border_styles[prev_vert[0]].latex : LATEX_NO_BORDER]
1224 [border_styles[clines[0]].latex]
1225 [next_vert ? border_styles[next_vert[0]].latex : LATEX_NO_BORDER].p_2);
1226 for (col = 0; col < n - 1; col++) {
1227 gsf_output_printf (output, "%s", border_styles[clines[col]].horizontal);
1228 gsf_output_printf (output, "%s", conn_styles[border_styles[clines[col]].latex]
1229 [prev_vert ? border_styles[prev_vert[col + 1]].latex :
1230 LATEX_NO_BORDER]
1231 [border_styles[clines[col+1]].latex]
1232 [next_vert ? border_styles[next_vert[col + 1]].latex :
1233 LATEX_NO_BORDER].p_1);
1234 gsf_output_printf (output, "%s", conn_styles[border_styles[clines[col]].latex]
1235 [prev_vert ? border_styles[prev_vert[col + 1]].latex :
1236 LATEX_NO_BORDER]
1237 [border_styles[clines[col+1]].latex]
1238 [next_vert ? border_styles[next_vert[col + 1]].latex :
1239 LATEX_NO_BORDER].p_2);
1241 gsf_output_printf (output, "%s", border_styles[clines[n - 1]].horizontal);
1242 gsf_output_printf (output, "%s", conn_styles[border_styles[clines[n - 1]].latex]
1243 [prev_vert ? border_styles[prev_vert[n]].latex : LATEX_NO_BORDER]
1244 [LATEX_NO_BORDER]
1245 [next_vert ? border_styles[next_vert[n]].latex :
1246 LATEX_NO_BORDER].p_1);
1247 gsf_output_printf (output, "%s", conn_styles[border_styles[clines[n - 1]].latex]
1248 [prev_vert ? border_styles[prev_vert[n]].latex : LATEX_NO_BORDER]
1249 [LATEX_NO_BORDER]
1250 [next_vert ? border_styles[next_vert[n]].latex :
1251 LATEX_NO_BORDER].p_2);
1253 gsf_output_printf (output, "}\n");
1256 static GnmRange
1257 file_saver_sheet_get_extent (Sheet *sheet)
1259 GnmRangeRef *range
1260 = g_object_get_data (G_OBJECT (sheet->workbook),
1261 "ssconvert-range");
1262 if (range) {
1263 Sheet *start_sheet, *end_sheet;
1264 GnmEvalPos ep;
1265 GnmRange r;
1267 gnm_rangeref_normalize (range,
1268 eval_pos_init_sheet (&ep, sheet),
1269 &start_sheet, &end_sheet,
1270 &r);
1271 if (start_sheet == sheet)
1272 return r;
1274 return sheet_get_extent (sheet, TRUE, TRUE);
1278 * latex_file_save : The LaTeX2e exporter plugin function.
1280 * @FileSaver: New structure for file plugins. I don't understand.
1281 * @IOcontext: currently not used but reserved for the future.
1282 * @WorkbookView: this provides the way to access the sheet being exported.
1283 * @filename: where we'll write.
1285 * This writes the top sheet of a Gnumeric workbook to a LaTeX2e longtable. We
1286 * check for merges here, then call the function latex2e_write_multicolum_cell()
1287 * to render the format and contents of the cell.
1289 void
1290 latex_file_save (G_GNUC_UNUSED GOFileSaver const *fs, G_GNUC_UNUSED GOIOContext *io_context,
1291 WorkbookView const *wb_view, GsfOutput *output)
1293 GnmCell *cell;
1294 Sheet *current_sheet;
1295 GnmRange total_range;
1296 GnmRange const *merge_range;
1297 int row, col, num_cols, length;
1298 int num_merged_cols, num_merged_rows;
1299 GnmStyleBorderType *clines, *this_clines;
1300 GnmStyleBorderType *prev_vert = NULL, *next_vert = NULL, *this_vert;
1301 gboolean needs_hline;
1303 /* Get the topmost sheet and its range from the plugin function argument. */
1304 current_sheet = wb_view_cur_sheet(wb_view);
1305 total_range = file_saver_sheet_get_extent (current_sheet);
1307 /* This is the preamble of the LaTeX2e file. */
1308 latex2e_write_file_header(output, current_sheet, &total_range);
1310 num_cols = total_range.end.col - total_range.start.col + 1;
1312 gsf_output_printf (output, "\\setlength\\gnumericTableWidth{%%\n");
1313 for (col = total_range.start.col; col <= total_range.end.col; col++) {
1314 ColRowInfo const * ci;
1315 ci = sheet_col_get_info (current_sheet, col);
1316 gsf_output_printf (output, "\t%ipt+%%\n", ci->size_pixels * 10 / 12);
1318 gsf_output_printf (output, "0pt}\n\\def\\gumericNumCols{%i}\n", num_cols);
1320 gsf_output_puts (output, ""
1321 "\\setlength\\gnumericTableWidthComplete{\\gnumericTableWidth+%\n"
1322 " \\tabcolsep*\\gumericNumCols*2+\\arrayrulewidth*\\gumericNumCols}\n"
1323 "\\ifthenelse{\\lengthtest{\\gnumericTableWidthComplete > \\linewidth}}%\n"
1324 " {\\def\\gnumericScale{\\ratio{\\linewidth-%\n"
1325 " \\tabcolsep*\\gumericNumCols*2-%\n"
1326 " \\arrayrulewidth*\\gumericNumCols}%\n"
1327 "{\\gnumericTableWidth}}}%\n"
1328 "{\\def\\gnumericScale{1}}\n"
1329 "\n"
1330 "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n"
1331 "%% %%\n"
1332 "%% The following are the widths of the various columns. We are %%\n"
1333 "%% defining them here because then they are easier to change. %%\n"
1334 "%% Depending on the cell formats we may use them more than once. %%\n"
1335 "%% %%\n"
1336 "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n"
1337 "\n"
1340 for (col = total_range.start.col; col <= total_range.end.col; col++) {
1341 ColRowInfo const * ci;
1342 char const *colname = col_name (col);
1344 ci = sheet_col_get_info (current_sheet, col);
1345 gsf_output_printf (output, "\\ifthenelse{\\isundefined{\\gnumericCol%s}}"
1346 "{\\newlength{\\gnumericCol%s}}{}\\settowidth{\\gnumericCol%s}"
1347 "{\\begin{tabular}{@{}p{%ipt*\\gnumericScale}@{}}x\\end{tabular}}\n",
1348 colname, colname, colname, ci->size_pixels * 10 / 12);
1351 /* Start outputting the table. */
1352 gsf_output_printf (output, "\n\\begin{longtable}[c]{%%\n");
1353 for (col = total_range.start.col; col <= total_range.end.col; col++) {
1354 gsf_output_printf (output, "\tb{\\gnumericCol%s}%%\n", col_name (col));
1356 gsf_output_printf (output, "\t}\n\n");
1358 /* Output the table header. */
1359 latex2e_write_table_header (output, num_cols);
1362 /* Step through the sheet, writing cells as appropriate. */
1363 for (row = total_range.start.row; row <= total_range.end.row; row++) {
1364 ColRowInfo const * ri;
1365 ri = sheet_row_get_info (current_sheet, row);
1366 if (ri->needs_respan)
1367 row_calc_spans ((ColRowInfo *) ri, row, current_sheet);
1369 /* We need to check for horizontal borders at the top of this row */
1370 length = num_cols;
1371 clines = g_new0 (GnmStyleBorderType, length);
1372 needs_hline = FALSE;
1373 this_clines = clines;
1374 for (col = total_range.start.col; col <= total_range.end.col; col++) {
1375 needs_hline = latex2e_find_hhlines (this_clines, length, col, row,
1376 current_sheet, MSTYLE_BORDER_TOP)
1377 || needs_hline;
1378 this_clines ++;
1379 length--;
1381 /* or at the bottom of the previous */
1382 if (row > total_range.start.row) {
1383 length = num_cols;
1384 this_clines = clines;
1385 for (col = total_range.start.col; col <= total_range.end.col; col++) {
1386 needs_hline = latex2e_find_hhlines (this_clines, length, col,
1387 row - 1, current_sheet,
1388 MSTYLE_BORDER_BOTTOM)
1389 || needs_hline;
1390 this_clines ++;
1391 length--;
1394 /* We also need to know vertical borders */
1395 /* We do this here rather than as we output the cells since */
1396 /* we need to know the right connectors! */
1397 prev_vert = next_vert;
1398 next_vert = g_new0 (GnmStyleBorderType, num_cols + 1);
1399 this_vert = next_vert;
1400 *this_vert = latex2e_find_vline (total_range.start.col, row,
1401 current_sheet, MSTYLE_BORDER_LEFT);
1402 this_vert++;
1403 for (col = total_range.start.col; col <= total_range.end.col; col++) {
1404 *this_vert = latex2e_find_vline (col, row, current_sheet,
1405 MSTYLE_BORDER_RIGHT);
1406 this_vert ++;
1409 if (needs_hline)
1410 latex2e_print_hhline (output, clines, num_cols, prev_vert, next_vert);
1411 g_free (clines);
1413 for (col = total_range.start.col; col <= total_range.end.col; col++) {
1414 GnmCellPos pos;
1416 pos.col = col;
1417 pos.row = row;
1419 /* Get the cell. */
1420 cell = sheet_cell_get (current_sheet, col, row);
1422 /* Check if we are not the first cell in the row.*/
1423 if (col != total_range.start.col)
1424 gsf_output_printf (output, "\t&");
1425 else
1426 gsf_output_printf (output, "\t ");
1428 /* Check a merge. */
1429 merge_range = gnm_sheet_merge_is_corner (current_sheet, &pos);
1430 if (merge_range == NULL) {
1431 if (gnm_cell_is_empty(cell))
1432 latex2e_write_blank_multicolumn_cell(output, col, row,
1433 1, 1,
1434 col - total_range.start.col,
1435 next_vert, current_sheet);
1436 else
1437 latex2e_write_multicolumn_cell(output, cell, col,
1438 1, 1,
1439 col - total_range.start.col,
1440 next_vert, current_sheet);
1441 continue;
1444 /* Get the extent of the merge. */
1445 num_merged_cols = merge_range->end.col - merge_range->start.col + 1;
1446 num_merged_rows = merge_range->end.row - merge_range->start.row + 1;
1448 if (gnm_cell_is_empty(cell))
1449 latex2e_write_blank_multicolumn_cell(output, col, row,
1450 num_merged_cols,
1451 num_merged_rows,
1452 col - total_range.start.col,
1453 next_vert, current_sheet);
1454 else
1455 latex2e_write_multicolumn_cell(output, cell, col, num_merged_cols,
1456 num_merged_rows,
1457 col - total_range.start.col,
1458 next_vert, current_sheet);
1459 col += (num_merged_cols - 1);
1460 continue;
1462 gsf_output_printf (output, "\\\\\n");
1463 g_free (prev_vert);
1466 /* We need to check for horizontal borders at the bottom of the last row */
1467 clines = g_new0 (GnmStyleBorderType, total_range.end.col - total_range.start.col + 1);
1468 needs_hline = FALSE;
1469 /* In case that we are at the very bottom of the sheet we can not */
1470 /* check on the next line! */
1471 if (row < colrow_max (FALSE, current_sheet)) {
1472 length = num_cols;
1473 this_clines = clines;
1474 for (col = total_range.start.col; col <= total_range.end.col; col++) {
1475 needs_hline = latex2e_find_hhlines (this_clines, length, col, row,
1476 current_sheet, MSTYLE_BORDER_TOP)
1477 || needs_hline;
1478 this_clines ++;
1479 length--;
1482 length = num_cols;
1483 this_clines = clines;
1484 for (col = total_range.start.col; col <= total_range.end.col; col++) {
1485 needs_hline = latex2e_find_hhlines (this_clines, length, col,
1486 row - 1, current_sheet,
1487 MSTYLE_BORDER_BOTTOM)
1488 || needs_hline;
1489 this_clines ++;
1490 length--;
1492 if (needs_hline)
1493 latex2e_print_hhline (output, clines, num_cols, next_vert, NULL);
1494 g_free (clines);
1496 g_free (next_vert);
1498 gsf_output_puts (output, "\\end{longtable}\n\n"
1499 "\\ifthenelse{\\isundefined{\\languageshorthands}}"
1500 "{}{\\languageshorthands{\\languagename}}\n"
1501 "\\gnumericTableEnd\n");
1506 * latex2e_table_cell:
1508 * @output: output stream where the cell contents will be written.
1509 * @cell: the cell whose contents are to be written.
1511 * This function creates all the LaTeX code for the cell of a table (i.e. all
1512 * the code that might fall between two ampersands (&)).
1515 static void
1516 latex2e_table_write_cell (GsfOutput *output, GnmCell *cell)
1518 GnmStyle const *style = gnm_cell_get_style (cell);
1520 if (gnm_style_get_contents_hidden (style))
1521 return;
1523 if (!gnm_cell_is_empty (cell)) {
1524 char * rendered_string;
1526 rendered_string = gnm_cell_get_rendered_text (cell);
1527 latex_fputs (rendered_string, output);
1528 g_free (rendered_string);
1534 * latex2e_table_write_file_header:
1536 * @output: Output stream where the cell contents will be written.
1538 * This ouputs the LaTeX header. Kept separate for esthetics.
1541 static void
1542 latex2e_table_write_file_header(GsfOutput *output)
1544 gsf_output_puts (output,
1545 "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n"
1546 "%% %%\n"
1547 "%% This is a LaTeX2e table fragment exported from Gnumeric. %%\n"
1548 "%% %%\n"
1549 "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n"
1554 * latex_table_file_save : The LaTeX2e exporter plugin function.
1556 * @WorkbookView: this provides the way to access the sheet being exported.
1557 * @outpu: where we'll write.
1558 * @all: Whether to write all rows or just the visible ones.
1560 * This writes the top sheet of a Gnumeric workbook as the content of a latex table environment.
1561 * We try to avoid all formatting.
1563 static void
1564 latex_table_file_save_impl (WorkbookView const *wb_view, GsfOutput *output, gboolean all)
1566 GnmCell *cell;
1567 Sheet *current_sheet;
1568 GnmRange total_range;
1569 int row, col;
1571 /* This is the preamble of the LaTeX2e file. */
1572 latex2e_table_write_file_header(output);
1574 /* Get the topmost sheet and its range from the plugin function argument. */
1575 current_sheet = wb_view_cur_sheet(wb_view);
1576 total_range = file_saver_sheet_get_extent (current_sheet);
1578 /* Step through the sheet, writing cells as appropriate. */
1579 for (row = total_range.start.row; row <= total_range.end.row; row++) {
1580 ColRowInfo const * ri;
1581 ri = sheet_row_get_info (current_sheet, row);
1582 if (all || ri->visible) {
1583 if (ri->needs_respan)
1584 row_calc_spans ((ColRowInfo *) ri, row, current_sheet);
1586 for (col = total_range.start.col; col <= total_range.end.col; col++) {
1587 /* Get the cell. */
1588 cell = sheet_cell_get (current_sheet, col, row);
1590 /* Check if we are not the first cell in the row.*/
1591 if (col != total_range.start.col)
1592 gsf_output_printf (output, "\t&");
1594 if (gnm_cell_is_empty (cell))
1595 continue;
1597 latex2e_table_write_cell(output, cell);
1599 gsf_output_printf (output, "\\\\\n");
1605 * latex_table_file_save : The LaTeX2e exporter plugin function.
1607 * @FileSaver: New structure for file plugins. I don't understand.
1608 * @IOcontext: currently not used but reserved for the future.
1609 * @WorkbookView: this provides the way to access the sheet being exported.
1610 * @output: where we'll write.
1612 * This writes the top sheet of a Gnumeric workbook as the content of a latex table environment.
1613 * We try to avoid all formatting.
1615 void
1616 latex_table_file_save (G_GNUC_UNUSED GOFileSaver const *fs,
1617 G_GNUC_UNUSED GOIOContext *io_context,
1618 WorkbookView const *wb_view, GsfOutput *output)
1620 latex_table_file_save_impl (wb_view, output, TRUE);
1624 * latex_table_visible_file_save : The LaTeX2e exporter plugin function.
1626 * @FileSaver: New structure for file plugins. I don't understand.
1627 * @IOcontext: currently not used but reserved for the future.
1628 * @WorkbookView: this provides the way to access the sheet being exported.
1629 * @output: where we'll write.
1631 * This writes the top sheet of a Gnumeric workbook as the content of a latex table environment.
1632 * We try to avoid all formatting.
1634 void
1635 latex_table_visible_file_save (G_GNUC_UNUSED GOFileSaver const *fs,
1636 G_GNUC_UNUSED GOIOContext *io_context,
1637 WorkbookView const *wb_view, GsfOutput *output)
1639 latex_table_file_save_impl (wb_view, output, FALSE);