ssconvert: enable --export-file-per-sheet for html and latex.
[gnumeric.git] / plugins / html / html.c
blobf400c7ad52c39c521106e1281b72367331b1d620
1 /* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 /*
3 * html.c
5 * Copyright (C) 1999, 2000 Rasca, Berlin
6 * EMail: thron@gmx.de
7 * Copyright (c) 2001-2013 Andreas J. Guelzow
8 * EMail: aguelzow@pyrshep.ca
9 * Copyright 2013 Morten Welinder <terra@gnone.org>
11 * Contributors :
12 * Almer. S. Tigelaar <almer1@dds.nl>
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/>.
28 #include <gnumeric-config.h>
29 #include <gnumeric.h>
30 #include <goffice/goffice.h>
31 #include "workbook-view.h"
32 #include "workbook.h"
33 #include "sheet-style.h"
34 #include "style.h"
35 #include "style-color.h"
36 #include "html.h"
37 #include "cell.h"
38 #include "sheet.h"
39 #include "sheet-merge.h"
40 #include "value.h"
41 #include "font.h"
42 #include "cellspan.h"
43 #include "style-border.h"
44 #include <rendered-value.h>
45 #include "style.h"
46 #include "hlink.h"
48 #include <gsf/gsf-output.h>
49 #include <string.h>
51 #define SHEET_SELECTION_KEY "sheet-selection"
54 * html_version_t:
56 * version selector
59 typedef enum {
60 HTML40 = 0,
61 HTML32 = 1,
62 HTML40F = 2,
63 XHTML = 3
64 } html_version_t;
67 * html_print_encoded:
69 * @output: the stream
70 * @str: the string
72 * print the string to output encoded all special chars
75 static void
76 html_print_encoded (GsfOutput *output, char const *str)
78 gunichar c;
80 if (str == NULL)
81 return;
82 for (; *str != '\0' ; str = g_utf8_next_char (str)) {
83 switch (*str) {
84 case '<':
85 gsf_output_puts (output, "&lt;");
86 break;
87 case '>':
88 gsf_output_puts (output, "&gt;");
89 break;
90 case '&':
91 gsf_output_puts (output, "&amp;");
92 break;
93 case '\"':
94 gsf_output_puts (output, "&quot;");
95 break;
96 case '\n':
97 gsf_output_puts (output, "<br>\n");
98 break;
99 case '\r':
100 gsf_output_puts (output, "<br>\r");
101 if( *(str+1) == '\n' ) {
102 gsf_output_puts (output, "\n");
103 str++;
105 break;
106 default:
107 c = g_utf8_get_char (str);
108 if (((c >= 0x20) && (c < 0x80)) ||
109 (c == '\n') || (c == '\r') || (c == '\t'))
110 gsf_output_write (output, 1, str);
111 else
112 gsf_output_printf (output, "&#%u;", c);
113 break;
118 static void
119 html_get_text_color (GnmCell *cell, GnmStyle const *style, guint *r, guint *g, guint *b)
121 GOColor fore = gnm_cell_get_render_color (cell);
123 if (fore == 0)
124 *r = *g = *b = 0;
125 else {
126 *r = GO_COLOR_UINT_R (fore);
127 *g = GO_COLOR_UINT_G (fore);
128 *b = GO_COLOR_UINT_B (fore);
131 static void
132 html_get_back_color (GnmStyle const *style, guint *r, guint *g, guint *b)
134 GnmColor const *color = gnm_style_get_back_color (style);
135 *r = GO_COLOR_UINT_R (color->go_color);
136 *g = GO_COLOR_UINT_G (color->go_color);
137 *b = GO_COLOR_UINT_B (color->go_color);
140 /*****************************************************************************/
143 static void
144 cb_html_add_chars (GsfOutput *output, char const *text, int len)
146 char * str;
148 g_return_if_fail (len > 0);
150 str = g_strndup (text, len);
151 html_print_encoded (output, str);
152 g_free (str);
155 static char const *
156 cb_html_attrs_as_string (GsfOutput *output, PangoAttribute *a, html_version_t version)
158 /* PangoColor const *c; */
159 char const *closure = NULL;
161 switch (a->klass->type) {
162 case PANGO_ATTR_FAMILY :
163 break; /* ignored */
164 case PANGO_ATTR_SIZE :
165 break; /* ignored */
166 case PANGO_ATTR_RISE:
167 if (((PangoAttrInt *)a)->value > 5) {
168 gsf_output_puts (output, "<sup>");
169 closure = "</sup>";
170 } else if (((PangoAttrInt *)a)->value < -5) {
171 gsf_output_puts (output, "<sub>");
172 closure = "</sub>";
174 break;
175 case PANGO_ATTR_STYLE :
176 if (((PangoAttrInt *)a)->value == PANGO_STYLE_ITALIC) {
177 gsf_output_puts (output, "<i>");
178 closure = "</i>";
180 break;
181 case PANGO_ATTR_WEIGHT :
182 if (((PangoAttrInt *)a)->value > 600){
183 gsf_output_puts (output, "<b>");
184 closure = "</b>";
186 break;
187 case PANGO_ATTR_STRIKETHROUGH :
188 if (((PangoAttrInt *)a)->value == 1) {
189 if (version == HTML32) {
190 gsf_output_puts (output, "<strike>");
191 closure = "</strike>";
192 } else {
193 gsf_output_puts
194 (output,
195 "<span style=\"text-decoration: "
196 "line-through;\">");
197 closure = "</span>";
200 break;
201 case PANGO_ATTR_UNDERLINE :
202 if ((version != HTML40) &&
203 (((PangoAttrInt *)a)->value != PANGO_UNDERLINE_NONE)) {
204 gsf_output_puts (output, "<u>");
205 closure = "</u>";
207 break;
208 case PANGO_ATTR_FOREGROUND :
209 /* c = &((PangoAttrColor *)a)->color; */
210 /* g_string_append_printf (accum, "[color=%02xx%02xx%02x", */
211 /* ((c->red & 0xff00) >> 8), */
212 /* ((c->green & 0xff00) >> 8), */
213 /* ((c->blue & 0xff00) >> 8)); */
214 break;/* ignored */
215 default :
216 if (a->klass->type ==
217 go_pango_attr_subscript_get_attr_type ()) {
218 if (((GOPangoAttrSubscript *)a)->val) {
219 gsf_output_puts (output, "<sub>");
220 closure = "</sub>";
222 } else if (a->klass->type ==
223 go_pango_attr_superscript_get_attr_type ()) {
224 if (((GOPangoAttrSuperscript *)a)->val) {
225 gsf_output_puts (output, "<sup>");
226 closure = "</sup>";
229 break; /* ignored */
232 return closure;
235 static void
236 html_new_markup (GsfOutput *output, const PangoAttrList *markup, char const *text,
237 html_version_t version)
239 int handled = 0;
240 PangoAttrIterator * iter;
241 int from, to;
242 int len = strlen (text);
243 GString *closure = g_string_new ("");
245 iter = pango_attr_list_get_iterator ((PangoAttrList *) markup);
247 do {
248 GSList *list, *l;
250 g_string_erase (closure, 0, -1);
251 pango_attr_iterator_range (iter, &from, &to);
252 from = (from > len) ? len : from; /* Since "from" can be really big! */
253 to = (to > len) ? len : to; /* Since "to" can be really big! */
254 if (from > handled)
255 cb_html_add_chars (output, text + handled, from - handled);
256 list = pango_attr_iterator_get_attrs (iter);
257 for (l = list; l != NULL; l = l->next) {
258 char const *result = cb_html_attrs_as_string (output, l->data, version);
259 if (result != NULL)
260 g_string_prepend (closure, result);
262 g_slist_free (list);
263 if (to > from)
264 cb_html_add_chars (output, text + from, to - from);
265 gsf_output_puts (output, closure->str);
266 handled = to;
267 } while (pango_attr_iterator_next (iter));
269 g_string_free (closure, TRUE);
270 pango_attr_iterator_destroy (iter);
272 return;
276 /*****************************************************************************/
278 static void
279 html_write_cell_content (GsfOutput *output, GnmCell *cell, GnmStyle const *style, html_version_t version)
281 guint r = 0;
282 guint g = 0;
283 guint b = 0;
284 char *rendered_string;
285 gboolean hidden = gnm_style_get_contents_hidden (style);
286 GnmHLink* hlink = gnm_style_get_hlink (style);
287 const guchar* hlink_target = NULL;
289 if (hlink && GNM_IS_HLINK_URL (hlink)) {
290 hlink_target = gnm_hlink_get_target (hlink);
293 if (version == HTML32 && hidden)
294 gsf_output_puts (output, "<!-- 'HIDDEN DATA' -->");
295 else {
296 if (style != NULL) {
297 if (gnm_style_get_font_italic (style))
298 gsf_output_puts (output, "<i>");
299 if (gnm_style_get_font_bold (style))
300 gsf_output_puts (output, "<b>");
301 if (gnm_style_get_font_uline (style) != UNDERLINE_NONE)
302 gsf_output_puts (output, "<u>");
303 if (font_is_monospaced (style))
304 gsf_output_puts (output, "<tt>");
305 if (gnm_style_get_font_strike (style)) {
306 if (version == HTML32)
307 gsf_output_puts (output, "<strike>");
308 else
309 gsf_output_puts (output,
310 "<span style=\"text-decoration: line-through;\">");
312 switch (gnm_style_get_font_script (style)) {
313 case GO_FONT_SCRIPT_SUB:
314 gsf_output_puts (output, "<sub>");
315 break;
316 case GO_FONT_SCRIPT_SUPER:
317 gsf_output_puts (output, "<sup>");
318 break;
319 default:
320 break;
324 if (hlink_target)
325 gsf_output_printf (output, "<a href=\"%s\">", hlink_target);
327 if (cell != NULL) {
328 const PangoAttrList * markup = NULL;
330 if (style != NULL && version != HTML40) {
331 html_get_text_color (cell, style, &r, &g, &b);
332 if (r > 0 || g > 0 || b > 0)
333 gsf_output_printf (output, "<font color=\"#%02X%02X%02X\">", r, g, b);
336 if (VALUE_IS_STRING (cell->value)
337 && (VALUE_FMT (cell->value) != NULL)
338 && go_format_is_markup (VALUE_FMT (cell->value)))
339 markup = go_format_get_markup (VALUE_FMT (cell->value));
341 if (markup != NULL) {
342 GString *str = g_string_new ("");
343 value_get_as_gstring (cell->value, str, NULL);
344 html_new_markup (output, markup, str->str, version);
345 g_string_free (str, TRUE);
346 } else {
347 rendered_string = gnm_cell_get_rendered_text (cell);
348 html_print_encoded (output, rendered_string);
349 g_free (rendered_string);
353 if (r > 0 || g > 0 || b > 0)
354 gsf_output_puts (output, "</font>");
355 if (hlink_target)
356 gsf_output_puts (output, "</a>");
357 if (style != NULL) {
358 if (gnm_style_get_font_strike (style)) {
359 if (version == HTML32)
360 gsf_output_puts (output, "</strike>");
361 else
362 gsf_output_puts (output, "</span>");
364 switch (gnm_style_get_font_script (style)) {
365 case GO_FONT_SCRIPT_SUB:
366 gsf_output_puts (output, "</sub>");
367 break;
368 case GO_FONT_SCRIPT_SUPER:
369 gsf_output_puts (output, "</sup>");
370 break;
371 default:
372 break;
374 if (font_is_monospaced (style))
375 gsf_output_puts (output, "</tt>");
376 if (gnm_style_get_font_uline (style) != UNDERLINE_NONE)
377 gsf_output_puts (output, "</u>");
378 if (gnm_style_get_font_bold (style))
379 gsf_output_puts (output, "</b>");
380 if (gnm_style_get_font_italic (style))
381 gsf_output_puts (output, "</i>");
386 static char *
387 html_get_border_style (GnmBorder *border)
389 GString *text = g_string_new (NULL);
390 char *result;
392 switch (border->line_type) {
393 case GNM_STYLE_BORDER_THIN:
394 g_string_append (text, "thin solid");
395 break;
396 case GNM_STYLE_BORDER_MEDIUM:
397 g_string_append (text, "medium solid");
398 break;
399 case GNM_STYLE_BORDER_DASHED:
400 g_string_append (text, "thin dashed");
401 break;
402 case GNM_STYLE_BORDER_DOTTED:
403 g_string_append (text, "thin dotted");
404 break;
405 case GNM_STYLE_BORDER_THICK:
406 g_string_append (text, "thick solid");
407 break;
408 case GNM_STYLE_BORDER_DOUBLE:
409 g_string_append (text, "thick double");
410 break;
411 case GNM_STYLE_BORDER_HAIR:
412 g_string_append (text, "0.5pt solid");
413 break;
414 case GNM_STYLE_BORDER_MEDIUM_DASH:
415 g_string_append (text, "medium dashed");
416 break;
417 case GNM_STYLE_BORDER_DASH_DOT:
418 g_string_append (text, "thin dashed");
419 break;
420 case GNM_STYLE_BORDER_MEDIUM_DASH_DOT:
421 g_string_append (text, "medium dashed");
422 break;
423 case GNM_STYLE_BORDER_DASH_DOT_DOT:
424 g_string_append (text, "thin dotted");
425 break;
426 case GNM_STYLE_BORDER_MEDIUM_DASH_DOT_DOT:
427 g_string_append (text, "medium dotted");
428 break;
429 case GNM_STYLE_BORDER_SLANTED_DASH_DOT:
430 g_string_append (text, "thin dashed");
431 break;
432 default:
433 break;
436 if (border->color) {
437 guint r, g, b;
438 r = GO_COLOR_UINT_R (border->color->go_color);
439 g = GO_COLOR_UINT_G (border->color->go_color);
440 b = GO_COLOR_UINT_B (border->color->go_color);
441 g_string_append_printf (text, " #%02X%02X%02X", r, g, b);
444 result = text->str;
445 g_string_free (text, FALSE);
446 return result;
449 static void
450 html_write_one_border_style_40 (GsfOutput *output, GnmBorder *border, char const *border_name)
452 char *text;
453 text = html_get_border_style (border);
454 if (text == NULL || strlen (text) == 0)
455 return;
456 gsf_output_printf (output, " %s:%s;", border_name, text);
457 g_free (text);
460 static void
461 html_write_border_style_40 (GsfOutput *output, GnmStyle const *style)
463 GnmBorder *border;
465 border = gnm_style_get_border (style, MSTYLE_BORDER_TOP);
466 if (!gnm_style_border_is_blank (border))
467 html_write_one_border_style_40 (output, border, "border-top");
468 border = gnm_style_get_border (style, MSTYLE_BORDER_BOTTOM);
469 if (!gnm_style_border_is_blank (border))
470 html_write_one_border_style_40 (output, border, "border-bottom");
471 border = gnm_style_get_border (style, MSTYLE_BORDER_LEFT);
472 if (!gnm_style_border_is_blank (border))
473 html_write_one_border_style_40 (output, border, "border-left");
474 border = gnm_style_get_border (style, MSTYLE_BORDER_RIGHT);
475 if (!gnm_style_border_is_blank (border))
476 html_write_one_border_style_40 (output, border, "border-right");
479 static void
480 html_write_border_style_40_for_merged_cell (GsfOutput *output, GnmStyle const *style,
481 Sheet *sheet, gint row, gint col)
483 GnmBorder *border;
484 GnmRange const *merge_range;
485 GnmCellPos pos;
486 pos.col = col;
487 pos.row = row;
490 border = gnm_style_get_border (style, MSTYLE_BORDER_TOP);
491 if (!gnm_style_border_is_blank (border))
492 html_write_one_border_style_40 (output, border, "border-top");
493 border = gnm_style_get_border (style, MSTYLE_BORDER_LEFT);
494 if (!gnm_style_border_is_blank (border))
495 html_write_one_border_style_40 (output, border, "border-left");
497 merge_range = gnm_sheet_merge_contains_pos (sheet, &pos);
498 if (merge_range != NULL) {
499 style = sheet_style_get (sheet, merge_range->end.col, merge_range->end.row);
500 if (style == NULL)
501 return;
504 border = gnm_style_get_border (style, MSTYLE_BORDER_BOTTOM);
505 if (!gnm_style_border_is_blank (border))
506 html_write_one_border_style_40 (output, border, "border-bottom");
507 border = gnm_style_get_border (style, MSTYLE_BORDER_RIGHT);
508 if (!gnm_style_border_is_blank (border))
509 html_write_one_border_style_40 (output, border, "border-right");
512 static void
513 write_cell (GsfOutput *output, Sheet *sheet, gint row, gint col, html_version_t version, gboolean is_merge)
515 GnmCell *cell;
516 GnmStyle const *style;
517 guint r, g, b;
519 style = sheet_style_get (sheet, col, row);
520 if (style != NULL && version != HTML32 && version != HTML40 &&
521 gnm_style_get_pattern (style) != 0 &&
522 gnm_style_is_element_set (style, MSTYLE_COLOR_BACK)) {
523 html_get_back_color (style, &r, &g, &b);
524 gsf_output_printf (output, " bgcolor=\"#%02X%02X%02X\"", r, g, b);
527 cell = sheet_cell_get (sheet, col, row);
528 if (cell != NULL) {
530 switch (gnm_style_get_align_v (style)) {
531 case GNM_VALIGN_TOP:
532 gsf_output_puts (output, " valign=\"top\" ");
533 break;
534 case GNM_VALIGN_BOTTOM:
535 gsf_output_puts (output, " valign=\"bottom\" ");
536 break;
537 case GNM_VALIGN_DISTRIBUTED:
538 case GNM_VALIGN_CENTER:
539 gsf_output_puts (output, " valign=\"center\" ");
540 break;
541 case GNM_VALIGN_JUSTIFY:
542 gsf_output_puts (output, " valign=\"baseline\" ");
543 break;
544 default:
545 break;
547 switch (gnm_style_default_halign (style, cell)) {
548 case GNM_HALIGN_RIGHT:
549 gsf_output_puts (output, " align=\"right\" ");
550 break;
551 case GNM_HALIGN_DISTRIBUTED:
552 case GNM_HALIGN_CENTER:
553 case GNM_HALIGN_CENTER_ACROSS_SELECTION:
554 gsf_output_puts (output, " align=\"center\" ");
555 break;
556 case GNM_HALIGN_LEFT:
557 gsf_output_puts (output, " align=\"left\" ");
558 break;
559 case GNM_HALIGN_JUSTIFY:
560 gsf_output_puts (output, " align=\"justify\" ");
561 break;
562 default:
563 break;
567 if (version == HTML40 || version == HTML40F || version ==XHTML) {
568 if (style != NULL) {
569 gsf_output_printf (output, " style=\"");
570 if (gnm_style_get_pattern (style) != 0 &&
571 gnm_style_is_element_set (style, MSTYLE_COLOR_BACK)) {
572 html_get_back_color (style, &r, &g, &b);
573 gsf_output_printf (output, "background:#%02X%02X%02X;", r, g, b);
575 if (cell != NULL) {
576 gint size = (int) (gnm_style_get_font_size (style) + 0.5);
577 gsf_output_printf (output, " font-size:%ipt;", size);
578 html_get_text_color (cell, style, &r, &g, &b);
579 if (r > 0 || g > 0 || b > 0)
580 gsf_output_printf (output, " color:#%02X%02X%02X;", r, g, b);
581 if (gnm_style_get_contents_hidden (style))
582 gsf_output_puts (output, " visibility:hidden;");
584 if (is_merge)
585 html_write_border_style_40_for_merged_cell (output, style, sheet, row, col);
586 else
587 html_write_border_style_40 (output, style);
588 gsf_output_printf (output, "\"");
591 gsf_output_printf (output, ">");
592 html_write_cell_content (output, cell, style, version);
593 gsf_output_puts (output, "</td>\n");
598 * write_row:
600 * @output: the stream
601 * @sheet: the gnumeric sheet
602 * @row: the row number
604 * Set up a TD node for each cell in the given row, witht eh appropriate
605 * colspan and rowspan.
606 * Call write_cell for each cell.
608 static void
609 write_row (GsfOutput *output, Sheet *sheet, gint row, GnmRange *range, html_version_t version)
611 gint col;
612 ColRowInfo const *ri = sheet_row_get_info (sheet, row);
613 if (ri->needs_respan)
614 row_calc_spans ((ColRowInfo *) ri, row, sheet);
616 for (col = range->start.col; col <= range->end.col; col++) {
617 CellSpanInfo const *the_span;
618 GnmRange const *merge_range;
619 GnmCellPos pos;
620 pos.col = col;
621 pos.row = row;
623 /* Is this a span */
624 the_span = row_span_get (ri, col);
625 if (the_span != NULL) {
626 gsf_output_printf (output, "<td colspan=\"%i\" ", the_span->right - col + 1);
627 write_cell (output, sheet, row, the_span->cell->pos.col, version, FALSE);
628 col = the_span->right;
629 continue;
632 /* is this covered by a merge */
633 merge_range = gnm_sheet_merge_contains_pos (sheet, &pos);
634 if (merge_range != NULL) {
635 if (merge_range->start.col != col ||
636 merge_range->start.row != row)
637 continue;
638 gsf_output_printf (output, "<td colspan=\"%i\" rowspan=\"%i\" ",
639 merge_range->end.col - merge_range->start.col + 1,
640 merge_range->end.row - merge_range->start.row + 1);
641 write_cell (output, sheet, row, col, version, TRUE);
642 col = merge_range->end.col;
643 continue;
645 gsf_output_puts (output, "<td ");
646 write_cell (output, sheet, row, col, version, FALSE);
651 * write_sheet:
653 * @output: the stream
654 * @sheet: the gnumeric sheet
656 * set up a table and call write_row for each row
658 static void
659 write_sheet (GsfOutput *output, Sheet *sheet,
660 html_version_t version, GOFileSaveScope save_scope)
662 GnmRange total_range;
663 gint row;
665 switch (version) {
666 case HTML40:
667 case HTML40F:
668 case XHTML:
669 gsf_output_puts (output, "<p></p><table cellspacing=\"0\" cellpadding=\"3\">\n");
670 break;
671 default:
672 gsf_output_puts (output, "<p><table border=\"1\">\n");
673 break;
676 if (save_scope != GO_FILE_SAVE_RANGE) {
677 gsf_output_puts (output, "<caption>");
678 html_print_encoded (output, sheet->name_unquoted);
679 gsf_output_puts (output, "</caption>\n");
681 total_range = sheet_get_extent (sheet, TRUE, TRUE);
682 for (row = total_range.start.row; row <= total_range.end.row; row++) {
683 gsf_output_puts (output, "<tr>\n");
684 write_row (output, sheet, row, &total_range, version);
685 gsf_output_puts (output, "</tr>\n");
687 gsf_output_puts (output, "</table>\n");
691 * html_file_save:
693 * write the html file (version of html according to version argument)
695 static void
696 html_file_save (GOFileSaver const *fs, GOIOContext *io_context,
697 WorkbookView const *wb_view, GsfOutput *output, html_version_t version)
699 Workbook *wb = wb_view_get_workbook (wb_view);
700 GOFileSaveScope save_scope;
701 GPtrArray *sel;
702 unsigned ui, count;
704 g_return_if_fail (fs != NULL);
705 g_return_if_fail (wb != NULL);
706 g_return_if_fail (output != NULL);
708 switch (version) {
709 case HTML32:
710 gsf_output_puts (output,
711 "<!DOCTYPE html PUBLIC \"-//W3C//DTD HTML 3.2 Final//EN\">\n"
712 "<html>\n"
713 "<head>\n\t<title>Tables</title>\n"
714 "<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\">\n"
715 "<meta name=\"generator\" content=\"Gnumeric " GNM_VERSION_FULL " via " G_PLUGIN_FOR_HTML "\">\n"
716 "<style><!--\n"
717 "tt {\n"
718 "\tfont-family: courier;\n"
719 "}\n"
720 "td {\n"
721 "\tfont-family: helvetica, sans-serif;\n"
722 "}\n"
723 "caption {\n"
724 "\tfont-family: helvetica, sans-serif;\n"
725 "\tfont-size: 14pt;\n"
726 "\ttext-align: left;\n"
727 "}\n"
728 "--></style>\n"
729 "</head>\n<body>\n");
730 break;
731 case HTML40:
732 gsf_output_puts (output,
733 "<!DOCTYPE html PUBLIC \"-//W3C//DTD HTML 4.01//EN\"\n"
734 "\t\t\"http://www.w3.org/TR/html4/strict.dtd\">\n"
735 "<html>\n"
736 "<head>\n\t<title>Tables</title>\n"
737 "<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\">\n"
738 "<meta name=\"generator\" content=\"Gnumeric " GNM_VERSION_FULL " via " G_PLUGIN_FOR_HTML "\">\n"
739 "<style type=\"text/css\">\n"
740 "tt {\n"
741 "\tfont-family: courier;\n"
742 "}\n"
743 "td {\n"
744 "\tfont-family: helvetica, sans-serif;\n"
745 "}\n"
746 "caption {\n"
747 "\tfont-family: helvetica, sans-serif;\n"
748 "\tfont-size: 14pt;\n"
749 "\ttext-align: left;\n"
750 "}\n"
751 "</style>\n"
752 "</head>\n<body>\n");
753 break;
754 case XHTML :
755 gsf_output_puts (output,
756 "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\"\n"
757 "\t\t\"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n"
758 "<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\">\n"
759 "<head>\n\t<title>Tables</title>\n"
760 "<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\" />\n"
761 "<meta name=\"generator\" content=\"Gnumeric " GNM_VERSION_FULL " via " G_PLUGIN_FOR_HTML "\" />\n"
762 "<style type=\"text/css\">\n"
763 "tt {\n"
764 "\tfont-family: courier;\n"
765 "}\n"
766 "td {\n"
767 "\tfont-family: helvetica, sans-serif;\n"
768 "}\n"
769 "caption {\n"
770 "\tfont-family: helvetica, sans-serif;\n"
771 "\tfont-size: 14pt;\n"
772 "\ttext-align: left;\n"
773 "}\n"
774 "</style>\n"
775 "</head>\n<body>\n");
776 break;
777 default:
778 break;
781 save_scope = go_file_saver_get_save_scope (fs);
783 sel = g_object_get_data (G_OBJECT (wb), SHEET_SELECTION_KEY);
784 count = sel ? sel->len : workbook_sheet_count (wb);
785 for (ui = 0; ui < count; ui++) {
786 Sheet *sheet = sel
787 ? g_ptr_array_index (sel, ui)
788 : workbook_sheet_by_index (wb, ui);
789 write_sheet (output, sheet, version, save_scope);
792 if (version == HTML32 || version == HTML40 || version == XHTML)
793 gsf_output_puts (output, "</body>\n</html>\n");
796 void
797 html40_file_save (GOFileSaver const *fs, GOIOContext *io_context,
798 WorkbookView const *wb_view, GsfOutput *output)
800 html_file_save (fs, io_context, wb_view, output, HTML40);
803 void
804 html32_file_save (GOFileSaver const *fs, GOIOContext *io_context,
805 WorkbookView const *wb_view, GsfOutput *output)
807 html_file_save (fs, io_context, wb_view, output, HTML32);
810 void
811 html40frag_file_save (GOFileSaver const *fs, GOIOContext *io_context,
812 WorkbookView const *wb_view, GsfOutput *output)
814 html_file_save (fs, io_context, wb_view, output, HTML40F);
817 void
818 xhtml_file_save (GOFileSaver const *fs, GOIOContext *io_context,
819 WorkbookView const *wb_view, GsfOutput *output)
821 html_file_save (fs, io_context, wb_view, output, XHTML);
824 void
825 xhtml_range_file_save (GOFileSaver const *fs, GOIOContext *io_context,
826 WorkbookView const *wb_view, GsfOutput *output)
828 /* Identical, but fs->save_scope is different */
829 xhtml_file_save (fs, io_context, wb_view, output);