org-e-odt: Fix handling of inline formula.
[org-mode/org-mode-NeilSmithlineMods.git] / EXPERIMENTAL / org-e-odt.el
blobbe01fc8e3451a691ff4a3ba2c3a802d3ef607e0a
1 ;;; org-e-odt.el --- OpenDocument Text exporter for Org-mode
3 ;; Copyright (C) 2010-2012 Free Software Foundation, Inc.
5 ;; Author: Jambunathan K <kjambunathan at gmail dot com>
6 ;; Keywords: outlines, hypermedia, calendar, wp
7 ;; Homepage: http://orgmode.org
9 ;; This file is part of GNU Emacs.
11 ;; GNU Emacs is free software: you can redistribute it and/or modify
12 ;; it under the terms of the GNU General Public License as published by
13 ;; the Free Software Foundation, either version 3 of the License, or
14 ;; (at your option) any later version.
16 ;; GNU Emacs is distributed in the hope that it will be useful,
17 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
18 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 ;; GNU General Public License for more details.
21 ;; You should have received a copy of the GNU General Public License
22 ;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
24 ;;; Commentary:
26 ;;; Code:
27 (eval-when-compile
28 (require 'cl))
30 (defgroup org-export-e-odt nil
31 "Options specific for ODT export of Org-mode files."
32 :tag "Org Export ODT"
33 :group 'org-export
34 :version "24.1")
36 ;; FIXMES
37 ;; org-export-preprocess-after-blockquote-hook
38 ;; org-e-odt-preprocess-latex-fragments
39 ;; org-export-as-e-odt-and-open
40 ;; org-export-as-e-odt-batch
41 ;; org-export-as-e-odt
43 (defun org-e-odt-get-style-name-for-entity (category &optional entity)
44 (let ((entity (or entity 'default)))
45 (or
46 (cdr (assoc entity (cdr (assoc category
47 org-e-odt-org-styles-alist))))
48 (cdr (assoc entity (cdr (assoc category
49 org-e-odt-default-org-styles-alist))))
50 (error "Cannot determine style name for entity %s of type %s"
51 entity category))))
54 ;; Following variable is let bound when `org-do-lparse' is in
55 ;; progress. See org-html.el.
57 (defun org-e-odt-format-preamble (info)
58 (let* ((title (org-export-secondary-string
59 (plist-get info :title) 'e-odt info))
60 (author (and (plist-get info :with-author)
61 (let ((auth (plist-get info :author)))
62 (and auth (org-export-secondary-string
63 auth 'e-odt info)))))
64 (date (plist-get info :date))
65 (iso-date (org-e-odt-format-date date))
66 (date (org-e-odt-format-date date "%d %b %Y"))
67 (email (plist-get info :email))
68 ;; switch on or off above vars based on user settings
69 (author (and (plist-get info :with-author) (or author email)))
70 ;; (date (and (plist-get info :time-stamp-file) date))
71 (email (and (plist-get info :with-email) email)))
72 (concat
73 ;; title
74 (when title
75 (concat
76 (org-e-odt-format-stylized-paragraph
77 'title (format "\n<text:title>%s</text:title>" title))
78 ;; separator
79 "\n<text:p text:style-name=\"OrgTitle\"/>"))
80 (cond
81 ((and author (not email))
82 ;; author only
83 (concat
84 (org-e-odt-format-stylized-paragraph
85 'subtitle
86 (format "<text:initial-creator>%s</text:initial-creator>" author))
87 ;; separator
88 "\n<text:p text:style-name=\"OrgSubtitle\"/>"))
89 ((and author email)
90 ;; author and email
91 (concat
92 (org-e-odt-format-stylized-paragraph
93 'subtitle
94 (org-e-odt-format-link
95 (format "<text:initial-creator>%s</text:initial-creator>" author)
96 (concat "mailto:" email)))
97 ;; separator
98 "\n<text:p text:style-name=\"OrgSubtitle\"/>")))
99 ;; date
100 (when date
101 (concat
102 (org-e-odt-format-stylized-paragraph
103 'subtitle
104 (org-odt-format-tags
105 '("<text:date style:data-style-name=\"%s\" text:date-value=\"%s\">"
106 . "</text:date>")
107 date "N75" iso-date))
108 ;; separator
109 "<text:p text:style-name=\"OrgSubtitle\"/>")))))
111 (defun org-e-odt-begin-section (style &optional name)
112 (let ((default-name (car (org-e-odt-add-automatic-style "Section"))))
113 (format "<text:section text:style-name=\"%s\" text:name=\"%s\">"
114 style (or name default-name))))
116 (defun org-e-odt-end-section ()
117 "</text:section>")
119 (defun org-e-odt-begin-paragraph (&optional style)
120 (format "<text:p%s>" (org-e-odt-get-extra-attrs-for-paragraph-style style)))
122 (defun org-e-odt-end-paragraph ()
123 "</text:p>")
125 (defun org-e-odt-get-extra-attrs-for-paragraph-style (style)
126 (let (style-name)
127 (setq style-name
128 (cond
129 ((stringp style) style)
130 ((symbolp style) (org-e-odt-get-style-name-for-entity
131 'paragraph style))))
132 (unless style-name
133 (error "Don't know how to handle paragraph style %s" style))
134 (format " text:style-name=\"%s\"" style-name)))
136 (defun org-e-odt-format-stylized-paragraph (style text)
137 (format "\n<text:p%s>%s</text:p>"
138 (org-e-odt-get-extra-attrs-for-paragraph-style style)
139 text))
141 (defun org-e-odt-format-author (&optional author )
142 (when (setq author (or author (plist-get org-lparse-opt-plist :author)))
143 (format "<dc:creator>%s</dc:creator>" author)))
145 (defun org-e-odt-format-date (&optional org-ts fmt)
146 (save-match-data
147 (let* ((time
148 (and (stringp org-ts)
149 (string-match org-ts-regexp0 org-ts)
150 (apply 'encode-time
151 (org-fix-decoded-time
152 (org-parse-time-string (match-string 0 org-ts) t)))))
153 date)
154 (cond
155 (fmt (format-time-string fmt time))
156 (t (setq date (format-time-string "%Y-%m-%dT%H:%M:%S%z" time))
157 (format "%s:%s" (substring date 0 -2) (substring date -2)))))))
159 (defun org-e-odt-begin-annotation (&optional author date)
160 (concat
161 "<office:annotation>\n"
162 (and author (org-e-odt-format-author author))
163 (org-e-odt-format-tags
164 '("<dc:date>" . "</dc:date>")
165 (org-e-odt-format-date
166 (or date (plist-get org-lparse-opt-plist :date))))
167 (org-e-odt-begin-paragraph)))
169 (defun org-e-odt-end-annotation ()
170 "</office:annotation>")
172 (defun org-e-odt-begin-plain-list (ltype)
173 (let* ((style-name (org-e-odt-get-style-name-for-entity 'list ltype))
174 (extra (concat
175 ;; (if (or org-lparse-list-table-p
176 ;; (and (= 1 (length org-lparse-list-stack))
177 ;; (null org-e-odt-list-stack-stashed)))
178 ;; " text:continue-numbering=\"false\""
179 ;; " text:continue-numbering=\"true\"")
181 " text:continue-numbering=\"true\""
183 (when style-name
184 (format " text:style-name=\"%s\"" style-name)))))
185 (case ltype
186 ((ordered unordered descriptive)
187 (concat
188 ;; (org-e-odt-end-paragraph)
189 (format "<text:list%s>" extra)))
190 (t (error "Unknown list type: %s" ltype)))))
192 (defun org-e-odt-end-plain-list (ltype)
193 (if ltype "</text:list>"
194 (error "Unknown list type: %s" ltype)))
196 (defun org-e-odt-begin-list-item (ltype &optional arg headline)
197 (case ltype
198 (ordered
199 (assert (not headline) t)
200 (let* ((counter arg) (extra ""))
201 (concat "<text:list-item>" ;; (org-e-odt-begin-paragraph)
203 ;; (if (= (length org-lparse-list-stack)
204 ;; (length org-e-odt-list-stack-stashed))
205 ;; "<text:list-header>" "<text:list-item>")
207 (unordered
208 (let* ((id arg) (extra ""))
209 (concat
210 "<text:list-item>"
211 ;; (org-e-odt-begin-paragraph)
212 (if headline (org-e-odt-format-target headline id)
213 (org-e-odt-format-bookmark "" id)))
214 ;; (if (= (length org-lparse-list-stack)
215 ;; (length org-e-odt-list-stack-stashed))
216 ;; "<text:list-header>" "<text:list-item>")
218 (descriptive
219 (assert (not headline) t)
220 (let ((term (or arg "(no term)")))
221 (concat
222 (org-e-odt-format-tags
223 '("<text:list-item>" . "</text:list-item>")
224 (org-e-odt-format-stylized-paragraph 'definition-term term))
225 (org-e-odt-begin-list-item 'unordered)
226 (org-e-odt-begin-plain-list 'descriptive)
227 (org-e-odt-begin-list-item 'unordered))))
228 (t (error "Unknown list type"))))
230 (defun org-e-odt-end-list-item (ltype)
231 (case ltype
232 ((ordered unordered)
233 ;; (org-lparse-insert-tag
234 ;; (if (= (length org-lparse-list-stack)
235 ;; (length org-e-odt-list-stack-stashed))
236 ;; (prog1 "</text:list-header>"
237 ;; (setq org-e-odt-list-stack-stashed nil))
238 ;; "</text:list-item>")
239 "</text:list-item>"
240 ;; )
242 (descriptive
243 (concat
244 (org-e-odt-end-list-item 'unordered)
245 (org-e-odt-end-plain-list 'descriptive)
246 (org-e-odt-end-list-item 'unordered)
248 (t (error "Unknown list type"))))
250 (defun org-e-odt-discontinue-list ()
251 (let ((stashed-stack org-lparse-list-stack))
252 (loop for list-type in stashed-stack
253 do (org-lparse-end-list-item-1 list-type)
254 (org-lparse-end-list list-type))
255 (setq org-e-odt-list-stack-stashed stashed-stack)))
257 (defun org-e-odt-continue-list ()
258 (setq org-e-odt-list-stack-stashed (nreverse org-e-odt-list-stack-stashed))
259 (loop for list-type in org-e-odt-list-stack-stashed
260 do (org-lparse-begin-list list-type)
261 (org-lparse-begin-list-item list-type)))
263 (defun org-e-odt-write-automatic-styles ()
264 "Write automatic styles to \"content.xml\"."
265 (with-current-buffer
266 (find-file-noselect (expand-file-name "content.xml") t)
267 ;; position the cursor
268 (goto-char (point-min))
269 (re-search-forward " </office:automatic-styles>" nil t)
270 (goto-char (match-beginning 0))
271 ;; write automatic table styles
272 (loop for (style-name props) in
273 (plist-get org-e-odt-automatic-styles 'Table) do
274 (when (setq props (or (plist-get props :rel-width) 96))
275 (insert (format org-e-odt-table-style-format style-name props))))))
277 (defun org-e-odt-add-automatic-style (object-type &optional object-props)
278 "Create an automatic style of type OBJECT-TYPE with param OBJECT-PROPS.
279 OBJECT-PROPS is (typically) a plist created by passing
280 \"#+ATTR_ODT: \" option of the object in question to
281 `org-e-odt-parse-block-attributes'.
283 Use `org-e-odt-object-counters' to generate an automatic
284 OBJECT-NAME and STYLE-NAME. If OBJECT-PROPS is non-nil, add a
285 new entry in `org-e-odt-automatic-styles'. Return (OBJECT-NAME
286 . STYLE-NAME)."
287 (assert (stringp object-type))
288 (let* ((object (intern object-type))
289 (seqvar object)
290 (seqno (1+ (or (plist-get org-e-odt-object-counters seqvar) 0)))
291 (object-name (format "%s%d" object-type seqno)) style-name)
292 (setq org-e-odt-object-counters
293 (plist-put org-e-odt-object-counters seqvar seqno))
294 (when object-props
295 (setq style-name (format "Org%s" object-name))
296 (setq org-e-odt-automatic-styles
297 (plist-put org-e-odt-automatic-styles object
298 (append (list (list style-name object-props))
299 (plist-get org-e-odt-automatic-styles object)))))
300 (cons object-name style-name)))
302 (defun org-e-odt-format-table-columns ()
303 (let* ((num-cols (length (plist-get table-info :alignment)))
304 (col-nos (loop for i from 0 below num-cols collect i))
305 (levels )
306 (col-widths (plist-get table-info :width))
307 (style (or (nth 1 org-e-odt-table-style-spec) "OrgTable")))
308 (mapconcat
309 (lambda (c)
310 (let* ((width (or (and org-lparse-table-is-styled (aref col-widths c))
311 0)))
312 (org-e-odt-make-string
313 (1+ width)
314 (org-e-odt-format-tags
315 "<table:table-column table:style-name=\"%sColumn\"/>" "" style))))
316 col-nos "\n")))
319 (defun org-e-odt-begin-table (caption label attributes)
320 ;; (setq org-e-odt-table-indentedp (not (null org-lparse-list-stack)))
321 (setq org-e-odt-table-indentedp nil) ; FIXME
322 (when org-e-odt-table-indentedp
323 ;; Within the Org file, the table is appearing within a list item.
324 ;; OpenDocument doesn't allow table to appear within list items.
325 ;; Temporarily terminate the list, emit the table and then
326 ;; re-continue the list.
327 (org-e-odt-discontinue-list)
328 ;; Put the Table in an indented section.
329 (let ((level (length org-e-odt-list-stack-stashed)))
330 (org-e-odt-begin-section (format "OrgIndentedSection-Level-%d" level))))
331 (setq attributes (org-e-odt-parse-block-attributes attributes))
332 (setq org-e-odt-table-style (plist-get attributes :style))
333 (setq org-e-odt-table-style-spec
334 (assoc org-e-odt-table-style org-e-odt-table-styles))
335 (concat
336 (org-e-odt-format-stylized-paragraph
337 'table (org-e-odt-format-entity-caption label caption "__Table__"))
338 (let ((name-and-style (org-e-odt-add-automatic-style "Table" attributes)))
339 (format
340 "\n<table:table table:name=\"%s\" table:style-name=\"%s\">\n"
341 (car name-and-style) (or (nth 1 org-e-odt-table-style-spec)
342 (cdr name-and-style) "OrgTable")))
343 (org-e-odt-format-table-columns) "\n")
345 ;; (org-e-html-pp table-info)
349 (defun org-e-odt-end-table ()
350 (concat
351 "</table:table>"
352 ;; (when org-e-odt-table-indentedp
353 ;; (org-e-odt-end-section)
354 ;; (org-e-odt-continue-list))
357 (defun org-e-odt-begin-table-rowgroup (&optional is-header-row)
358 (prog1
359 (concat (when org-e-odt-table-rowgrp-open
360 (org-e-odt-end-table-rowgroup))
361 (if is-header-row "<table:table-header-rows>"
362 "<table:table-rows>"))
363 (setq org-e-odt-table-rowgrp-open t)
364 (setq org-e-odt-table-cur-rowgrp-is-hdr is-header-row)))
366 (defun org-e-odt-end-table-rowgroup ()
367 (when org-e-odt-table-rowgrp-open
368 (setq org-e-odt-table-rowgrp-open nil)
369 (if org-e-odt-table-cur-rowgrp-is-hdr
370 "</table:table-header-rows>" "</table:table-rows>")))
372 (defun org-e-odt-format-table-row (row)
373 (org-e-odt-format-tags
374 '("<table:table-row>" . "</table:table-row>") row))
376 (defun org-e-odt-get-column-alignment (c)
377 (let ((colalign-vector (plist-get table-info :alignment)))
378 ;; FIXME
379 (assoc-default (aref colalign-vector c)
380 '(("l" . "left")
381 ("r" . "right")
382 ("c" . "center")))))
384 (defun org-e-odt-get-table-cell-styles (r c &optional style-spec)
385 "Retrieve styles applicable to a table cell.
386 R and C are (zero-based) row and column numbers of the table
387 cell. STYLE-SPEC is an entry in `org-e-odt-table-styles'
388 applicable to the current table. It is `nil' if the table is not
389 associated with any style attributes.
391 Return a cons of (TABLE-CELL-STYLE-NAME . PARAGRAPH-STYLE-NAME).
393 When STYLE-SPEC is nil, style the table cell the conventional way
394 - choose cell borders based on row and column groupings and
395 choose paragraph alignment based on `org-col-cookies' text
396 property. See also
397 `org-e-odt-get-paragraph-style-cookie-for-table-cell'.
399 When STYLE-SPEC is non-nil, ignore the above cookie and return
400 styles congruent with the ODF-1.2 specification."
401 (cond
402 (style-spec
404 ;; LibreOffice - particularly the Writer - honors neither table
405 ;; templates nor custom table-cell styles. Inorder to retain
406 ;; inter-operability with LibreOffice, only automatic styles are
407 ;; used for styling of table-cells. The current implementation is
408 ;; congruent with ODF-1.2 specification and hence is
409 ;; future-compatible.
411 ;; Additional Note: LibreOffice's AutoFormat facility for tables -
412 ;; which recognizes as many as 16 different cell types - is much
413 ;; richer. Unfortunately it is NOT amenable to easy configuration
414 ;; by hand.
416 (let* ((template-name (nth 1 style-spec))
417 (cell-style-selectors (nth 2 style-spec))
418 (cell-type
419 (cond
420 ((and (cdr (assoc 'use-first-column-styles cell-style-selectors))
421 (= c 0)) "FirstColumn")
422 ((and (cdr (assoc 'use-last-column-styles cell-style-selectors))
423 (= c (1- org-lparse-table-ncols))) "LastColumn")
424 ((and (cdr (assoc 'use-first-row-styles cell-style-selectors))
425 (= r 0)) "FirstRow")
426 ((and (cdr (assoc 'use-last-row-styles cell-style-selectors))
427 (= r org-e-odt-table-rownum))
428 "LastRow")
429 ((and (cdr (assoc 'use-banding-rows-styles cell-style-selectors))
430 (= (% r 2) 1)) "EvenRow")
431 ((and (cdr (assoc 'use-banding-rows-styles cell-style-selectors))
432 (= (% r 2) 0)) "OddRow")
433 ((and (cdr (assoc 'use-banding-columns-styles cell-style-selectors))
434 (= (% c 2) 1)) "EvenColumn")
435 ((and (cdr (assoc 'use-banding-columns-styles cell-style-selectors))
436 (= (% c 2) 0)) "OddColumn")
437 (t ""))))
438 (cons
439 (concat template-name cell-type "TableCell")
440 (concat template-name cell-type "TableParagraph"))))
442 (cons
443 (concat
444 "OrgTblCell"
445 (cond
446 ((= r 0) "T")
447 ((eq (cdr (assoc r nil ;; org-lparse-table-rowgrp-info FIXME
448 )) :start) "T")
449 (t ""))
450 (when (= r org-e-odt-table-rownum) "B")
451 (cond
452 ((= c 0) "")
453 ((or (memq (nth c org-table-colgroup-info) '(:start :startend))
454 (memq (nth (1- c) org-table-colgroup-info) '(:end :startend))) "L")
455 (t "")))
456 (capitalize (org-e-odt-get-column-alignment c))))))
458 (defun org-e-odt-get-paragraph-style-cookie-for-table-cell (r c)
459 (concat
460 (and (not org-e-odt-table-style-spec)
461 (cond
462 (org-e-odt-table-cur-rowgrp-is-hdr "OrgTableHeading")
463 ((and (= c 0) nil
464 ;; (org-lparse-get 'TABLE-FIRST-COLUMN-AS-LABELS)
466 "OrgTableHeading")
467 (t "OrgTableContents")))
468 (and org-lparse-table-is-styled
469 (cdr (org-e-odt-get-table-cell-styles
470 r c org-e-odt-table-style-spec)))))
472 (defun org-e-odt-get-style-name-cookie-for-table-cell (r c)
473 (when org-lparse-table-is-styled
474 (let* ((cell-styles (org-e-odt-get-table-cell-styles
475 r c org-e-odt-table-style-spec))
476 (table-cell-style (car cell-styles)))
477 table-cell-style)))
479 (defun org-e-odt-format-table-cell (data r c horiz-span)
480 (concat
481 (let* ((paragraph-style-cookie
482 (org-e-odt-get-paragraph-style-cookie-for-table-cell r c))
483 (style-name-cookie
484 (org-e-odt-get-style-name-cookie-for-table-cell r c))
485 (extra (and style-name-cookie
486 (format " table:style-name=\"%s\"" style-name-cookie)))
487 (extra (concat extra
488 (and (> horiz-span 0)
489 (format " table:number-columns-spanned=\"%d\""
490 (1+ horiz-span))))))
491 (org-e-odt-format-tags
492 '("<table:table-cell%s>" . "</table:table-cell>")
493 (if org-lparse-list-table-p data
494 (org-e-odt-format-stylized-paragraph paragraph-style-cookie data)) extra))
495 (let (s)
496 (dotimes (i horiz-span)
497 (setq s (concat s "\n<table:covered-table-cell/>"))) s)
498 "\n"))
500 (defun org-e-odt-begin-toc (lang-specific-heading max-level)
501 (concat
502 (format "
503 <text:table-of-content text:style-name=\"Sect2\" text:protected=\"true\" text:name=\"Table of Contents1\">
504 <text:table-of-content-source text:outline-level=\"%d\">
505 <text:index-title-template text:style-name=\"Contents_20_Heading\">%s</text:index-title-template>
506 " max-level lang-specific-heading)
508 (let ((entry-templates ""))
509 (loop for level from 1 upto 10
510 do (setq entry-templates
511 (concat entry-templates
512 (format
514 <text:table-of-content-entry-template text:outline-level=\"%d\" text:style-name=\"Contents_20_%d\">
515 <text:index-entry-link-start text:style-name=\"Internet_20_link\"/>
516 <text:index-entry-chapter/>
517 <text:index-entry-text/>
518 <text:index-entry-link-end/>
519 </text:table-of-content-entry-template>
520 " level level))))
521 entry-templates)
523 (format "
524 </text:table-of-content-source>
526 <text:index-body>
527 <text:index-title text:style-name=\"Sect1\" text:name=\"Table of Contents1_Head\">
528 <text:p text:style-name=\"Contents_20_Heading\">%s</text:p>
529 </text:index-title>
530 " lang-specific-heading)))
532 (defun org-e-odt-end-toc ()
533 (format "
534 </text:index-body>
535 </text:table-of-content>
538 (defun org-e-odt-format-toc-entry (snumber todo headline tags href)
540 ;; FIXME
541 (setq headline (concat
542 (and org-export-with-section-numbers
543 (concat snumber ". "))
544 headline
545 (and tags
546 (concat
547 (org-e-odt-format-spaces 3)
548 (org-e-odt-format-fontify tags "tag")))))
549 (when todo
550 (setq headline (org-e-odt-format-fontify headline "todo")))
552 (let ((org-e-odt-suppress-xref t))
553 (org-e-odt-format-link headline (concat "#" href))))
555 (defun org-e-odt-format-toc-item (toc-entry level org-last-level)
556 (let ((style (format "Contents_20_%d"
557 (+ level (or ;; (org-lparse-get 'TOPLEVEL-HLEVEL)
559 1) -1))))
560 (concat "\n" (org-e-odt-format-stylized-paragraph style toc-entry) "\n")))
562 ;; Following variable is let bound during 'ORG-LINK callback. See
563 ;; org-html.el
565 (defun org-e-odt-format-link (desc href &optional attr)
566 (cond
567 ((and (= (string-to-char href) ?#) (not org-e-odt-suppress-xref))
568 (setq href (substring href 1))
569 (let ((xref-format "text"))
570 (when (numberp desc)
571 (setq desc (format "%d" desc) xref-format "number"))
572 (when (listp desc)
573 (setq desc (mapconcat 'identity desc ".") xref-format "chapter"))
574 (setq href (concat org-e-odt-bookmark-prefix href))
575 (org-e-odt-format-tags-simple
576 '("<text:bookmark-ref text:reference-format=\"%s\" text:ref-name=\"%s\">" .
577 "</text:bookmark-ref>")
578 desc xref-format href)))
579 (org-lparse-link-description-is-image
580 (org-e-odt-format-tags
581 '("<draw:a xlink:type=\"simple\" xlink:href=\"%s\" %s>" . "</draw:a>")
582 desc href (or attr "")))
584 (org-e-odt-format-tags-simple
585 '("<text:a xlink:type=\"simple\" xlink:href=\"%s\" %s>" . "</text:a>")
586 desc href (or attr "")))))
588 (defun org-e-odt-format-spaces (n)
589 (cond
590 ((= n 1) " ")
591 ((> n 1) (concat
592 " " (org-e-odt-format-tags "<text:s text:c=\"%d\"/>" "" (1- n))))
593 (t "")))
595 (defun org-e-odt-format-tabs (&optional n)
596 (let ((tab "<text:tab/>")
597 (n (or n 1)))
598 (insert tab)))
600 (defun org-e-odt-format-line-break ()
601 (org-e-odt-format-tags "<text:line-break/>" ""))
603 (defun org-e-odt-format-horizontal-line ()
604 (org-e-odt-format-stylized-paragraph 'horizontal-line ""))
606 (defun org-e-odt-encode-plain-text (line &optional no-whitespace-filling)
607 (setq line (org-e-html-encode-plain-text line))
608 (if no-whitespace-filling line
609 (org-e-odt-fill-tabs-and-spaces line)))
611 (defun org-e-odt-format-line (line)
612 (case org-lparse-dyn-current-environment
613 (fixedwidth (concat
614 (org-e-odt-format-stylized-paragraph
615 'fixedwidth (org-e-odt-encode-plain-text line)) "\n"))
616 (t (concat line "\n"))))
618 (defun org-e-odt-format-comment (fmt &rest args)
619 (let ((comment (apply 'format fmt args)))
620 (format "\n<!-- %s -->\n" comment)))
622 (defun org-e-odt-format-org-entity (wd)
623 (org-entity-get-representation wd 'utf8))
625 (defun org-e-odt-fill-tabs-and-spaces (line)
626 (replace-regexp-in-string
627 "\\([\t]\\|\\([ ]+\\)\\)" (lambda (s)
628 (cond
629 ((string= s "\t") (org-e-odt-format-tabs))
630 (t (org-e-odt-format-spaces (length s))))) line))
632 (defun org-e-odt-hfy-face-to-css (fn)
633 "Create custom style for face FN.
634 When FN is the default face, use it's foreground and background
635 properties to create \"OrgSrcBlock\" paragraph style. Otherwise
636 use it's color attribute to create a character style whose name
637 is obtained from FN. Currently all attributes of FN other than
638 color are ignored.
640 The style name for a face FN is derived using the following
641 operations on the face name in that order - de-dash, CamelCase
642 and prefix with \"OrgSrc\". For example,
643 `font-lock-function-name-face' is associated with
644 \"OrgSrcFontLockFunctionNameFace\"."
645 (let* ((css-list (hfy-face-to-style fn))
646 (style-name ((lambda (fn)
647 (concat "OrgSrc"
648 (mapconcat
649 'capitalize (split-string
650 (hfy-face-or-def-to-name fn) "-")
651 ""))) fn))
652 (color-val (cdr (assoc "color" css-list)))
653 (background-color-val (cdr (assoc "background" css-list)))
654 (style (and org-e-odt-create-custom-styles-for-srcblocks
655 (cond
656 ((eq fn 'default)
657 (format org-src-block-paragraph-format
658 background-color-val color-val))
660 (format
662 <style:style style:name=\"%s\" style:family=\"text\">
663 <style:text-properties fo:color=\"%s\"/>
664 </style:style>" style-name color-val))))))
665 (cons style-name style)))
667 (defun org-e-odt-insert-custom-styles-for-srcblocks (styles)
668 "Save STYLES used for colorizing of source blocks.
669 Update styles.xml with styles that were collected as part of
670 `org-e-odt-hfy-face-to-css' callbacks."
671 (when styles
672 (with-current-buffer
673 (find-file-noselect (expand-file-name "styles.xml") t)
674 (goto-char (point-min))
675 (when (re-search-forward "</office:styles>" nil t)
676 (goto-char (match-beginning 0))
677 (insert "\n<!-- Org Htmlfontify Styles -->\n" styles "\n")))))
679 (defun org-e-odt-remap-stylenames (style-name)
681 (cdr (assoc style-name '(("timestamp-wrapper" . "OrgTimestampWrapper")
682 ("timestamp" . "OrgTimestamp")
683 ("timestamp-kwd" . "OrgTimestampKeyword")
684 ("tag" . "OrgTag")
685 ("todo" . "OrgTodo")
686 ("done" . "OrgDone")
687 ("target" . "OrgTarget"))))
688 style-name))
690 (defun org-e-odt-format-fontify (text style &optional id)
691 (let* ((style-name
692 (cond
693 ((stringp style)
694 (org-e-odt-remap-stylenames style))
695 ((symbolp style)
696 (org-e-odt-get-style-name-for-entity 'character style))
697 ((listp style)
698 (assert (< 1 (length style)))
699 (let ((parent-style (pop style)))
700 (mapconcat (lambda (s)
701 ;; (assert (stringp s) t)
702 (org-e-odt-remap-stylenames s)) style "")
703 (org-e-odt-remap-stylenames parent-style)))
704 (t (error "Don't how to handle style %s" style)))))
705 (org-e-odt-format-tags
706 '("<text:span text:style-name=\"%s\">" . "</text:span>")
707 text style-name)))
709 (defun org-e-odt-relocate-relative-path (path dir)
710 (if (file-name-absolute-p path) path
711 (file-relative-name (expand-file-name path dir)
712 (expand-file-name "eyecandy" dir))))
714 (defun org-e-odt-format-formula (src &optional caption label attr)
715 (let* ((href
716 (org-e-odt-format-tags
717 "<draw:object xlink:href=\"%s\" xlink:type=\"simple\" xlink:show=\"embed\" xlink:actuate=\"onLoad\"/>" ""
718 (file-name-directory (org-e-odt-copy-formula-file src))))
719 ;; FIXME
720 ;; (caption (org-find-text-property-in-string 'org-caption src))
721 ;; (caption (and caption (org-xml-format-desc caption)))
722 ;; (label (org-find-text-property-in-string 'org-label src))
723 ;; (latex-frag (org-find-text-property-in-string 'org-latex-src src))
724 (embed-as (or
725 ;; FIXME
726 ;; (and latex-frag
727 ;; (org-find-text-property-in-string
728 ;; 'org-latex-src-embed-type src))
729 (if (or caption label) 'paragraph 'character)))
730 width height)
731 ;; FIXME
732 ;; (when latex-frag
733 ;; (setq href (org-propertize href :title "LaTeX Fragment"
734 ;; :description latex-frag)))
735 (cond
736 ((eq embed-as 'character)
737 (org-e-odt-format-entity "InlineFormula" href width height))
739 ;; (org-lparse-end-paragraph)
741 (let ((table-info nil)
742 (table-info
743 '(:alignment ["c" "c"]
744 :column-groups [nil nil]
745 :row-groups (0)
746 :special-column-p nil :width [8 1]))
747 (org-lparse-table-ncols 2)
748 ) ; FIXME
749 (org-e-odt-list-table
750 `((,(org-e-odt-format-entity
751 (if caption "CaptionedDisplayFormula" "DisplayFormula")
752 href width height :caption caption :label nil)
753 ,(if (not label) ""
754 (org-e-odt-format-entity-caption label nil "__MathFormula__"))))
755 nil nil ":style \"OrgEquation\"" ;; nil '((1 "c" 8) (2 "c" 1)) FIXME
758 ;; (throw 'nextline nil)
759 ))))
761 (defun org-e-odt-copy-formula-file (path)
762 "Returns the internal name of the file"
763 (let* ((src-file (expand-file-name
764 path (file-name-directory org-current-export-file)))
765 (target-dir (format "Formula-%04d/"
766 (incf org-e-odt-embedded-formulas-count)))
767 (target-file (concat target-dir "content.xml")))
768 (message "Embedding %s as %s ..."
769 (substring-no-properties path) target-file)
771 (make-directory target-dir)
772 (org-e-odt-create-manifest-file-entry
773 "application/vnd.oasis.opendocument.formula" target-dir "1.2")
775 (case (org-e-odt-is-formula-link-p src-file)
776 (mathml
777 (copy-file src-file target-file 'overwrite))
778 (odf
779 (org-e-odt-zip-extract-one src-file "content.xml" target-dir))
781 (error "%s is not a formula file" src-file)))
783 (org-e-odt-create-manifest-file-entry "text/xml" target-file)
784 target-file))
786 (defun org-e-odt-is-formula-link-p (file)
787 (let ((case-fold-search nil))
788 (cond
789 ((string-match "\\.\\(mathml\\|mml\\)\\'" file)
790 'mathml)
791 ((string-match "\\.odf\\'" file)
792 'odf))))
794 (defun org-e-odt-format-org-link (opt-plist type-1 path fragment desc attr
795 descp)
796 "Make a OpenDocument link.
797 OPT-PLIST is an options list.
798 TYPE-1 is the device-type of the link (THIS://foo.html).
799 PATH is the path of the link (http://THIS#location).
800 FRAGMENT is the fragment part of the link, if any (foo.html#THIS).
801 DESC is the link description, if any.
802 ATTR is a string of other attributes of the a element."
803 (declare (special org-lparse-par-open))
804 (save-match-data
805 (let* ((may-inline-p
806 (and (member type-1 '("http" "https" "file"))
807 (org-lparse-should-inline-p path descp)
808 (not fragment)))
809 (type (if (equal type-1 "id") "file" type-1))
810 (filename path)
811 (thefile path))
812 (cond
813 ;; check for inlined images
814 ((and (member type '("file"))
815 (not fragment)
816 (org-file-image-p
817 filename org-e-odt-inline-image-extensions)
818 (not descp))
819 (org-e-odt-format-inline-image thefile))
820 ;; check for embedded formulas
821 ((and (member type '("file"))
822 (not fragment)
823 (org-e-odt-is-formula-link-p filename)
824 (or (not descp)))
825 (org-e-odt-format-formula thefile))
826 ((string= type "coderef")
827 (let* ((ref fragment)
828 (lineno-or-ref (cdr (assoc ref org-export-code-refs)))
829 (desc (and descp desc))
830 (org-e-odt-suppress-xref nil)
831 (href (org-xml-format-href (concat "#coderef-" ref))))
832 (cond
833 ((and (numberp lineno-or-ref) (not desc))
834 (org-e-odt-format-link lineno-or-ref href))
835 ((and (numberp lineno-or-ref) desc
836 (string-match (regexp-quote (concat "(" ref ")")) desc))
837 (format (replace-match "%s" t t desc)
838 (org-e-odt-format-link lineno-or-ref href)))
840 (setq desc (format
841 (if (and desc (string-match
842 (regexp-quote (concat "(" ref ")"))
843 desc))
844 (replace-match "%s" t t desc)
845 (or desc "%s"))
846 lineno-or-ref))
847 (org-e-odt-format-link (org-xml-format-desc desc) href)))))
849 (when (string= type "file")
850 (setq thefile
851 (cond
852 ((file-name-absolute-p path)
853 (concat "file://" (expand-file-name path)))
854 (t (org-e-odt-relocate-relative-path
855 thefile org-current-export-file)))))
857 (when (and (member type '("" "http" "https" "file")) fragment)
858 (setq thefile (concat thefile "#" fragment)))
860 (setq thefile (org-xml-format-href thefile))
862 (when (not (member type '("" "file")))
863 (setq thefile (concat type ":" thefile)))
865 (let ((org-e-odt-suppress-xref nil))
866 (org-e-odt-format-link
867 (org-xml-format-desc desc) thefile attr)))))))
869 (defun org-e-odt-format-anchor (text name &optional class)
870 (org-e-odt-format-target text name))
872 (defun org-e-odt-format-bookmark (text id)
873 (if id
874 (org-e-odt-format-tags "<text:bookmark text:name=\"%s\"/>" text id)
875 text))
877 (defun org-e-odt-format-target (text id)
878 (let ((name (concat org-e-odt-bookmark-prefix id)))
879 (concat
880 (and id (org-e-odt-format-tags
881 "<text:bookmark-start text:name=\"%s\"/>" "" name))
882 (org-e-odt-format-bookmark text id)
883 (and id (org-e-odt-format-tags
884 "<text:bookmark-end text:name=\"%s\"/>" "" name)))))
886 (defun org-e-odt-format-footnote (n def)
887 (setq n (format "%d" n))
888 (let ((id (concat "fn" n))
889 (note-class "footnote")
890 (par-style "Footnote"))
891 (org-e-odt-format-tags
892 '("<text:note text:id=\"%s\" text:note-class=\"%s\">" . "</text:note>")
893 (concat
894 (org-e-odt-format-tags-simple
895 '("<text:note-citation>" . "</text:note-citation>") n)
896 (org-e-odt-format-tags
897 '("<text:note-body>" . "</text:note-body>") def))
898 id note-class)))
900 (defun org-e-odt-format-footnote-reference (n def refcnt)
901 (if (= refcnt 1)
902 (org-e-odt-format-footnote n def)
903 (org-e-odt-format-footnote-ref n)))
905 (defun org-e-odt-format-footnote-ref (n)
906 (setq n (format "%d" n))
907 (let ((note-class "footnote")
908 (ref-format "text")
909 (ref-name (concat "fn" n)))
910 (org-e-odt-format-tags
911 '("<text:span text:style-name=\"%s\">" . "</text:span>")
912 (org-e-odt-format-tags-simple
913 '("<text:note-ref text:note-class=\"%s\" text:reference-format=\"%s\" text:ref-name=\"%s\">" . "</text:note-ref>")
914 n note-class ref-format ref-name)
915 "OrgSuperscript")))
917 (defun org-e-odt-parse-block-attributes (params)
918 (save-match-data
919 (when params
920 (setq params (org-trim params))
921 (unless (string-match "\\`(.*)\\'" params)
922 (setq params (format "(%s)" params)))
923 (ignore-errors (read params)))))
925 (defun org-e-odt-format-image (src &optional
926 caption label attr
927 embed-as ; FIXME
928 category ; FIXME
930 "Create image tag with source and attributes."
931 (let* ((href (org-e-odt-format-tags
932 "<draw:image xlink:href=\"%s\" xlink:type=\"simple\" xlink:show=\"embed\" xlink:actuate=\"onLoad\"/>" ""
933 (org-e-odt-copy-image-file src)))
934 ;; (caption (org-find-text-property-in-string 'org-caption src))
935 ;; (caption (and caption (org-xml-format-desc caption)))
936 ;; (attr (org-find-text-property-in-string 'org-attributes src))
937 ;; (label (org-find-text-property-in-string 'org-label src))
938 ;; (latex-frag (org-find-text-property-in-string
939 ;; 'org-latex-src src))
940 ;; (category (and latex-frag "__DvipngImage__")) ; FIXME
941 (attr-plist (org-e-odt-parse-block-attributes attr))
942 (user-frame-anchor
943 (car (assoc-string (plist-get attr-plist :anchor)
944 '(("as-char") ("paragraph") ("page")) t)))
945 (user-frame-style
946 (and user-frame-anchor (plist-get attr-plist :style)))
947 (user-frame-attrs
948 (and user-frame-anchor (plist-get attr-plist :attributes)))
949 (user-frame-params
950 (list user-frame-style user-frame-attrs user-frame-anchor))
951 (embed-as (or embed-as user-frame-anchor "paragraph"))
952 ;; (embed-as (cond
953 ;; (latex-frag
954 ;; (symbol-name
955 ;; (case (org-find-text-property-in-string ; FIXME
956 ;; 'org-latex-src-embed-type src)
957 ;; (paragraph 'paragraph)
958 ;; (t 'as-char))))
959 ;; (user-frame-anchor)
960 ;; (t "paragraph")))
961 (size (org-e-odt-image-size-from-file
962 src (plist-get attr-plist :width)
963 (plist-get attr-plist :height)
964 (plist-get attr-plist :scale) nil embed-as))
965 (width (car size)) (height (cdr size)))
966 ;; (when latex-frag ; FIXME
967 ;; (setq href (org-propertize href :title "LaTeX Fragment"
968 ;; :description latex-frag)))
969 (let ((frame-style-handle (concat (and (or caption label) "Captioned")
970 embed-as "Image")))
971 (org-e-odt-format-entity
972 frame-style-handle href width height
973 :caption caption :label label :category category
974 :user-frame-params user-frame-params))))
976 (defun org-e-odt-format-object-description (title description)
977 (concat (and title (org-e-odt-format-tags
978 '("<svg:title>" . "</svg:title>")
979 (org-e-odt-encode-plain-text title t)))
980 (and description (org-e-odt-format-tags
981 '("<svg:desc>" . "</svg:desc>")
982 (org-e-odt-encode-plain-text description t)))))
984 (defun org-e-odt-format-frame (text width height style &optional
985 extra anchor-type)
986 (let ((frame-attrs
987 (concat
988 (if width (format " svg:width=\"%0.2fcm\"" width) "")
989 (if height (format " svg:height=\"%0.2fcm\"" height) "")
990 extra
991 (format " text:anchor-type=\"%s\"" (or anchor-type "paragraph")))))
992 (org-e-odt-format-tags
993 '("<draw:frame draw:style-name=\"%s\"%s>" . "</draw:frame>")
994 (concat text (org-e-odt-format-object-description
995 (get-text-property 0 :title text)
996 (get-text-property 0 :description text)))
997 style frame-attrs)))
999 (defun org-e-odt-format-textbox (text width height style &optional
1000 extra anchor-type)
1001 (org-e-odt-format-frame
1002 (org-e-odt-format-tags
1003 '("<draw:text-box %s>" . "</draw:text-box>")
1004 text (concat (format " fo:min-height=\"%0.2fcm\"" (or height .2))
1005 (unless width
1006 (format " fo:min-width=\"%0.2fcm\"" (or width .2)))))
1007 width nil style extra anchor-type))
1009 (defun org-e-odt-merge-frame-params(default-frame-params user-frame-params)
1010 (if (not user-frame-params) default-frame-params
1011 (assert (= (length default-frame-params) 3))
1012 (assert (= (length user-frame-params) 3))
1013 (loop for user-frame-param in user-frame-params
1014 for default-frame-param in default-frame-params
1015 collect (or user-frame-param default-frame-param))))
1017 (defun* org-e-odt-format-entity (entity href width height
1018 &key caption label category
1019 user-frame-params)
1020 (let* ((entity-style (assoc-string entity org-e-odt-entity-frame-styles t))
1021 default-frame-params frame-params)
1022 (cond
1023 ((not (or caption label))
1024 (setq default-frame-params (nth 2 entity-style))
1025 (setq frame-params (org-e-odt-merge-frame-params
1026 default-frame-params user-frame-params))
1027 (apply 'org-e-odt-format-frame href width height frame-params))
1029 (setq default-frame-params (nth 3 entity-style))
1030 (setq frame-params (org-e-odt-merge-frame-params
1031 default-frame-params user-frame-params))
1032 (apply 'org-e-odt-format-textbox
1033 (org-e-odt-format-stylized-paragraph
1034 'illustration
1035 (concat
1036 (apply 'org-e-odt-format-frame href width height
1037 (nth 2 entity-style))
1038 (org-e-odt-format-entity-caption
1039 label caption (or category (nth 1 entity-style)))))
1040 width height frame-params)))))
1042 (defun org-e-odt-copy-image-file (path)
1043 "Returns the internal name of the file"
1044 (let* ((image-type (file-name-extension path))
1045 (media-type (format "image/%s" image-type))
1046 (src-file (expand-file-name
1047 path (file-name-directory org-current-export-file)))
1048 (target-dir "Images/")
1049 (target-file
1050 (format "%s%04d.%s" target-dir
1051 (incf org-e-odt-embedded-images-count) image-type)))
1052 (message "Embedding %s as %s ..."
1053 (substring-no-properties path) target-file)
1055 (when (= 1 org-e-odt-embedded-images-count)
1056 (make-directory target-dir)
1057 (org-e-odt-create-manifest-file-entry "" target-dir))
1059 (copy-file src-file target-file 'overwrite)
1060 (org-e-odt-create-manifest-file-entry media-type target-file)
1061 target-file))
1063 (defun org-e-odt-do-image-size (probe-method file &optional dpi anchor-type)
1064 (setq dpi (or dpi org-e-odt-pixels-per-inch))
1065 (setq anchor-type (or anchor-type "paragraph"))
1066 (flet ((size-in-cms (size-in-pixels)
1067 (flet ((pixels-to-cms (pixels)
1068 (let* ((cms-per-inch 2.54)
1069 (inches (/ pixels dpi)))
1070 (* cms-per-inch inches))))
1071 (and size-in-pixels
1072 (cons (pixels-to-cms (car size-in-pixels))
1073 (pixels-to-cms (cdr size-in-pixels)))))))
1074 (case probe-method
1075 (emacs
1076 (size-in-cms (ignore-errors ; Emacs could be in batch mode
1077 (clear-image-cache)
1078 (image-size (create-image file) 'pixels))))
1079 (imagemagick
1080 (size-in-cms
1081 (let ((dim (shell-command-to-string
1082 (format "identify -format \"%%w:%%h\" \"%s\"" file))))
1083 (when (string-match "\\([0-9]+\\):\\([0-9]+\\)" dim)
1084 (cons (string-to-number (match-string 1 dim))
1085 (string-to-number (match-string 2 dim)))))))
1087 (cdr (assoc-string anchor-type
1088 org-e-odt-default-image-sizes-alist))))))
1090 (defun org-e-odt-image-size-from-file (file &optional user-width
1091 user-height scale dpi embed-as)
1092 (unless (file-name-absolute-p file)
1093 (setq file (expand-file-name
1094 file (file-name-directory org-current-export-file))))
1095 (let* (size width height)
1096 (unless (and user-height user-width)
1097 (loop for probe-method in org-e-odt-image-size-probe-method
1098 until size
1099 do (setq size (org-e-odt-do-image-size
1100 probe-method file dpi embed-as)))
1101 (or size (error "Cannot determine Image size. Aborting ..."))
1102 (setq width (car size) height (cdr size)))
1103 (cond
1104 (scale
1105 (setq width (* width scale) height (* height scale)))
1106 ((and user-height user-width)
1107 (setq width user-width height user-height))
1108 (user-height
1109 (setq width (* user-height (/ width height)) height user-height))
1110 (user-width
1111 (setq height (* user-width (/ height width)) width user-width))
1112 (t (ignore)))
1113 ;; ensure that an embedded image fits comfortably within a page
1114 (let ((max-width (car org-e-odt-max-image-size))
1115 (max-height (cdr org-e-odt-max-image-size)))
1116 (when (or (> width max-width) (> height max-height))
1117 (let* ((scale1 (/ max-width width))
1118 (scale2 (/ max-height height))
1119 (scale (min scale1 scale2)))
1120 (setq width (* scale width) height (* scale height)))))
1121 (cons width height)))
1123 (defun org-e-odt-add-label-definition (label default-category)
1124 "Create an entry in `org-e-odt-entity-labels-alist' and return it."
1125 (setq label (substring-no-properties label))
1126 (let* ((label-props (assoc default-category org-e-odt-category-map-alist))
1127 (category (nth 1 label-props))
1128 (counter category)
1129 (label-style (nth 2 label-props))
1130 (sequence-var (intern (mapconcat
1131 'downcase
1132 (org-split-string counter) "-")))
1133 (seqno (1+ (or (plist-get org-e-odt-entity-counts-plist sequence-var)
1134 0)))
1135 (label-props (list label category seqno label-style)))
1136 (setq org-e-odt-entity-counts-plist
1137 (plist-put org-e-odt-entity-counts-plist sequence-var seqno))
1138 (push label-props org-e-odt-entity-labels-alist)
1139 label-props))
1141 (defun org-e-odt-format-label-reference (label default-category
1142 seqno) ; FIXME
1143 (let* ((label-props (assoc default-category org-e-odt-category-map-alist))
1144 (category (nth 1 label-props))
1145 (counter category) ; FIXME
1146 (label-style (nth 2 label-props)))
1147 (unless label-props
1148 (error "Unknown category: %S" default-category))
1149 (org-e-odt-do-format-label-reference label category seqno label-style)))
1151 (defun org-e-odt-format-label-definition (caption label category seqno label-style)
1152 (assert label)
1153 (setq label (org-solidify-link-text label))
1154 (format-spec
1155 (cadr (assoc-string label-style org-e-odt-label-styles t))
1156 `((?e . ,category)
1157 (?n . ,(org-e-odt-format-tags-simple
1158 '("<text:sequence text:ref-name=\"%s\" text:name=\"%s\" text:formula=\"ooow:%s+1\" style:num-format=\"1\">" . "</text:sequence>")
1159 (format "%d" seqno) label category category))
1160 (?c . ,(or (and caption (concat ": " caption)) "")))))
1162 (defun org-e-odt-do-format-label-reference (label category seqno label-style)
1163 (assert label)
1164 (save-match-data
1165 (let* ((fmt (cddr (assoc-string label-style org-e-odt-label-styles t)))
1166 (fmt1 (car fmt))
1167 (fmt2 (cadr fmt)))
1168 (org-e-odt-format-tags-simple
1169 '("<text:sequence-ref text:reference-format=\"%s\" text:ref-name=\"%s\">"
1170 . "</text:sequence-ref>")
1171 (format-spec fmt2 `((?e . ,category)
1172 (?n . ,(format "%d" seqno)))) fmt1 label))))
1174 (defun org-e-odt-format-entity-caption (label caption category)
1175 (or (and label
1176 (apply 'org-e-odt-format-label-definition
1177 caption (org-e-odt-add-label-definition label category)))
1178 caption ""))
1180 (defun org-e-odt-format-tags-1 (tag text prefix suffix &rest args)
1181 (cond
1182 ((consp tag)
1183 (concat prefix (apply 'format (car tag) args) text suffix
1184 (format (cdr tag))))
1185 ((stringp tag) ; singleton tag
1186 (concat prefix (apply 'format tag args) text))))
1188 (defun org-e-odt-format-tags (tag text &rest args)
1189 (apply 'org-e-odt-format-tags-1 tag text "\n" "\n" args))
1191 (defun org-e-odt-format-tags-simple (tag text &rest args)
1192 (apply 'org-e-odt-format-tags-1 tag text nil nil args))
1194 (defun org-e-odt-init-outfile ()
1195 (unless (executable-find "zip")
1196 ;; Not at all OSes ship with zip by default
1197 (error "Executable \"zip\" needed for creating OpenDocument files"))
1199 (let* ((outdir (make-temp-file
1200 (format org-e-odt-tmpdir-prefix 'odt) t)) ; FIXME
1201 (content-file (expand-file-name "content.xml" outdir)))
1203 ;; reset variables
1204 (setq org-e-odt-manifest-file-entries nil
1205 org-e-odt-embedded-images-count 0
1206 org-e-odt-embedded-formulas-count 0
1207 org-e-odt-section-count 0
1208 org-e-odt-entity-labels-alist nil
1209 org-e-odt-list-stack-stashed nil
1210 org-e-odt-automatic-styles nil
1211 org-e-odt-object-counters nil
1212 org-e-odt-entity-counts-plist nil)
1214 ;; let `htmlfontify' know that we are interested in collecting
1215 ;; styles - FIXME
1217 (setq hfy-user-sheet-assoc nil)
1219 ;; init conten.xml
1220 (with-current-buffer
1221 (find-file-noselect content-file t)
1222 (current-buffer))))
1226 (defun org-e-odt-save-as-outfile (target opt-plist)
1227 ;; write automatic styles
1228 (org-e-odt-write-automatic-styles)
1230 ;; write styles file
1231 ;; (when (equal org-lparse-backend 'odt) FIXME
1232 ;; )
1234 ;; (org-e-odt-update-styles-file opt-plist)
1236 ;; create mimetype file
1237 (let ((mimetype (org-e-odt-write-mimetype-file ;; org-lparse-backend FIXME
1238 'odt)))
1239 (org-e-odt-create-manifest-file-entry mimetype "/" "1.2"))
1241 ;; create a manifest entry for content.xml
1242 (org-e-odt-create-manifest-file-entry "text/xml" "content.xml")
1244 ;; write out the manifest entries before zipping
1245 (org-e-odt-write-manifest-file)
1247 (let ((xml-files '("mimetype" "META-INF/manifest.xml" "content.xml"
1248 "meta.xml"))
1249 (zipdir default-directory))
1250 (when (or t (equal org-lparse-backend 'odt)) ; FIXME
1251 (push "styles.xml" xml-files))
1252 (message "Switching to directory %s" (expand-file-name zipdir))
1254 ;; save all xml files
1255 (mapc (lambda (file)
1256 (with-current-buffer
1257 (find-file-noselect (expand-file-name file) t)
1258 ;; prettify output if needed
1259 (when org-e-odt-prettify-xml
1260 (indent-region (point-min) (point-max)))
1261 (save-buffer 0)))
1262 xml-files)
1264 (let* ((target-name (file-name-nondirectory target))
1265 (target-dir (file-name-directory target))
1266 (cmds `(("zip" "-mX0" ,target-name "mimetype")
1267 ("zip" "-rmTq" ,target-name "."))))
1268 (when (file-exists-p target)
1269 ;; FIXME: If the file is locked this throws a cryptic error
1270 (delete-file target))
1272 (let ((coding-system-for-write 'no-conversion) exitcode err-string)
1273 (message "Creating odt file...")
1274 (mapc
1275 (lambda (cmd)
1276 (message "Running %s" (mapconcat 'identity cmd " "))
1277 (setq err-string
1278 (with-output-to-string
1279 (setq exitcode
1280 (apply 'call-process (car cmd)
1281 nil standard-output nil (cdr cmd)))))
1282 (or (zerop exitcode)
1283 (ignore (message "%s" err-string))
1284 (error "Unable to create odt file (%S)" exitcode)))
1285 cmds))
1287 ;; move the file from outdir to target-dir
1288 (rename-file target-name target-dir)
1290 ;; kill all xml buffers
1291 (mapc (lambda (file)
1292 (kill-buffer
1293 (find-file-noselect (expand-file-name file zipdir) t)))
1294 xml-files)
1296 (delete-directory zipdir)))
1297 (message "Created %s" target)
1298 (set-buffer (find-file-noselect target t)))
1301 (defun org-e-odt-create-manifest-file-entry (&rest args)
1302 (push args org-e-odt-manifest-file-entries))
1304 (defun org-e-odt-write-manifest-file ()
1305 (make-directory "META-INF")
1306 (let ((manifest-file (expand-file-name "META-INF/manifest.xml")))
1307 (with-current-buffer
1308 (find-file-noselect manifest-file t)
1309 (insert
1310 "<?xml version=\"1.0\" encoding=\"UTF-8\"?>
1311 <manifest:manifest xmlns:manifest=\"urn:oasis:names:tc:opendocument:xmlns:manifest:1.0\" manifest:version=\"1.2\">\n")
1312 (mapc
1313 (lambda (file-entry)
1314 (let* ((version (nth 2 file-entry))
1315 (extra (if version
1316 (format " manifest:version=\"%s\"" version)
1317 "")))
1318 (insert
1319 (format org-e-odt-manifest-file-entry-tag
1320 (nth 0 file-entry) (nth 1 file-entry) extra))))
1321 org-e-odt-manifest-file-entries)
1322 (insert "\n</manifest:manifest>"))))
1324 (defun org-e-odt-update-meta-file (info) ; FIXME opt-plist
1325 (let ((title (org-export-secondary-string
1326 (plist-get info :title) 'e-odt info))
1327 (author (or (let ((auth (plist-get info :author)))
1328 (and auth (org-export-secondary-string
1329 auth 'e-odt info))) ""))
1330 (date (org-e-odt-format-date (plist-get info :date)))
1331 (email (plist-get info :email))
1332 (keywords (plist-get info :keywords))
1333 (description (plist-get info :description)))
1334 (write-region
1335 (concat
1336 "<?xml version=\"1.0\" encoding=\"UTF-8\"?>
1337 <office:document-meta
1338 xmlns:office=\"urn:oasis:names:tc:opendocument:xmlns:office:1.0\"
1339 xmlns:xlink=\"http://www.w3.org/1999/xlink\"
1340 xmlns:dc=\"http://purl.org/dc/elements/1.1/\"
1341 xmlns:meta=\"urn:oasis:names:tc:opendocument:xmlns:meta:1.0\"
1342 xmlns:ooo=\"http://openoffice.org/2004/office\"
1343 office:version=\"1.2\">
1344 <office:meta>\n"
1345 (org-e-odt-format-author author) "\n"
1346 (format "<meta:initial-creator>%s</meta:initial-creator>\n" author)
1347 (format "<dc:date>%s</dc:date>\n" date)
1348 (format "<meta:creation-date>%s</meta:creation-date>\n" date)
1349 (format "<meta:generator>%s</meta:generator>\n"
1350 (when org-export-creator-info
1351 (format "Org-%s/Emacs-%s"
1352 org-version emacs-version)))
1353 (format "<meta:keyword>%s</meta:keyword>\n" keywords)
1354 (format "<dc:subject>%s</dc:subject>\n" description)
1355 (format "<dc:title>%s</dc:title>\n" title)
1356 "\n"
1357 " </office:meta>\n" "</office:document-meta>")
1358 nil (expand-file-name "meta.xml")))
1360 ;; create a manifest entry for meta.xml
1361 (org-e-odt-create-manifest-file-entry "text/xml" "meta.xml"))
1363 (defun org-e-odt-update-styles-file (info)
1364 ;; write styles file
1365 (let ((styles-file (plist-get info :odt-styles-file)))
1366 (org-e-odt-copy-styles-file (and styles-file
1367 (read (org-trim styles-file))))
1369 ;; FIXME: Who is opening an empty styles.xml before this point?
1370 (with-current-buffer
1371 (find-file-noselect (expand-file-name "styles.xml") t)
1372 (revert-buffer t t)))
1374 ;; Write custom styles for source blocks
1375 (org-e-odt-insert-custom-styles-for-srcblocks
1376 (mapconcat
1377 (lambda (style)
1378 (format " %s\n" (cddr style)))
1379 hfy-user-sheet-assoc "")))
1381 (defun org-e-odt-write-mimetype-file (format)
1382 ;; create mimetype file
1383 (let ((mimetype
1384 (case format
1385 (odt "application/vnd.oasis.opendocument.text")
1386 (odf "application/vnd.oasis.opendocument.formula")
1387 (t (error "Unknown OpenDocument backend %S" org-lparse-backend)))))
1388 (write-region mimetype nil (expand-file-name "mimetype"))
1389 mimetype))
1391 (defun org-e-odt-finalize-outfile ()
1392 (org-e-odt-delete-empty-paragraphs))
1394 (defun org-e-odt-delete-empty-paragraphs ()
1395 (goto-char (point-min))
1396 (let ((open "<text:p[^>]*>")
1397 (close "</text:p>"))
1398 (while (re-search-forward (format "%s[ \r\n\t]*%s" open close) nil t)
1399 (replace-match ""))))
1401 (declare-function org-create-math-formula "org"
1402 (latex-frag &optional mathml-file))
1404 ;;;###autoload
1405 (defun org-e-odt-convert (&optional in-file out-fmt prefix-arg)
1406 "Convert IN-FILE to format OUT-FMT using a command line converter.
1407 IN-FILE is the file to be converted. If unspecified, it defaults
1408 to variable `buffer-file-name'. OUT-FMT is the desired output
1409 format. Use `org-e-odt-convert-process' as the converter.
1410 If PREFIX-ARG is non-nil then the newly converted file is opened
1411 using `org-open-file'."
1412 (interactive
1413 (append (org-lparse-convert-read-params) current-prefix-arg))
1414 (org-lparse-do-convert in-file out-fmt prefix-arg))
1416 (defun org-e-odt-get (what &optional opt-plist)
1417 (case what
1418 (BACKEND 'odt)
1419 (EXPORT-DIR (org-export-directory :html opt-plist))
1420 (FILE-NAME-EXTENSION "odt")
1421 (EXPORT-BUFFER-NAME "*Org ODT Export*")
1422 (ENTITY-CONTROL org-e-odt-entity-control-callbacks-alist)
1423 (ENTITY-FORMAT org-e-odt-entity-format-callbacks-alist)
1424 (INIT-METHOD 'org-e-odt-init-outfile)
1425 (FINAL-METHOD 'org-e-odt-finalize-outfile)
1426 (SAVE-METHOD 'org-e-odt-save-as-outfile)
1427 (CONVERT-METHOD
1428 (and org-e-odt-convert-process
1429 (cadr (assoc-string org-e-odt-convert-process
1430 org-e-odt-convert-processes t))))
1431 (CONVERT-CAPABILITIES
1432 (and org-e-odt-convert-process
1433 (cadr (assoc-string org-e-odt-convert-process
1434 org-e-odt-convert-processes t))
1435 org-e-odt-convert-capabilities))
1436 (TOPLEVEL-HLEVEL 1)
1437 (SPECIAL-STRING-REGEXPS org-e-odt-special-string-regexps)
1438 (INLINE-IMAGES 'maybe)
1439 (INLINE-IMAGE-EXTENSIONS '("png" "jpeg" "jpg" "gif" "svg"))
1440 (PLAIN-TEXT-MAP '(("&" . "&amp;") ("<" . "&lt;") (">" . "&gt;")))
1441 (TABLE-FIRST-COLUMN-AS-LABELS nil)
1442 (FOOTNOTE-SEPARATOR )
1443 (CODING-SYSTEM-FOR-WRITE 'utf-8)
1444 (CODING-SYSTEM-FOR-SAVE 'utf-8)
1445 (t (error "Unknown property: %s" what))))
1447 (defun org-e-odt-do-preprocess-latex-fragments ()
1448 "Convert LaTeX fragments to images."
1449 (let* ((latex-frag-opt (plist-get org-lparse-opt-plist :LaTeX-fragments))
1450 (latex-frag-opt ; massage the options
1451 (or (and (member latex-frag-opt '(mathjax t))
1452 (not (and (fboundp 'org-format-latex-mathml-available-p)
1453 (org-format-latex-mathml-available-p)))
1454 (prog1 org-lparse-latex-fragment-fallback
1455 (org-lparse-warn
1456 (concat
1457 "LaTeX to MathML converter not available. "
1458 (format "Using %S instead."
1459 org-lparse-latex-fragment-fallback)))))
1460 latex-frag-opt))
1461 cache-dir display-msg)
1462 (cond
1463 ((eq latex-frag-opt 'dvipng)
1464 (setq cache-dir "ltxpng/")
1465 (setq display-msg "Creating LaTeX image %s"))
1466 ((member latex-frag-opt '(mathjax t))
1467 (setq latex-frag-opt 'mathml)
1468 (setq cache-dir "ltxmathml/")
1469 (setq display-msg "Creating MathML formula %s")))
1470 (when (and org-current-export-file)
1471 (org-format-latex
1472 (concat cache-dir (file-name-sans-extension
1473 (file-name-nondirectory org-current-export-file)))
1474 org-current-export-dir nil display-msg
1475 nil nil latex-frag-opt))))
1477 (eval-after-load 'org-odt
1478 '(ad-deactivate 'org-format-latex-as-mathml))
1480 ; FIXME
1482 ;; (defadvice org-format-latex-as-mathml ; FIXME
1483 ;; (after org-e-odt-protect-latex-fragment activate)
1484 ;; "Encode LaTeX fragment as XML.
1485 ;; Do this when translation to MathML fails."
1486 ;; (when (or (not (> (length ad-return-value) 0))
1487 ;; (get-text-property 0 'org-protected ad-return-value))
1488 ;; (setq ad-return-value
1489 ;; (org-propertize (org-e-odt-encode-plain-text (ad-get-arg 0))
1490 ;; 'org-protected t))))
1492 (defun org-e-odt-preprocess-latex-fragments ()
1493 (when (equal org-export-current-backend 'odt)
1494 (org-e-odt-do-preprocess-latex-fragments)))
1496 ;; process latex fragments as part of
1497 ;; `org-export-preprocess-after-blockquote-hook'. Note that this hook
1498 ;; is the one that is closest and well before the call to
1499 ;; `org-export-attach-captions-and-attributes' in
1500 ;; `org-export-preprocess-string'. The above arrangement permits
1501 ;; captions, labels and attributes to be attached to png images
1502 ;; generated out of latex equations.
1503 (add-hook 'org-export-preprocess-after-blockquote-hook
1504 'org-e-odt-preprocess-latex-fragments)
1506 (defun org-e-odt-zip-extract-one (archive member &optional target)
1507 (require 'arc-mode)
1508 (let* ((target (or target default-directory))
1509 (archive (expand-file-name archive))
1510 (archive-zip-extract
1511 (list "unzip" "-qq" "-o" "-d" target))
1512 exit-code command-output)
1513 (setq command-output
1514 (with-temp-buffer
1515 (setq exit-code (archive-zip-extract archive member))
1516 (buffer-string)))
1517 (unless (zerop exit-code)
1518 (message command-output)
1519 (error "Extraction failed"))))
1521 (defun org-e-odt-zip-extract (archive members &optional target)
1522 (when (atom members) (setq members (list members)))
1523 (mapc (lambda (member)
1524 (org-e-odt-zip-extract-one archive member target))
1525 members))
1527 (defun org-e-odt-copy-styles-file (&optional styles-file)
1528 ;; Non-availability of styles.xml is not a critical error. For now
1529 ;; throw an error purely for aesthetic reasons.
1530 (setq styles-file (or styles-file
1531 org-e-odt-styles-file
1532 (expand-file-name "OrgOdtStyles.xml"
1533 org-e-odt-styles-dir)
1534 (error "org-e-odt: Missing styles file?")))
1535 (cond
1536 ((listp styles-file)
1537 (let ((archive (nth 0 styles-file))
1538 (members (nth 1 styles-file)))
1539 (org-e-odt-zip-extract archive members)
1540 (mapc
1541 (lambda (member)
1542 (when (org-file-image-p member)
1543 (let* ((image-type (file-name-extension member))
1544 (media-type (format "image/%s" image-type)))
1545 (org-e-odt-create-manifest-file-entry media-type member))))
1546 members)))
1547 ((and (stringp styles-file) (file-exists-p styles-file))
1548 (let ((styles-file-type (file-name-extension styles-file)))
1549 (cond
1550 ((string= styles-file-type "xml")
1551 (copy-file styles-file (expand-file-name "styles.xml") t))
1552 ((member styles-file-type '("odt" "ott"))
1553 (org-e-odt-zip-extract styles-file "styles.xml")))))
1555 (error (format "Invalid specification of styles.xml file: %S"
1556 org-e-odt-styles-file))))
1558 ;; create a manifest entry for styles.xml
1559 (org-e-odt-create-manifest-file-entry "text/xml" "styles.xml"))
1561 (defun org-e-odt-configure-outline-numbering ()
1562 "Outline numbering is retained only upto LEVEL.
1563 To disable outline numbering pass a LEVEL of 0."
1564 (goto-char (point-min))
1565 (let ((regex
1566 "<text:outline-level-style\\([^>]*\\)text:level=\"\\([^\"]*\\)\"\\([^>]*\\)>")
1567 (replacement
1568 "<text:outline-level-style\\1text:level=\"\\2\" style:num-format=\"\">"))
1569 (while (re-search-forward regex nil t)
1570 (unless (let ((sec-num (plist-get info :section-numbers))
1571 (level (string-to-number (match-string 2))))
1572 (if (wholenump sec-num) (<= level sec-num) sec-num))
1573 (replace-match replacement t nil))))
1574 (save-buffer 0))
1576 ;;;###autoload
1577 (defun org-export-as-odf (latex-frag &optional odf-file)
1578 "Export LATEX-FRAG as OpenDocument formula file ODF-FILE.
1579 Use `org-create-math-formula' to convert LATEX-FRAG first to
1580 MathML. When invoked as an interactive command, use
1581 `org-latex-regexps' to infer LATEX-FRAG from currently active
1582 region. If no LaTeX fragments are found, prompt for it. Push
1583 MathML source to kill ring, if `org-export-copy-to-kill-ring' is
1584 non-nil."
1585 (interactive
1586 `(,(let (frag)
1587 (setq frag (and (setq frag (and (region-active-p)
1588 (buffer-substring (region-beginning)
1589 (region-end))))
1590 (loop for e in org-latex-regexps
1591 thereis (when (string-match (nth 1 e) frag)
1592 (match-string (nth 2 e) frag)))))
1593 (read-string "LaTeX Fragment: " frag nil frag))
1594 ,(let ((odf-filename (expand-file-name
1595 (concat
1596 (file-name-sans-extension
1597 (or (file-name-nondirectory buffer-file-name)))
1598 "." "odf")
1599 (file-name-directory buffer-file-name))))
1600 (read-file-name "ODF filename: " nil odf-filename nil
1601 (file-name-nondirectory odf-filename)))))
1602 (let* ((org-lparse-backend 'odf)
1603 org-lparse-opt-plist
1604 (filename (or odf-file
1605 (expand-file-name
1606 (concat
1607 (file-name-sans-extension
1608 (or (file-name-nondirectory buffer-file-name)))
1609 "." "odf")
1610 (file-name-directory buffer-file-name))))
1611 (buffer (find-file-noselect (org-e-odt-init-outfile filename)))
1612 (coding-system-for-write 'utf-8)
1613 (save-buffer-coding-system 'utf-8))
1614 (set-buffer buffer)
1615 (set-buffer-file-coding-system coding-system-for-write)
1616 (let ((mathml (org-create-math-formula latex-frag)))
1617 (unless mathml (error "No Math formula created"))
1618 (insert mathml)
1619 (or (org-export-push-to-kill-ring
1620 (upcase (symbol-name org-lparse-backend)))
1621 (message "Exporting... done")))
1622 (org-e-odt-save-as-outfile filename nil ; FIXME
1625 ;;;###autoload
1626 (defun org-export-as-odf-and-open ()
1627 "Export LaTeX fragment as OpenDocument formula and immediately open it.
1628 Use `org-export-as-odf' to read LaTeX fragment and OpenDocument
1629 formula file."
1630 (interactive)
1631 (org-lparse-and-open
1632 nil nil nil (call-interactively 'org-export-as-odf)))
1637 ;;; Driver Starts here
1638 ;;; Dependencies
1640 (require 'format-spec)
1641 (eval-when-compile (require 'cl) (require 'table))
1645 ;;; Hooks
1647 ;; FIXME: it already exists in org-e-odt.el
1648 ;;; Function Declarations
1650 (declare-function org-element-property "org-element" (property element))
1651 (declare-function org-element-normalize-string "org-element" (s))
1652 (declare-function org-element-parse-secondary-string
1653 "org-element" (string restriction &optional buffer))
1654 (defvar org-element-string-restrictions)
1655 (defvar org-element-object-restrictions)
1657 (declare-function org-export-clean-table "org-export" (table specialp))
1658 (declare-function org-export-data "org-export" (data backend info))
1659 (declare-function org-export-directory "org-export" (type plist))
1660 (declare-function org-export-expand-macro "org-export" (macro info))
1661 (declare-function org-export-first-sibling-p "org-export" (headline info))
1662 (declare-function org-export-footnote-first-reference-p "org-export"
1663 (footnote-reference info))
1664 (declare-function org-export-get-coderef-format "org-export" (path desc))
1665 (declare-function org-export-get-footnote-definition "org-export"
1666 (footnote-reference info))
1667 (declare-function org-export-get-footnote-number "org-export" (footnote info))
1668 (declare-function org-export-get-previous-element "org-export" (blob info))
1669 (declare-function org-export-get-relative-level "org-export" (headline info))
1670 (declare-function org-export-handle-code
1671 "org-export" (element info &optional num-fmt ref-fmt delayed))
1672 (declare-function org-export-included-file "org-export" (keyword backend info))
1673 (declare-function org-export-inline-image-p "org-export"
1674 (link &optional extensions))
1675 (declare-function org-export-last-sibling-p "org-export" (headline info))
1676 (declare-function org-export-low-level-p "org-export" (headline info))
1677 (declare-function org-export-output-file-name
1678 "org-export" (extension &optional subtreep pub-dir))
1679 (declare-function org-export-resolve-coderef "org-export" (ref info))
1680 (declare-function org-export-resolve-fuzzy-link "org-export" (link info))
1681 (declare-function org-export-secondary-string "org-export"
1682 (secondary backend info))
1683 (declare-function org-export-solidify-link-text "org-export" (s))
1684 (declare-function org-export-table-format-info "org-export" (table))
1685 (declare-function
1686 org-export-to-buffer "org-export"
1687 (backend buffer &optional subtreep visible-only body-only ext-plist))
1688 (declare-function
1689 org-export-to-file "org-export"
1690 (backend file &optional subtreep visible-only body-only ext-plist))
1692 (declare-function org-id-find-id-file "org-id" (id))
1693 (declare-function htmlize-region "ext:htmlize" (beg end))
1694 (declare-function org-pop-to-buffer-same-window
1695 "org-compat" (&optional buffer-or-name norecord label))
1701 (declare-function hfy-face-to-style "htmlfontify" (fn))
1702 (declare-function hfy-face-or-def-to-name "htmlfontify" (fn))
1703 (declare-function archive-zip-extract "arc-mode.el" (archive name))
1705 ;;; Internal Variables
1707 ;;;; ODT Internal Variables
1709 (defconst org-e-odt-lib-dir
1710 (file-name-directory load-file-name)
1711 "Location of ODT exporter.
1712 Use this to infer values of `org-e-odt-styles-dir' and
1713 `org-e-odt-schema-dir'.")
1715 (defvar org-e-odt-data-dir
1716 (expand-file-name "../etc/" org-e-odt-lib-dir)
1717 "Data directory for ODT exporter.
1718 Use this to infer values of `org-e-odt-styles-dir' and
1719 `org-e-odt-schema-dir'.")
1724 (defconst org-e-odt-special-string-regexps
1725 '(("\\\\-" . "&#x00ad;\\1") ; shy
1726 ("---\\([^-]\\)" . "&#x2014;\\1") ; mdash
1727 ("--\\([^-]\\)" . "&#x2013;\\1") ; ndash
1728 ("\\.\\.\\." . "&#x2026;")) ; hellip
1729 "Regular expressions for special string conversion.")
1731 (defconst org-e-odt-schema-dir-list
1732 (list
1733 (and org-e-odt-data-dir
1734 (expand-file-name "./schema/" org-e-odt-data-dir)) ; bail out
1735 (eval-when-compile
1736 (and (boundp 'org-e-odt-data-dir) org-e-odt-data-dir ; see make install
1737 (expand-file-name "./schema/" org-e-odt-data-dir)))
1738 (expand-file-name "../contrib/odt/etc/schema/" org-e-odt-lib-dir) ; git
1740 "List of directories to search for OpenDocument schema files.
1741 Use this list to set the default value of
1742 `org-e-odt-schema-dir'. The entries in this list are
1743 populated heuristically based on the values of `org-e-odt-lib-dir'
1744 and `org-e-odt-data-dir'.")
1747 (defconst org-e-odt-styles-dir-list
1748 (list
1749 (and org-e-odt-data-dir
1750 (expand-file-name "./styles/" org-e-odt-data-dir)) ; bail out
1751 (eval-when-compile
1752 (and (boundp 'org-e-odt-data-dir) org-e-odt-data-dir ; see make install
1753 (expand-file-name "./styles/" org-e-odt-data-dir)))
1754 (expand-file-name "../etc/styles/" org-e-odt-lib-dir) ; git
1755 (expand-file-name "./etc/styles/" org-e-odt-lib-dir) ; elpa
1756 (expand-file-name "./org/" data-directory) ; system
1758 "List of directories to search for OpenDocument styles files.
1759 See `org-e-odt-styles-dir'. The entries in this list are populated
1760 heuristically based on the values of `org-e-odt-lib-dir' and
1761 `org-e-odt-data-dir'.")
1763 (defconst org-e-odt-styles-dir
1764 (let* ((styles-dir
1765 (catch 'styles-dir
1766 (message "Debug (org-e-odt): Searching for OpenDocument styles files...")
1767 (mapc (lambda (styles-dir)
1768 (when styles-dir
1769 (message "Debug (org-e-odt): Trying %s..." styles-dir)
1770 (when (and (file-readable-p
1771 (expand-file-name
1772 "OrgOdtContentTemplate.xml" styles-dir))
1773 (file-readable-p
1774 (expand-file-name
1775 "OrgOdtStyles.xml" styles-dir)))
1776 (message "Debug (org-e-odt): Using styles under %s"
1777 styles-dir)
1778 (throw 'styles-dir styles-dir))))
1779 org-e-odt-styles-dir-list)
1780 nil)))
1781 (unless styles-dir
1782 (error "Error (org-e-odt): Cannot find factory styles files. Aborting."))
1783 styles-dir)
1784 "Directory that holds auxiliary XML files used by the ODT exporter.
1786 This directory contains the following XML files -
1787 \"OrgOdtStyles.xml\" and \"OrgOdtContentTemplate.xml\". These
1788 XML files are used as the default values of
1789 `org-e-odt-styles-file' and
1790 `org-e-odt-content-template-file'.
1792 The default value of this variable varies depending on the
1793 version of org in use and is initialized from
1794 `org-e-odt-styles-dir-list'. Note that the user could be using org
1795 from one of: org's own private git repository, GNU ELPA tar or
1796 standard Emacs.")
1798 (defconst org-e-odt-tmpdir-prefix "%s-")
1799 (defconst org-e-odt-bookmark-prefix "OrgXref.")
1801 (defconst org-e-odt-manifest-file-entry-tag
1803 <manifest:file-entry manifest:media-type=\"%s\" manifest:full-path=\"%s\"%s/>")
1807 (defvar org-lparse-dyn-first-heading-pos) ; let bound during org-do-lparse
1809 (defvar org-e-odt-suppress-xref nil)
1810 (defvar org-e-odt-file-extensions
1811 '(("odt" . "OpenDocument Text")
1812 ("ott" . "OpenDocument Text Template")
1813 ("odm" . "OpenDocument Master Document")
1814 ("ods" . "OpenDocument Spreadsheet")
1815 ("ots" . "OpenDocument Spreadsheet Template")
1816 ("odg" . "OpenDocument Drawing (Graphics)")
1817 ("otg" . "OpenDocument Drawing Template")
1818 ("odp" . "OpenDocument Presentation")
1819 ("otp" . "OpenDocument Presentation Template")
1820 ("odi" . "OpenDocument Image")
1821 ("odf" . "OpenDocument Formula")
1822 ("odc" . "OpenDocument Chart")))
1824 (defvar org-e-odt-default-org-styles-alist
1825 '((paragraph . ((default . "Text_20_body")
1826 (fixedwidth . "OrgFixedWidthBlock")
1827 (verse . "OrgVerse")
1828 (quote . "Quotations")
1829 (blockquote . "Quotations")
1830 (center . "OrgCenter")
1831 (left . "OrgLeft")
1832 (right . "OrgRight")
1833 (title . "OrgTitle")
1834 (subtitle . "OrgSubtitle")
1835 (footnote . "Footnote")
1836 (src . "OrgSrcBlock")
1837 (illustration . "Illustration")
1838 (table . "Table")
1839 (definition-term . "Text_20_body_20_bold")
1840 (horizontal-line . "Horizontal_20_Line")))
1841 (character . ((bold . "Bold")
1842 (emphasis . "Emphasis")
1843 (code . "OrgCode")
1844 (verbatim . "OrgCode")
1845 (strike . "Strikethrough")
1846 (underline . "Underline")
1847 (subscript . "OrgSubscript")
1848 (superscript . "OrgSuperscript")))
1849 (list . ((ordered . "OrgNumberedList")
1850 (unordered . "OrgBulletedList")
1851 (descriptive . "OrgDescriptionList"))))
1852 "Default styles for various entities.")
1854 (defvar org-e-odt-org-styles-alist org-e-odt-default-org-styles-alist)
1856 ;;;_. callbacks
1857 ;;;_. control callbacks
1858 ;;;_ , document body
1860 (defvar org-lparse-body-only) ; let bound during org-do-lparse
1861 (defvar org-lparse-opt-plist) ; bound during org-do-lparse
1862 (defvar org-lparse-list-stack) ; dynamically bound in org-do-lparse
1863 (defvar org-e-odt-list-stack-stashed)
1864 (defvar org-lparse-table-ncols)
1865 (defvar org-e-odt-table-rowgrp-open)
1866 (defvar org-e-odt-table-rownum)
1867 (defvar org-e-odt-table-cur-rowgrp-is-hdr)
1868 (defvar org-lparse-table-is-styled)
1869 (defvar org-lparse-table-rowgrp-info)
1870 (defvar org-lparse-table-colalign-vector)
1872 (defvar org-e-odt-table-style nil
1873 "Table style specified by \"#+ATTR_ODT: <style-name>\" line.
1874 This is set during `org-e-odt-begin-table'.")
1876 (defvar org-e-odt-table-style-spec nil
1877 "Entry for `org-e-odt-table-style' in `org-e-odt-table-styles'.")
1880 (defvar org-e-odt-table-style-format
1882 <style:style style:name=\"%s\" style:family=\"table\">
1883 <style:table-properties style:rel-width=\"%d%%\" fo:margin-top=\"0cm\" fo:margin-bottom=\"0.20cm\" table:align=\"center\"/>
1884 </style:style>
1886 "Template for auto-generated Table styles.")
1888 (defvar org-e-odt-automatic-styles '()
1889 "Registry of automatic styles for various OBJECT-TYPEs.
1890 The variable has the following form:
1891 \(\(OBJECT-TYPE-A
1892 \(\(OBJECT-NAME-A.1 OBJECT-PROPS-A.1\)
1893 \(OBJECT-NAME-A.2 OBJECT-PROPS-A.2\) ...\)\)
1894 \(OBJECT-TYPE-B
1895 \(\(OBJECT-NAME-B.1 OBJECT-PROPS-B.1\)
1896 \(OBJECT-NAME-B.2 OBJECT-PROPS-B.2\) ...\)\)
1897 ...\).
1899 OBJECT-TYPEs could be \"Section\", \"Table\", \"Figure\" etc.
1900 OBJECT-PROPS is (typically) a plist created by passing
1901 \"#+ATTR_ODT: \" option to `org-e-odt-parse-block-attributes'.
1903 Use `org-e-odt-add-automatic-style' to add update this variable.'")
1905 (defvar org-e-odt-object-counters nil
1906 "Running counters for various OBJECT-TYPEs.
1907 Use this to generate automatic names and style-names. See
1908 `org-e-odt-add-automatic-style'.")
1910 (defvar org-e-odt-table-indentedp nil)
1911 (defvar org-lparse-table-colalign-info)
1912 (defvar org-lparse-link-description-is-image nil)
1915 (defvar org-src-block-paragraph-format
1916 "<style:style style:name=\"OrgSrcBlock\" style:family=\"paragraph\" style:parent-style-name=\"Preformatted_20_Text\">
1917 <style:paragraph-properties fo:background-color=\"%s\" fo:padding=\"0.049cm\" fo:border=\"0.51pt solid #000000\" style:shadow=\"none\">
1918 <style:background-image/>
1919 </style:paragraph-properties>
1920 <style:text-properties fo:color=\"%s\"/>
1921 </style:style>"
1922 "Custom paragraph style for colorized source and example blocks.
1923 This style is much the same as that of \"OrgFixedWidthBlock\"
1924 except that the foreground and background colors are set
1925 according to the default face identified by the `htmlfontify'.")
1927 (defvar hfy-optimisations)
1928 (defvar org-e-odt-embedded-formulas-count 0)
1929 (defvar org-e-odt-entity-frame-styles
1930 '(("As-CharImage" "__Figure__" ("OrgInlineImage" nil "as-char"))
1931 ("ParagraphImage" "__Figure__" ("OrgDisplayImage" nil "paragraph"))
1932 ("PageImage" "__Figure__" ("OrgPageImage" nil "page"))
1933 ("CaptionedAs-CharImage" "__Figure__"
1934 ("OrgCaptionedImage"
1935 " style:rel-width=\"100%\" style:rel-height=\"scale\"" "paragraph")
1936 ("OrgInlineImage" nil "as-char"))
1937 ("CaptionedParagraphImage" "__Figure__"
1938 ("OrgCaptionedImage"
1939 " style:rel-width=\"100%\" style:rel-height=\"scale\"" "paragraph")
1940 ("OrgImageCaptionFrame" nil "paragraph"))
1941 ("CaptionedPageImage" "__Figure__"
1942 ("OrgCaptionedImage"
1943 " style:rel-width=\"100%\" style:rel-height=\"scale\"" "paragraph")
1944 ("OrgPageImageCaptionFrame" nil "page"))
1945 ("InlineFormula" "__MathFormula__" ("OrgInlineFormula" nil "as-char"))
1946 ("DisplayFormula" "__MathFormula__" ("OrgDisplayFormula" nil "as-char"))
1947 ("CaptionedDisplayFormula" "__MathFormula__"
1948 ("OrgCaptionedFormula" nil "paragraph")
1949 ("OrgFormulaCaptionFrame" nil "as-char"))))
1951 (defvar org-e-odt-embedded-images-count 0)
1953 (defvar org-e-odt-image-size-probe-method
1954 (append (and (executable-find "identify") '(imagemagick)) ; See Bug#10675
1955 '(emacs fixed))
1956 "Ordered list of methods for determining image sizes.")
1958 (defvar org-e-odt-default-image-sizes-alist
1959 '(("as-char" . (5 . 0.4))
1960 ("paragraph" . (5 . 5)))
1961 "Hardcoded image dimensions one for each of the anchor
1962 methods.")
1964 ;; A4 page size is 21.0 by 29.7 cms
1965 ;; The default page settings has 2cm margin on each of the sides. So
1966 ;; the effective text area is 17.0 by 25.7 cm
1967 (defvar org-e-odt-max-image-size '(17.0 . 20.0)
1968 "Limiting dimensions for an embedded image.")
1970 (defvar org-e-odt-entity-labels-alist nil
1971 "Associate Labels with the Labeled entities.
1972 Each element of the alist is of the form (LABEL-NAME
1973 CATEGORY-NAME SEQNO LABEL-STYLE-NAME). LABEL-NAME is same as
1974 that specified by \"#+LABEL: ...\" line. CATEGORY-NAME is the
1975 type of the entity that LABEL-NAME is attached to. CATEGORY-NAME
1976 can be one of \"Table\", \"Figure\" or \"Equation\". SEQNO is
1977 the unique number assigned to the referenced entity on a
1978 per-CATEGORY basis. It is generated sequentially and is 1-based.
1979 LABEL-STYLE-NAME is a key `org-e-odt-label-styles'.
1981 See `org-e-odt-add-label-definition' and
1982 `org-e-odt-fixup-label-references'.")
1984 (defvar org-e-odt-entity-counts-plist nil
1985 "Plist of running counters of SEQNOs for each of the CATEGORY-NAMEs.
1986 See `org-e-odt-entity-labels-alist' for known CATEGORY-NAMEs.")
1988 (defvar org-e-odt-label-styles
1989 '(("text" "(%n)" "text" "(%n)")
1990 ("category-and-value" "%e %n%c" "category-and-value" "%e %n")
1991 ("value" "%e %n%c" "value" "%n"))
1992 "Specify how labels are applied and referenced.
1993 This is an alist where each element is of the
1994 form (LABEL-STYLE-NAME LABEL-ATTACH-FMT LABEL-REF-MODE
1995 LABEL-REF-FMT).
1997 LABEL-ATTACH-FMT controls how labels and captions are attached to
1998 an entity. It may contain following specifiers - %e, %n and %c.
1999 %e is replaced with the CATEGORY-NAME. %n is replaced with
2000 \"<text:sequence ...> SEQNO </text:sequence>\". %c is replaced
2001 with CAPTION. See `org-e-odt-format-label-definition'.
2003 LABEL-REF-MODE and LABEL-REF-FMT controls how label references
2004 are generated. The following XML is generated for a label
2005 reference - \"<text:sequence-ref
2006 text:reference-format=\"LABEL-REF-MODE\" ...> LABEL-REF-FMT
2007 </text:sequence-ref>\". LABEL-REF-FMT may contain following
2008 specifiers - %e and %n. %e is replaced with the CATEGORY-NAME.
2009 %n is replaced with SEQNO. See
2010 `org-e-odt-format-label-reference'.")
2012 (defvar org-e-odt-category-map-alist
2013 '(("__Table__" "Table" "value")
2014 ("__Figure__" "Figure" "value")
2015 ("__MathFormula__" "Equation" "text")
2016 ("__DvipngImage__" "Equation" "value")
2017 ;; ("__Table__" "Table" "category-and-value")
2018 ;; ("__Figure__" "Figure" "category-and-value")
2019 ;; ("__DvipngImage__" "Equation" "category-and-value")
2021 "Map a CATEGORY-HANDLE to CATEGORY-NAME and LABEL-STYLE.
2022 This is an alist where each element is of the form
2023 \\(CATEGORY-HANDLE CATEGORY-NAME LABEL-STYLE\\). CATEGORY_HANDLE
2024 could either be one of the internal handles (as seen above) or be
2025 derived from the \"#+LABEL:<label-name>\" specification. See
2026 `org-e-odt-get-category-from-label'. CATEGORY-NAME and
2027 LABEL-STYLE are used for generating ODT labels. See
2028 `org-e-odt-label-styles'.")
2030 (defvar org-e-odt-manifest-file-entries nil)
2031 (defvar hfy-user-sheet-assoc) ; bound during org-do-lparse
2032 (defvar org-lparse-latex-fragment-fallback) ; set by org-do-lparse
2035 ;;;; HTML Internal Variables
2037 (defvar org-e-odt-option-alist
2039 ;; (:agenda-style nil nil org-agenda-export-html-style)
2040 ;; (:convert-org-links nil nil org-e-odt-link-org-files-as-html)
2041 ;; ;; FIXME Use (org-xml-encode-org-text-skip-links s) ??
2042 ;; ;; (:expand-quoted-html nil "@" org-e-odt-expand)
2043 ;; (:inline-images nil nil org-e-odt-inline-images)
2044 ;; ;; (:link-home nil nil org-e-odt-link-home) FIXME
2045 ;; ;; (:link-up nil nil org-e-odt-link-up) FIXME
2046 ;; (:style nil nil org-e-odt-style)
2047 ;; (:style-extra nil nil org-e-odt-style-extra)
2048 ;; (:style-include-default nil nil org-e-odt-style-include-default)
2049 ;; (:style-include-scripts nil nil org-e-odt-style-include-scripts)
2050 ;; ;; (:timestamp nil nil org-e-odt-with-timestamp)
2051 ;; (:html-extension nil nil org-e-odt-extension)
2052 ;; (:html-postamble nil nil org-e-odt-postamble)
2053 ;; (:html-preamble nil nil org-e-odt-preamble)
2054 ;; (:html-table-tag nil nil org-e-odt-table-tag)
2055 ;; (:xml-declaration nil nil org-e-odt-xml-declaration)
2056 (:odt-styles-file "ODT_STYLES_FILE" nil nil t)
2057 (:LaTeX-fragments nil "LaTeX" org-export-with-LaTeX-fragments))
2058 "Alist between export properties and ways to set them.
2060 The car of the alist is the property name, and the cdr is a list
2061 like \(KEYWORD OPTION DEFAULT BEHAVIOUR\) where:
2063 KEYWORD is a string representing a buffer keyword, or nil.
2064 OPTION is a string that could be found in an #+OPTIONS: line.
2065 DEFAULT is the default value for the property.
2066 BEHAVIOUR determine how Org should handle multiple keywords for
2067 the same property. It is a symbol among:
2068 nil Keep old value and discard the new one.
2069 t Replace old value with the new one.
2070 `space' Concatenate the values, separating them with a space.
2071 `newline' Concatenate the values, separating them with
2072 a newline.
2073 `split' Split values at white spaces, and cons them to the
2074 previous list.
2076 KEYWORD and OPTION have precedence over DEFAULT.
2078 All these properties should be back-end agnostic. For back-end
2079 specific properties, define a similar variable named
2080 `org-BACKEND-option-alist', replacing BACKEND with the name of
2081 the appropriate back-end. You can also redefine properties
2082 there, as they have precedence over these.")
2084 (defvar html-table-tag nil) ; dynamically scoped into this.
2086 ;; FIXME: it already exists in org-e-odt.el
2087 (defconst org-e-odt-cvt-link-fn
2089 "Function to convert link URLs to exportable URLs.
2090 Takes two arguments, TYPE and PATH.
2091 Returns exportable url as (TYPE PATH), or nil to signal that it
2092 didn't handle this case.
2093 Intended to be locally bound around a call to `org-export-as-html'." )
2098 (defvar org-e-odt-format-table-no-css)
2099 (defvar htmlize-buffer-places) ; from htmlize.el
2100 (defvar body-only) ; dynamically scoped into this.
2102 (defvar org-e-odt-table-rowgrp-open)
2103 (defvar org-e-odt-table-rownum)
2104 (defvar org-e-odt-table-cur-rowgrp-is-hdr)
2105 (defvar org-lparse-table-is-styled)
2108 (defvar org-e-odt-headline-formatter
2109 (lambda (level snumber todo todo-type priority
2110 title tags target extra-targets extra-class)
2111 (concat snumber " " title)))
2115 ;;; User Configuration Variables
2117 (defgroup org-export-e-odt nil
2118 "Options for exporting Org mode files to HTML."
2119 :tag "Org Export HTML"
2120 :group 'org-export)
2122 (defcustom org-e-odt-protect-char-alist
2123 '(("&" . "&amp;")
2124 ("<" . "&lt;")
2125 (">" . "&gt;"))
2126 "Alist of characters to be converted by `org-e-html-protect'."
2127 :group 'org-export-e-html
2128 :type '(repeat (cons (string :tag "Character")
2129 (string :tag "ODT equivalent"))))
2130 (defcustom org-e-odt-schema-dir
2131 (let* ((schema-dir
2132 (catch 'schema-dir
2133 (message "Debug (org-e-odt): Searching for OpenDocument schema files...")
2134 (mapc
2135 (lambda (schema-dir)
2136 (when schema-dir
2137 (message "Debug (org-e-odt): Trying %s..." schema-dir)
2138 (when (and (file-readable-p
2139 (expand-file-name "od-manifest-schema-v1.2-cs01.rnc"
2140 schema-dir))
2141 (file-readable-p
2142 (expand-file-name "od-schema-v1.2-cs01.rnc"
2143 schema-dir))
2144 (file-readable-p
2145 (expand-file-name "schemas.xml" schema-dir)))
2146 (message "Debug (org-e-odt): Using schema files under %s"
2147 schema-dir)
2148 (throw 'schema-dir schema-dir))))
2149 org-e-odt-schema-dir-list)
2150 (message "Debug (org-e-odt): No OpenDocument schema files installed")
2151 nil)))
2152 schema-dir)
2153 "Directory that contains OpenDocument schema files.
2155 This directory contains:
2156 1. rnc files for OpenDocument schema
2157 2. a \"schemas.xml\" file that specifies locating rules needed
2158 for auto validation of OpenDocument XML files.
2160 Use the customize interface to set this variable. This ensures
2161 that `rng-schema-locating-files' is updated and auto-validation
2162 of OpenDocument XML takes place based on the value
2163 `rng-nxml-auto-validate-flag'.
2165 The default value of this variable varies depending on the
2166 version of org in use and is initialized from
2167 `org-e-odt-schema-dir-list'. The OASIS schema files are available
2168 only in the org's private git repository. It is *not* bundled
2169 with GNU ELPA tar or standard Emacs distribution."
2170 :type '(choice
2171 (const :tag "Not set" nil)
2172 (directory :tag "Schema directory"))
2173 :group 'org-export-e-odt
2174 :version "24.1"
2175 :set
2176 (lambda (var value)
2177 "Set `org-e-odt-schema-dir'.
2178 Also add it to `rng-schema-locating-files'."
2179 (let ((schema-dir value))
2180 (set var
2181 (if (and
2182 (file-readable-p
2183 (expand-file-name "od-manifest-schema-v1.2-cs01.rnc" schema-dir))
2184 (file-readable-p
2185 (expand-file-name "od-schema-v1.2-cs01.rnc" schema-dir))
2186 (file-readable-p
2187 (expand-file-name "schemas.xml" schema-dir)))
2188 schema-dir
2189 (when value
2190 (message "Error (org-e-odt): %s has no OpenDocument schema files"
2191 value))
2192 nil)))
2193 (when org-e-odt-schema-dir
2194 (eval-after-load 'rng-loc
2195 '(add-to-list 'rng-schema-locating-files
2196 (expand-file-name "schemas.xml"
2197 org-e-odt-schema-dir))))))
2199 (defcustom org-e-odt-content-template-file nil
2200 "Template file for \"content.xml\".
2201 The exporter embeds the exported content just before
2202 \"</office:text>\" element.
2204 If unspecified, the file named \"OrgOdtContentTemplate.xml\"
2205 under `org-e-odt-styles-dir' is used."
2206 :type 'file
2207 :group 'org-export-e-odt
2208 :version "24.1")
2210 (defcustom org-e-odt-styles-file nil
2211 "Default styles file for use with ODT export.
2212 Valid values are one of:
2213 1. nil
2214 2. path to a styles.xml file
2215 3. path to a *.odt or a *.ott file
2216 4. list of the form (ODT-OR-OTT-FILE (FILE-MEMBER-1 FILE-MEMBER-2
2217 ...))
2219 In case of option 1, an in-built styles.xml is used. See
2220 `org-e-odt-styles-dir' for more information.
2222 In case of option 3, the specified file is unzipped and the
2223 styles.xml embedded therein is used.
2225 In case of option 4, the specified ODT-OR-OTT-FILE is unzipped
2226 and FILE-MEMBER-1, FILE-MEMBER-2 etc are copied in to the
2227 generated odt file. Use relative path for specifying the
2228 FILE-MEMBERS. styles.xml must be specified as one of the
2229 FILE-MEMBERS.
2231 Use options 1, 2 or 3 only if styles.xml alone suffices for
2232 achieving the desired formatting. Use option 4, if the styles.xml
2233 references additional files like header and footer images for
2234 achieving the desired formatting.
2236 Use \"#+ODT_STYLES_FILE: ...\" directive to set this variable on
2237 a per-file basis. For example,
2239 #+ODT_STYLES_FILE: \"/path/to/styles.xml\" or
2240 #+ODT_STYLES_FILE: (\"/path/to/file.ott\" (\"styles.xml\" \"image/hdr.png\"))."
2241 :group 'org-export-e-odt
2242 :version "24.1"
2243 :type
2244 '(choice
2245 (const :tag "Factory settings" nil)
2246 (file :must-match t :tag "styles.xml")
2247 (file :must-match t :tag "ODT or OTT file")
2248 (list :tag "ODT or OTT file + Members"
2249 (file :must-match t :tag "ODF Text or Text Template file")
2250 (cons :tag "Members"
2251 (file :tag " Member" "styles.xml")
2252 (repeat (file :tag "Member"))))))
2255 (defcustom org-e-odt-inline-image-extensions
2256 '("png" "jpeg" "jpg" "gif")
2257 "Extensions of image files that can be inlined into HTML."
2258 :type '(repeat (string :tag "Extension"))
2259 :group 'org-export-e-odt
2260 :version "24.1")
2262 (defcustom org-e-odt-pixels-per-inch display-pixels-per-inch
2263 "Scaling factor for converting images pixels to inches.
2264 Use this for sizing of embedded images. See Info node `(org)
2265 Images in ODT export' for more information."
2266 :type 'float
2267 :group 'org-export-e-odt
2268 :version "24.1")
2270 (defcustom org-e-odt-create-custom-styles-for-srcblocks t
2271 "Whether custom styles for colorized source blocks be automatically created.
2272 When this option is turned on, the exporter creates custom styles
2273 for source blocks based on the advice of `htmlfontify'. Creation
2274 of custom styles happen as part of `org-e-odt-hfy-face-to-css'.
2276 When this option is turned off exporter does not create such
2277 styles.
2279 Use the latter option if you do not want the custom styles to be
2280 based on your current display settings. It is necessary that the
2281 styles.xml already contains needed styles for colorizing to work.
2283 This variable is effective only if
2284 `org-e-odt-fontify-srcblocks' is turned on."
2285 :group 'org-export-e-odt
2286 :version "24.1"
2287 :type 'boolean)
2289 (defcustom org-e-odt-preferred-output-format nil
2290 "Automatically post-process to this format after exporting to \"odt\".
2291 Interactive commands `org-export-as-e-odt' and
2292 `org-export-as-e-odt-and-open' export first to \"odt\" format and
2293 then use `org-e-odt-convert-process' to convert the
2294 resulting document to this format. During customization of this
2295 variable, the list of valid values are populated based on
2296 `org-e-odt-convert-capabilities'."
2297 :group 'org-export-e-odt
2298 :version "24.1"
2299 :type '(choice :convert-widget
2300 (lambda (w)
2301 (apply 'widget-convert (widget-type w)
2302 (eval (car (widget-get w :args)))))
2303 `((const :tag "None" nil)
2304 ,@(mapcar (lambda (c)
2305 `(const :tag ,c ,c))
2306 (org-lparse-reachable-formats "odt")))))
2308 (defcustom org-e-odt-table-styles
2309 '(("OrgEquation" "OrgEquation"
2310 ((use-first-column-styles . t)
2311 (use-last-column-styles . t))))
2312 "Specify how Table Styles should be derived from a Table Template.
2313 This is a list where each element is of the
2314 form (TABLE-STYLE-NAME TABLE-TEMPLATE-NAME TABLE-CELL-OPTIONS).
2316 TABLE-STYLE-NAME is the style associated with the table through
2317 `org-e-odt-table-style'.
2319 TABLE-TEMPLATE-NAME is a set of - upto 9 - automatic
2320 TABLE-CELL-STYLE-NAMEs and PARAGRAPH-STYLE-NAMEs (as defined
2321 below) that is included in
2322 `org-e-odt-content-template-file'.
2324 TABLE-CELL-STYLE-NAME := TABLE-TEMPLATE-NAME + TABLE-CELL-TYPE +
2325 \"TableCell\"
2326 PARAGRAPH-STYLE-NAME := TABLE-TEMPLATE-NAME + TABLE-CELL-TYPE +
2327 \"TableParagraph\"
2328 TABLE-CELL-TYPE := \"FirstRow\" | \"LastColumn\" |
2329 \"FirstRow\" | \"LastRow\" |
2330 \"EvenRow\" | \"OddRow\" |
2331 \"EvenColumn\" | \"OddColumn\" | \"\"
2332 where \"+\" above denotes string concatenation.
2334 TABLE-CELL-OPTIONS is an alist where each element is of the
2335 form (TABLE-CELL-STYLE-SELECTOR . ON-OR-OFF).
2336 TABLE-CELL-STYLE-SELECTOR := `use-first-row-styles' |
2337 `use-last-row-styles' |
2338 `use-first-column-styles' |
2339 `use-last-column-styles' |
2340 `use-banding-rows-styles' |
2341 `use-banding-columns-styles' |
2342 `use-first-row-styles'
2343 ON-OR-OFF := `t' | `nil'
2345 For example, with the following configuration
2347 \(setq org-e-odt-table-styles
2348 '\(\(\"TableWithHeaderRowsAndColumns\" \"Custom\"
2349 \(\(use-first-row-styles . t\)
2350 \(use-first-column-styles . t\)\)\)
2351 \(\"TableWithHeaderColumns\" \"Custom\"
2352 \(\(use-first-column-styles . t\)\)\)\)\)
2354 1. A table associated with \"TableWithHeaderRowsAndColumns\"
2355 style will use the following table-cell styles -
2356 \"CustomFirstRowTableCell\", \"CustomFirstColumnTableCell\",
2357 \"CustomTableCell\" and the following paragraph styles
2358 \"CustomFirstRowTableParagraph\",
2359 \"CustomFirstColumnTableParagraph\", \"CustomTableParagraph\"
2360 as appropriate.
2362 2. A table associated with \"TableWithHeaderColumns\" style will
2363 use the following table-cell styles -
2364 \"CustomFirstColumnTableCell\", \"CustomTableCell\" and the
2365 following paragraph styles
2366 \"CustomFirstColumnTableParagraph\", \"CustomTableParagraph\"
2367 as appropriate..
2369 Note that TABLE-TEMPLATE-NAME corresponds to the
2370 \"<table:table-template>\" elements contained within
2371 \"<office:styles>\". The entries (TABLE-STYLE-NAME
2372 TABLE-TEMPLATE-NAME TABLE-CELL-OPTIONS) correspond to
2373 \"table:template-name\" and \"table:use-first-row-styles\" etc
2374 attributes of \"<table:table>\" element. Refer ODF-1.2
2375 specification for more information. Also consult the
2376 implementation filed under `org-e-odt-get-table-cell-styles'.
2378 The TABLE-STYLE-NAME \"OrgEquation\" is used internally for
2379 formatting of numbered display equations. Do not delete this
2380 style from the list."
2381 :group 'org-export-e-odt
2382 :version "24.1"
2383 :type '(choice
2384 (const :tag "None" nil)
2385 (repeat :tag "Table Styles"
2386 (list :tag "Table Style Specification"
2387 (string :tag "Table Style Name")
2388 (string :tag "Table Template Name")
2389 (alist :options (use-first-row-styles
2390 use-last-row-styles
2391 use-first-column-styles
2392 use-last-column-styles
2393 use-banding-rows-styles
2394 use-banding-columns-styles)
2395 :key-type symbol
2396 :value-type (const :tag "True" t))))))
2397 (defcustom org-e-odt-fontify-srcblocks t
2398 "Specify whether or not source blocks need to be fontified.
2399 Turn this option on if you want to colorize the source code
2400 blocks in the exported file. For colorization to work, you need
2401 to make available an enhanced version of `htmlfontify' library."
2402 :type 'boolean
2403 :group 'org-export-e-odt
2404 :version "24.1")
2406 (defcustom org-e-odt-prettify-xml t ; FIXME
2407 "Specify whether or not the xml output should be prettified.
2408 When this option is turned on, `indent-region' is run on all
2409 component xml buffers before they are saved. Turn this off for
2410 regular use. Turn this on if you need to examine the xml
2411 visually."
2412 :group 'org-export-e-odt
2413 :version "24.1"
2414 :type 'boolean)
2416 (defcustom org-e-odt-convert-processes
2417 '(("LibreOffice"
2418 "soffice --headless --convert-to %f%x --outdir %d %i")
2419 ("unoconv"
2420 "unoconv -f %f -o %d %i"))
2421 "Specify a list of document converters and their usage.
2422 The converters in this list are offered as choices while
2423 customizing `org-e-odt-convert-process'.
2425 This variable is a list where each element is of the
2426 form (CONVERTER-NAME CONVERTER-CMD). CONVERTER-NAME is the name
2427 of the converter. CONVERTER-CMD is the shell command for the
2428 converter and can contain format specifiers. These format
2429 specifiers are interpreted as below:
2431 %i input file name in full
2432 %I input file name as a URL
2433 %f format of the output file
2434 %o output file name in full
2435 %O output file name as a URL
2436 %d output dir in full
2437 %D output dir as a URL.
2438 %x extra options as set in `org-e-odt-convert-capabilities'."
2439 :group 'org-export-e-odt
2440 :version "24.1"
2441 :type
2442 '(choice
2443 (const :tag "None" nil)
2444 (alist :tag "Converters"
2445 :key-type (string :tag "Converter Name")
2446 :value-type (group (string :tag "Command line")))))
2448 (defcustom org-e-odt-convert-process "LibreOffice"
2449 "Use this converter to convert from \"odt\" format to other formats.
2450 During customization, the list of converter names are populated
2451 from `org-e-odt-convert-processes'."
2452 :group 'org-export-e-odt
2453 :version "24.1"
2454 :type '(choice :convert-widget
2455 (lambda (w)
2456 (apply 'widget-convert (widget-type w)
2457 (eval (car (widget-get w :args)))))
2458 `((const :tag "None" nil)
2459 ,@(mapcar (lambda (c)
2460 `(const :tag ,(car c) ,(car c)))
2461 org-e-odt-convert-processes))))
2463 (defcustom org-e-odt-convert-capabilities
2464 '(("Text"
2465 ("odt" "ott" "doc" "rtf" "docx")
2466 (("pdf" "pdf") ("odt" "odt") ("rtf" "rtf") ("ott" "ott")
2467 ("doc" "doc" ":\"MS Word 97\"") ("docx" "docx") ("html" "html")))
2468 ("Web"
2469 ("html")
2470 (("pdf" "pdf") ("odt" "odt") ("html" "html")))
2471 ("Spreadsheet"
2472 ("ods" "ots" "xls" "csv" "xlsx")
2473 (("pdf" "pdf") ("ots" "ots") ("html" "html") ("csv" "csv") ("ods" "ods")
2474 ("xls" "xls") ("xlsx" "xlsx")))
2475 ("Presentation"
2476 ("odp" "otp" "ppt" "pptx")
2477 (("pdf" "pdf") ("swf" "swf") ("odp" "odp") ("otp" "otp") ("ppt" "ppt")
2478 ("pptx" "pptx") ("odg" "odg"))))
2479 "Specify input and output formats of `org-e-odt-convert-process'.
2480 More correctly, specify the set of input and output formats that
2481 the user is actually interested in.
2483 This variable is an alist where each element is of the
2484 form (DOCUMENT-CLASS INPUT-FMT-LIST OUTPUT-FMT-ALIST).
2485 INPUT-FMT-LIST is a list of INPUT-FMTs. OUTPUT-FMT-ALIST is an
2486 alist where each element is of the form (OUTPUT-FMT
2487 OUTPUT-FILE-EXTENSION EXTRA-OPTIONS).
2489 The variable is interpreted as follows:
2490 `org-e-odt-convert-process' can take any document that is in
2491 INPUT-FMT-LIST and produce any document that is in the
2492 OUTPUT-FMT-LIST. A document converted to OUTPUT-FMT will have
2493 OUTPUT-FILE-EXTENSION as the file name extension. OUTPUT-FMT
2494 serves dual purposes:
2495 - It is used for populating completion candidates during
2496 `org-e-odt-convert' commands.
2497 - It is used as the value of \"%f\" specifier in
2498 `org-e-odt-convert-process'.
2500 EXTRA-OPTIONS is used as the value of \"%x\" specifier in
2501 `org-e-odt-convert-process'.
2503 DOCUMENT-CLASS is used to group a set of file formats in
2504 INPUT-FMT-LIST in to a single class.
2506 Note that this variable inherently captures how LibreOffice based
2507 converters work. LibreOffice maps documents of various formats
2508 to classes like Text, Web, Spreadsheet, Presentation etc and
2509 allow document of a given class (irrespective of it's source
2510 format) to be converted to any of the export formats associated
2511 with that class.
2513 See default setting of this variable for an typical
2514 configuration."
2515 :group 'org-export-e-odt
2516 :version "24.1"
2517 :type
2518 '(choice
2519 (const :tag "None" nil)
2520 (alist :tag "Capabilities"
2521 :key-type (string :tag "Document Class")
2522 :value-type
2523 (group (repeat :tag "Input formats" (string :tag "Input format"))
2524 (alist :tag "Output formats"
2525 :key-type (string :tag "Output format")
2526 :value-type
2527 (group (string :tag "Output file extension")
2528 (choice
2529 (const :tag "None" nil)
2530 (string :tag "Extra options"))))))))
2532 ;;;; Debugging
2535 ;;;; Document
2537 ;;;; Document Header (Styles)
2539 ;;;; Document Header (Scripts)
2541 ;;;; Document Header (Mathjax)
2543 ;;;; Preamble
2545 ;;;; Postamble
2547 ;;;; Emphasis
2549 ;;;; Todos
2551 ;;;; Tags
2553 ;;;; Time-stamps
2554 ;;;; Statistics Cookie
2555 ;;;; Subscript
2556 ;;;; Superscript
2558 ;;;; Inline images
2560 ;;;; Block
2561 ;;;; Comment
2562 ;;;; Comment Block
2563 ;;;; Drawer
2564 ;;;; Dynamic Block
2565 ;;;; Emphasis
2566 ;;;; Entity
2567 ;;;; Example Block
2568 ;;;; Export Snippet
2569 ;;;; Export Block
2570 ;;;; Fixed Width
2571 ;;;; Footnotes
2573 ;;;; Headline
2574 ;;;; Horizontal Rule
2575 ;;;; Inline Babel Call
2576 ;;;; Inline Src Block
2577 ;;;; Inlinetask
2578 ;;;; Item
2579 ;;;; Keyword
2580 ;;;; Latex Environment
2581 ;;;; Latex Fragment
2582 ;;;; Line Break
2583 ;;;; Link
2584 ;;;; Babel Call
2585 ;;;; Macro
2586 ;;;; Paragraph
2587 ;;;; Plain List
2588 ;;;; Plain Text
2589 ;;;; Property Drawer
2590 ;;;; Quote Block
2591 ;;;; Quote Section
2592 ;;;; Section
2593 ;;;; Radio Target
2594 ;;;; Special Block
2595 ;;;; Src Block
2597 ;;;; Table
2599 ;;;; Target
2600 ;;;; Time-stamp
2602 ;;;; Verbatim
2603 ;;;; Verse Block
2604 ;;;; Headline
2606 ;;;; Links
2607 ;;;; Drawers
2608 ;;;; Inlinetasks
2609 ;;;; Publishing
2611 ;;;; Compilation
2615 ;;; User Configurable Variables (MAYBE)
2617 ;;;; Preamble
2619 ;;;; Headline
2621 ;;;; Emphasis
2623 (defcustom org-e-odt-format-headline-function nil
2624 "Function to format headline text.
2626 This function will be called with 5 arguments:
2627 TODO the todo keyword \(string or nil\).
2628 TODO-TYPE the type of todo \(symbol: `todo', `done', nil\)
2629 PRIORITY the priority of the headline \(integer or nil\)
2630 TEXT the main headline text \(string\).
2631 TAGS the tags string, separated with colons \(string or nil\).
2633 The function result will be used in the section format string.
2635 As an example, one could set the variable to the following, in
2636 order to reproduce the default set-up:
2638 \(defun org-e-odt-format-headline \(todo todo-type priority text tags\)
2639 \"Default format function for an headline.\"
2640 \(concat \(when todo
2641 \(format \"\\\\textbf{\\\\textsc{\\\\textsf{%s}}} \" todo\)\)
2642 \(when priority
2643 \(format \"\\\\framebox{\\\\#%c} \" priority\)\)
2644 text
2645 \(when tags \(format \"\\\\hfill{}\\\\textsc{%s}\" tags\)\)\)\)"
2646 :group 'org-export-e-odt
2647 :type 'function)
2649 ;;;; Footnotes
2651 ;;;; Time-stamps
2653 (defcustom org-e-odt-active-timestamp-format "\\textit{%s}"
2654 "A printf format string to be applied to active time-stamps."
2655 :group 'org-export-e-odt
2656 :type 'string)
2658 (defcustom org-e-odt-inactive-timestamp-format "\\textit{%s}"
2659 "A printf format string to be applied to inactive time-stamps."
2660 :group 'org-export-e-odt
2661 :type 'string)
2663 (defcustom org-e-odt-diary-timestamp-format "\\textit{%s}"
2664 "A printf format string to be applied to diary time-stamps."
2665 :group 'org-export-e-odt
2666 :type 'string)
2669 ;;;; Links
2671 (defcustom org-e-odt-inline-image-rules
2672 '(("file" . "\\.\\(jpeg\\|jpg\\|png\\|gif\\)\\'"))
2673 "Rules characterizing image files that can be inlined into HTML.
2675 A rule consists in an association whose key is the type of link
2676 to consider, and value is a regexp that will be matched against
2677 link's path.
2679 Note that, by default, the image extension *actually* allowed
2680 depend on the way the HTML file is processed. When used with
2681 pdflatex, pdf, jpg and png images are OK. When processing
2682 through dvi to Postscript, only ps and eps are allowed. The
2683 default we use here encompasses both."
2684 :group 'org-export-e-odt
2685 :type '(alist :key-type (string :tag "Type")
2686 :value-type (regexp :tag "Path")))
2688 ;;;; Tables
2690 (defcustom org-e-odt-table-caption-above t
2691 "When non-nil, place caption string at the beginning of the table.
2692 Otherwise, place it near the end."
2693 :group 'org-export-e-odt
2694 :type 'boolean)
2696 ;;;; Drawers
2698 (defcustom org-e-odt-format-drawer-function nil
2699 "Function called to format a drawer in HTML code.
2701 The function must accept two parameters:
2702 NAME the drawer name, like \"LOGBOOK\"
2703 CONTENTS the contents of the drawer.
2705 The function should return the string to be exported.
2707 For example, the variable could be set to the following function
2708 in order to mimic default behaviour:
2710 \(defun org-e-odt-format-drawer-default \(name contents\)
2711 \"Format a drawer element for HTML export.\"
2712 contents\)"
2713 :group 'org-export-e-odt
2714 :type 'function)
2717 ;;;; Inlinetasks
2719 (defcustom org-e-odt-format-inlinetask-function nil
2720 "Function called to format an inlinetask in HTML code.
2722 The function must accept six parameters:
2723 TODO the todo keyword, as a string
2724 TODO-TYPE the todo type, a symbol among `todo', `done' and nil.
2725 PRIORITY the inlinetask priority, as a string
2726 NAME the inlinetask name, as a string.
2727 TAGS the inlinetask tags, as a string.
2728 CONTENTS the contents of the inlinetask, as a string.
2730 The function should return the string to be exported.
2732 For example, the variable could be set to the following function
2733 in order to mimic default behaviour:
2735 \(defun org-e-odt-format-inlinetask \(todo type priority name tags contents\)
2736 \"Format an inline task element for HTML export.\"
2737 \(let \(\(full-title
2738 \(concat
2739 \(when todo
2740 \(format \"\\\\textbf{\\\\textsf{\\\\textsc{%s}}} \" todo\)\)
2741 \(when priority \(format \"\\\\framebox{\\\\#%c} \" priority\)\)
2742 title
2743 \(when tags \(format \"\\\\hfill{}\\\\textsc{%s}\" tags\)\)\)\)\)
2744 \(format \(concat \"\\\\begin{center}\\n\"
2745 \"\\\\fbox{\\n\"
2746 \"\\\\begin{minipage}[c]{.6\\\\textwidth}\\n\"
2747 \"%s\\n\\n\"
2748 \"\\\\rule[.8em]{\\\\textwidth}{2pt}\\n\\n\"
2749 \"%s\"
2750 \"\\\\end{minipage}}\"
2751 \"\\\\end{center}\"\)
2752 full-title contents\)\)"
2753 :group 'org-export-e-odt
2754 :type 'function)
2757 ;; Src blocks
2759 ;;;; Plain text
2761 (defcustom org-e-odt-quotes
2762 '(("fr" ("\\(\\s-\\|[[(]\\)\"" . "«~") ("\\(\\S-\\)\"" . "~»") ("\\(\\s-\\|(\\)'" . "'"))
2763 ("en" ("\\(\\s-\\|[[(]\\)\"" . "``") ("\\(\\S-\\)\"" . "''") ("\\(\\s-\\|(\\)'" . "`")))
2764 "Alist for quotes to use when converting english double-quotes.
2766 The CAR of each item in this alist is the language code.
2767 The CDR of each item in this alist is a list of three CONS:
2768 - the first CONS defines the opening quote;
2769 - the second CONS defines the closing quote;
2770 - the last CONS defines single quotes.
2772 For each item in a CONS, the first string is a regexp
2773 for allowed characters before/after the quote, the second
2774 string defines the replacement string for this quote."
2775 :group 'org-export-e-odt
2776 :type '(list
2777 (cons :tag "Opening quote"
2778 (string :tag "Regexp for char before")
2779 (string :tag "Replacement quote "))
2780 (cons :tag "Closing quote"
2781 (string :tag "Regexp for char after ")
2782 (string :tag "Replacement quote "))
2783 (cons :tag "Single quote"
2784 (string :tag "Regexp for char before")
2785 (string :tag "Replacement quote "))))
2788 ;;;; Compilation
2792 ;;; Internal Functions (HTML)
2794 ;; (defun org-e-odt-format-inline-image (path &optional caption label attr)
2795 ;; ;; FIXME: alt text missing here?
2796 ;; (let ((inline-image (format "<img src=\"%s\" alt=\"%s\"/>"
2797 ;; path (file-name-nondirectory path))))
2798 ;; (if (not label) inline-image
2799 ;; (org-e-odt-format-section inline-image "figure" label))))
2801 ;;;; Bibliography
2803 (defun org-e-odt-bibliography ()
2804 "Find bibliography, cut it out and return it."
2805 (catch 'exit
2806 (let (beg end (cnt 1) bib)
2807 (save-excursion
2808 (goto-char (point-min))
2809 (when (re-search-forward
2810 "^[ \t]*<div \\(id\\|class\\)=\"bibliography\"" nil t)
2811 (setq beg (match-beginning 0))
2812 (while (re-search-forward "</?div\\>" nil t)
2813 (setq cnt (+ cnt (if (string= (match-string 0) "<div") +1 -1)))
2814 (when (= cnt 0)
2815 (and (looking-at ">") (forward-char 1))
2816 (setq bib (buffer-substring beg (point)))
2817 (delete-region beg (point))
2818 (throw 'exit bib))))
2819 nil))))
2821 ;;;; Table
2823 (defun org-e-odt-format-table (lines olines)
2824 (let ((org-e-odt-format-table-no-css nil))
2825 (org-lparse-format-table lines olines)))
2827 (defun org-e-odt-splice-attributes (tag attributes)
2828 "Read attributes in string ATTRIBUTES, add and replace in HTML tag TAG."
2829 (if (not attributes)
2831 (let (oldatt newatt)
2832 (setq oldatt (org-extract-attributes-from-string tag)
2833 tag (pop oldatt)
2834 newatt (cdr (org-extract-attributes-from-string attributes)))
2835 (while newatt
2836 (setq oldatt (plist-put oldatt (pop newatt) (pop newatt))))
2837 (if (string-match ">" tag)
2838 (setq tag
2839 (replace-match (concat (org-attributes-to-string oldatt) ">")
2840 t t tag)))
2841 tag)))
2843 (defun org-export-splice-style (style extra)
2844 "Splice EXTRA into STYLE, just before \"</style>\"."
2845 (if (and (stringp extra)
2846 (string-match "\\S-" extra)
2847 (string-match "</style>" style))
2848 (concat (substring style 0 (match-beginning 0))
2849 "\n" extra "\n"
2850 (substring style (match-beginning 0)))
2851 style))
2853 (defun org-e-odt-toc-entry-formatter
2854 (level snumber todo todo-type priority
2855 headline tags target extra-targets extra-class)
2856 (org-e-odt-format-toc-entry snumber todo headline tags target))
2858 (defun org-e-odt-make-string (n string)
2859 (let (out) (dotimes (i n out) (setq out (concat string out)))))
2861 (defun org-e-odt-toc-text (toc-entries)
2862 (let* ((prev-level (1- (nth 1 (car toc-entries))))
2863 (start-level prev-level))
2864 (mapconcat
2865 (lambda (entry)
2866 (let ((headline (nth 0 entry))
2867 (level (nth 1 entry)))
2868 (prog1 (org-e-odt-format-toc-item headline level prev-level)
2869 (setq prev-level level))))
2870 toc-entries "")))
2872 (defun* org-e-odt-format-toc-headline
2873 (todo todo-type priority text tags
2874 &key level section-number headline-label &allow-other-keys)
2875 ;; FIXME
2876 (setq text (concat
2877 (and org-export-with-section-numbers
2878 (concat section-number ". "))
2879 text
2880 (and tags
2881 (concat
2882 (org-e-odt-format-spaces 3)
2883 (org-e-odt-format-fontify tags "tag")))))
2884 (when todo
2885 (setq text (org-e-odt-format-fontify text "todo")))
2887 (let ((org-e-odt-suppress-xref t))
2888 (org-e-odt-format-link text (concat "#" headline-label))))
2890 (defun org-e-odt-toc (depth info)
2891 (assert (wholenump depth))
2892 (let* ((headlines (org-export-collect-headlines info depth))
2893 (toc-entries
2894 (loop for headline in headlines collect
2895 (list (org-e-odt-format-headline--wrap
2896 headline info 'org-e-odt-format-toc-headline)
2897 (org-export-get-relative-level headline info)))))
2898 (when toc-entries
2899 (let* ((lang-specific-heading "Table of Contents")) ; FIXME
2900 (concat
2901 (org-e-odt-begin-toc lang-specific-heading depth)
2902 (org-e-odt-toc-text toc-entries)
2903 (org-e-odt-end-toc))))))
2905 (defun org-e-odt-begin-outline (level1 snumber title tags
2906 target extra-targets extra-class)
2907 (let* ((class (format "outline-%d" level1))
2908 (class (if extra-class (concat class " " extra-class) class))
2909 (id (format "outline-container-%s"
2910 (org-lparse-suffix-from-snumber snumber)))
2911 (extra (concat (when id (format " id=\"%s\"" id))
2912 (when class (format " class=\"%s\"" class)))))
2913 (org-lparse-insert-tag "<div%s>" extra)
2914 (insert
2915 (org-lparse-format 'HEADING
2916 (org-lparse-format
2917 'HEADLINE title extra-targets tags snumber level1)
2918 level1 target))))
2920 (defun org-e-odt-end-outline ()
2921 (org-lparse-insert-tag "</div>"))
2923 (defun org-e-odt-suffix-from-snumber (snumber)
2924 (let* ((snu (replace-regexp-in-string "\\." "-" snumber))
2925 (href (cdr (assoc (concat "sec-" snu)
2926 org-export-preferred-target-alist))))
2927 (org-solidify-link-text (or href snu))))
2929 (defun org-e-odt-format-outline (contents level1 snumber title
2930 tags target extra-targets extra-class)
2933 ;; (defun org-e-odt-format-line (line)
2934 ;; (case org-lparse-dyn-current-environment
2935 ;; ((quote fixedwidth) (concat (org-e-odt-encode-plain-text line) "\n"))
2936 ;; (t (concat line "\n"))))
2938 (defun org-e-odt-fix-class-name (kwd) ; audit callers of this function
2939 "Turn todo keyword into a valid class name.
2940 Replaces invalid characters with \"_\"."
2941 (save-match-data
2942 (while (string-match "[^a-zA-Z0-9_]" kwd)
2943 (setq kwd (replace-match "_" t t kwd))))
2944 kwd)
2946 (defun org-e-odt-format-internal-link (text href &optional extra)
2947 (org-e-odt-format-link text (concat "#" href) extra))
2949 (defun org-e-odt-format-extra-targets (extra-targets)
2950 (if (not extra-targets) ""
2951 (mapconcat (lambda (x)
2952 (when x
2953 (setq x (org-solidify-link-text
2954 (if (org-uuidgen-p x) (concat "ID-" x) x)))
2955 (org-e-odt-format-anchor "" x))) extra-targets "")))
2957 (defun org-e-odt-format-org-tags (tags)
2958 (if (not tags) ""
2959 (org-e-odt-format-fontify
2960 (mapconcat
2961 (lambda (x)
2962 (org-e-odt-format-fontify
2963 x (concat "" ;; org-e-odt-tag-class-prefix
2964 (org-e-odt-fix-class-name x))))
2965 (org-split-string tags ":")
2966 (org-e-odt-format-spaces 1)) "tag")))
2968 (defun org-e-odt-format-section-number (&optional snumber level)
2969 ;; FIXME
2970 (and nil org-export-with-section-numbers
2971 ;; (not org-lparse-body-only)
2972 snumber level
2973 (org-e-odt-format-fontify snumber (format "section-number-%d" level))))
2975 ;; (defun org-e-odt-format-headline (title extra-targets tags
2976 ;; &optional snumber level)
2977 ;; (concat
2978 ;; (org-e-odt-format-extra-targets extra-targets)
2979 ;; (concat (org-e-odt-format-section-number snumber level) " ")
2980 ;; title
2981 ;; (and tags (concat (org-e-odt-format-spaces 3)
2982 ;; (org-e-odt-format-org-tags tags)))))
2984 (defun org-e-odt-get-coding-system-for-write ()
2985 (or org-e-odt-coding-system
2986 (and (boundp 'buffer-file-coding-system) buffer-file-coding-system)))
2988 (defun org-e-odt-get-coding-system-for-save ()
2989 (or org-e-odt-coding-system
2990 (and (boundp 'buffer-file-coding-system) buffer-file-coding-system)))
2992 ;; (defun org-e-odt-format-date (info)
2993 ;; (let ((date (plist-get info :date)))
2994 ;; (cond
2995 ;; ((and date (string-match "%" date))
2996 ;; (format-time-string date))
2997 ;; (date date)
2998 ;; (t (format-time-string "%Y-%m-%d %T %Z")))))
3002 ;;; Internal Functions (Ngz)
3004 (defun org-e-odt--caption/label-string (caption label info)
3005 "Return caption and label HTML string for floats.
3007 CAPTION is a cons cell of secondary strings, the car being the
3008 standard caption and the cdr its short form. LABEL is a string
3009 representing the label. INFO is a plist holding contextual
3010 information.
3012 If there's no caption nor label, return the empty string.
3014 For non-floats, see `org-e-odt--wrap-label'."
3015 (setq label nil) ;; FIXME
3017 (let ((label-str (if label (format "\\label{%s}" label) "")))
3018 (cond
3019 ((and (not caption) (not label)) "")
3020 ((not caption) (format "\\label{%s}\n" label))
3021 ;; Option caption format with short name.
3022 ((cdr caption)
3023 (format "\\caption[%s]{%s%s}\n"
3024 (org-export-secondary-string (cdr caption) 'e-odt info)
3025 label-str
3026 (org-export-secondary-string (car caption) 'e-odt info)))
3027 ;; Standard caption format.
3028 ;; (t (format "\\caption{%s%s}\n"
3029 ;; label-str
3030 ;; (org-export-secondary-string (car caption) 'e-odt info)))
3032 (t (org-export-secondary-string (car caption) 'e-odt info)))))
3034 (defun org-e-odt--find-verb-separator (s)
3035 "Return a character not used in string S.
3036 This is used to choose a separator for constructs like \\verb."
3037 (let ((ll "~,./?;':\"|!@#%^&-_=+abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ<>()[]{}"))
3038 (loop for c across ll
3039 when (not (string-match (regexp-quote (char-to-string c)) s))
3040 return (char-to-string c))))
3042 (defun org-e-odt--quotation-marks (text info)
3043 "Export quotation marks depending on language conventions.
3044 TEXT is a string containing quotation marks to be replaced. INFO
3045 is a plist used as a communication channel."
3046 (mapc (lambda(l)
3047 (let ((start 0))
3048 (while (setq start (string-match (car l) text start))
3049 (let ((new-quote (concat (match-string 1 text) (cdr l))))
3050 (setq text (replace-match new-quote t t text))))))
3051 (cdr (or (assoc (plist-get info :language) org-e-odt-quotes)
3052 ;; Falls back on English.
3053 (assoc "en" org-e-odt-quotes))))
3054 text)
3056 (defun org-e-odt--wrap-label (element output)
3057 "Wrap label associated to ELEMENT around OUTPUT, if appropriate.
3058 This function shouldn't be used for floats. See
3059 `org-e-odt--caption/label-string'."
3060 ;; (let ((label (org-element-property :name element)))
3061 ;; (if (or (not output) (not label) (string= output "") (string= label ""))
3062 ;; output
3063 ;; (concat (format "\\label{%s}\n" label) output)))
3064 output)
3068 ;;; Transcode Helpers
3070 (defun* org-e-odt-format-headline
3071 (todo todo-type priority text tags
3072 &key level section-number headline-label &allow-other-keys)
3073 (concat (org-e-odt-todo todo) (and todo " ") text
3074 (and tags (org-e-odt-format-spaces 3))
3075 (and tags (org-e-odt-format-org-tags tags))))
3077 ;;;; Src Code
3079 (defun org-e-odt-htmlfontify-string (line)
3080 (let* ((hfy-html-quote-regex "\\([<\"&> ]\\)")
3081 (hfy-html-quote-map '(("\"" "&quot;")
3082 ("<" "&lt;")
3083 ("&" "&amp;")
3084 (">" "&gt;")
3085 (" " "<text:s/>")
3086 (" " "<text:tab/>")))
3087 (hfy-face-to-css 'org-e-odt-hfy-face-to-css)
3088 (hfy-optimisations-1 (copy-seq hfy-optimisations))
3089 (hfy-optimisations (add-to-list 'hfy-optimisations-1
3090 'body-text-only))
3091 (hfy-begin-span-handler
3092 (lambda (style text-block text-id text-begins-block-p)
3093 (insert (format "<text:span text:style-name=\"%s\">" style))))
3094 (hfy-end-span-handler (lambda nil (insert "</text:span>"))))
3095 (htmlfontify-string line)))
3097 (defun org-e-odt-do-format-code
3098 (code &optional lang refs retain-labels num-start)
3099 (let* ((lang (or (assoc-default lang org-src-lang-modes) lang))
3100 (lang-mode (and lang (intern (format "%s-mode" lang))))
3101 (code-lines (org-split-string code "\n"))
3102 (code-length (length code-lines))
3103 (use-htmlfontify-p (and (functionp lang-mode)
3104 org-e-odt-fontify-srcblocks
3105 (require 'htmlfontify nil t)
3106 (fboundp 'htmlfontify-string)))
3107 (code (if (not use-htmlfontify-p) code
3108 (with-temp-buffer
3109 (insert code)
3110 (funcall lang-mode)
3111 (font-lock-fontify-buffer)
3112 (buffer-string))))
3113 (fontifier (if use-htmlfontify-p 'org-e-odt-htmlfontify-string
3114 'org-e-odt-encode-plain-text))
3115 (par-style (if use-htmlfontify-p "OrgSrcBlock"
3116 "OrgFixedWidthBlock"))
3117 (i 0))
3118 (assert (= code-length (length (org-split-string code "\n"))))
3119 (setq code
3120 (org-export-format-code
3121 code
3122 (lambda (loc line-num ref)
3123 (setq par-style
3124 (concat par-style (and (= (incf i) code-length) "LastLine")))
3126 (setq loc (concat loc (and ref retain-labels (format " (%s)" ref))))
3127 (setq loc (funcall fontifier loc))
3128 (when ref
3129 (setq loc (org-e-odt-format-target loc (concat "coderef-" ref))))
3130 (setq loc (org-e-odt-format-stylized-paragraph par-style loc))
3131 (if (not line-num) loc
3132 (org-e-odt-format-tags
3133 '("<text:list-item>" . "</text:list-item>") loc)))
3134 num-start refs))
3135 (cond
3136 ((not num-start) code)
3137 ((equal num-start 0)
3138 (org-e-odt-format-tags
3139 '("<text:list text:style-name=\"OrgSrcBlockNumberedLine\"%s>"
3140 . "</text:list>") code " text:continue-numbering=\"false\""))
3141 (t (org-e-odt-format-tags
3142 '("<text:list text:style-name=\"OrgSrcBlockNumberedLine\"%s>"
3143 . "</text:list>") code " text:continue-numbering=\"true\"")))))
3145 (defun org-e-odt-format-code (element info)
3146 (let* ((lang (org-element-property :language element))
3147 ;; Extract code and references.
3148 (code-info (org-export-unravel-code element))
3149 (code (car code-info))
3150 (refs (cdr code-info))
3151 ;; Does the src block contain labels?
3152 (retain-labels (org-element-property :retain-labels element))
3153 ;; Does it have line numbers?
3154 (num-start (case (org-element-property :number-lines element)
3155 (continued (org-export-get-loc element info))
3156 (new 0))))
3157 (org-e-odt-do-format-code code lang refs retain-labels num-start)))
3161 ;;; Template
3163 (defun org-e-odt-template (contents info)
3164 "Return complete document string after HTML conversion.
3165 CONTENTS is the transcoded contents string. RAW-DATA is the
3166 original parsed data. INFO is a plist holding export options."
3167 ;; write meta file
3168 (org-e-odt-update-meta-file info)
3169 (with-temp-buffer
3170 (insert-file-contents
3171 (or org-e-odt-content-template-file
3172 (expand-file-name "OrgOdtContentTemplate.xml"
3173 org-e-odt-styles-dir)))
3174 (goto-char (point-min))
3175 (re-search-forward "</office:text>" nil nil)
3176 (goto-char (match-beginning 0))
3178 ;; Title
3179 (insert (org-e-odt-format-preamble info))
3180 ;; Table of Contents
3181 (let ((depth (plist-get info :with-toc)))
3182 (when (wholenump depth) (insert (org-e-odt-toc depth info))))
3184 ;; Copy styles.xml. Also dump htmlfontify styles, if there is any.
3185 (org-e-odt-update-styles-file info)
3187 ;; Update styles.xml - take care of outline numbering
3188 (with-current-buffer
3189 (find-file-noselect (expand-file-name "styles.xml") t)
3190 ;; Don't make automatic backup of styles.xml file. This setting
3191 ;; prevents the backed-up styles.xml file from being zipped in to
3192 ;; odt file. This is more of a hackish fix. Better alternative
3193 ;; would be to fix the zip command so that the output odt file
3194 ;; includes only the needed files and excludes any auto-generated
3195 ;; extra files like backups and auto-saves etc etc. Note that
3196 ;; currently the zip command zips up the entire temp directory so
3197 ;; that any auto-generated files created under the hood ends up in
3198 ;; the resulting odt file.
3199 (set (make-local-variable 'backup-inhibited) t)
3200 (org-e-odt-configure-outline-numbering))
3202 ;; Contents
3203 (insert contents)
3204 (buffer-substring-no-properties (point-min) (point-max))))
3208 ;;; Transcode Functions
3210 ;;;; Block
3212 (defun org-e-odt-center-block (center-block contents info)
3213 "Transcode a CENTER-BLOCK element from Org to HTML.
3214 CONTENTS holds the contents of the block. INFO is a plist
3215 holding contextual information."
3216 (org-e-odt--wrap-label center-block contents))
3219 ;;;; Comment
3221 ;; Comments are ignored.
3224 ;;;; Comment Block
3226 ;; Comment Blocks are ignored.
3229 ;;;; Drawer
3231 (defun org-e-odt-drawer (drawer contents info)
3232 "Transcode a DRAWER element from Org to HTML.
3233 CONTENTS holds the contents of the block. INFO is a plist
3234 holding contextual information."
3235 (let* ((name (org-element-property :drawer-name drawer))
3236 (output (if (functionp org-e-odt-format-drawer-function)
3237 (funcall org-e-odt-format-drawer-function
3238 name contents)
3239 ;; If there's no user defined function: simply
3240 ;; display contents of the drawer.
3241 contents)))
3242 (org-e-odt--wrap-label drawer output)))
3245 ;;;; Dynamic Block
3247 (defun org-e-odt-dynamic-block (dynamic-block contents info)
3248 "Transcode a DYNAMIC-BLOCK element from Org to HTML.
3249 CONTENTS holds the contents of the block. INFO is a plist
3250 holding contextual information. See
3251 `org-export-data'."
3252 (org-e-odt--wrap-label dynamic-block contents))
3255 ;;;; Emphasis
3257 (defun org-e-odt-emphasis (emphasis contents info)
3258 "Transcode EMPHASIS from Org to HTML.
3259 CONTENTS is the contents of the emphasized text. INFO is a plist
3260 holding contextual information.."
3261 ;; (format (cdr (assoc (org-element-property :marker emphasis)
3262 ;; org-e-odt-emphasis-alist))
3263 ;; contents)
3264 (org-e-odt-format-fontify
3265 contents (cadr (assoc
3266 (org-element-property :marker emphasis)
3267 '(("*" bold)
3268 ("/" emphasis)
3269 ("_" underline)
3270 ("=" code)
3271 ("~" verbatim)
3272 ("+" strike))))))
3275 ;;;; Entity
3277 (defun org-e-odt-entity (entity contents info)
3278 "Transcode an ENTITY object from Org to HTML.
3279 CONTENTS are the definition itself. INFO is a plist holding
3280 contextual information."
3281 ;; (let ((ent (org-element-property :latex entity)))
3282 ;; (if (org-element-property :latex-math-p entity)
3283 ;; (format "$%s$" ent)
3284 ;; ent))
3285 (org-element-property :utf-8 entity))
3288 ;;;; Example Block
3290 (defun org-e-odt-example-block (example-block contents info)
3291 "Transcode a EXAMPLE-BLOCK element from Org to HTML.
3292 CONTENTS is nil. INFO is a plist holding contextual information."
3293 (let* ((options (or (org-element-property :options example-block) ""))
3294 (value (org-export-handle-code example-block info nil nil t)))
3295 (org-e-odt--wrap-label
3296 example-block (org-e-odt-format-source-code-or-example value nil))))
3299 ;;;; Export Snippet
3301 (defun org-e-odt-export-snippet (export-snippet contents info)
3302 "Transcode a EXPORT-SNIPPET object from Org to HTML.
3303 CONTENTS is nil. INFO is a plist holding contextual information."
3304 (when (eq (org-export-snippet-backend export-snippet) 'e-odt)
3305 (org-element-property :value export-snippet)))
3308 ;;;; Export Block
3310 (defun org-e-odt-export-block (export-block contents info)
3311 "Transcode a EXPORT-BLOCK element from Org to HTML.
3312 CONTENTS is nil. INFO is a plist holding contextual information."
3313 (when (string= (org-element-property :type export-block) "latex")
3314 (org-remove-indentation (org-element-property :value export-block))))
3317 ;;;; Fixed Width
3319 (defun org-e-odt-fixed-width (fixed-width contents info)
3320 "Transcode a FIXED-WIDTH element from Org to HTML.
3321 CONTENTS is nil. INFO is a plist holding contextual information."
3322 (let* ((value (org-element-normalize-string
3323 (replace-regexp-in-string
3324 "^[ \t]*: ?" ""
3325 (org-element-property :value fixed-width)))))
3326 (org-e-odt--wrap-label
3327 fixed-width (org-e-odt-format-source-code-or-example value nil))))
3330 ;;;; Footnote Definition
3332 ;; Footnote Definitions are ignored.
3335 ;;;; Footnote Reference
3337 (defun org-e-odt-footnote-def (raw info) ; FIXME
3338 (if (equal (org-element-type raw) 'org-data)
3339 (org-trim (org-export-data raw 'e-odt info)) ; fix paragraph
3340 ; style
3341 (org-odt-format-stylized-paragraph
3342 'footnote (org-trim (org-export-secondary-string raw 'e-odt info)))))
3344 (defvar org-e-odt-footnote-separator
3345 (org-e-odt-format-fontify "," 'superscript))
3347 (defun org-e-odt-footnote-reference (footnote-reference contents info)
3348 "Transcode a FOOTNOTE-REFERENCE element from Org to HTML.
3349 CONTENTS is nil. INFO is a plist holding contextual information."
3350 (concat
3351 ;; Insert separator between two footnotes in a row.
3352 (let ((prev (org-export-get-previous-element footnote-reference info)))
3353 (when (eq (org-element-type prev) 'footnote-reference)
3354 org-e-odt-footnote-separator))
3355 (cond
3356 ((not (org-export-footnote-first-reference-p footnote-reference info))
3357 (let* ((n (org-export-get-footnote-number footnote-reference info)))
3358 (org-e-odt-format-footnote-reference n "IGNORED" 100)))
3359 ;; Inline definitions are secondary strings.
3360 ((eq (org-element-property :type footnote-reference) 'inline)
3361 (let* ((raw (org-export-get-footnote-definition footnote-reference info))
3362 (n (org-export-get-footnote-number footnote-reference info))
3363 (def (org-e-odt-footnote-def raw info)))
3364 (org-e-odt-format-footnote-reference n def 1)))
3365 ;; Non-inline footnotes definitions are full Org data.
3367 (let* ((raw (org-export-get-footnote-definition footnote-reference info))
3368 (n (org-export-get-footnote-number footnote-reference info))
3369 (def (org-e-odt-footnote-def raw info)))
3370 (org-e-odt-format-footnote-reference n def 1))))))
3373 ;;;; Headline
3375 (defun org-e-odt-todo (todo)
3376 (when todo
3377 (org-e-odt-format-fontify
3378 (concat
3379 "" ; org-e-odt-todo-kwd-class-prefix
3380 (org-e-odt-fix-class-name todo))
3381 (list (if (member todo org-done-keywords) "done" "todo")
3382 todo))))
3384 (defun org-e-odt-format-headline--wrap (headline info
3385 &optional format-function
3386 &rest extra-keys)
3387 "Transcode an HEADLINE element from Org to ODT.
3388 CONTENTS holds the contents of the headline. INFO is a plist
3389 holding contextual information."
3390 (let* ((level (+ (org-export-get-relative-level headline info)))
3391 (headline-number (org-export-get-headline-number headline info))
3392 (section-number (and (org-export-numbered-headline-p headline info)
3393 (mapconcat 'number-to-string
3394 headline-number ".")))
3395 (todo (and (plist-get info :with-todo-keywords)
3396 (let ((todo (org-element-property
3397 :todo-keyword headline)))
3398 (and todo
3399 (org-export-secondary-string todo 'e-odt info)))))
3400 (todo-type (and todo (org-element-property :todo-type headline)))
3401 (priority (and (plist-get info :with-priority)
3402 (org-element-property :priority headline)))
3403 (text (org-export-secondary-string
3404 (org-element-property :title headline) 'e-odt info))
3405 (tags (and (plist-get info :with-tags)
3406 (org-element-property :tags headline)))
3407 (headline-label (concat "sec-" (mapconcat 'number-to-string
3408 headline-number "-")))
3409 (format-function (cond
3410 ((functionp format-function) format-function)
3411 ((functionp org-e-odt-format-headline-function)
3412 (function*
3413 (lambda (todo todo-type priority text tags
3414 &allow-other-keys)
3415 (funcall org-e-odt-format-headline-function
3416 todo todo-type priority text tags))))
3417 (t 'org-e-odt-format-headline))))
3418 (apply format-function
3419 todo todo-type priority text tags
3420 :headline-label headline-label :level level
3421 :section-number section-number extra-keys)))
3423 (defun org-e-odt-headline (headline contents info)
3424 "Transcode an HEADLINE element from Org to HTML.
3425 CONTENTS holds the contents of the headline. INFO is a plist
3426 holding contextual information."
3427 (let* ((numberedp (org-export-numbered-headline-p headline info))
3428 ;; Get level relative to current parsed data.
3429 (level (org-export-get-relative-level headline info))
3430 (text (org-export-secondary-string
3431 (org-element-property :title headline) 'e-odt info))
3432 ;; Create the headline text.
3433 (full-text (org-e-odt-format-headline--wrap headline info)))
3434 (cond
3435 ;; Case 1: This is a footnote section: ignore it.
3436 ((org-element-property :footnote-section-p headline) nil)
3437 ;; Case 2. This is a deep sub-tree: export it as a list item.
3438 ;; Also export as items headlines for which no section
3439 ;; format has been found.
3440 ((org-export-low-level-p headline info) ; FIXME (or (not section-fmt))
3441 ;; Build the real contents of the sub-tree.
3442 (let* ((type (if numberedp 'unordered 'unordered)) ; FIXME
3443 (itemized-body (org-e-odt-format-list-item
3444 contents type nil nil full-text)))
3445 (concat
3446 (and (org-export-first-sibling-p headline info)
3447 (org-e-odt-begin-plain-list type))
3448 itemized-body
3449 (and (org-export-last-sibling-p headline info)
3450 (org-e-odt-end-plain-list type)))))
3451 ;; Case 3. Standard headline. Export it as a section.
3453 (let* ((extra-ids (list (org-element-property :custom-id headline)
3454 (org-element-property :id headline)))
3455 (extra-ids nil) ; FIXME
3456 (id (concat "sec-" (mapconcat 'number-to-string
3457 (org-export-get-headline-number
3458 headline info) "-"))))
3459 (concat
3460 (org-e-odt-format-tags
3461 '("<text:h text:style-name=\"Heading_20_%s\" text:outline-level=\"%s\">" .
3462 "</text:h>")
3463 (concat (org-e-odt-format-extra-targets extra-ids)
3464 (if (not id) full-text (org-e-odt-format-target full-text id) ))
3465 level level)
3466 contents))))))
3469 ;;;; Horizontal Rule
3471 (defun org-e-odt-horizontal-rule (horizontal-rule contents info)
3472 "Transcode an HORIZONTAL-RULE object from Org to HTML.
3473 CONTENTS is nil. INFO is a plist holding contextual information."
3474 (let ((attr (mapconcat #'identity
3475 (org-element-property :attr_odt horizontal-rule)
3476 " ")))
3477 (org-e-odt--wrap-label horizontal-rule
3478 (org-e-odt-format-horizontal-line))))
3481 ;;;; Inline Babel Call
3483 ;; Inline Babel Calls are ignored.
3486 ;;;; Inline Src Block
3488 (defun org-e-odt-inline-src-block (inline-src-block contents info)
3489 "Transcode an INLINE-SRC-BLOCK element from Org to HTML.
3490 CONTENTS holds the contents of the item. INFO is a plist holding
3491 contextual information."
3492 (let* ((org-lang (org-element-property :language inline-src-block))
3493 (code (org-element-property :value inline-src-block))
3494 (separator (org-e-odt--find-verb-separator code)))
3495 (error "FIXME")))
3498 ;;;; Inlinetask
3500 (defun org-e-odt-format-section (text class &optional id)
3501 (let ((extra (concat (when id (format " id=\"%s\"" id)))))
3502 (concat (format "<div class=\"%s\"%s>\n" class extra) text "</div>\n")))
3504 (defun org-e-odt-inlinetask (inlinetask contents info)
3505 "Transcode an INLINETASK element from Org to ODT.
3506 CONTENTS holds the contents of the block. INFO is a plist
3507 holding contextual information."
3508 (cond
3509 ;; If `org-e-odt-format-inlinetask-function' is provided, call it
3510 ;; with appropriate arguments.
3511 ((functionp org-e-odt-format-inlinetask-function)
3512 (let ((format-function
3513 (function*
3514 (lambda (todo todo-type priority text tags
3515 &key contents &allow-other-keys)
3516 (funcall org-e-odt-format-inlinetask-function
3517 todo todo-type priority text tags contents)))))
3518 (org-e-odt-format-headline--wrap
3519 inlinetask info format-function :contents contents)))
3520 ;; Otherwise, use a default template.
3521 (t (org-e-odt--wrap-label
3522 inlinetask
3523 (org-e-odt-format-stylized-paragraph
3524 nil (org-e-odt-format-textbox
3525 (concat (org-e-odt-format-stylized-paragraph
3526 "OrgInlineTaskHeading" (org-e-odt-format-headline--wrap
3527 inlinetask info))
3528 contents)
3529 nil nil "OrgInlineTaskFrame" " style:rel-width=\"100%\""))))))
3531 ;;;; Item
3533 (defun org-e-odt-format-list-item (contents type checkbox
3534 &optional term-counter-id
3535 headline)
3536 (when checkbox
3537 (setq checkbox
3538 (org-e-odt-format-fontify (case checkbox
3539 (on "[X]")
3540 (off "[&nbsp;]")
3541 (trans "[-]")) 'code)))
3542 (concat
3543 (org-e-odt-begin-list-item type term-counter-id headline)
3544 ;; FIXME checkbox (and checkbox " ")
3545 contents
3546 (org-e-odt-end-list-item type)))
3548 (defun org-e-odt-item (item contents info)
3549 "Transcode an ITEM element from Org to HTML.
3550 CONTENTS holds the contents of the item. INFO is a plist holding
3551 contextual information."
3552 ;; Grab `:level' from plain-list properties, which is always the
3553 ;; first element above current item.
3554 (let* ((plain-list (org-export-get-parent item info))
3555 (type (org-element-property :type plain-list))
3556 (level (org-element-property :level plain-list))
3557 (counter (org-element-property :counter item))
3558 (checkbox (org-element-property :checkbox item))
3559 (tag (let ((tag (org-element-property :tag item)))
3560 (and tag (org-export-secondary-string tag 'e-odt info)))))
3561 (org-e-odt-format-list-item
3562 contents type checkbox (or tag counter))))
3565 ;;;; Keyword
3567 (defun org-e-odt-keyword (keyword contents info)
3568 "Transcode a KEYWORD element from Org to HTML.
3569 CONTENTS is nil. INFO is a plist holding contextual information."
3570 (let ((key (org-element-property :key keyword))
3571 (value (org-element-property :value keyword)))
3572 (cond
3573 ((string= key "LATEX") value)
3574 ((string= key "INDEX") (format "\\index{%s}" value))
3575 ((string= key "TARGET") nil ; FIXME
3576 ;; (format "\\label{%s}" (org-export-solidify-link-text value))
3578 ((string= key "toc")
3579 (let ((value (downcase value)))
3580 (cond
3581 ((string-match "\\<headlines\\>" value)
3582 (let ((depth (or (and (string-match "[0-9]+" value)
3583 (string-to-number (match-string 0 value)))
3584 (plist-get info :with-toc))))
3585 (when (wholenump depth) (org-e-odt-toc depth info))))
3586 ((string= "tables" value) "FIXME")
3587 ((string= "figures" value) "FIXME")
3588 ((string= "listings" value)
3589 (cond
3590 ;; At the moment, src blocks with a caption are wrapped
3591 ;; into a figure environment.
3592 (t "FIXME")))))))))
3595 ;;;; Latex Environment
3597 (defun org-e-odt-format-latex (latex-frag processing-type)
3598 (let* ((prefix (case processing-type
3599 (dvipng "ltxpng/")
3600 (mathml "ltxmathml/")))
3601 (cache-relpath
3602 (concat prefix (file-name-sans-extension
3603 (file-name-nondirectory (buffer-file-name)))))
3604 (cache-dir (file-name-directory (buffer-file-name )))
3605 (display-msg (case processing-type
3606 (dvipng "Creating LaTeX Image...")
3607 (mathml "Creating MathML snippet..."))))
3608 (with-temp-buffer
3609 (insert latex-frag)
3610 (org-format-latex cache-relpath cache-dir nil display-msg
3611 nil nil processing-type)
3612 (buffer-string))))
3614 (defun org-e-odt-latex-environment (latex-environment contents info)
3615 "Transcode a LATEX-ENVIRONMENT element from Org to HTML.
3616 CONTENTS is nil. INFO is a plist holding contextual information."
3617 (org-e-odt--wrap-label
3618 latex-environment
3619 (let* ((latex-frag
3620 (org-remove-indentation
3621 (org-element-property :value latex-environment)))
3622 (processing-type (plist-get info :LaTeX-fragments))
3623 (caption (org-element-property :caption latex-environment))
3624 (short-caption (and (cdr caption) (org-export-secondary-string
3625 (cdr caption) 'e-odt info)))
3626 (caption (and (car caption) (org-export-secondary-string
3627 (car caption) 'e-odt info)))
3628 (label (org-element-property :name latex-environment))
3629 (attr nil) ; FIXME
3630 (label (org-element-property :name latex-environment)))
3631 (cond
3632 ((member processing-type '(t mathjax))
3633 (let* ((formula-link (org-e-odt-format-latex latex-frag 'mathml)))
3634 (when (and formula-link
3635 (string-match "file:\\([^]]*\\)" formula-link))
3636 (org-e-odt-format-formula
3637 (match-string 1 formula-link) caption label attr))))
3638 ((equal processing-type 'dvipng)
3639 (let* ((formula-link (org-e-odt-format-latex
3640 latex-frag processing-type)))
3641 (when (and formula-link
3642 (string-match "file:\\([^]]*\\)" formula-link))
3643 (org-e-odt-format-image
3644 (match-string 1 formula-link) caption label attr "paragraph"
3645 "__DvipngImage__"))))
3646 (t latex-frag)))))
3649 ;;;; Latex Fragment
3651 (defun org-e-odt-latex-fragment (latex-fragment contents info)
3652 "Transcode a LATEX-FRAGMENT object from Org to HTML.
3653 CONTENTS is nil. INFO is a plist holding contextual information."
3654 (let* ((latex-frag (org-element-property :value latex-fragment))
3655 (processing-type (plist-get info :LaTeX-fragments)))
3656 (cond
3657 ((member processing-type '(t mathjax))
3658 (let* ((formula-link (org-e-odt-format-latex latex-frag 'mathml))
3659 (src (and formula-link
3660 (string-match "file:\\([^]]*\\)" formula-link)
3661 (match-string 1 formula-link))))
3662 (assert src)
3663 (org-e-odt-format-formula src)))
3664 ((equal processing-type 'dvipng)
3665 (let* ((formula-link (org-e-odt-format-latex latex-frag processing-type))
3666 (src (and formula-link
3667 (string-match "file:\\([^]]*\\)" formula-link)
3668 (match-string 1 formula-link))))
3669 (assert src)
3670 (org-e-odt-format-image src)))
3671 (t latex-frag))))
3674 ;;;; Line Break
3676 (defun org-e-odt-line-break (line-break contents info)
3677 "Transcode a LINE-BREAK object from Org to HTML.
3678 CONTENTS is nil. INFO is a plist holding contextual information."
3679 "<text:line-break/>\n")
3682 ;;;; Link
3684 (defun org-e-odt-link--inline-image (link desc info)
3685 "Return HTML code for an inline image.
3686 LINK is the link pointing to the inline image. INFO is a plist
3687 used as a communication channel."
3688 (let* ((type (org-element-property :type link))
3689 (raw-path (org-element-property :path link))
3690 (path (cond ((member type '("http" "https"))
3691 (concat type ":" raw-path))
3692 ((file-name-absolute-p raw-path)
3693 (expand-file-name raw-path))
3694 (t raw-path)))
3695 (parent (org-export-get-parent-paragraph link info))
3696 (caption (org-element-property :caption parent))
3697 (short-caption (and (cdr caption) (org-export-secondary-string
3698 (cdr caption) 'e-odt info)))
3699 (caption (and (car caption) (org-export-secondary-string
3700 (car caption) 'e-odt info)))
3701 (label (org-element-property :name parent))
3702 ;; Retrieve latex attributes from the element around.
3703 (attr (let ((raw-attr
3704 (mapconcat #'identity
3705 (org-element-property :attr_odt parent)
3706 " ")))
3707 (unless (string= raw-attr "") raw-attr))))
3708 ;; Now clear ATTR from any special keyword and set a default
3709 ;; value if nothing is left.
3710 (setq attr (if (not attr) "" (org-trim attr)))
3711 ;; Return proper string, depending on DISPOSITION.
3712 (org-e-odt-format-image
3713 path caption label attr (if (org-e-html-standalone-image-p link info)
3714 "paragraph" "as-char"))))
3716 (defvar org-e-odt-standalone-image-predicate
3717 (function (lambda (paragraph)
3718 (or (org-element-property :caption paragraph)
3719 (org-element-property :name paragraph)))))
3721 (defun org-e-odt-standalone-image-p (element info &optional predicate)
3722 "Test if ELEMENT is a standalone image for the purpose ODT export.
3723 INFO is a plist holding contextual information.
3725 Return non-nil, if ELEMENT is of type paragraph and it's sole
3726 content, save for whitespaces, is a link that qualifies as an
3727 inline image.
3729 Return non-nil, if ELEMENT is of type link and it's containing
3730 paragraph has no other content save for leading and trailing
3731 whitespaces.
3733 Return nil, otherwise.
3735 Bind `org-e-odt-standalone-image-predicate' to constrain
3736 paragraph further. For example, to check for only captioned
3737 standalone images, do the following.
3739 \(setq org-e-odt-standalone-image-predicate
3740 \(lambda \(paragraph\)
3741 \(org-element-property :caption paragraph\)\)\)
3743 (let ((paragraph (case (org-element-type element)
3744 (paragraph element)
3745 (link (and (org-export-inline-image-p
3746 element org-e-odt-inline-image-rules)
3747 (org-export-get-parent element info)))
3748 (t nil))))
3749 (when paragraph
3750 (assert (eq (org-element-type paragraph) 'paragraph))
3751 (when (or (not (and (boundp 'org-e-odt-standalone-image-predicate)
3752 (functionp org-e-odt-standalone-image-predicate)))
3753 (funcall org-e-odt-standalone-image-predicate paragraph))
3754 (let ((contents (org-element-contents paragraph)))
3755 (loop for x in contents
3756 with inline-image-count = 0
3757 always (cond
3758 ((eq (org-element-type x) 'plain-text)
3759 (not (org-string-nw-p x)))
3760 ((eq (org-element-type x) 'link)
3761 (when (org-export-inline-image-p
3762 x org-e-odt-inline-image-rules)
3763 (= (incf inline-image-count) 1)))
3764 (t nil))))))))
3766 (defun org-e-odt-link (link desc info)
3767 "Transcode a LINK object from Org to HTML.
3769 DESC is the description part of the link, or the empty string.
3770 INFO is a plist holding contextual information. See
3771 `org-export-data'."
3772 (let* ((type (org-element-property :type link))
3773 (raw-path (org-element-property :path link))
3774 ;; Ensure DESC really exists, or set it to nil.
3775 (desc (and (not (string= desc "")) desc))
3776 (imagep (org-export-inline-image-p
3777 link org-e-odt-inline-image-rules))
3778 (path (cond
3779 ((member type '("http" "https" "ftp" "mailto"))
3780 (concat type ":" raw-path))
3781 ((string= type "file")
3782 (when (string-match "\\(.+\\)::.+" raw-path)
3783 (setq raw-path (match-string 1 raw-path)))
3784 (if (file-name-absolute-p raw-path)
3785 (concat "file://" (expand-file-name raw-path))
3786 ;; TODO: Not implemented yet. Concat also:
3787 ;; (org-export-directory :HTML info)
3788 (concat "file://" raw-path)))
3789 (t raw-path)))
3790 protocol)
3791 (cond
3792 ;; Image file.
3793 ((and (not desc) (org-export-inline-image-p
3794 link org-e-odt-inline-image-rules))
3795 (org-e-odt-link--inline-image link desc info))
3796 ;; Radioed target: Target's name is obtained from original raw
3797 ;; link. Path is parsed and transcoded in order to have a proper
3798 ;; display of the contents.
3799 ((string= type "radio")
3800 (org-e-odt-format-internal-link
3801 (org-export-secondary-string
3802 (org-element-parse-secondary-string
3803 path (cdr (assq 'radio-target org-element-object-restrictions)))
3804 'e-odt info)
3805 (org-export-solidify-link-text path)))
3806 ;; Links pointing to an headline: Find destination and build
3807 ;; appropriate referencing command.
3808 ((member type '("custom-id" "fuzzy" "id"))
3809 (let ((destination (if (string= type "fuzzy")
3810 (org-export-resolve-fuzzy-link link info)
3811 (org-export-resolve-id-link link info))))
3812 (case (org-element-type destination)
3813 ;; Fuzzy link points nowhere.
3814 ('nil
3815 (org-e-odt-format-fontify
3816 (or desc (org-export-secondary-string
3817 (org-element-property :raw-link link)
3818 'e-odt info)) 'emphasis))
3819 ;; Fuzzy link points to an invisible target.
3820 (keyword nil)
3821 ;; LINK points to an headline. If headlines are numbered
3822 ;; and the link has no description, display headline's
3823 ;; number. Otherwise, display description or headline's
3824 ;; title.
3825 (headline
3826 (let* ((headline-no (org-export-get-headline-number destination info))
3827 (label (format "sec-%s" (mapconcat 'number-to-string
3828 headline-no "-")))
3829 (section-no (mapconcat 'number-to-string headline-no ".")))
3830 (setq desc
3831 (cond
3832 (desc desc)
3833 ((plist-get info :section-numbers) section-no)
3834 (t (org-export-secondary-string
3835 (org-element-property :title destination)
3836 'e-odt info))))
3837 (org-e-odt-format-internal-link desc label)))
3838 ;; Fuzzy link points to a target. Do as above.
3839 (otherwise
3840 ;; "__Table__"
3841 ;; "__Figure__"
3842 ;; "__MathFormula__"
3843 ;; "__DvipngImage__"
3844 (let ((path (org-export-solidify-link-text path)))
3845 (unless desc
3846 (setq number (cond
3847 ((org-e-odt-standalone-image-p destination info)
3848 (org-export-get-ordinal
3849 (assoc 'link (org-element-contents destination))
3850 info 'link 'org-e-odt-standalone-image-p))
3851 (t (org-export-get-ordinal destination info))))
3852 (setq desc (when number
3853 (if (atom number) (number-to-string number)
3854 (mapconcat 'number-to-string number ".")))))
3855 (let ((label path)
3856 (default-category
3857 (cond
3858 ((eq (org-element-type destination) 'table)
3859 "__Table__")
3860 ((org-e-odt-standalone-image-p destination info)
3861 "__Figure__")
3862 ((eq (org-element-type destination) 'latex-environment)
3863 ; FIXME: Check if it is
3864 ; acutally latex eqn.
3865 "__MathFormula__")
3866 (t (error "Handle enumeration of %S" destination)))))
3867 (org-e-odt-format-label-reference label default-category number)))))))
3868 ;; Coderef: replace link with the reference name or the
3869 ;; equivalent line number.
3870 ((string= type "coderef")
3871 (let* ((fmt (org-export-get-coderef-format path (or desc "%s")))
3872 (res (org-export-resolve-coderef path info))
3873 (org-e-odt-suppress-xref nil)
3874 (href (org-xml-format-href (concat "#coderef-" path))))
3875 (format fmt (org-e-odt-format-link res href))))
3876 ;; Link type is handled by a special function.
3877 ((functionp (setq protocol (nth 2 (assoc type org-link-protocols))))
3878 (funcall protocol (org-link-unescape path) desc 'html))
3879 ;; External link with a description part.
3880 ((and path desc) (org-e-odt-format-link desc path))
3881 ;; External link without a description part.
3882 (path (org-e-odt-format-link path path))
3883 ;; No path, only description. Try to do something useful.
3884 (t (org-e-odt-format-fontify desc 'emphasis)))))
3887 ;;;; Babel Call
3889 ;; Babel Calls are ignored.
3892 ;;;; Macro
3894 (defun org-e-odt-macro (macro contents info)
3895 "Transcode a MACRO element from Org to HTML.
3896 CONTENTS is nil. INFO is a plist holding contextual information."
3897 ;; Use available tools.
3898 (org-export-expand-macro macro info))
3901 ;;;; Paragraph
3903 (defun org-e-odt-paragraph (paragraph contents info)
3904 "Transcode a PARAGRAPH element from Org to HTML.
3905 CONTENTS is the contents of the paragraph, as a string. INFO is
3906 the plist used as a communication channel."
3907 (let* ((style nil) ; FIXME
3908 (class (cdr (assoc style '((footnote . "footnote")
3909 (verse . nil)))))
3910 (extra (if class (format " class=\"%s\"" class) ""))
3911 (parent (org-export-get-parent paragraph info))
3912 (parent-type (org-element-type parent))
3913 (style (case parent-type
3914 (quote-block 'quote)
3915 (center-block 'center)
3916 (footnote-definition 'footnote)
3917 (t nil))))
3918 (org-e-odt-format-stylized-paragraph style contents)))
3921 ;;;; Plain List
3923 (defun org-e-odt-plain-list (plain-list contents info)
3924 "Transcode a PLAIN-LIST element from Org to HTML.
3925 CONTENTS is the contents of the list. INFO is a plist holding
3926 contextual information."
3927 (let* (arg1 ;; FIXME
3928 (type (org-element-property :type plain-list))
3929 (attr (mapconcat #'identity
3930 (org-element-property :attr_odt plain-list)
3931 " ")))
3932 (org-e-odt--wrap-label
3933 plain-list (format "%s\n%s%s"
3934 (org-e-odt-begin-plain-list type)
3935 contents (org-e-odt-end-plain-list type)))))
3937 ;;;; Plain Text
3939 (defun org-e-odt-convert-special-strings (string)
3940 "Convert special characters in STRING to ODT."
3941 (let ((all org-e-odt-special-string-regexps)
3942 e a re rpl start)
3943 (while (setq a (pop all))
3944 (setq re (car a) rpl (cdr a) start 0)
3945 (while (string-match re string start)
3946 (setq string (replace-match rpl t nil string))))
3947 string))
3949 ;; (defun org-e-odt-encode-plain-text (s)
3950 ;; "Convert plain text characters to HTML equivalent.
3951 ;; Possible conversions are set in `org-export-html-protect-char-alist'."
3952 ;; (let ((cl org-e-odt-protect-char-alist) c)
3953 ;; (while (setq c (pop cl))
3954 ;; (let ((start 0))
3955 ;; (while (string-match (car c) s start)
3956 ;; (setq s (replace-match (cdr c) t t s)
3957 ;; start (1+ (match-beginning 0))))))
3958 ;; s))
3960 (defun org-e-odt-plain-text (text info)
3961 "Transcode a TEXT string from Org to HTML.
3962 TEXT is the string to transcode. INFO is a plist holding
3963 contextual information."
3964 (setq text (org-e-odt-encode-plain-text text t))
3965 ;; Protect %, #, &, $, ~, ^, _, { and }.
3966 ;; (while (string-match "\\([^\\]\\|^\\)\\([%$#&{}~^_]\\)" text)
3967 ;; (setq text
3968 ;; (replace-match (format "\\%s" (match-string 2 text)) nil t text 2)))
3969 ;; Protect \
3970 ;; (setq text (replace-regexp-in-string
3971 ;; "\\(?:[^\\]\\|^\\)\\(\\\\\\)\\(?:[^%$#&{}~^_\\]\\|$\\)"
3972 ;; "$\\backslash$" text nil t 1))
3973 ;; HTML into \HTML{} and TeX into \TeX{}.
3974 ;; (let ((case-fold-search nil)
3975 ;; (start 0))
3976 ;; (while (string-match "\\<\\(\\(?:La\\)?TeX\\)\\>" text start)
3977 ;; (setq text (replace-match
3978 ;; (format "\\%s{}" (match-string 1 text)) nil t text)
3979 ;; start (match-end 0))))
3980 ;; Handle quotation marks
3981 ;; (setq text (org-e-odt--quotation-marks text info))
3982 ;; Convert special strings.
3983 ;; (when (plist-get info :with-special-strings)
3984 ;; (while (string-match (regexp-quote "...") text)
3985 ;; (setq text (replace-match "\\ldots{}" nil t text))))
3986 (when (plist-get info :with-special-strings)
3987 (setq text (org-e-odt-convert-special-strings text)))
3988 ;; Handle break preservation if required.
3989 (when (plist-get info :preserve-breaks)
3990 (setq text (replace-regexp-in-string "\\(\\\\\\\\\\)?[ \t]*\n" " \\\\\\\\\n"
3991 text)))
3992 ;; Return value.
3993 text)
3996 ;;;; Property Drawer
3998 (defun org-e-odt-property-drawer (property-drawer contents info)
3999 "Transcode a PROPERTY-DRAWER element from Org to HTML.
4000 CONTENTS is nil. INFO is a plist holding contextual
4001 information."
4002 ;; The property drawer isn't exported but we want separating blank
4003 ;; lines nonetheless.
4007 ;;;; Quote Block
4009 (defun org-e-odt-quote-block (quote-block contents info)
4010 "Transcode a QUOTE-BLOCK element from Org to HTML.
4011 CONTENTS holds the contents of the block. INFO is a plist
4012 holding contextual information."
4013 (org-e-odt--wrap-label quote-block contents))
4016 ;;;; Quote Section
4018 (defun org-e-odt-quote-section (quote-section contents info)
4019 "Transcode a QUOTE-SECTION element from Org to HTML.
4020 CONTENTS is nil. INFO is a plist holding contextual information."
4021 (let ((value (org-remove-indentation
4022 (org-element-property :value quote-section))))
4023 (when value (org-e-odt-format-source-code-or-example value nil))))
4026 ;;;; Section
4028 (defun org-e-odt-section (section contents info) ; FIXME
4029 "Transcode a SECTION element from Org to HTML.
4030 CONTENTS holds the contents of the section. INFO is a plist
4031 holding contextual information."
4032 contents)
4034 ;;;; Radio Target
4036 (defun org-e-odt-radio-target (radio-target text info)
4037 "Transcode a RADIO-TARGET object from Org to HTML.
4038 TEXT is the text of the target. INFO is a plist holding
4039 contextual information."
4040 (org-e-odt-format-anchor
4041 text (org-export-solidify-link-text
4042 (org-element-property :value radio-target))))
4045 ;;;; Special Block
4047 (defun org-e-odt-special-block (special-block contents info)
4048 "Transcode a SPECIAL-BLOCK element from Org to HTML.
4049 CONTENTS holds the contents of the block. INFO is a plist
4050 holding contextual information."
4051 (let ((type (downcase (org-element-property :type special-block))))
4052 (org-e-odt--wrap-label
4053 special-block
4054 (format "\\begin{%s}\n%s\\end{%s}" type contents type))))
4057 ;;;; Src Block
4059 (defun org-e-odt-src-block (src-block contents info)
4060 "Transcode a SRC-BLOCK element from Org to HTML.
4061 CONTENTS holds the contents of the item. INFO is a plist holding
4062 contextual information."
4063 (let* ((lang (org-element-property :language src-block))
4064 (caption (org-element-property :caption src-block))
4065 (label (org-element-property :name src-block)))
4066 ;; FIXME: Handle caption
4067 ;; caption-str (when caption)
4068 ;; (main (org-export-secondary-string (car caption) 'e-odt info))
4069 ;; (secondary (org-export-secondary-string (cdr caption) 'e-odt info))
4070 ;; (caption-str (org-e-odt--caption/label-string caption label info))
4071 (org-e-odt-format-code src-block info)))
4074 ;;;; Statistics Cookie
4076 (defun org-e-odt-statistics-cookie (statistics-cookie contents info)
4077 "Transcode a STATISTICS-COOKIE object from Org to HTML.
4078 CONTENTS is nil. INFO is a plist holding contextual information."
4079 (let ((cookie-value (org-element-property :value statistics-cookie)))
4080 (org-e-odt-format-fontify cookie-value 'code)))
4083 ;;;; Subscript
4085 (defun org-e-odt-subscript (subscript contents info)
4086 "Transcode a SUBSCRIPT object from Org to HTML.
4087 CONTENTS is the contents of the object. INFO is a plist holding
4088 contextual information."
4089 ;; (format (if (= (length contents) 1) "$_%s$" "$_{\\mathrm{%s}}$") contents)
4090 (org-e-odt-format-fontify contents 'subscript))
4093 ;;;; Superscript
4095 (defun org-e-odt-superscript (superscript contents info)
4096 "Transcode a SUPERSCRIPT object from Org to HTML.
4097 CONTENTS is the contents of the object. INFO is a plist holding
4098 contextual information."
4099 ;; (format (if (= (length contents) 1) "$^%s$" "$^{\\mathrm{%s}}$") contents)
4100 (org-e-odt-format-fontify contents 'superscript))
4103 ;;;; Table
4105 (defun org-e-odt-get-colwidth (c)
4106 (let ((col-widths (plist-get table-info :width)))
4107 (or (and org-lparse-table-is-styled (aref col-widths c)) 0)))
4109 (defun org-e-odt-table-row (fields &optional text-for-empty-fields)
4110 (incf org-e-odt-table-rownum)
4111 (let ((i -1))
4112 (org-e-odt-format-table-row
4113 (mapconcat
4114 (lambda (x)
4115 (when (and (string= x "") text-for-empty-fields)
4116 (setq x text-for-empty-fields))
4117 (incf i)
4118 (let ((horiz-span (org-e-odt-get-colwidth i)))
4119 (org-e-odt-format-table-cell
4120 x org-e-odt-table-rownum i horiz-span)))
4121 fields "\n"))))
4123 (defun org-e-odt-table-preamble ()
4124 (let ((colgroup-vector (plist-get table-info :column-groups)) ;; FIXME
4125 c gr colgropen preamble)
4126 (unless (aref colgroup-vector 0)
4127 (setf (aref colgroup-vector 0) 'start))
4128 (dotimes (c columns-number preamble)
4129 (setq gr (aref colgroup-vector c))
4130 (setq preamble
4131 (concat
4132 preamble
4133 (when (memq gr '(start start-end))
4134 (prog1 (if colgropen "</colgroup>\n<colgroup>" "\n<colgroup>")
4135 (setq colgropen t)))
4136 (let* ((colalign-vector (plist-get table-info :alignment)) ;; FIXME
4137 (align (cdr (assoc (aref colalign-vector c)
4138 '(("l" . "left")
4139 ("r" . "right")
4140 ("c" . "center")))))
4141 (alignspec (if (and (boundp 'org-e-odt-format-table-no-css)
4142 org-e-odt-format-table-no-css)
4143 " align=\"%s\"" " class=\"%s\""))
4144 (extra (format alignspec align)))
4145 (format "<col%s />" extra))
4146 (when (memq gr '(end start-end))
4147 (setq colgropen nil)
4148 "</colgroup>"))))
4149 (concat preamble (if colgropen "</colgroup>"))))
4151 (defun org-e-odt-list-table (lines caption label attributes)
4152 (let* ((splice nil) head
4153 (org-e-odt-table-rownum -1)
4154 i (cnt 0)
4155 fields line
4156 org-e-odt-table-cur-rowgrp-is-hdr
4157 org-e-odt-table-rowgrp-open
4159 (org-lparse-table-style 'org-table)
4160 org-lparse-table-is-styled)
4161 (cond
4162 (splice
4163 (setq org-lparse-table-is-styled nil)
4164 (mapconcat 'org-e-odt-table-row lines "\n"))
4166 (setq org-lparse-table-is-styled t)
4168 (concat
4169 (org-e-odt-begin-table caption label attributes)
4170 ;; FIXME (org-e-odt-table-preamble)
4171 (org-e-odt-begin-table-rowgroup head)
4173 (mapconcat
4174 (lambda (line)
4175 (cond
4176 ((equal line 'hline) (org-e-odt-begin-table-rowgroup))
4177 (t (org-e-odt-table-row line))))
4178 lines "\n")
4180 (org-e-odt-end-table-rowgroup)
4181 (org-e-odt-end-table))))))
4183 (defun org-e-odt-transcode-table-row (row)
4184 (if (string-match org-table-hline-regexp row) 'hline
4185 (mapcar
4186 (lambda (cell)
4187 (org-export-secondary-string
4188 (let ((cell (org-element-parse-secondary-string
4189 cell
4190 (cdr (assq 'table org-element-string-restrictions)))))
4191 cell)
4192 'e-odt info))
4193 (org-split-string row "[ \t]*|[ \t]*"))))
4195 (defun org-e-odt-org-table-to-list-table (lines &optional splice)
4196 "Convert org-table to list-table.
4197 LINES is a list of the form (ROW1 ROW2 ROW3 ...) where each
4198 element is a `string' representing a single row of org-table.
4199 Thus each ROW has vertical separators \"|\" separating the table
4200 fields. A ROW could also be a row-group separator of the form
4201 \"|---...|\". Return a list of the form (ROW1 ROW2 ROW3
4202 ...). ROW could either be symbol `'hline' or a list of the
4203 form (FIELD1 FIELD2 FIELD3 ...) as appropriate."
4204 (let (line lines-1)
4205 (cond
4206 (splice
4207 (while (setq line (pop lines))
4208 (unless (string-match "^[ \t]*|-" line)
4209 (push (org-e-odt-transcode-table-row line) lines-1))))
4210 (t (while (setq line (pop lines))
4211 (cond
4212 ((string-match "^[ \t]*|-" line)
4213 (when lines (push 'hline lines-1)))
4214 (t (push (org-e-odt-transcode-table-row line) lines-1))))))
4215 (nreverse lines-1)))
4217 (defun org-e-odt-table-table (raw-table)
4218 (require 'table)
4219 (with-current-buffer (get-buffer-create "*org-export-table*")
4220 (erase-buffer))
4221 (let ((output (with-temp-buffer
4222 (insert raw-table)
4223 (goto-char 1)
4224 (re-search-forward "^[ \t]*|[^|]" nil t)
4225 (table-generate-source 'html "*org-export-table*")
4226 (with-current-buffer "*org-export-table*"
4227 (org-trim (buffer-string))))))
4228 (kill-buffer (get-buffer "*org-export-table*"))
4229 output))
4231 (defun org-e-odt-table (table contents info)
4232 "Transcode a TABLE element from Org to HTML.
4233 CONTENTS is nil. INFO is a plist holding contextual information."
4234 (let* ((caption (org-element-property :caption table))
4235 (short-caption (and (cdr caption) (org-export-secondary-string
4236 (cdr caption) 'e-odt info)))
4237 (caption (and (car caption) (org-export-secondary-string
4238 (car caption) 'e-odt info)))
4239 (label (org-element-property :name table))
4240 (attr (mapconcat #'identity
4241 (org-element-property :attr_odt table)
4242 " "))
4243 (raw-table (org-element-property :raw-table table))
4244 (table-type (org-element-property :type table)))
4245 (case table-type
4246 (table.el
4247 ;; (org-e-odt-table-table raw-table)
4250 (let* ((table-info (org-export-table-format-info raw-table))
4251 (columns-number (length (plist-get table-info :alignment)))
4252 (lines (org-split-string
4253 (org-export-clean-table
4254 raw-table (plist-get table-info :special-column-p)) "\n"))
4256 (genealogy (org-export-get-genealogy table info))
4257 (parent (car genealogy))
4258 (parent-type (org-element-type parent)))
4259 (org-e-odt-list-table
4260 (org-e-odt-org-table-to-list-table lines) caption label attr))))))
4263 ;;;; Target
4265 (defun org-e-odt-target (target contents info)
4266 "Transcode a TARGET object from Org to HTML.
4267 CONTENTS is nil. INFO is a plist holding contextual
4268 information."
4269 (org-e-odt-format-anchor
4270 "" (org-export-solidify-link-text (org-element-property :value target))))
4273 ;;;; Time-stamp
4275 (defun org-e-odt-time-stamp (time-stamp contents info)
4276 "Transcode a TIME-STAMP object from Org to HTML.
4277 CONTENTS is nil. INFO is a plist holding contextual
4278 information."
4279 ;; (let ((value (org-element-property :value time-stamp))
4280 ;; (type (org-element-property :type time-stamp))
4281 ;; (appt-type (org-element-property :appt-type time-stamp)))
4282 ;; (concat (cond ((eq appt-type 'scheduled)
4283 ;; (format "\\textbf{\\textsc{%s}} " org-scheduled-string))
4284 ;; ((eq appt-type 'deadline)
4285 ;; (format "\\textbf{\\textsc{%s}} " org-deadline-string))
4286 ;; ((eq appt-type 'closed)
4287 ;; (format "\\textbf{\\textsc{%s}} " org-closed-string)))
4288 ;; (cond ((memq type '(active active-range))
4289 ;; (format org-e-odt-active-timestamp-format value))
4290 ;; ((memq type '(inactive inactive-range))
4291 ;; (format org-e-odt-inactive-timestamp-format value))
4292 ;; (t
4293 ;; (format org-e-odt-diary-timestamp-format value)))))
4294 (let ((value (org-element-property :value time-stamp))
4295 (type (org-element-property :type time-stamp))
4296 (appt-type (org-element-property :appt-type time-stamp)))
4297 (setq value (org-export-secondary-string value 'e-odt info))
4298 (org-e-odt-format-fontify
4299 (concat
4300 (org-e-odt-format-fontify
4301 (cond ((eq appt-type 'scheduled) org-scheduled-string)
4302 ((eq appt-type 'deadline) org-deadline-string)
4303 ((eq appt-type 'closed) org-closed-string)) "timestamp-kwd")
4304 ;; FIXME: (org-translate-time value)
4305 (org-e-odt-format-fontify value "timestamp"))
4306 "timestamp-wrapper")))
4309 ;;;; Verbatim
4311 (defun org-e-odt-verbatim (verbatim contents info)
4312 "Transcode a VERBATIM object from Org to HTML.
4313 CONTENTS is nil. INFO is a plist used as a communication
4314 channel."
4315 (org-e-odt-emphasis
4316 verbatim (org-element-property :value verbatim) info))
4319 ;;;; Verse Block
4321 (defun org-e-odt-verse-block (verse-block contents info)
4322 "Transcode a VERSE-BLOCK element from Org to HTML.
4323 CONTENTS is nil. INFO is a plist holding contextual information."
4324 ;; Replace each newline character with line break. Also replace
4325 ;; each blank line with a line break.
4326 (setq contents (replace-regexp-in-string
4327 "^ *\\\\\\\\$" "<br/>\n"
4328 (replace-regexp-in-string
4329 "\\(\\\\\\\\\\)?[ \t]*\n" " <br/>\n"
4330 (org-remove-indentation
4331 (org-export-secondary-string
4332 (org-element-property :value verse-block)
4333 'e-odt info)))))
4335 ;; Replace each white space at beginning of a line with a
4336 ;; non-breaking space.
4337 (while (string-match "^[ \t]+" contents)
4338 (let ((new-str (org-e-odt-format-spaces
4339 (length (match-string 0 contents)))))
4340 (setq contents (replace-match new-str nil t contents))))
4342 (org-e-odt--wrap-label
4343 verse-block (format "<p class=\"verse\">\n%s</p>" contents)))
4348 ;;; Filter Functions
4350 ;;;; Filter Settings
4351 ;;;; Filters
4353 ;;; Interactive functions
4355 (defun org-e-odt-export-to-odt
4356 (&optional subtreep visible-only body-only ext-plist pub-dir)
4357 "Export current buffer to a HTML file.
4359 If narrowing is active in the current buffer, only export its
4360 narrowed part.
4362 If a region is active, export that region.
4364 When optional argument SUBTREEP is non-nil, export the sub-tree
4365 at point, extracting information from the headline properties
4366 first.
4368 When optional argument VISIBLE-ONLY is non-nil, don't export
4369 contents of hidden elements.
4371 When optional argument BODY-ONLY is non-nil, only write code
4372 between \"\\begin{document}\" and \"\\end{document}\".
4374 EXT-PLIST, when provided, is a property list with external
4375 parameters overriding Org default settings, but still inferior to
4376 file-local settings.
4378 When optional argument PUB-DIR is set, use it as the publishing
4379 directory.
4381 Return output file's name."
4382 (interactive)
4383 (setq debug-on-error t)
4385 ;; (let* ((outfile (org-export-output-file-name ".html" subtreep pub-dir))
4386 ;; (outfile "content.xml"))
4387 ;; (org-export-to-file
4388 ;; 'e-odt outfile subtreep visible-only body-only ext-plist))
4390 (let* ((outbuf (org-e-odt-init-outfile))
4391 (target (org-export-output-file-name ".odt" subtreep pub-dir))
4392 (outdir (file-name-directory (buffer-file-name outbuf)))
4393 (default-directory outdir))
4395 ;; FIXME: for copying embedded images
4396 (setq org-current-export-file
4397 (file-name-directory
4398 (org-export-output-file-name ".odt" subtreep nil)))
4400 (org-export-to-buffer
4401 'e-odt outbuf
4402 (memq 'subtree optns) (memq 'visible optns) (memq 'body optns))
4404 (setq org-lparse-opt-plist nil) ; FIXME
4405 (org-e-odt-save-as-outfile target ;; info
4409 ;; return outfile
4410 target))
4415 ;;; FIXMES, TODOS, FOR REVIEW etc
4417 ;;;; org-format-table-html
4418 ;;;; org-format-org-table-html
4419 ;;;; org-format-table-table-html
4420 ;;;; org-table-number-fraction
4421 ;;;; org-table-number-regexp
4422 ;;;; org-e-odt-table-caption-above
4424 ;;;; org-whitespace
4425 ;;;; "<span style=\"visibility:hidden;\">%s</span>"
4426 ;;;; Remove display properties
4428 ;;;; org-e-odt-with-timestamp
4429 ;;;; org-e-odt-html-helper-timestamp
4431 ;;;; org-export-as-html-and-open
4432 ;;;; org-export-as-html-batch
4433 ;;;; org-export-as-html-to-buffer
4434 ;;;; org-replace-region-by-html
4435 ;;;; org-export-region-as-html
4436 ;;;; org-export-as-html
4438 ;;;; (org-export-directory :html opt-plist)
4439 ;;;; (plist-get opt-plist :html-extension)
4440 ;;;; org-e-odt-toplevel-hlevel
4441 ;;;; org-e-odt-special-string-regexps
4442 ;;;; org-e-odt-coding-system
4443 ;;;; org-e-odt-coding-system
4444 ;;;; org-e-odt-inline-image-extensions
4445 ;;;; org-e-odt-protect-char-alist
4446 ;;;; org-e-odt-table-use-header-tags-for-first-column
4447 ;;;; org-e-odt-todo-kwd-class-prefix
4448 ;;;; org-e-odt-tag-class-prefix
4449 ;;;; org-e-odt-footnote-separator
4452 ;;; Library Initializations
4454 (mapc
4455 (lambda (desc)
4456 ;; Let Org open all OpenDocument files using system-registered app
4457 (add-to-list 'org-file-apps
4458 (cons (concat "\\." (car desc) "\\'") 'system))
4459 ;; Let Emacs open all OpenDocument files in archive mode
4460 (add-to-list 'auto-mode-alist
4461 (cons (concat "\\." (car desc) "\\'") 'archive-mode)))
4462 org-e-odt-file-extensions)
4464 ;; FIXME
4465 ;; (eval-after-load 'org-exp
4466 ;; '(add-to-list 'org-export-inbuffer-options-extra
4467 ;; '("ODT_STYLES_FILE" :odt-styles-file)))
4469 (provide 'org-e-odt)
4471 ;;; org-e-odt.el ends here