Require one or more spaces (+) between keyword and headline
[org-mode/org-kjn.git] / EXPERIMENTAL / org-e-odt.el
blob9b59954f46e22364dfc98f7a95f1e5553620d04d
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-export-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-export-e-odt-org-styles-alist))))
48 (cdr (assoc entity (cdr (assoc category
49 org-export-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 (plist-get info :title))
59 (author (plist-get info :author))
60 (date (plist-get info :date))
61 (iso-date (org-e-odt-format-date date))
62 (date (org-e-odt-format-date date "%d %b %Y"))
63 (email (plist-get info :email))
64 ;; switch on or off above vars based on user settings
65 (author (and (plist-get info :with-author) (or author email)))
66 (email (and (plist-get info :with-email) email))
67 ;; (date (and (plist-get info :time-stamp-file) date))
69 (concat
70 ;; title
71 (when title
72 (concat
73 (org-e-odt-format-stylized-paragraph
74 'title (format "\n<text:title>%s</text:title>" title))
75 ;; separator
76 "\n<text:p text:style-name=\"OrgTitle\"/>"))
77 (cond
78 ((and author (not email))
79 ;; author only
80 (concat
81 (org-e-odt-format-stylized-paragraph
82 'subtitle
83 (format "<text:initial-creator>%s</text:initial-creator>" author))
84 ;; separator
85 "\n<text:p text:style-name=\"OrgSubtitle\"/>"))
86 ((and author email)
87 ;; author and email
88 (concat
89 (org-e-odt-format-stylized-paragraph
90 'subtitle
91 (org-e-odt-format-link
92 (format "<text:initial-creator>%s</text:initial-creator>" author)
93 (concat "mailto:" email)))
94 ;; separator
95 "\n<text:p text:style-name=\"OrgSubtitle\"/>")))
96 ;; date
97 (when date
98 (concat
99 (org-e-odt-format-stylized-paragraph
100 'subtitle
101 (org-odt-format-tags
102 '("<text:date style:data-style-name=\"%s\" text:date-value=\"%s\">"
103 . "</text:date>")
104 date "N75" iso-date))
105 ;; separator
106 "<text:p text:style-name=\"OrgSubtitle\"/>")))))
108 (defun org-e-odt-begin-section (style &optional name)
109 (let ((default-name (car (org-e-odt-add-automatic-style "Section"))))
110 (format "<text:section text:style-name=\"%s\" text:name=\"%s\">"
111 style (or name default-name))))
113 (defun org-e-odt-end-section ()
114 "</text:section>")
116 (defun org-e-odt-begin-paragraph (&optional style)
117 (format "<text:p%s>" (org-e-odt-get-extra-attrs-for-paragraph-style style)))
119 (defun org-e-odt-end-paragraph ()
120 "</text:p>")
122 (defun org-e-odt-get-extra-attrs-for-paragraph-style (style)
123 (let (style-name)
124 (setq style-name
125 (cond
126 ((stringp style) style)
127 ((symbolp style) (org-e-odt-get-style-name-for-entity
128 'paragraph style))))
129 (unless style-name
130 (error "Don't know how to handle paragraph style %s" style))
131 (format " text:style-name=\"%s\"" style-name)))
133 (defun org-e-odt-format-stylized-paragraph (style text)
134 (format "\n<text:p%s>%s</text:p>"
135 (org-e-odt-get-extra-attrs-for-paragraph-style style)
136 text))
138 (defun org-e-odt-format-author (&optional author )
139 (when (setq author (or author (plist-get org-lparse-opt-plist :author)))
140 (format "<dc:creator>%s</dc:creator>" author)))
142 (defun org-e-odt-format-date (&optional org-ts fmt)
143 (save-match-data
144 (let* ((time
145 (and (stringp org-ts)
146 (string-match org-ts-regexp0 org-ts)
147 (apply 'encode-time
148 (org-fix-decoded-time
149 (org-parse-time-string (match-string 0 org-ts) t)))))
150 date)
151 (cond
152 (fmt (format-time-string fmt time))
153 (t (setq date (format-time-string "%Y-%m-%dT%H:%M:%S%z" time))
154 (format "%s:%s" (substring date 0 -2) (substring date -2)))))))
156 (defun org-e-odt-begin-annotation (&optional author date)
157 (concat
158 "<office:annotation>\n"
159 (and author (org-e-odt-format-author author))
160 (org-e-odt-format-tags
161 '("<dc:date>" . "</dc:date>")
162 (org-e-odt-format-date
163 (or date (plist-get org-lparse-opt-plist :date))))
164 (org-e-odt-begin-paragraph)))
166 (defun org-e-odt-end-annotation ()
167 "</office:annotation>")
169 (defun org-e-odt-begin-plain-list (ltype)
170 (let* ((style-name (org-e-odt-get-style-name-for-entity 'list ltype))
171 (extra (concat
172 ;; (if (or org-lparse-list-table-p
173 ;; (and (= 1 (length org-lparse-list-stack))
174 ;; (null org-e-odt-list-stack-stashed)))
175 ;; " text:continue-numbering=\"false\""
176 ;; " text:continue-numbering=\"true\"")
178 " text:continue-numbering=\"true\""
180 (when style-name
181 (format " text:style-name=\"%s\"" style-name)))))
182 (case ltype
183 ((ordered unordered descriptive)
184 (concat
185 ;; (org-e-odt-end-paragraph)
186 (format "<text:list%s>" extra)))
187 (t (error "Unknown list type: %s" ltype)))))
189 (defun org-e-odt-end-plain-list (ltype)
190 (if ltype "</text:list>"
191 (error "Unknown list type: %s" ltype)))
193 (defun org-e-odt-begin-list-item (ltype &optional arg headline)
194 (case ltype
195 (ordered
196 (assert (not headline) t)
197 (let* ((counter arg) (extra ""))
198 (concat "<text:list-item>" ;; (org-e-odt-begin-paragraph)
200 ;; (if (= (length org-lparse-list-stack)
201 ;; (length org-e-odt-list-stack-stashed))
202 ;; "<text:list-header>" "<text:list-item>")
204 (unordered
205 (let* ((id arg) (extra ""))
206 (concat
207 "<text:list-item>"
208 ;; (org-e-odt-begin-paragraph)
209 (if headline (org-e-odt-format-target headline id)
210 (org-e-odt-format-bookmark "" id)))
211 ;; (if (= (length org-lparse-list-stack)
212 ;; (length org-e-odt-list-stack-stashed))
213 ;; "<text:list-header>" "<text:list-item>")
215 (descriptive
216 (assert (not headline) t)
217 (let ((term (or arg "(no term)")))
218 (concat
219 (org-e-odt-format-tags
220 '("<text:list-item>" . "</text:list-item>")
221 (org-e-odt-format-stylized-paragraph 'definition-term term))
222 (org-e-odt-begin-list-item 'unordered)
223 (org-e-odt-begin-plain-list 'descriptive)
224 (org-e-odt-begin-list-item 'unordered))))
225 (t (error "Unknown list type"))))
227 (defun org-e-odt-end-list-item (ltype)
228 (case ltype
229 ((ordered unordered)
230 ;; (org-lparse-insert-tag
231 ;; (if (= (length org-lparse-list-stack)
232 ;; (length org-e-odt-list-stack-stashed))
233 ;; (prog1 "</text:list-header>"
234 ;; (setq org-e-odt-list-stack-stashed nil))
235 ;; "</text:list-item>")
236 "</text:list-item>"
237 ;; )
239 (descriptive
240 (concat
241 (org-e-odt-end-list-item 'unordered)
242 (org-e-odt-end-plain-list 'descriptive)
243 (org-e-odt-end-list-item 'unordered)
245 (t (error "Unknown list type"))))
247 (defun org-e-odt-discontinue-list ()
248 (let ((stashed-stack org-lparse-list-stack))
249 (loop for list-type in stashed-stack
250 do (org-lparse-end-list-item-1 list-type)
251 (org-lparse-end-list list-type))
252 (setq org-e-odt-list-stack-stashed stashed-stack)))
254 (defun org-e-odt-continue-list ()
255 (setq org-e-odt-list-stack-stashed (nreverse org-e-odt-list-stack-stashed))
256 (loop for list-type in org-e-odt-list-stack-stashed
257 do (org-lparse-begin-list list-type)
258 (org-lparse-begin-list-item list-type)))
260 (defun org-e-odt-write-automatic-styles ()
261 "Write automatic styles to \"content.xml\"."
262 (with-current-buffer
263 (find-file-noselect (expand-file-name "content.xml") t)
264 ;; position the cursor
265 (goto-char (point-min))
266 (re-search-forward " </office:automatic-styles>" nil t)
267 (goto-char (match-beginning 0))
268 ;; write automatic table styles
269 (loop for (style-name props) in
270 (plist-get org-e-odt-automatic-styles 'Table) do
271 (when (setq props (or (plist-get props :rel-width) 96))
272 (insert (format org-e-odt-table-style-format style-name props))))))
274 (defun org-e-odt-add-automatic-style (object-type &optional object-props)
275 "Create an automatic style of type OBJECT-TYPE with param OBJECT-PROPS.
276 OBJECT-PROPS is (typically) a plist created by passing
277 \"#+ATTR_ODT: \" option of the object in question to
278 `org-lparse-get-block-params'.
280 Use `org-e-odt-object-counters' to generate an automatic
281 OBJECT-NAME and STYLE-NAME. If OBJECT-PROPS is non-nil, add a
282 new entry in `org-e-odt-automatic-styles'. Return (OBJECT-NAME
283 . STYLE-NAME)."
284 (assert (stringp object-type))
285 (let* ((object (intern object-type))
286 (seqvar object)
287 (seqno (1+ (or (plist-get org-e-odt-object-counters seqvar) 0)))
288 (object-name (format "%s%d" object-type seqno)) style-name)
289 (setq org-e-odt-object-counters
290 (plist-put org-e-odt-object-counters seqvar seqno))
291 (when object-props
292 (setq style-name (format "Org%s" object-name))
293 (setq org-e-odt-automatic-styles
294 (plist-put org-e-odt-automatic-styles object
295 (append (list (list style-name object-props))
296 (plist-get org-e-odt-automatic-styles object)))))
297 (cons object-name style-name)))
299 (defun org-e-odt-format-table-columns ()
300 (let* ((num-cols (length (plist-get table-info :alignment)))
301 (col-nos (loop for i from 0 below num-cols collect i))
302 (levels )
303 (col-widths (plist-get table-info :width))
304 (style (or (nth 1 org-e-odt-table-style-spec) "OrgTable")))
305 (mapconcat
306 (lambda (c)
307 (let* ((width (or (and org-lparse-table-is-styled (aref col-widths c))
308 0)))
309 (org-e-odt-make-string
310 (1+ width)
311 (org-e-odt-format-tags
312 "<table:table-column table:style-name=\"%sColumn\"/>" "" style))))
313 col-nos "\n")))
316 (defun org-e-odt-begin-table (caption label attributes)
317 ;; (setq org-e-odt-table-indentedp (not (null org-lparse-list-stack)))
318 (setq org-e-odt-table-indentedp nil) ; FIXME
319 (when org-e-odt-table-indentedp
320 ;; Within the Org file, the table is appearing within a list item.
321 ;; OpenDocument doesn't allow table to appear within list items.
322 ;; Temporarily terminate the list, emit the table and then
323 ;; re-continue the list.
324 (org-e-odt-discontinue-list)
325 ;; Put the Table in an indented section.
326 (let ((level (length org-e-odt-list-stack-stashed)))
327 (org-e-odt-begin-section (format "OrgIndentedSection-Level-%d" level))))
328 (setq attributes (org-lparse-get-block-params attributes))
329 (setq org-e-odt-table-style (plist-get attributes :style))
330 (setq org-e-odt-table-style-spec
331 (assoc org-e-odt-table-style org-export-e-odt-table-styles))
332 (concat
333 (org-e-odt-format-stylized-paragraph
334 'table (org-e-odt-format-entity-caption label caption "__Table__"))
335 (let ((name-and-style (org-e-odt-add-automatic-style "Table" attributes)))
336 (format
337 "\n<table:table table:name=\"%s\" table:style-name=\"%s\">\n"
338 (car name-and-style) (or (nth 1 org-e-odt-table-style-spec)
339 (cdr name-and-style) "OrgTable")))
340 (org-e-odt-format-table-columns) "\n")
342 ;; (org-e-html-pp table-info)
346 (defun org-e-odt-end-table ()
347 (concat
348 "</table:table>"
349 ;; (when org-e-odt-table-indentedp
350 ;; (org-e-odt-end-section)
351 ;; (org-e-odt-continue-list))
354 (defun org-e-odt-begin-table-rowgroup (&optional is-header-row)
355 (prog1
356 (concat (when org-e-odt-table-rowgrp-open
357 (org-e-odt-end-table-rowgroup))
358 (if is-header-row "<table:table-header-rows>"
359 "<table:table-rows>"))
360 (setq org-e-odt-table-rowgrp-open t)
361 (setq org-e-odt-table-cur-rowgrp-is-hdr is-header-row)))
363 (defun org-e-odt-end-table-rowgroup ()
364 (when org-e-odt-table-rowgrp-open
365 (setq org-e-odt-table-rowgrp-open nil)
366 (if org-e-odt-table-cur-rowgrp-is-hdr
367 "</table:table-header-rows>" "</table:table-rows>")))
369 (defun org-e-odt-format-table-row (row)
370 (org-e-odt-format-tags
371 '("<table:table-row>" . "</table:table-row>") row))
373 (defun org-e-odt-get-column-alignment (c)
374 (let ((colalign-vector (plist-get table-info :alignment)))
375 ;; FIXME
376 (assoc-default (aref colalign-vector c)
377 '(("l" . "left")
378 ("r" . "right")
379 ("c" . "center")))))
381 (defun org-e-odt-get-table-cell-styles (r c &optional style-spec)
382 "Retrieve styles applicable to a table cell.
383 R and C are (zero-based) row and column numbers of the table
384 cell. STYLE-SPEC is an entry in `org-export-e-odt-table-styles'
385 applicable to the current table. It is `nil' if the table is not
386 associated with any style attributes.
388 Return a cons of (TABLE-CELL-STYLE-NAME . PARAGRAPH-STYLE-NAME).
390 When STYLE-SPEC is nil, style the table cell the conventional way
391 - choose cell borders based on row and column groupings and
392 choose paragraph alignment based on `org-col-cookies' text
393 property. See also
394 `org-e-odt-get-paragraph-style-cookie-for-table-cell'.
396 When STYLE-SPEC is non-nil, ignore the above cookie and return
397 styles congruent with the ODF-1.2 specification."
398 (cond
399 (style-spec
401 ;; LibreOffice - particularly the Writer - honors neither table
402 ;; templates nor custom table-cell styles. Inorder to retain
403 ;; inter-operability with LibreOffice, only automatic styles are
404 ;; used for styling of table-cells. The current implementation is
405 ;; congruent with ODF-1.2 specification and hence is
406 ;; future-compatible.
408 ;; Additional Note: LibreOffice's AutoFormat facility for tables -
409 ;; which recognizes as many as 16 different cell types - is much
410 ;; richer. Unfortunately it is NOT amenable to easy configuration
411 ;; by hand.
413 (let* ((template-name (nth 1 style-spec))
414 (cell-style-selectors (nth 2 style-spec))
415 (cell-type
416 (cond
417 ((and (cdr (assoc 'use-first-column-styles cell-style-selectors))
418 (= c 0)) "FirstColumn")
419 ((and (cdr (assoc 'use-last-column-styles cell-style-selectors))
420 (= c (1- org-lparse-table-ncols))) "LastColumn")
421 ((and (cdr (assoc 'use-first-row-styles cell-style-selectors))
422 (= r 0)) "FirstRow")
423 ((and (cdr (assoc 'use-last-row-styles cell-style-selectors))
424 (= r org-e-odt-table-rownum))
425 "LastRow")
426 ((and (cdr (assoc 'use-banding-rows-styles cell-style-selectors))
427 (= (% r 2) 1)) "EvenRow")
428 ((and (cdr (assoc 'use-banding-rows-styles cell-style-selectors))
429 (= (% r 2) 0)) "OddRow")
430 ((and (cdr (assoc 'use-banding-columns-styles cell-style-selectors))
431 (= (% c 2) 1)) "EvenColumn")
432 ((and (cdr (assoc 'use-banding-columns-styles cell-style-selectors))
433 (= (% c 2) 0)) "OddColumn")
434 (t ""))))
435 (cons
436 (concat template-name cell-type "TableCell")
437 (concat template-name cell-type "TableParagraph"))))
439 (cons
440 (concat
441 "OrgTblCell"
442 (cond
443 ((= r 0) "T")
444 ((eq (cdr (assoc r nil ;; org-lparse-table-rowgrp-info FIXME
445 )) :start) "T")
446 (t ""))
447 (when (= r org-e-odt-table-rownum) "B")
448 (cond
449 ((= c 0) "")
450 ((or (memq (nth c org-table-colgroup-info) '(:start :startend))
451 (memq (nth (1- c) org-table-colgroup-info) '(:end :startend))) "L")
452 (t "")))
453 (capitalize (org-e-odt-get-column-alignment c))))))
455 (defun org-e-odt-get-paragraph-style-cookie-for-table-cell (r c)
456 (concat
457 (and (not org-e-odt-table-style-spec)
458 (cond
459 (org-e-odt-table-cur-rowgrp-is-hdr "OrgTableHeading")
460 ((and (= c 0) nil
461 ;; (org-lparse-get 'TABLE-FIRST-COLUMN-AS-LABELS)
463 "OrgTableHeading")
464 (t "OrgTableContents")))
465 (and org-lparse-table-is-styled
466 (cdr (org-e-odt-get-table-cell-styles
467 r c org-e-odt-table-style-spec)))))
469 (defun org-e-odt-get-style-name-cookie-for-table-cell (r c)
470 (when org-lparse-table-is-styled
471 (let* ((cell-styles (org-e-odt-get-table-cell-styles
472 r c org-e-odt-table-style-spec))
473 (table-cell-style (car cell-styles)))
474 table-cell-style)))
476 (defun org-e-odt-format-table-cell (data r c horiz-span)
477 (concat
478 (let* ((paragraph-style-cookie
479 (org-e-odt-get-paragraph-style-cookie-for-table-cell r c))
480 (style-name-cookie
481 (org-e-odt-get-style-name-cookie-for-table-cell r c))
482 (extra (and style-name-cookie
483 (format " table:style-name=\"%s\"" style-name-cookie)))
484 (extra (concat extra
485 (and (> horiz-span 0)
486 (format " table:number-columns-spanned=\"%d\""
487 (1+ horiz-span))))))
488 (org-e-odt-format-tags
489 '("<table:table-cell%s>" . "</table:table-cell>")
490 (if org-lparse-list-table-p data
491 (org-e-odt-format-stylized-paragraph paragraph-style-cookie data)) extra))
492 (let (s)
493 (dotimes (i horiz-span)
494 (setq s (concat s "\n<table:covered-table-cell/>"))) s)
495 "\n"))
497 (defun org-e-odt-begin-toc (lang-specific-heading max-level)
498 (concat
499 (format "
500 <text:table-of-content text:style-name=\"Sect2\" text:protected=\"true\" text:name=\"Table of Contents1\">
501 <text:table-of-content-source text:outline-level=\"%d\">
502 <text:index-title-template text:style-name=\"Contents_20_Heading\">%s</text:index-title-template>
503 " max-level lang-specific-heading)
505 (let ((entry-templates ""))
506 (loop for level from 1 upto 10
507 do (setq entry-templates
508 (concat entry-templates
509 (format
511 <text:table-of-content-entry-template text:outline-level=\"%d\" text:style-name=\"Contents_20_%d\">
512 <text:index-entry-link-start text:style-name=\"Internet_20_link\"/>
513 <text:index-entry-chapter/>
514 <text:index-entry-text/>
515 <text:index-entry-link-end/>
516 </text:table-of-content-entry-template>
517 " level level))))
518 entry-templates)
520 (format "
521 </text:table-of-content-source>
523 <text:index-body>
524 <text:index-title text:style-name=\"Sect1\" text:name=\"Table of Contents1_Head\">
525 <text:p text:style-name=\"Contents_20_Heading\">%s</text:p>
526 </text:index-title>
527 " lang-specific-heading)))
529 (defun org-e-odt-end-toc ()
530 (format "
531 </text:index-body>
532 </text:table-of-content>
535 (defun org-e-odt-format-toc-entry (snumber todo headline tags href)
537 ;; FIXME
538 (setq headline (concat
539 (and org-export-with-section-numbers
540 (concat snumber ". "))
541 headline
542 (and tags
543 (concat
544 (org-e-odt-format-spaces 3)
545 (org-e-odt-format-fontify tags "tag")))))
546 (when todo
547 (setq headline (org-e-odt-format-fontify headline "todo")))
549 (let ((org-e-odt-suppress-xref t))
550 (org-e-odt-format-link headline (concat "#" href))))
552 (defun org-e-odt-format-toc-item (toc-entry level org-last-level)
553 (let ((style (format "Contents_20_%d"
554 (+ level (or ;; (org-lparse-get 'TOPLEVEL-HLEVEL)
556 1) -1))))
557 (concat "\n" (org-e-odt-format-stylized-paragraph style toc-entry) "\n")))
559 ;; Following variable is let bound during 'ORG-LINK callback. See
560 ;; org-html.el
562 (defun org-e-odt-format-link (desc href &optional attr)
563 (cond
564 ((and (= (string-to-char href) ?#) (not org-e-odt-suppress-xref))
565 (setq href (concat org-export-e-odt-bookmark-prefix (substring href 1)))
566 (let ((xref-format "text"))
567 (when (numberp desc)
568 (setq desc (format "%d" desc) xref-format "number"))
569 (org-e-odt-format-tags-simple
570 '("<text:bookmark-ref text:reference-format=\"%s\" text:ref-name=\"%s\">" .
571 "</text:bookmark-ref>")
572 desc xref-format href)))
573 (org-lparse-link-description-is-image
574 (org-e-odt-format-tags
575 '("<draw:a xlink:type=\"simple\" xlink:href=\"%s\" %s>" . "</draw:a>")
576 desc href (or attr "")))
578 (org-e-odt-format-tags-simple
579 '("<text:a xlink:type=\"simple\" xlink:href=\"%s\" %s>" . "</text:a>")
580 desc href (or attr "")))))
582 (defun org-e-odt-format-spaces (n)
583 (cond
584 ((= n 1) " ")
585 ((> n 1) (concat
586 " " (org-e-odt-format-tags "<text:s text:c=\"%d\"/>" "" (1- n))))
587 (t "")))
589 (defun org-e-odt-format-tabs (&optional n)
590 (let ((tab "<text:tab/>")
591 (n (or n 1)))
592 (insert tab)))
594 (defun org-e-odt-format-line-break ()
595 (org-e-odt-format-tags "<text:line-break/>" ""))
597 (defun org-e-odt-format-horizontal-line ()
598 (org-e-odt-format-stylized-paragraph 'horizontal-line ""))
600 (defun org-e-odt-encode-plain-text (line &optional no-whitespace-filling)
601 (setq line (org-e-html-encode-plain-text line))
602 (if no-whitespace-filling line
603 (org-e-odt-fill-tabs-and-spaces line)))
605 (defun org-e-odt-format-line (line)
606 (case org-lparse-dyn-current-environment
607 (fixedwidth (concat
608 (org-e-odt-format-stylized-paragraph
609 'fixedwidth (org-e-odt-encode-plain-text line)) "\n"))
610 (t (concat line "\n"))))
612 (defun org-e-odt-format-comment (fmt &rest args)
613 (let ((comment (apply 'format fmt args)))
614 (format "\n<!-- %s -->\n" comment)))
616 (defun org-e-odt-format-org-entity (wd)
617 (org-entity-get-representation wd 'utf8))
619 (defun org-e-odt-fill-tabs-and-spaces (line)
620 (replace-regexp-in-string
621 "\\([\t]\\|\\([ ]+\\)\\)" (lambda (s)
622 (cond
623 ((string= s "\t") (org-e-odt-format-tabs))
624 (t (org-e-odt-format-spaces (length s))))) line))
626 (defun org-e-odt-hfy-face-to-css (fn)
627 "Create custom style for face FN.
628 When FN is the default face, use it's foreground and background
629 properties to create \"OrgSrcBlock\" paragraph style. Otherwise
630 use it's color attribute to create a character style whose name
631 is obtained from FN. Currently all attributes of FN other than
632 color are ignored.
634 The style name for a face FN is derived using the following
635 operations on the face name in that order - de-dash, CamelCase
636 and prefix with \"OrgSrc\". For example,
637 `font-lock-function-name-face' is associated with
638 \"OrgSrcFontLockFunctionNameFace\"."
639 (let* ((css-list (hfy-face-to-style fn))
640 (style-name ((lambda (fn)
641 (concat "OrgSrc"
642 (mapconcat
643 'capitalize (split-string
644 (hfy-face-or-def-to-name fn) "-")
645 ""))) fn))
646 (color-val (cdr (assoc "color" css-list)))
647 (background-color-val (cdr (assoc "background" css-list)))
648 (style (and org-export-e-odt-create-custom-styles-for-srcblocks
649 (cond
650 ((eq fn 'default)
651 (format org-src-block-paragraph-format
652 background-color-val color-val))
654 (format
656 <style:style style:name=\"%s\" style:family=\"text\">
657 <style:text-properties fo:color=\"%s\"/>
658 </style:style>" style-name color-val))))))
659 (cons style-name style)))
661 (defun org-e-odt-insert-custom-styles-for-srcblocks (styles)
662 "Save STYLES used for colorizing of source blocks.
663 Update styles.xml with styles that were collected as part of
664 `org-e-odt-hfy-face-to-css' callbacks."
665 (when styles
666 (with-current-buffer
667 (find-file-noselect (expand-file-name "styles.xml") t)
668 (goto-char (point-min))
669 (when (re-search-forward "</office:styles>" nil t)
670 (goto-char (match-beginning 0))
671 (insert "\n<!-- Org Htmlfontify Styles -->\n" styles "\n")))))
673 (defun org-e-odt-remap-stylenames (style-name)
675 (cdr (assoc style-name '(("timestamp-wrapper" . "OrgTimestampWrapper")
676 ("timestamp" . "OrgTimestamp")
677 ("timestamp-kwd" . "OrgTimestampKeyword")
678 ("tag" . "OrgTag")
679 ("todo" . "OrgTodo")
680 ("done" . "OrgDone")
681 ("target" . "OrgTarget"))))
682 style-name))
684 (defun org-e-odt-format-fontify (text style &optional id)
685 (let* ((style-name
686 (cond
687 ((stringp style)
688 (org-e-odt-remap-stylenames style))
689 ((symbolp style)
690 (org-e-odt-get-style-name-for-entity 'character style))
691 ((listp style)
692 (assert (< 1 (length style)))
693 (let ((parent-style (pop style)))
694 (mapconcat (lambda (s)
695 ;; (assert (stringp s) t)
696 (org-e-odt-remap-stylenames s)) style "")
697 (org-e-odt-remap-stylenames parent-style)))
698 (t (error "Don't how to handle style %s" style)))))
699 (org-e-odt-format-tags
700 '("<text:span text:style-name=\"%s\">" . "</text:span>")
701 text style-name)))
703 (defun org-e-odt-relocate-relative-path (path dir)
704 (if (file-name-absolute-p path) path
705 (file-relative-name (expand-file-name path dir)
706 (expand-file-name "eyecandy" dir))))
708 (defun org-e-odt-format-inline-image (thefile
709 &optional caption label attrs ; FIXME - CLA
711 (let* ((thelink (if (file-name-absolute-p thefile) thefile
712 (org-xml-format-href
713 (org-e-odt-relocate-relative-path
714 thefile org-current-export-file))))
715 (href
716 (org-e-odt-format-tags
717 "<draw:image xlink:href=\"%s\" xlink:type=\"simple\" xlink:show=\"embed\" xlink:actuate=\"onLoad\"/>" ""
718 (if org-export-e-odt-embed-images
719 (org-e-odt-copy-image-file thefile) thelink))))
720 (org-export-e-odt-format-image thefile href)))
722 (defun org-export-e-odt-format-formula (src href)
723 (save-match-data
724 (let* ((caption (org-find-text-property-in-string 'org-caption src))
725 (caption (and caption (org-xml-format-desc caption)))
726 (label (org-find-text-property-in-string 'org-label src))
727 (latex-frag (org-find-text-property-in-string 'org-latex-src src))
728 (embed-as (or (and latex-frag
729 (org-find-text-property-in-string
730 'org-latex-src-embed-type src))
731 (if (or caption label) 'paragraph 'character)))
732 width height)
733 (when latex-frag
734 (setq href (org-propertize href :title "LaTeX Fragment"
735 :description latex-frag)))
736 (cond
737 ((eq embed-as 'character)
738 (org-e-odt-format-entity "InlineFormula" href width height))
740 (org-lparse-end-paragraph)
741 (org-lparse-insert-list-table
742 `((,(org-e-odt-format-entity
743 (if caption "CaptionedDisplayFormula" "DisplayFormula")
744 href width height :caption caption :label nil)
745 ,(if (not label) ""
746 (org-e-odt-format-entity-caption label nil "__MathFormula__"))))
747 nil nil nil ":style \"OrgEquation\"" nil '((1 "c" 8) (2 "c" 1)))
748 (throw 'nextline nil))))))
750 (defun org-e-odt-copy-formula-file (path)
751 "Returns the internal name of the file"
752 (let* ((src-file (expand-file-name
753 path (file-name-directory org-current-export-file)))
754 (target-dir (format "Formula-%04d/"
755 (incf org-e-odt-embedded-formulas-count)))
756 (target-file (concat target-dir "content.xml")))
757 (message "Embedding %s as %s ..."
758 (substring-no-properties path) target-file)
760 (make-directory target-dir)
761 (org-e-odt-create-manifest-file-entry
762 "application/vnd.oasis.opendocument.formula" target-dir "1.2")
764 (case (org-e-odt-is-formula-link-p src-file)
765 (mathml
766 (copy-file src-file target-file 'overwrite))
767 (odf
768 (org-e-odt-zip-extract-one src-file "content.xml" target-dir))
770 (error "%s is not a formula file" src-file)))
772 (org-e-odt-create-manifest-file-entry "text/xml" target-file)
773 target-file))
775 (defun org-e-odt-format-inline-formula (thefile)
776 (let* ((thelink (if (file-name-absolute-p thefile) thefile
777 (org-xml-format-href
778 (org-e-odt-relocate-relative-path
779 thefile org-current-export-file))))
780 (href
781 (org-e-odt-format-tags
782 "<draw:object xlink:href=\"%s\" xlink:type=\"simple\" xlink:show=\"embed\" xlink:actuate=\"onLoad\"/>" ""
783 (file-name-directory (org-e-odt-copy-formula-file thefile)))))
784 (org-export-e-odt-format-formula thefile href)))
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-export-e-odt-inline-image-extensions)
818 (or (eq t org-export-e-odt-inline-images)
819 (and org-export-e-odt-inline-images (not descp))))
820 (org-e-odt-format-inline-image thefile))
821 ;; check for embedded formulas
822 ((and (member type '("file"))
823 (not fragment)
824 (org-e-odt-is-formula-link-p filename)
825 (or (not descp)))
826 (org-e-odt-format-inline-formula thefile))
827 ((string= type "coderef")
828 (let* ((ref fragment)
829 (lineno-or-ref (cdr (assoc ref org-export-code-refs)))
830 (desc (and descp desc))
831 (org-e-odt-suppress-xref nil)
832 (href (org-xml-format-href (concat "#coderef-" ref))))
833 (cond
834 ((and (numberp lineno-or-ref) (not desc))
835 (org-e-odt-format-link lineno-or-ref href))
836 ((and (numberp lineno-or-ref) desc
837 (string-match (regexp-quote (concat "(" ref ")")) desc))
838 (format (replace-match "%s" t t desc)
839 (org-e-odt-format-link lineno-or-ref href)))
841 (setq desc (format
842 (if (and desc (string-match
843 (regexp-quote (concat "(" ref ")"))
844 desc))
845 (replace-match "%s" t t desc)
846 (or desc "%s"))
847 lineno-or-ref))
848 (org-e-odt-format-link (org-xml-format-desc desc) href)))))
850 (when (string= type "file")
851 (setq thefile
852 (cond
853 ((file-name-absolute-p path)
854 (concat "file://" (expand-file-name path)))
855 (t (org-e-odt-relocate-relative-path
856 thefile org-current-export-file)))))
858 (when (and (member type '("" "http" "https" "file")) fragment)
859 (setq thefile (concat thefile "#" fragment)))
861 (setq thefile (org-xml-format-href thefile))
863 (when (not (member type '("" "file")))
864 (setq thefile (concat type ":" thefile)))
866 (let ((org-e-odt-suppress-xref nil))
867 (org-e-odt-format-link
868 (org-xml-format-desc desc) thefile attr)))))))
870 (defun org-e-odt-format-heading (text level &optional id)
871 (let* ((text (if id (org-e-odt-format-target text id) text)))
872 (org-e-odt-format-tags
873 '("<text:h text:style-name=\"Heading_20_%s\" text:outline-level=\"%s\">" .
874 "</text:h>") text level level)))
876 (defun org-e-odt-format-headline (title extra-targets tags
877 &optional snumber level)
878 (concat
879 (org-e-odt-format-extra-targets extra-targets)
881 ;; No need to generate section numbers. They are auto-generated by
882 ;; the application
884 ;; (concat (org-lparse-format 'SECTION-NUMBER snumber level) " ")
885 title
886 (and tags (concat (org-e-odt-format-spaces 3)
887 (org-e-odt-format-org-tags tags)))))
889 (defun org-e-odt-format-anchor (text name &optional class)
890 (org-e-odt-format-target text name))
892 (defun org-e-odt-format-bookmark (text id)
893 (if id
894 (org-e-odt-format-tags "<text:bookmark text:name=\"%s\"/>" text id)
895 text))
897 (defun org-e-odt-format-target (text id)
898 (let ((name (concat org-export-e-odt-bookmark-prefix id)))
899 (concat
900 (and id (org-e-odt-format-tags
901 "<text:bookmark-start text:name=\"%s\"/>" "" name))
902 (org-e-odt-format-bookmark text id)
903 (and id (org-e-odt-format-tags
904 "<text:bookmark-end text:name=\"%s\"/>" "" name)))))
906 (defun org-e-odt-format-footnote (n def)
907 (setq n (format "%d" n))
908 (let ((id (concat "fn" n))
909 (note-class "footnote")
910 (par-style "Footnote"))
911 (org-e-odt-format-tags
912 '("<text:note text:id=\"%s\" text:note-class=\"%s\">" .
913 "</text:note>")
914 (concat
915 (org-e-odt-format-tags
916 '("<text:note-citation>" . "</text:note-citation>")
918 (org-e-odt-format-tags
919 '("<text:note-body>" . "</text:note-body>")
920 def))
921 id note-class)))
923 (defun org-e-odt-format-footnote-reference (n def refcnt)
924 (if (= refcnt 1)
925 (org-e-odt-format-footnote n def)
926 (org-e-odt-format-footnote-ref n)))
928 (defun org-e-odt-format-footnote-ref (n)
929 (setq n (format "%d" n))
930 (let ((note-class "footnote")
931 (ref-format "text")
932 (ref-name (concat "fn" n)))
933 (org-e-odt-format-tags
934 '("<text:span text:style-name=\"%s\">" . "</text:span>")
935 (org-e-odt-format-tags
936 '("<text:note-ref text:note-class=\"%s\" text:reference-format=\"%s\" text:ref-name=\"%s\">" . "</text:note-ref>")
937 n note-class ref-format ref-name)
938 "OrgSuperscript")))
940 (defun org-e-odt-get-image-name (file-name)
941 (require 'sha1)
942 (file-relative-name
943 (expand-file-name
944 (concat (sha1 file-name) "." (file-name-extension file-name)) "Pictures")))
946 (defun org-export-e-odt-format-image (src href)
947 "Create image tag with source and attributes."
948 (save-match-data
949 (let* ((caption (org-find-text-property-in-string 'org-caption src))
950 (caption (and caption (org-xml-format-desc caption)))
951 (attr (org-find-text-property-in-string 'org-attributes src))
952 (label (org-find-text-property-in-string 'org-label src))
953 (latex-frag (org-find-text-property-in-string
954 'org-latex-src src))
955 (category (and latex-frag "__DvipngImage__"))
956 (attr-plist (org-lparse-get-block-params attr))
957 (user-frame-anchor
958 (car (assoc-string (plist-get attr-plist :anchor)
959 '(("as-char") ("paragraph") ("page")) t)))
960 (user-frame-style
961 (and user-frame-anchor (plist-get attr-plist :style)))
962 (user-frame-attrs
963 (and user-frame-anchor (plist-get attr-plist :attributes)))
964 (user-frame-params
965 (list user-frame-style user-frame-attrs user-frame-anchor))
966 (embed-as (cond
967 (latex-frag
968 (symbol-name
969 (case (org-find-text-property-in-string
970 'org-latex-src-embed-type src)
971 (paragraph 'paragraph)
972 (t 'as-char))))
973 (user-frame-anchor)
974 (t "paragraph")))
975 (size (org-e-odt-image-size-from-file
976 src (plist-get attr-plist :width)
977 (plist-get attr-plist :height)
978 (plist-get attr-plist :scale) nil embed-as))
979 (width (car size)) (height (cdr size)))
980 (when latex-frag
981 (setq href (org-propertize href :title "LaTeX Fragment"
982 :description latex-frag)))
983 (let ((frame-style-handle (concat (and (or caption label) "Captioned")
984 embed-as "Image")))
985 (org-e-odt-format-entity
986 frame-style-handle href width height
987 :caption caption :label label :category category
988 :user-frame-params user-frame-params)))))
990 (defun org-e-odt-format-object-description (title description)
991 (concat (and title (org-e-odt-format-tags
992 '("<svg:title>" . "</svg:title>")
993 (org-e-odt-encode-plain-text title t)))
994 (and description (org-e-odt-format-tags
995 '("<svg:desc>" . "</svg:desc>")
996 (org-e-odt-encode-plain-text description t)))))
998 (defun org-e-odt-format-frame (text width height style &optional
999 extra anchor-type)
1000 (let ((frame-attrs
1001 (concat
1002 (if width (format " svg:width=\"%0.2fcm\"" width) "")
1003 (if height (format " svg:height=\"%0.2fcm\"" height) "")
1004 extra
1005 (format " text:anchor-type=\"%s\"" (or anchor-type "paragraph")))))
1006 (org-e-odt-format-tags
1007 '("<draw:frame draw:style-name=\"%s\"%s>" . "</draw:frame>")
1008 (concat text (org-e-odt-format-object-description
1009 (get-text-property 0 :title text)
1010 (get-text-property 0 :description text)))
1011 style frame-attrs)))
1013 (defun org-e-odt-format-textbox (text width height style &optional
1014 extra anchor-type)
1015 (org-e-odt-format-frame
1016 (org-e-odt-format-tags
1017 '("<draw:text-box %s>" . "</draw:text-box>")
1018 text (concat (format " fo:min-height=\"%0.2fcm\"" (or height .2))
1019 (unless width
1020 (format " fo:min-width=\"%0.2fcm\"" (or width .2)))))
1021 width nil style extra anchor-type))
1023 (defun org-e-odt-format-inlinetask (heading content
1024 &optional todo priority tags)
1025 (org-e-odt-format-stylized-paragraph
1026 nil (org-e-odt-format-textbox
1027 (concat (org-e-odt-format-stylized-paragraph
1028 "OrgInlineTaskHeading"
1029 (org-lparse-format
1030 'HEADLINE (concat (org-lparse-format-todo todo) " " heading)
1031 nil tags))
1032 content) nil nil "OrgInlineTaskFrame" " style:rel-width=\"100%\"")))
1035 (defun org-e-odt-merge-frame-params(default-frame-params user-frame-params)
1036 (if (not user-frame-params) default-frame-params
1037 (assert (= (length default-frame-params) 3))
1038 (assert (= (length user-frame-params) 3))
1039 (loop for user-frame-param in user-frame-params
1040 for default-frame-param in default-frame-params
1041 collect (or user-frame-param default-frame-param))))
1043 (defun* org-e-odt-format-entity (entity href width height
1044 &key caption label category
1045 user-frame-params)
1046 (let* ((entity-style (assoc-string entity org-e-odt-entity-frame-styles t))
1047 default-frame-params frame-params)
1048 (cond
1049 ((not (or caption label))
1050 (setq default-frame-params (nth 2 entity-style))
1051 (setq frame-params (org-e-odt-merge-frame-params
1052 default-frame-params user-frame-params))
1053 (apply 'org-e-odt-format-frame href width height frame-params))
1055 (setq default-frame-params (nth 3 entity-style))
1056 (setq frame-params (org-e-odt-merge-frame-params
1057 default-frame-params user-frame-params))
1058 (apply 'org-e-odt-format-textbox
1059 (org-e-odt-format-stylized-paragraph
1060 'illustration
1061 (concat
1062 (apply 'org-e-odt-format-frame href width height
1063 (nth 2 entity-style))
1064 (org-e-odt-format-entity-caption
1065 label caption (or category (nth 1 entity-style)))))
1066 width height frame-params)))))
1068 (defun org-e-odt-copy-image-file (path)
1069 "Returns the internal name of the file"
1070 (let* ((image-type (file-name-extension path))
1071 (media-type (format "image/%s" image-type))
1072 (src-file (expand-file-name
1073 path (file-name-directory org-current-export-file)))
1074 (target-dir "Images/")
1075 (target-file
1076 (format "%s%04d.%s" target-dir
1077 (incf org-e-odt-embedded-images-count) image-type)))
1078 (message "Embedding %s as %s ..."
1079 (substring-no-properties path) target-file)
1081 (when (= 1 org-e-odt-embedded-images-count)
1082 (make-directory target-dir)
1083 (org-e-odt-create-manifest-file-entry "" target-dir))
1085 (copy-file src-file target-file 'overwrite)
1086 (org-e-odt-create-manifest-file-entry media-type target-file)
1087 target-file))
1089 (defun org-e-odt-do-image-size (probe-method file &optional dpi anchor-type)
1090 (setq dpi (or dpi org-export-e-odt-pixels-per-inch))
1091 (setq anchor-type (or anchor-type "paragraph"))
1092 (flet ((size-in-cms (size-in-pixels)
1093 (flet ((pixels-to-cms (pixels)
1094 (let* ((cms-per-inch 2.54)
1095 (inches (/ pixels dpi)))
1096 (* cms-per-inch inches))))
1097 (and size-in-pixels
1098 (cons (pixels-to-cms (car size-in-pixels))
1099 (pixels-to-cms (cdr size-in-pixels)))))))
1100 (case probe-method
1101 (emacs
1102 (size-in-cms (ignore-errors ; Emacs could be in batch mode
1103 (clear-image-cache)
1104 (image-size (create-image file) 'pixels))))
1105 (imagemagick
1106 (size-in-cms
1107 (let ((dim (shell-command-to-string
1108 (format "identify -format \"%%w:%%h\" \"%s\"" file))))
1109 (when (string-match "\\([0-9]+\\):\\([0-9]+\\)" dim)
1110 (cons (string-to-number (match-string 1 dim))
1111 (string-to-number (match-string 2 dim)))))))
1113 (cdr (assoc-string anchor-type
1114 org-export-e-odt-default-image-sizes-alist))))))
1116 (defun org-e-odt-image-size-from-file (file &optional user-width
1117 user-height scale dpi embed-as)
1118 (unless (file-name-absolute-p file)
1119 (setq file (expand-file-name
1120 file (file-name-directory org-current-export-file))))
1121 (let* (size width height)
1122 (unless (and user-height user-width)
1123 (loop for probe-method in org-export-e-odt-image-size-probe-method
1124 until size
1125 do (setq size (org-e-odt-do-image-size
1126 probe-method file dpi embed-as)))
1127 (or size (error "Cannot determine Image size. Aborting ..."))
1128 (setq width (car size) height (cdr size)))
1129 (cond
1130 (scale
1131 (setq width (* width scale) height (* height scale)))
1132 ((and user-height user-width)
1133 (setq width user-width height user-height))
1134 (user-height
1135 (setq width (* user-height (/ width height)) height user-height))
1136 (user-width
1137 (setq height (* user-width (/ height width)) width user-width))
1138 (t (ignore)))
1139 ;; ensure that an embedded image fits comfortably within a page
1140 (let ((max-width (car org-export-e-odt-max-image-size))
1141 (max-height (cdr org-export-e-odt-max-image-size)))
1142 (when (or (> width max-width) (> height max-height))
1143 (let* ((scale1 (/ max-width width))
1144 (scale2 (/ max-height height))
1145 (scale (min scale1 scale2)))
1146 (setq width (* scale width) height (* scale height)))))
1147 (cons width height)))
1149 (defun org-e-odt-get-label-category-and-style (label default-category)
1150 "See `org-export-e-odt-get-category-from-label'."
1151 (let ((default-category-map
1152 (assoc default-category org-e-odt-category-map-alist))
1153 user-category user-category-map category)
1154 (cond
1155 ((not org-export-e-odt-get-category-from-label)
1156 default-category-map)
1157 ((not (setq user-category
1158 (save-match-data
1159 (and (string-match "\\`\\(.*\\):.+" label)
1160 (match-string 1 label)))))
1161 default-category-map)
1163 (setq user-category-map
1164 (or (assoc user-category org-e-odt-category-map-alist)
1165 (list nil user-category "category-and-value"))
1166 category (nth 1 user-category-map))
1167 (if (member category org-export-e-odt-user-categories)
1168 user-category-map
1169 default-category-map)))))
1171 (defun org-e-odt-add-label-definition (label default-category)
1172 "Create an entry in `org-e-odt-entity-labels-alist' and return it."
1173 (setq label (substring-no-properties label))
1174 (let* ((label-props (org-e-odt-get-label-category-and-style
1175 label default-category))
1176 (category (nth 1 label-props))
1177 (counter category)
1178 (label-style (nth 2 label-props))
1179 (sequence-var (intern (mapconcat
1180 'downcase
1181 (org-split-string counter) "-")))
1182 (seqno (1+ (or (plist-get org-e-odt-entity-counts-plist sequence-var)
1183 0)))
1184 (label-props (list label category seqno label-style)))
1185 (setq org-e-odt-entity-counts-plist
1186 (plist-put org-e-odt-entity-counts-plist sequence-var seqno))
1187 (push label-props org-e-odt-entity-labels-alist)
1188 label-props))
1190 (defun org-e-odt-format-label-definition (caption label category seqno label-style)
1191 (assert label)
1192 (format-spec
1193 (cadr (assoc-string label-style org-e-odt-label-styles t))
1194 `((?e . ,category)
1195 (?n . ,(org-e-odt-format-tags
1196 '("<text:sequence text:ref-name=\"%s\" text:name=\"%s\" text:formula=\"ooow:%s+1\" style:num-format=\"1\">" . "</text:sequence>")
1197 (format "%d" seqno) label category category))
1198 (?c . ,(or (and caption (concat ": " caption)) "")))))
1200 (defun org-e-odt-format-label-reference (label category seqno label-style)
1201 (assert label)
1202 (save-match-data
1203 (let* ((fmt (cddr (assoc-string label-style org-e-odt-label-styles t)))
1204 (fmt1 (car fmt))
1205 (fmt2 (cadr fmt)))
1206 (org-e-odt-format-tags
1207 '("<text:sequence-ref text:reference-format=\"%s\" text:ref-name=\"%s\">"
1208 . "</text:sequence-ref>")
1209 (format-spec fmt2 `((?e . ,category)
1210 (?n . ,(format "%d" seqno)))) fmt1 label))))
1212 (defun org-e-odt-fixup-label-references ()
1213 (goto-char (point-min))
1214 (while (re-search-forward
1215 "<text:sequence-ref text:ref-name=\"\\([^\"]+\\)\">[ \t\n]*</text:sequence-ref>"
1216 nil t)
1217 (let* ((label (match-string 1))
1218 (label-def (assoc label org-e-odt-entity-labels-alist))
1219 (rpl (and label-def
1220 (apply 'org-e-odt-format-label-reference label-def))))
1221 (if rpl (replace-match rpl t t)
1222 (org-lparse-warn
1223 (format "Unable to resolve reference to label \"%s\"" label))))))
1225 (defun org-e-odt-format-entity-caption (label caption category)
1226 (or (and label
1227 (apply 'org-e-odt-format-label-definition
1228 caption (org-e-odt-add-label-definition label category)))
1229 caption ""))
1231 (defun org-e-odt-format-tags-1 (tag text prefix suffix &rest args)
1232 (cond
1233 ((consp tag)
1234 (concat prefix (apply 'format (car tag) args) text suffix
1235 (format (cdr tag))))
1236 ((stringp tag) ; singleton tag
1237 (concat prefix (apply 'format tag args) text))))
1239 (defun org-e-odt-format-tags (tag text &rest args)
1240 (apply 'org-e-odt-format-tags-1 tag text "\n" "\n" args))
1242 (defun org-e-odt-format-tags-simple (tag text &rest args)
1243 (apply 'org-e-odt-format-tags-1 tag text nil nil args))
1245 (defun org-e-odt-init-outfile ()
1246 (unless (executable-find "zip")
1247 ;; Not at all OSes ship with zip by default
1248 (error "Executable \"zip\" needed for creating OpenDocument files"))
1250 (let* ((outdir (make-temp-file
1251 (format org-export-e-odt-tmpdir-prefix org-lparse-backend) t))
1252 (content-file (expand-file-name "content.xml" outdir)))
1254 ;; reset variables
1255 (setq org-e-odt-manifest-file-entries nil
1256 org-e-odt-embedded-images-count 0
1257 org-e-odt-embedded-formulas-count 0
1258 org-e-odt-section-count 0
1259 org-e-odt-entity-labels-alist nil
1260 org-e-odt-list-stack-stashed nil
1261 org-e-odt-automatic-styles nil
1262 org-e-odt-object-counters nil
1263 org-e-odt-entity-counts-plist nil)
1265 ;; let `htmlfontify' know that we are interested in collecting
1266 ;; styles - FIXME
1268 (setq hfy-user-sheet-assoc nil)
1270 ;; init conten.xml
1271 (with-current-buffer
1272 (find-file-noselect content-file t)
1273 (current-buffer))))
1277 (defun org-e-odt-save-as-outfile (target opt-plist)
1278 ;; write automatic styles
1279 (org-e-odt-write-automatic-styles)
1281 ;; write styles file
1282 ;; (when (equal org-lparse-backend 'odt) FIXME
1283 ;; )
1285 (org-e-odt-update-styles-file opt-plist)
1287 ;; create mimetype file
1288 (let ((mimetype (org-e-odt-write-mimetype-file ;; org-lparse-backend FIXME
1289 'odt)))
1290 (org-e-odt-create-manifest-file-entry mimetype "/" "1.2"))
1292 ;; create a manifest entry for content.xml
1293 (org-e-odt-create-manifest-file-entry "text/xml" "content.xml")
1295 ;; write out the manifest entries before zipping
1296 (org-e-odt-write-manifest-file)
1298 (let ((xml-files '("mimetype" "META-INF/manifest.xml" "content.xml"
1299 "meta.xml"))
1300 (zipdir default-directory))
1301 (when (or t (equal org-lparse-backend 'odt)) ; FIXME
1302 (push "styles.xml" xml-files))
1303 (message "Switching to directory %s" (expand-file-name zipdir))
1305 ;; save all xml files
1306 (mapc (lambda (file)
1307 (with-current-buffer
1308 (find-file-noselect (expand-file-name file) t)
1309 ;; prettify output if needed
1310 (when org-export-e-odt-prettify-xml
1311 (indent-region (point-min) (point-max)))
1312 (save-buffer 0)))
1313 xml-files)
1315 (let* ((target-name (file-name-nondirectory target))
1316 (target-dir (file-name-directory target))
1317 (cmds `(("zip" "-mX0" ,target-name "mimetype")
1318 ("zip" "-rmTq" ,target-name "."))))
1319 (when (file-exists-p target)
1320 ;; FIXME: If the file is locked this throws a cryptic error
1321 (delete-file target))
1323 (let ((coding-system-for-write 'no-conversion) exitcode err-string)
1324 (message "Creating odt file...")
1325 (mapc
1326 (lambda (cmd)
1327 (message "Running %s" (mapconcat 'identity cmd " "))
1328 (setq err-string
1329 (with-output-to-string
1330 (setq exitcode
1331 (apply 'call-process (car cmd)
1332 nil standard-output nil (cdr cmd)))))
1333 (or (zerop exitcode)
1334 (ignore (message "%s" err-string))
1335 (error "Unable to create odt file (%S)" exitcode)))
1336 cmds))
1338 ;; move the file from outdir to target-dir
1339 (rename-file target-name target-dir)
1341 ;; kill all xml buffers
1342 (mapc (lambda (file)
1343 (kill-buffer
1344 (find-file-noselect (expand-file-name file zipdir) t)))
1345 xml-files)
1347 (delete-directory zipdir)))
1348 (message "Created %s" target)
1349 (set-buffer (find-file-noselect target t)))
1352 (defun org-e-odt-create-manifest-file-entry (&rest args)
1353 (push args org-e-odt-manifest-file-entries))
1355 (defun org-e-odt-write-manifest-file ()
1356 (make-directory "META-INF")
1357 (let ((manifest-file (expand-file-name "META-INF/manifest.xml")))
1358 (with-current-buffer
1359 (find-file-noselect manifest-file t)
1360 (insert
1361 "<?xml version=\"1.0\" encoding=\"UTF-8\"?>
1362 <manifest:manifest xmlns:manifest=\"urn:oasis:names:tc:opendocument:xmlns:manifest:1.0\" manifest:version=\"1.2\">\n")
1363 (mapc
1364 (lambda (file-entry)
1365 (let* ((version (nth 2 file-entry))
1366 (extra (if version
1367 (format " manifest:version=\"%s\"" version)
1368 "")))
1369 (insert
1370 (format org-e-odt-manifest-file-entry-tag
1371 (nth 0 file-entry) (nth 1 file-entry) extra))))
1372 org-e-odt-manifest-file-entries)
1373 (insert "\n</manifest:manifest>"))))
1375 (defun org-e-odt-update-meta-file (info) ; FIXME opt-plist
1376 (let ((date (org-e-odt-format-date (plist-get info :date)))
1377 (author (or (plist-get info :author) ""))
1378 (email (plist-get info :email))
1379 (keywords (plist-get info :keywords))
1380 (description (plist-get info :description))
1381 (title (plist-get info :title)))
1382 (write-region
1383 (concat
1384 "<?xml version=\"1.0\" encoding=\"UTF-8\"?>
1385 <office:document-meta
1386 xmlns:office=\"urn:oasis:names:tc:opendocument:xmlns:office:1.0\"
1387 xmlns:xlink=\"http://www.w3.org/1999/xlink\"
1388 xmlns:dc=\"http://purl.org/dc/elements/1.1/\"
1389 xmlns:meta=\"urn:oasis:names:tc:opendocument:xmlns:meta:1.0\"
1390 xmlns:ooo=\"http://openoffice.org/2004/office\"
1391 office:version=\"1.2\">
1392 <office:meta>\n"
1393 (org-e-odt-format-author author) "\n"
1394 (format "<meta:initial-creator>%s</meta:initial-creator>\n" author)
1395 (format "<dc:date>%s</dc:date>\n" date)
1396 (format "<meta:creation-date>%s</meta:creation-date>\n" date)
1397 (format "<meta:generator>%s</meta:generator>\n"
1398 (when org-export-creator-info
1399 (format "Org-%s/Emacs-%s"
1400 org-version emacs-version)))
1401 (format "<meta:keyword>%s</meta:keyword>\n" keywords)
1402 (format "<dc:subject>%s</dc:subject>\n" description)
1403 (format "<dc:title>%s</dc:title>\n" title)
1404 "\n"
1405 " </office:meta>\n" "</office:document-meta>")
1406 nil (expand-file-name "meta.xml")))
1408 ;; create a manifest entry for meta.xml
1409 (org-e-odt-create-manifest-file-entry "text/xml" "meta.xml"))
1411 (defun org-e-odt-update-styles-file (opt-plist)
1412 ;; write styles file
1413 (let ((styles-file (plist-get opt-plist :odt-styles-file)))
1414 (org-e-odt-copy-styles-file (and styles-file
1415 (read (org-trim styles-file)))))
1417 ;; Update styles.xml - take care of outline numbering
1418 (with-current-buffer
1419 (find-file-noselect (expand-file-name "styles.xml") t)
1420 ;; Don't make automatic backup of styles.xml file. This setting
1421 ;; prevents the backed-up styles.xml file from being zipped in to
1422 ;; odt file. This is more of a hackish fix. Better alternative
1423 ;; would be to fix the zip command so that the output odt file
1424 ;; includes only the needed files and excludes any auto-generated
1425 ;; extra files like backups and auto-saves etc etc. Note that
1426 ;; currently the zip command zips up the entire temp directory so
1427 ;; that any auto-generated files created under the hood ends up in
1428 ;; the resulting odt file.
1429 (set (make-local-variable 'backup-inhibited) t)
1431 ;; Import local setting of `org-export-with-section-numbers'
1432 (org-e-odt-configure-outline-numbering
1433 (if org-export-with-section-numbers org-export-headline-levels 0)))
1435 ;; Write custom styles for source blocks
1436 (org-e-odt-insert-custom-styles-for-srcblocks
1437 (mapconcat
1438 (lambda (style)
1439 (format " %s\n" (cddr style)))
1440 hfy-user-sheet-assoc "")))
1442 (defun org-e-odt-write-mimetype-file (format)
1443 ;; create mimetype file
1444 (let ((mimetype
1445 (case format
1446 (odt "application/vnd.oasis.opendocument.text")
1447 (odf "application/vnd.oasis.opendocument.formula")
1448 (t (error "Unknown OpenDocument backend %S" org-lparse-backend)))))
1449 (write-region mimetype nil (expand-file-name "mimetype"))
1450 mimetype))
1452 (defun org-e-odt-finalize-outfile ()
1453 (org-e-odt-delete-empty-paragraphs))
1455 (defun org-e-odt-delete-empty-paragraphs ()
1456 (goto-char (point-min))
1457 (let ((open "<text:p[^>]*>")
1458 (close "</text:p>"))
1459 (while (re-search-forward (format "%s[ \r\n\t]*%s" open close) nil t)
1460 (replace-match ""))))
1462 (declare-function org-create-math-formula "org"
1463 (latex-frag &optional mathml-file))
1465 ;;;###autoload
1466 (defun org-export-e-odt-convert (&optional in-file out-fmt prefix-arg)
1467 "Convert IN-FILE to format OUT-FMT using a command line converter.
1468 IN-FILE is the file to be converted. If unspecified, it defaults
1469 to variable `buffer-file-name'. OUT-FMT is the desired output
1470 format. Use `org-export-e-odt-convert-process' as the converter.
1471 If PREFIX-ARG is non-nil then the newly converted file is opened
1472 using `org-open-file'."
1473 (interactive
1474 (append (org-lparse-convert-read-params) current-prefix-arg))
1475 (org-lparse-do-convert in-file out-fmt prefix-arg))
1477 (defun org-e-odt-get (what &optional opt-plist)
1478 (case what
1479 (BACKEND 'odt)
1480 (EXPORT-DIR (org-export-directory :html opt-plist))
1481 (FILE-NAME-EXTENSION "odt")
1482 (EXPORT-BUFFER-NAME "*Org ODT Export*")
1483 (ENTITY-CONTROL org-e-odt-entity-control-callbacks-alist)
1484 (ENTITY-FORMAT org-e-odt-entity-format-callbacks-alist)
1485 (INIT-METHOD 'org-e-odt-init-outfile)
1486 (FINAL-METHOD 'org-e-odt-finalize-outfile)
1487 (SAVE-METHOD 'org-e-odt-save-as-outfile)
1488 (CONVERT-METHOD
1489 (and org-export-e-odt-convert-process
1490 (cadr (assoc-string org-export-e-odt-convert-process
1491 org-export-e-odt-convert-processes t))))
1492 (CONVERT-CAPABILITIES
1493 (and org-export-e-odt-convert-process
1494 (cadr (assoc-string org-export-e-odt-convert-process
1495 org-export-e-odt-convert-processes t))
1496 org-export-e-odt-convert-capabilities))
1497 (TOPLEVEL-HLEVEL 1)
1498 (SPECIAL-STRING-REGEXPS org-export-e-odt-special-string-regexps)
1499 (INLINE-IMAGES 'maybe)
1500 (INLINE-IMAGE-EXTENSIONS '("png" "jpeg" "jpg" "gif" "svg"))
1501 (PLAIN-TEXT-MAP '(("&" . "&amp;") ("<" . "&lt;") (">" . "&gt;")))
1502 (TABLE-FIRST-COLUMN-AS-LABELS nil)
1503 (FOOTNOTE-SEPARATOR )
1504 (CODING-SYSTEM-FOR-WRITE 'utf-8)
1505 (CODING-SYSTEM-FOR-SAVE 'utf-8)
1506 (t (error "Unknown property: %s" what))))
1508 (defun org-export-e-odt-do-preprocess-latex-fragments ()
1509 "Convert LaTeX fragments to images."
1510 (let* ((latex-frag-opt (plist-get org-lparse-opt-plist :LaTeX-fragments))
1511 (latex-frag-opt ; massage the options
1512 (or (and (member latex-frag-opt '(mathjax t))
1513 (not (and (fboundp 'org-format-latex-mathml-available-p)
1514 (org-format-latex-mathml-available-p)))
1515 (prog1 org-lparse-latex-fragment-fallback
1516 (org-lparse-warn
1517 (concat
1518 "LaTeX to MathML converter not available. "
1519 (format "Using %S instead."
1520 org-lparse-latex-fragment-fallback)))))
1521 latex-frag-opt))
1522 cache-dir display-msg)
1523 (cond
1524 ((eq latex-frag-opt 'dvipng)
1525 (setq cache-dir "ltxpng/")
1526 (setq display-msg "Creating LaTeX image %s"))
1527 ((member latex-frag-opt '(mathjax t))
1528 (setq latex-frag-opt 'mathml)
1529 (setq cache-dir "ltxmathml/")
1530 (setq display-msg "Creating MathML formula %s")))
1531 (when (and org-current-export-file)
1532 (org-format-latex
1533 (concat cache-dir (file-name-sans-extension
1534 (file-name-nondirectory org-current-export-file)))
1535 org-current-export-dir nil display-msg
1536 nil nil latex-frag-opt))))
1538 (defadvice org-format-latex-as-mathml
1539 (after org-e-odt-protect-latex-fragment activate)
1540 "Encode LaTeX fragment as XML.
1541 Do this when translation to MathML fails."
1542 (when (or (not (> (length ad-return-value) 0))
1543 (get-text-property 0 'org-protected ad-return-value))
1544 (setq ad-return-value
1545 (org-propertize (org-e-odt-encode-plain-text (ad-get-arg 0))
1546 'org-protected t))))
1548 (defun org-export-e-odt-preprocess-latex-fragments ()
1549 (when (equal org-export-current-backend 'odt)
1550 (org-export-e-odt-do-preprocess-latex-fragments)))
1552 (defun org-export-e-odt-preprocess-label-references ()
1553 (goto-char (point-min))
1554 (let (label label-components category value pretty-label)
1555 (while (re-search-forward "\\\\ref{\\([^{}\n]+\\)}" nil t)
1556 (org-if-unprotected-at (match-beginning 1)
1557 (replace-match
1558 (let ((org-lparse-encode-pending t)
1559 (label (match-string 1)))
1560 ;; markup generated below is mostly an eye-candy. At
1561 ;; pre-processing stage, there is no information on which
1562 ;; entity a label reference points to. The actual markup
1563 ;; is generated as part of `org-e-odt-fixup-label-references'
1564 ;; which gets called at the fag end of export. By this
1565 ;; time we would have seen and collected all the label
1566 ;; definitions in `org-e-odt-entity-labels-alist'.
1567 (org-e-odt-format-tags
1568 '("<text:sequence-ref text:ref-name=\"%s\">" .
1569 "</text:sequence-ref>")
1570 "" (org-add-props label '(org-protected t)))) t t)))))
1572 ;; process latex fragments as part of
1573 ;; `org-export-preprocess-after-blockquote-hook'. Note that this hook
1574 ;; is the one that is closest and well before the call to
1575 ;; `org-export-attach-captions-and-attributes' in
1576 ;; `org-export-preprocess-string'. The above arrangement permits
1577 ;; captions, labels and attributes to be attached to png images
1578 ;; generated out of latex equations.
1579 (add-hook 'org-export-preprocess-after-blockquote-hook
1580 'org-export-e-odt-preprocess-latex-fragments)
1582 (defun org-export-e-odt-preprocess (parameters)
1583 (org-export-e-odt-preprocess-label-references))
1586 (defun org-e-odt-zip-extract-one (archive member &optional target)
1587 (require 'arc-mode)
1588 (let* ((target (or target default-directory))
1589 (archive (expand-file-name archive))
1590 (archive-zip-extract
1591 (list "unzip" "-qq" "-o" "-d" target))
1592 exit-code command-output)
1593 (setq command-output
1594 (with-temp-buffer
1595 (setq exit-code (archive-zip-extract archive member))
1596 (buffer-string)))
1597 (unless (zerop exit-code)
1598 (message command-output)
1599 (error "Extraction failed"))))
1601 (defun org-e-odt-zip-extract (archive members &optional target)
1602 (when (atom members) (setq members (list members)))
1603 (mapc (lambda (member)
1604 (org-e-odt-zip-extract-one archive member target))
1605 members))
1607 (defun org-e-odt-copy-styles-file (&optional styles-file)
1608 ;; Non-availability of styles.xml is not a critical error. For now
1609 ;; throw an error purely for aesthetic reasons.
1610 (setq styles-file (or styles-file
1611 org-export-e-odt-styles-file
1612 (expand-file-name "OrgOdtStyles.xml"
1613 org-e-odt-styles-dir)
1614 (error "org-e-odt: Missing styles file?")))
1615 (cond
1616 ((listp styles-file)
1617 (let ((archive (nth 0 styles-file))
1618 (members (nth 1 styles-file)))
1619 (org-e-odt-zip-extract archive members)
1620 (mapc
1621 (lambda (member)
1622 (when (org-file-image-p member)
1623 (let* ((image-type (file-name-extension member))
1624 (media-type (format "image/%s" image-type)))
1625 (org-e-odt-create-manifest-file-entry media-type member))))
1626 members)))
1627 ((and (stringp styles-file) (file-exists-p styles-file))
1628 (let ((styles-file-type (file-name-extension styles-file)))
1629 (cond
1630 ((string= styles-file-type "xml")
1631 (copy-file styles-file "styles.xml" t))
1632 ((member styles-file-type '("odt" "ott"))
1633 (org-e-odt-zip-extract styles-file "styles.xml")))))
1635 (error (format "Invalid specification of styles.xml file: %S"
1636 org-export-e-odt-styles-file))))
1638 ;; create a manifest entry for styles.xml
1639 (org-e-odt-create-manifest-file-entry "text/xml" "styles.xml"))
1641 (defun org-e-odt-configure-outline-numbering (level)
1642 "Outline numbering is retained only upto LEVEL.
1643 To disable outline numbering pass a LEVEL of 0."
1644 (goto-char (point-min))
1645 (let ((regex
1646 "<text:outline-level-style\\([^>]*\\)text:level=\"\\([^\"]*\\)\"\\([^>]*\\)>")
1647 (replacement
1648 "<text:outline-level-style\\1text:level=\"\\2\" style:num-format=\"\">"))
1649 (while (re-search-forward regex nil t)
1650 (when (> (string-to-number (match-string 2)) level)
1651 (replace-match replacement t nil))))
1652 (save-buffer 0))
1654 ;;;###autoload
1655 (defun org-export-as-odf (latex-frag &optional odf-file)
1656 "Export LATEX-FRAG as OpenDocument formula file ODF-FILE.
1657 Use `org-create-math-formula' to convert LATEX-FRAG first to
1658 MathML. When invoked as an interactive command, use
1659 `org-latex-regexps' to infer LATEX-FRAG from currently active
1660 region. If no LaTeX fragments are found, prompt for it. Push
1661 MathML source to kill ring, if `org-export-copy-to-kill-ring' is
1662 non-nil."
1663 (interactive
1664 `(,(let (frag)
1665 (setq frag (and (setq frag (and (region-active-p)
1666 (buffer-substring (region-beginning)
1667 (region-end))))
1668 (loop for e in org-latex-regexps
1669 thereis (when (string-match (nth 1 e) frag)
1670 (match-string (nth 2 e) frag)))))
1671 (read-string "LaTeX Fragment: " frag nil frag))
1672 ,(let ((odf-filename (expand-file-name
1673 (concat
1674 (file-name-sans-extension
1675 (or (file-name-nondirectory buffer-file-name)))
1676 "." "odf")
1677 (file-name-directory buffer-file-name))))
1678 (read-file-name "ODF filename: " nil odf-filename nil
1679 (file-name-nondirectory odf-filename)))))
1680 (let* ((org-lparse-backend 'odf)
1681 org-lparse-opt-plist
1682 (filename (or odf-file
1683 (expand-file-name
1684 (concat
1685 (file-name-sans-extension
1686 (or (file-name-nondirectory buffer-file-name)))
1687 "." "odf")
1688 (file-name-directory buffer-file-name))))
1689 (buffer (find-file-noselect (org-e-odt-init-outfile filename)))
1690 (coding-system-for-write 'utf-8)
1691 (save-buffer-coding-system 'utf-8))
1692 (set-buffer buffer)
1693 (set-buffer-file-coding-system coding-system-for-write)
1694 (let ((mathml (org-create-math-formula latex-frag)))
1695 (unless mathml (error "No Math formula created"))
1696 (insert mathml)
1697 (or (org-export-push-to-kill-ring
1698 (upcase (symbol-name org-lparse-backend)))
1699 (message "Exporting... done")))
1700 (org-e-odt-save-as-outfile filename nil ; FIXME
1703 ;;;###autoload
1704 (defun org-export-as-odf-and-open ()
1705 "Export LaTeX fragment as OpenDocument formula and immediately open it.
1706 Use `org-export-as-odf' to read LaTeX fragment and OpenDocument
1707 formula file."
1708 (interactive)
1709 (org-lparse-and-open
1710 nil nil nil (call-interactively 'org-export-as-odf)))
1715 ;;; Driver Starts here
1716 ;;; Dependencies
1718 (require 'format-spec)
1719 (eval-when-compile (require 'cl) (require 'table))
1723 ;;; Hooks
1725 (defvar org-e-odt-after-blockquotes-hook nil
1726 "Hook run during HTML export, after blockquote, verse, center are done.")
1728 (defvar org-e-odt-final-hook nil
1729 "Hook run at the end of HTML export, in the new buffer.")
1731 ;; FIXME: it already exists in org-e-odt.el
1732 ;;; Function Declarations
1734 (declare-function org-element-property "org-element" (property element))
1735 (declare-function org-element-normalize-string "org-element" (s))
1736 (declare-function org-element-parse-secondary-string
1737 "org-element" (string restriction &optional buffer))
1738 (defvar org-element-string-restrictions)
1739 (defvar org-element-object-restrictions)
1741 (declare-function org-export-clean-table "org-export" (table specialp))
1742 (declare-function org-export-data "org-export" (data backend info))
1743 (declare-function org-export-directory "org-export" (type plist))
1744 (declare-function org-export-expand-macro "org-export" (macro info))
1745 (declare-function org-export-first-sibling-p "org-export" (headline info))
1746 (declare-function org-export-footnote-first-reference-p "org-export"
1747 (footnote-reference info))
1748 (declare-function org-export-get-coderef-format "org-export" (path desc))
1749 (declare-function org-export-get-footnote-definition "org-export"
1750 (footnote-reference info))
1751 (declare-function org-export-get-footnote-number "org-export" (footnote info))
1752 (declare-function org-export-get-previous-element "org-export" (blob info))
1753 (declare-function org-export-get-relative-level "org-export" (headline info))
1754 (declare-function org-export-handle-code
1755 "org-export" (element info &optional num-fmt ref-fmt delayed))
1756 (declare-function org-export-included-file "org-export" (keyword backend info))
1757 (declare-function org-export-inline-image-p "org-export"
1758 (link &optional extensions))
1759 (declare-function org-export-last-sibling-p "org-export" (headline info))
1760 (declare-function org-export-low-level-p "org-export" (headline info))
1761 (declare-function org-export-output-file-name
1762 "org-export" (extension &optional subtreep pub-dir))
1763 (declare-function org-export-resolve-coderef "org-export" (ref info))
1764 (declare-function org-export-resolve-fuzzy-link "org-export" (link info))
1765 (declare-function org-export-secondary-string "org-export"
1766 (secondary backend info))
1767 (declare-function org-export-solidify-link-text "org-export" (s))
1768 (declare-function org-export-table-format-info "org-export" (table))
1769 (declare-function
1770 org-export-to-buffer "org-export"
1771 (backend buffer &optional subtreep visible-only body-only ext-plist))
1772 (declare-function
1773 org-export-to-file "org-export"
1774 (backend file &optional subtreep visible-only body-only ext-plist))
1776 (declare-function org-id-find-id-file "org-id" (id))
1777 (declare-function htmlize-region "ext:htmlize" (beg end))
1778 (declare-function org-pop-to-buffer-same-window
1779 "org-compat" (&optional buffer-or-name norecord label))
1785 (declare-function hfy-face-to-style "htmlfontify" (fn))
1786 (declare-function hfy-face-or-def-to-name "htmlfontify" (fn))
1787 (declare-function archive-zip-extract "arc-mode.el" (archive name))
1789 ;;; Internal Variables
1791 ;;;; ODT Internal Variables
1793 (defconst org-e-odt-lib-dir
1794 (file-name-directory load-file-name)
1795 "Location of ODT exporter.
1796 Use this to infer values of `org-e-odt-styles-dir' and
1797 `org-export-e-odt-schema-dir'.")
1799 (defvar org-e-odt-data-dir
1800 (expand-file-name "../etc/" org-e-odt-lib-dir)
1801 "Data directory for ODT exporter.
1802 Use this to infer values of `org-e-odt-styles-dir' and
1803 `org-export-e-odt-schema-dir'.")
1808 (defconst org-export-e-odt-special-string-regexps
1809 '(("\\\\-" . "&#x00ad;\\1") ; shy
1810 ("---\\([^-]\\)" . "&#x2014;\\1") ; mdash
1811 ("--\\([^-]\\)" . "&#x2013;\\1") ; ndash
1812 ("\\.\\.\\." . "&#x2026;")) ; hellip
1813 "Regular expressions for special string conversion.")
1815 (defconst org-e-odt-schema-dir-list
1816 (list
1817 (and org-e-odt-data-dir
1818 (expand-file-name "./schema/" org-e-odt-data-dir)) ; bail out
1819 (eval-when-compile
1820 (and (boundp 'org-e-odt-data-dir) org-e-odt-data-dir ; see make install
1821 (expand-file-name "./schema/" org-e-odt-data-dir)))
1822 (expand-file-name "../contrib/odt/etc/schema/" org-e-odt-lib-dir) ; git
1824 "List of directories to search for OpenDocument schema files.
1825 Use this list to set the default value of
1826 `org-export-e-odt-schema-dir'. The entries in this list are
1827 populated heuristically based on the values of `org-e-odt-lib-dir'
1828 and `org-e-odt-data-dir'.")
1831 (defconst org-e-odt-styles-dir-list
1832 (list
1833 (and org-e-odt-data-dir
1834 (expand-file-name "./styles/" org-e-odt-data-dir)) ; bail out
1835 (eval-when-compile
1836 (and (boundp 'org-e-odt-data-dir) org-e-odt-data-dir ; see make install
1837 (expand-file-name "./styles/" org-e-odt-data-dir)))
1838 (expand-file-name "../etc/styles/" org-e-odt-lib-dir) ; git
1839 (expand-file-name "./etc/styles/" org-e-odt-lib-dir) ; elpa
1840 (expand-file-name "./org/" data-directory) ; system
1842 "List of directories to search for OpenDocument styles files.
1843 See `org-e-odt-styles-dir'. The entries in this list are populated
1844 heuristically based on the values of `org-e-odt-lib-dir' and
1845 `org-e-odt-data-dir'.")
1847 (defconst org-e-odt-styles-dir
1848 (let* ((styles-dir
1849 (catch 'styles-dir
1850 (message "Debug (org-e-odt): Searching for OpenDocument styles files...")
1851 (mapc (lambda (styles-dir)
1852 (when styles-dir
1853 (message "Debug (org-e-odt): Trying %s..." styles-dir)
1854 (when (and (file-readable-p
1855 (expand-file-name
1856 "OrgOdtContentTemplate.xml" styles-dir))
1857 (file-readable-p
1858 (expand-file-name
1859 "OrgOdtStyles.xml" styles-dir)))
1860 (message "Debug (org-e-odt): Using styles under %s"
1861 styles-dir)
1862 (throw 'styles-dir styles-dir))))
1863 org-e-odt-styles-dir-list)
1864 nil)))
1865 (unless styles-dir
1866 (error "Error (org-e-odt): Cannot find factory styles files. Aborting."))
1867 styles-dir)
1868 "Directory that holds auxiliary XML files used by the ODT exporter.
1870 This directory contains the following XML files -
1871 \"OrgOdtStyles.xml\" and \"OrgOdtContentTemplate.xml\". These
1872 XML files are used as the default values of
1873 `org-export-e-odt-styles-file' and
1874 `org-export-e-odt-content-template-file'.
1876 The default value of this variable varies depending on the
1877 version of org in use and is initialized from
1878 `org-e-odt-styles-dir-list'. Note that the user could be using org
1879 from one of: org's own private git repository, GNU ELPA tar or
1880 standard Emacs.")
1882 (defconst org-export-e-odt-tmpdir-prefix "%s-")
1883 (defconst org-export-e-odt-bookmark-prefix "OrgXref.")
1885 (defconst org-e-odt-manifest-file-entry-tag
1887 <manifest:file-entry manifest:media-type=\"%s\" manifest:full-path=\"%s\"%s/>")
1891 (defvar org-lparse-dyn-first-heading-pos) ; let bound during org-do-lparse
1893 (defvar org-e-odt-suppress-xref nil)
1894 (defvar org-e-odt-file-extensions
1895 '(("odt" . "OpenDocument Text")
1896 ("ott" . "OpenDocument Text Template")
1897 ("odm" . "OpenDocument Master Document")
1898 ("ods" . "OpenDocument Spreadsheet")
1899 ("ots" . "OpenDocument Spreadsheet Template")
1900 ("odg" . "OpenDocument Drawing (Graphics)")
1901 ("otg" . "OpenDocument Drawing Template")
1902 ("odp" . "OpenDocument Presentation")
1903 ("otp" . "OpenDocument Presentation Template")
1904 ("odi" . "OpenDocument Image")
1905 ("odf" . "OpenDocument Formula")
1906 ("odc" . "OpenDocument Chart")))
1908 (defvar org-export-e-odt-embed-images t
1909 "Should the images be copied in to the odt file or just linked?")
1911 (defvar org-export-e-odt-inline-images 'maybe)
1912 (defvar org-export-e-odt-default-org-styles-alist
1913 '((paragraph . ((default . "Text_20_body")
1914 (fixedwidth . "OrgFixedWidthBlock")
1915 (verse . "OrgVerse")
1916 (quote . "Quotations")
1917 (blockquote . "Quotations")
1918 (center . "OrgCenter")
1919 (left . "OrgLeft")
1920 (right . "OrgRight")
1921 (title . "OrgTitle")
1922 (subtitle . "OrgSubtitle")
1923 (footnote . "Footnote")
1924 (src . "OrgSrcBlock")
1925 (illustration . "Illustration")
1926 (table . "Table")
1927 (definition-term . "Text_20_body_20_bold")
1928 (horizontal-line . "Horizontal_20_Line")))
1929 (character . ((bold . "Bold")
1930 (emphasis . "Emphasis")
1931 (code . "OrgCode")
1932 (verbatim . "OrgCode")
1933 (strike . "Strikethrough")
1934 (underline . "Underline")
1935 (subscript . "OrgSubscript")
1936 (superscript . "OrgSuperscript")))
1937 (list . ((ordered . "OrgNumberedList")
1938 (unordered . "OrgBulletedList")
1939 (descriptive . "OrgDescriptionList"))))
1940 "Default styles for various entities.")
1942 (defvar org-export-e-odt-org-styles-alist org-export-e-odt-default-org-styles-alist)
1944 ;;;_. callbacks
1945 ;;;_. control callbacks
1946 ;;;_ , document body
1948 (defvar org-lparse-body-only) ; let bound during org-do-lparse
1949 (defvar org-lparse-opt-plist) ; bound during org-do-lparse
1950 (defvar org-lparse-list-stack) ; dynamically bound in org-do-lparse
1951 (defvar org-e-odt-list-stack-stashed)
1952 (defvar org-lparse-table-ncols)
1953 (defvar org-e-odt-table-rowgrp-open)
1954 (defvar org-e-odt-table-rownum)
1955 (defvar org-e-odt-table-cur-rowgrp-is-hdr)
1956 (defvar org-lparse-table-is-styled)
1957 (defvar org-lparse-table-rowgrp-info)
1958 (defvar org-lparse-table-colalign-vector)
1960 (defvar org-e-odt-table-style nil
1961 "Table style specified by \"#+ATTR_ODT: <style-name>\" line.
1962 This is set during `org-e-odt-begin-table'.")
1964 (defvar org-e-odt-table-style-spec nil
1965 "Entry for `org-e-odt-table-style' in `org-export-e-odt-table-styles'.")
1968 (defvar org-e-odt-table-style-format
1970 <style:style style:name=\"%s\" style:family=\"table\">
1971 <style:table-properties style:rel-width=\"%d%%\" fo:margin-top=\"0cm\" fo:margin-bottom=\"0.20cm\" table:align=\"center\"/>
1972 </style:style>
1974 "Template for auto-generated Table styles.")
1976 (defvar org-e-odt-automatic-styles '()
1977 "Registry of automatic styles for various OBJECT-TYPEs.
1978 The variable has the following form:
1979 \(\(OBJECT-TYPE-A
1980 \(\(OBJECT-NAME-A.1 OBJECT-PROPS-A.1\)
1981 \(OBJECT-NAME-A.2 OBJECT-PROPS-A.2\) ...\)\)
1982 \(OBJECT-TYPE-B
1983 \(\(OBJECT-NAME-B.1 OBJECT-PROPS-B.1\)
1984 \(OBJECT-NAME-B.2 OBJECT-PROPS-B.2\) ...\)\)
1985 ...\).
1987 OBJECT-TYPEs could be \"Section\", \"Table\", \"Figure\" etc.
1988 OBJECT-PROPS is (typically) a plist created by passing
1989 \"#+ATTR_ODT: \" option to `org-lparse-get-block-params'.
1991 Use `org-e-odt-add-automatic-style' to add update this variable.'")
1993 (defvar org-e-odt-object-counters nil
1994 "Running counters for various OBJECT-TYPEs.
1995 Use this to generate automatic names and style-names. See
1996 `org-e-odt-add-automatic-style'.")
1998 (defvar org-e-odt-table-indentedp nil)
1999 (defvar org-lparse-table-colalign-info)
2000 (defvar org-lparse-link-description-is-image nil)
2003 (defvar org-src-block-paragraph-format
2004 "<style:style style:name=\"OrgSrcBlock\" style:family=\"paragraph\" style:parent-style-name=\"Preformatted_20_Text\">
2005 <style:paragraph-properties fo:background-color=\"%s\" fo:padding=\"0.049cm\" fo:border=\"0.51pt solid #000000\" style:shadow=\"none\">
2006 <style:background-image/>
2007 </style:paragraph-properties>
2008 <style:text-properties fo:color=\"%s\"/>
2009 </style:style>"
2010 "Custom paragraph style for colorized source and example blocks.
2011 This style is much the same as that of \"OrgFixedWidthBlock\"
2012 except that the foreground and background colors are set
2013 according to the default face identified by the `htmlfontify'.")
2015 (defvar hfy-optimisations)
2016 (defvar org-e-odt-embedded-formulas-count 0)
2017 (defvar org-e-odt-entity-frame-styles
2018 '(("As-CharImage" "__Figure__" ("OrgInlineImage" nil "as-char"))
2019 ("ParagraphImage" "__Figure__" ("OrgDisplayImage" nil "paragraph"))
2020 ("PageImage" "__Figure__" ("OrgPageImage" nil "page"))
2021 ("CaptionedAs-CharImage" "__Figure__"
2022 ("OrgCaptionedImage"
2023 " style:rel-width=\"100%\" style:rel-height=\"scale\"" "paragraph")
2024 ("OrgInlineImage" nil "as-char"))
2025 ("CaptionedParagraphImage" "__Figure__"
2026 ("OrgCaptionedImage"
2027 " style:rel-width=\"100%\" style:rel-height=\"scale\"" "paragraph")
2028 ("OrgImageCaptionFrame" nil "paragraph"))
2029 ("CaptionedPageImage" "__Figure__"
2030 ("OrgCaptionedImage"
2031 " style:rel-width=\"100%\" style:rel-height=\"scale\"" "paragraph")
2032 ("OrgPageImageCaptionFrame" nil "page"))
2033 ("InlineFormula" "__MathFormula__" ("OrgInlineFormula" nil "as-char"))
2034 ("DisplayFormula" "__MathFormula__" ("OrgDisplayFormula" nil "as-char"))
2035 ("CaptionedDisplayFormula" "__MathFormula__"
2036 ("OrgCaptionedFormula" nil "paragraph")
2037 ("OrgFormulaCaptionFrame" nil "as-char"))))
2039 (defvar org-e-odt-embedded-images-count 0)
2041 (defvar org-export-e-odt-image-size-probe-method
2042 (append (and (executable-find "identify") '(imagemagick)) ; See Bug#10675
2043 '(emacs fixed))
2044 "Ordered list of methods for determining image sizes.")
2046 (defvar org-export-e-odt-default-image-sizes-alist
2047 '(("as-char" . (5 . 0.4))
2048 ("paragraph" . (5 . 5)))
2049 "Hardcoded image dimensions one for each of the anchor
2050 methods.")
2052 ;; A4 page size is 21.0 by 29.7 cms
2053 ;; The default page settings has 2cm margin on each of the sides. So
2054 ;; the effective text area is 17.0 by 25.7 cm
2055 (defvar org-export-e-odt-max-image-size '(17.0 . 20.0)
2056 "Limiting dimensions for an embedded image.")
2058 (defvar org-e-odt-entity-labels-alist nil
2059 "Associate Labels with the Labeled entities.
2060 Each element of the alist is of the form (LABEL-NAME
2061 CATEGORY-NAME SEQNO LABEL-STYLE-NAME). LABEL-NAME is same as
2062 that specified by \"#+LABEL: ...\" line. CATEGORY-NAME is the
2063 type of the entity that LABEL-NAME is attached to. CATEGORY-NAME
2064 can be one of \"Table\", \"Figure\" or \"Equation\". SEQNO is
2065 the unique number assigned to the referenced entity on a
2066 per-CATEGORY basis. It is generated sequentially and is 1-based.
2067 LABEL-STYLE-NAME is a key `org-e-odt-label-styles'.
2069 See `org-e-odt-add-label-definition' and
2070 `org-e-odt-fixup-label-references'.")
2072 (defvar org-e-odt-entity-counts-plist nil
2073 "Plist of running counters of SEQNOs for each of the CATEGORY-NAMEs.
2074 See `org-e-odt-entity-labels-alist' for known CATEGORY-NAMEs.")
2076 (defvar org-e-odt-label-styles
2077 '(("text" "(%n)" "text" "(%n)")
2078 ("category-and-value" "%e %n%c" "category-and-value" "%e %n")
2079 ("value" "%e %n%c" "value" "%n"))
2080 "Specify how labels are applied and referenced.
2081 This is an alist where each element is of the
2082 form (LABEL-STYLE-NAME LABEL-ATTACH-FMT LABEL-REF-MODE
2083 LABEL-REF-FMT).
2085 LABEL-ATTACH-FMT controls how labels and captions are attached to
2086 an entity. It may contain following specifiers - %e, %n and %c.
2087 %e is replaced with the CATEGORY-NAME. %n is replaced with
2088 \"<text:sequence ...> SEQNO </text:sequence>\". %c is replaced
2089 with CAPTION. See `org-e-odt-format-label-definition'.
2091 LABEL-REF-MODE and LABEL-REF-FMT controls how label references
2092 are generated. The following XML is generated for a label
2093 reference - \"<text:sequence-ref
2094 text:reference-format=\"LABEL-REF-MODE\" ...> LABEL-REF-FMT
2095 </text:sequence-ref>\". LABEL-REF-FMT may contain following
2096 specifiers - %e and %n. %e is replaced with the CATEGORY-NAME.
2097 %n is replaced with SEQNO. See
2098 `org-e-odt-format-label-reference'.")
2100 (defvar org-e-odt-category-map-alist
2101 '(("__Table__" "Table" "value")
2102 ("__Figure__" "Figure" "value")
2103 ("__MathFormula__" "Equation" "text")
2104 ("__DvipngImage__" "Equation" "value")
2105 ;; ("__Table__" "Table" "category-and-value")
2106 ;; ("__Figure__" "Figure" "category-and-value")
2107 ;; ("__DvipngImage__" "Equation" "category-and-value")
2109 "Map a CATEGORY-HANDLE to CATEGORY-NAME and LABEL-STYLE.
2110 This is an alist where each element is of the form
2111 \\(CATEGORY-HANDLE CATEGORY-NAME LABEL-STYLE\\). CATEGORY_HANDLE
2112 could either be one of the internal handles (as seen above) or be
2113 derived from the \"#+LABEL:<label-name>\" specification. See
2114 `org-export-e-odt-get-category-from-label'. CATEGORY-NAME and
2115 LABEL-STYLE are used for generating ODT labels. See
2116 `org-e-odt-label-styles'.")
2118 (defvar org-export-e-odt-user-categories
2119 '("Illustration" "Table" "Text" "Drawing" "Equation" "Figure"))
2121 (defvar org-export-e-odt-get-category-from-label nil
2122 "Should category of label be inferred from label itself.
2123 When this option is non-nil, a label is parsed in to two
2124 component parts delimited by a \":\" (colon) as shown here -
2125 #+LABEL:[CATEGORY-HANDLE:]EXTRA. The CATEGORY-HANDLE is mapped
2126 to a CATEGORY-NAME and LABEL-STYLE using
2127 `org-e-odt-category-map-alist'. (If no such map is provided and
2128 CATEGORY-NAME is set to CATEGORY-HANDLE and LABEL-STYLE is set to
2129 \"category-and-value\"). If CATEGORY-NAME so obtained is listed
2130 under `org-export-e-odt-user-categories' then the user specified
2131 styles are used. Otherwise styles as determined by the internal
2132 CATEGORY-HANDLE is used. See
2133 `org-e-odt-get-label-category-and-style' for details.")
2135 (defvar org-e-odt-manifest-file-entries nil)
2136 (defvar hfy-user-sheet-assoc) ; bound during org-do-lparse
2137 (defvar org-lparse-latex-fragment-fallback) ; set by org-do-lparse
2140 ;;;; HTML Internal Variables
2142 (defvar org-e-odt-option-alist
2144 ;; (:agenda-style nil nil org-agenda-export-html-style)
2145 ;; (:convert-org-links nil nil org-e-odt-link-org-files-as-html)
2146 ;; ;; FIXME Use (org-xml-encode-org-text-skip-links s) ??
2147 ;; ;; (:expand-quoted-html nil "@" org-e-odt-expand)
2148 ;; (:inline-images nil nil org-e-odt-inline-images)
2149 ;; ;; (:link-home nil nil org-e-odt-link-home) FIXME
2150 ;; ;; (:link-up nil nil org-e-odt-link-up) FIXME
2151 ;; (:style nil nil org-e-odt-style)
2152 ;; (:style-extra nil nil org-e-odt-style-extra)
2153 ;; (:style-include-default nil nil org-e-odt-style-include-default)
2154 ;; (:style-include-scripts nil nil org-e-odt-style-include-scripts)
2155 ;; ;; (:timestamp nil nil org-e-odt-with-timestamp)
2156 ;; (:html-extension nil nil org-e-odt-extension)
2157 ;; (:html-postamble nil nil org-e-odt-postamble)
2158 ;; (:html-preamble nil nil org-e-odt-preamble)
2159 ;; (:html-table-tag nil nil org-e-odt-table-tag)
2160 ;; (:xml-declaration nil nil org-e-odt-xml-declaration)
2161 (:LaTeX-fragments nil "LaTeX" org-export-with-LaTeX-fragments))
2162 "Alist between export properties and ways to set them.
2164 The car of the alist is the property name, and the cdr is a list
2165 like \(KEYWORD OPTION DEFAULT BEHAVIOUR\) where:
2167 KEYWORD is a string representing a buffer keyword, or nil.
2168 OPTION is a string that could be found in an #+OPTIONS: line.
2169 DEFAULT is the default value for the property.
2170 BEHAVIOUR determine how Org should handle multiple keywords for
2171 the same property. It is a symbol among:
2172 nil Keep old value and discard the new one.
2173 t Replace old value with the new one.
2174 `space' Concatenate the values, separating them with a space.
2175 `newline' Concatenate the values, separating them with
2176 a newline.
2177 `split' Split values at white spaces, and cons them to the
2178 previous list.
2180 KEYWORD and OPTION have precedence over DEFAULT.
2182 All these properties should be back-end agnostic. For back-end
2183 specific properties, define a similar variable named
2184 `org-BACKEND-option-alist', replacing BACKEND with the name of
2185 the appropriate back-end. You can also redefine properties
2186 there, as they have precedence over these.")
2188 (defvar html-table-tag nil) ; dynamically scoped into this.
2190 ;; FIXME: it already exists in org-e-odt.el
2191 (defconst org-e-odt-cvt-link-fn
2193 "Function to convert link URLs to exportable URLs.
2194 Takes two arguments, TYPE and PATH.
2195 Returns exportable url as (TYPE PATH), or nil to signal that it
2196 didn't handle this case.
2197 Intended to be locally bound around a call to `org-export-as-html'." )
2202 (defvar org-e-odt-format-table-no-css)
2203 (defvar htmlize-buffer-places) ; from htmlize.el
2204 (defvar body-only) ; dynamically scoped into this.
2206 (defvar org-e-odt-table-rowgrp-open)
2207 (defvar org-e-odt-table-rownum)
2208 (defvar org-e-odt-table-cur-rowgrp-is-hdr)
2209 (defvar org-lparse-table-is-styled)
2212 (defvar org-e-odt-headline-formatter
2213 (lambda (level snumber todo todo-type priority
2214 title tags target extra-targets extra-class)
2215 (concat snumber " " title)))
2219 ;;; User Configuration Variables
2221 (defgroup org-export-e-odt nil
2222 "Options for exporting Org mode files to HTML."
2223 :tag "Org Export HTML"
2224 :group 'org-export)
2226 (defcustom org-e-odt-protect-char-alist
2227 '(("&" . "&amp;")
2228 ("<" . "&lt;")
2229 (">" . "&gt;"))
2230 "Alist of characters to be converted by `org-e-html-protect'."
2231 :group 'org-export-e-html
2232 :type '(repeat (cons (string :tag "Character")
2233 (string :tag "ODT equivalent"))))
2234 (defcustom org-export-e-odt-schema-dir
2235 (let* ((schema-dir
2236 (catch 'schema-dir
2237 (message "Debug (org-e-odt): Searching for OpenDocument schema files...")
2238 (mapc
2239 (lambda (schema-dir)
2240 (when schema-dir
2241 (message "Debug (org-e-odt): Trying %s..." schema-dir)
2242 (when (and (file-readable-p
2243 (expand-file-name "od-manifest-schema-v1.2-cs01.rnc"
2244 schema-dir))
2245 (file-readable-p
2246 (expand-file-name "od-schema-v1.2-cs01.rnc"
2247 schema-dir))
2248 (file-readable-p
2249 (expand-file-name "schemas.xml" schema-dir)))
2250 (message "Debug (org-e-odt): Using schema files under %s"
2251 schema-dir)
2252 (throw 'schema-dir schema-dir))))
2253 org-e-odt-schema-dir-list)
2254 (message "Debug (org-e-odt): No OpenDocument schema files installed")
2255 nil)))
2256 schema-dir)
2257 "Directory that contains OpenDocument schema files.
2259 This directory contains:
2260 1. rnc files for OpenDocument schema
2261 2. a \"schemas.xml\" file that specifies locating rules needed
2262 for auto validation of OpenDocument XML files.
2264 Use the customize interface to set this variable. This ensures
2265 that `rng-schema-locating-files' is updated and auto-validation
2266 of OpenDocument XML takes place based on the value
2267 `rng-nxml-auto-validate-flag'.
2269 The default value of this variable varies depending on the
2270 version of org in use and is initialized from
2271 `org-e-odt-schema-dir-list'. The OASIS schema files are available
2272 only in the org's private git repository. It is *not* bundled
2273 with GNU ELPA tar or standard Emacs distribution."
2274 :type '(choice
2275 (const :tag "Not set" nil)
2276 (directory :tag "Schema directory"))
2277 :group 'org-export-e-odt
2278 :version "24.1"
2279 :set
2280 (lambda (var value)
2281 "Set `org-export-e-odt-schema-dir'.
2282 Also add it to `rng-schema-locating-files'."
2283 (let ((schema-dir value))
2284 (set var
2285 (if (and
2286 (file-readable-p
2287 (expand-file-name "od-manifest-schema-v1.2-cs01.rnc" schema-dir))
2288 (file-readable-p
2289 (expand-file-name "od-schema-v1.2-cs01.rnc" schema-dir))
2290 (file-readable-p
2291 (expand-file-name "schemas.xml" schema-dir)))
2292 schema-dir
2293 (when value
2294 (message "Error (org-e-odt): %s has no OpenDocument schema files"
2295 value))
2296 nil)))
2297 (when org-export-e-odt-schema-dir
2298 (eval-after-load 'rng-loc
2299 '(add-to-list 'rng-schema-locating-files
2300 (expand-file-name "schemas.xml"
2301 org-export-e-odt-schema-dir))))))
2303 (defcustom org-export-e-odt-content-template-file nil
2304 "Template file for \"content.xml\".
2305 The exporter embeds the exported content just before
2306 \"</office:text>\" element.
2308 If unspecified, the file named \"OrgOdtContentTemplate.xml\"
2309 under `org-e-odt-styles-dir' is used."
2310 :type 'file
2311 :group 'org-export-e-odt
2312 :version "24.1")
2314 (defcustom org-export-e-odt-styles-file nil
2315 "Default styles file for use with ODT export.
2316 Valid values are one of:
2317 1. nil
2318 2. path to a styles.xml file
2319 3. path to a *.odt or a *.ott file
2320 4. list of the form (ODT-OR-OTT-FILE (FILE-MEMBER-1 FILE-MEMBER-2
2321 ...))
2323 In case of option 1, an in-built styles.xml is used. See
2324 `org-e-odt-styles-dir' for more information.
2326 In case of option 3, the specified file is unzipped and the
2327 styles.xml embedded therein is used.
2329 In case of option 4, the specified ODT-OR-OTT-FILE is unzipped
2330 and FILE-MEMBER-1, FILE-MEMBER-2 etc are copied in to the
2331 generated odt file. Use relative path for specifying the
2332 FILE-MEMBERS. styles.xml must be specified as one of the
2333 FILE-MEMBERS.
2335 Use options 1, 2 or 3 only if styles.xml alone suffices for
2336 achieving the desired formatting. Use option 4, if the styles.xml
2337 references additional files like header and footer images for
2338 achieving the desired formatting.
2340 Use \"#+ODT_STYLES_FILE: ...\" directive to set this variable on
2341 a per-file basis. For example,
2343 #+ODT_STYLES_FILE: \"/path/to/styles.xml\" or
2344 #+ODT_STYLES_FILE: (\"/path/to/file.ott\" (\"styles.xml\" \"image/hdr.png\"))."
2345 :group 'org-export-e-odt
2346 :version "24.1"
2347 :type
2348 '(choice
2349 (const :tag "Factory settings" nil)
2350 (file :must-match t :tag "styles.xml")
2351 (file :must-match t :tag "ODT or OTT file")
2352 (list :tag "ODT or OTT file + Members"
2353 (file :must-match t :tag "ODF Text or Text Template file")
2354 (cons :tag "Members"
2355 (file :tag " Member" "styles.xml")
2356 (repeat (file :tag "Member"))))))
2359 (defcustom org-export-e-odt-inline-image-extensions
2360 '("png" "jpeg" "jpg" "gif")
2361 "Extensions of image files that can be inlined into HTML."
2362 :type '(repeat (string :tag "Extension"))
2363 :group 'org-export-e-odt
2364 :version "24.1")
2366 (defcustom org-export-e-odt-pixels-per-inch display-pixels-per-inch
2367 "Scaling factor for converting images pixels to inches.
2368 Use this for sizing of embedded images. See Info node `(org)
2369 Images in ODT export' for more information."
2370 :type 'float
2371 :group 'org-export-e-odt
2372 :version "24.1")
2374 (defcustom org-export-e-odt-create-custom-styles-for-srcblocks t
2375 "Whether custom styles for colorized source blocks be automatically created.
2376 When this option is turned on, the exporter creates custom styles
2377 for source blocks based on the advice of `htmlfontify'. Creation
2378 of custom styles happen as part of `org-e-odt-hfy-face-to-css'.
2380 When this option is turned off exporter does not create such
2381 styles.
2383 Use the latter option if you do not want the custom styles to be
2384 based on your current display settings. It is necessary that the
2385 styles.xml already contains needed styles for colorizing to work.
2387 This variable is effective only if
2388 `org-export-e-odt-fontify-srcblocks' is turned on."
2389 :group 'org-export-e-odt
2390 :version "24.1"
2391 :type 'boolean)
2393 (defcustom org-export-e-odt-preferred-output-format nil
2394 "Automatically post-process to this format after exporting to \"odt\".
2395 Interactive commands `org-export-as-e-odt' and
2396 `org-export-as-e-odt-and-open' export first to \"odt\" format and
2397 then use `org-export-e-odt-convert-process' to convert the
2398 resulting document to this format. During customization of this
2399 variable, the list of valid values are populated based on
2400 `org-export-e-odt-convert-capabilities'."
2401 :group 'org-export-e-odt
2402 :version "24.1"
2403 :type '(choice :convert-widget
2404 (lambda (w)
2405 (apply 'widget-convert (widget-type w)
2406 (eval (car (widget-get w :args)))))
2407 `((const :tag "None" nil)
2408 ,@(mapcar (lambda (c)
2409 `(const :tag ,c ,c))
2410 (org-lparse-reachable-formats "odt")))))
2412 (defcustom org-export-e-odt-table-styles
2413 '(("OrgEquation" "OrgEquation"
2414 ((use-first-column-styles . t)
2415 (use-last-column-styles . t))))
2416 "Specify how Table Styles should be derived from a Table Template.
2417 This is a list where each element is of the
2418 form (TABLE-STYLE-NAME TABLE-TEMPLATE-NAME TABLE-CELL-OPTIONS).
2420 TABLE-STYLE-NAME is the style associated with the table through
2421 `org-e-odt-table-style'.
2423 TABLE-TEMPLATE-NAME is a set of - upto 9 - automatic
2424 TABLE-CELL-STYLE-NAMEs and PARAGRAPH-STYLE-NAMEs (as defined
2425 below) that is included in
2426 `org-export-e-odt-content-template-file'.
2428 TABLE-CELL-STYLE-NAME := TABLE-TEMPLATE-NAME + TABLE-CELL-TYPE +
2429 \"TableCell\"
2430 PARAGRAPH-STYLE-NAME := TABLE-TEMPLATE-NAME + TABLE-CELL-TYPE +
2431 \"TableParagraph\"
2432 TABLE-CELL-TYPE := \"FirstRow\" | \"LastColumn\" |
2433 \"FirstRow\" | \"LastRow\" |
2434 \"EvenRow\" | \"OddRow\" |
2435 \"EvenColumn\" | \"OddColumn\" | \"\"
2436 where \"+\" above denotes string concatenation.
2438 TABLE-CELL-OPTIONS is an alist where each element is of the
2439 form (TABLE-CELL-STYLE-SELECTOR . ON-OR-OFF).
2440 TABLE-CELL-STYLE-SELECTOR := `use-first-row-styles' |
2441 `use-last-row-styles' |
2442 `use-first-column-styles' |
2443 `use-last-column-styles' |
2444 `use-banding-rows-styles' |
2445 `use-banding-columns-styles' |
2446 `use-first-row-styles'
2447 ON-OR-OFF := `t' | `nil'
2449 For example, with the following configuration
2451 \(setq org-export-e-odt-table-styles
2452 '\(\(\"TableWithHeaderRowsAndColumns\" \"Custom\"
2453 \(\(use-first-row-styles . t\)
2454 \(use-first-column-styles . t\)\)\)
2455 \(\"TableWithHeaderColumns\" \"Custom\"
2456 \(\(use-first-column-styles . t\)\)\)\)\)
2458 1. A table associated with \"TableWithHeaderRowsAndColumns\"
2459 style will use the following table-cell styles -
2460 \"CustomFirstRowTableCell\", \"CustomFirstColumnTableCell\",
2461 \"CustomTableCell\" and the following paragraph styles
2462 \"CustomFirstRowTableParagraph\",
2463 \"CustomFirstColumnTableParagraph\", \"CustomTableParagraph\"
2464 as appropriate.
2466 2. A table associated with \"TableWithHeaderColumns\" style will
2467 use the following table-cell styles -
2468 \"CustomFirstColumnTableCell\", \"CustomTableCell\" and the
2469 following paragraph styles
2470 \"CustomFirstColumnTableParagraph\", \"CustomTableParagraph\"
2471 as appropriate..
2473 Note that TABLE-TEMPLATE-NAME corresponds to the
2474 \"<table:table-template>\" elements contained within
2475 \"<office:styles>\". The entries (TABLE-STYLE-NAME
2476 TABLE-TEMPLATE-NAME TABLE-CELL-OPTIONS) correspond to
2477 \"table:template-name\" and \"table:use-first-row-styles\" etc
2478 attributes of \"<table:table>\" element. Refer ODF-1.2
2479 specification for more information. Also consult the
2480 implementation filed under `org-e-odt-get-table-cell-styles'.
2482 The TABLE-STYLE-NAME \"OrgEquation\" is used internally for
2483 formatting of numbered display equations. Do not delete this
2484 style from the list."
2485 :group 'org-export-e-odt
2486 :version "24.1"
2487 :type '(choice
2488 (const :tag "None" nil)
2489 (repeat :tag "Table Styles"
2490 (list :tag "Table Style Specification"
2491 (string :tag "Table Style Name")
2492 (string :tag "Table Template Name")
2493 (alist :options (use-first-row-styles
2494 use-last-row-styles
2495 use-first-column-styles
2496 use-last-column-styles
2497 use-banding-rows-styles
2498 use-banding-columns-styles)
2499 :key-type symbol
2500 :value-type (const :tag "True" t))))))
2501 (defcustom org-export-e-odt-fontify-srcblocks t
2502 "Specify whether or not source blocks need to be fontified.
2503 Turn this option on if you want to colorize the source code
2504 blocks in the exported file. For colorization to work, you need
2505 to make available an enhanced version of `htmlfontify' library."
2506 :type 'boolean
2507 :group 'org-export-e-odt
2508 :version "24.1")
2510 (defcustom org-export-e-odt-prettify-xml t ; FIXME
2511 "Specify whether or not the xml output should be prettified.
2512 When this option is turned on, `indent-region' is run on all
2513 component xml buffers before they are saved. Turn this off for
2514 regular use. Turn this on if you need to examine the xml
2515 visually."
2516 :group 'org-export-e-odt
2517 :version "24.1"
2518 :type 'boolean)
2520 (defcustom org-export-e-odt-convert-processes
2521 '(("LibreOffice"
2522 "soffice --headless --convert-to %f%x --outdir %d %i")
2523 ("unoconv"
2524 "unoconv -f %f -o %d %i"))
2525 "Specify a list of document converters and their usage.
2526 The converters in this list are offered as choices while
2527 customizing `org-export-e-odt-convert-process'.
2529 This variable is a list where each element is of the
2530 form (CONVERTER-NAME CONVERTER-CMD). CONVERTER-NAME is the name
2531 of the converter. CONVERTER-CMD is the shell command for the
2532 converter and can contain format specifiers. These format
2533 specifiers are interpreted as below:
2535 %i input file name in full
2536 %I input file name as a URL
2537 %f format of the output file
2538 %o output file name in full
2539 %O output file name as a URL
2540 %d output dir in full
2541 %D output dir as a URL.
2542 %x extra options as set in `org-export-e-odt-convert-capabilities'."
2543 :group 'org-export-e-odt
2544 :version "24.1"
2545 :type
2546 '(choice
2547 (const :tag "None" nil)
2548 (alist :tag "Converters"
2549 :key-type (string :tag "Converter Name")
2550 :value-type (group (string :tag "Command line")))))
2552 (defcustom org-export-e-odt-convert-process "LibreOffice"
2553 "Use this converter to convert from \"odt\" format to other formats.
2554 During customization, the list of converter names are populated
2555 from `org-export-e-odt-convert-processes'."
2556 :group 'org-export-e-odt
2557 :version "24.1"
2558 :type '(choice :convert-widget
2559 (lambda (w)
2560 (apply 'widget-convert (widget-type w)
2561 (eval (car (widget-get w :args)))))
2562 `((const :tag "None" nil)
2563 ,@(mapcar (lambda (c)
2564 `(const :tag ,(car c) ,(car c)))
2565 org-export-e-odt-convert-processes))))
2567 (defcustom org-export-e-odt-convert-capabilities
2568 '(("Text"
2569 ("odt" "ott" "doc" "rtf" "docx")
2570 (("pdf" "pdf") ("odt" "odt") ("rtf" "rtf") ("ott" "ott")
2571 ("doc" "doc" ":\"MS Word 97\"") ("docx" "docx") ("html" "html")))
2572 ("Web"
2573 ("html")
2574 (("pdf" "pdf") ("odt" "odt") ("html" "html")))
2575 ("Spreadsheet"
2576 ("ods" "ots" "xls" "csv" "xlsx")
2577 (("pdf" "pdf") ("ots" "ots") ("html" "html") ("csv" "csv") ("ods" "ods")
2578 ("xls" "xls") ("xlsx" "xlsx")))
2579 ("Presentation"
2580 ("odp" "otp" "ppt" "pptx")
2581 (("pdf" "pdf") ("swf" "swf") ("odp" "odp") ("otp" "otp") ("ppt" "ppt")
2582 ("pptx" "pptx") ("odg" "odg"))))
2583 "Specify input and output formats of `org-export-e-odt-convert-process'.
2584 More correctly, specify the set of input and output formats that
2585 the user is actually interested in.
2587 This variable is an alist where each element is of the
2588 form (DOCUMENT-CLASS INPUT-FMT-LIST OUTPUT-FMT-ALIST).
2589 INPUT-FMT-LIST is a list of INPUT-FMTs. OUTPUT-FMT-ALIST is an
2590 alist where each element is of the form (OUTPUT-FMT
2591 OUTPUT-FILE-EXTENSION EXTRA-OPTIONS).
2593 The variable is interpreted as follows:
2594 `org-export-e-odt-convert-process' can take any document that is in
2595 INPUT-FMT-LIST and produce any document that is in the
2596 OUTPUT-FMT-LIST. A document converted to OUTPUT-FMT will have
2597 OUTPUT-FILE-EXTENSION as the file name extension. OUTPUT-FMT
2598 serves dual purposes:
2599 - It is used for populating completion candidates during
2600 `org-export-e-odt-convert' commands.
2601 - It is used as the value of \"%f\" specifier in
2602 `org-export-e-odt-convert-process'.
2604 EXTRA-OPTIONS is used as the value of \"%x\" specifier in
2605 `org-export-e-odt-convert-process'.
2607 DOCUMENT-CLASS is used to group a set of file formats in
2608 INPUT-FMT-LIST in to a single class.
2610 Note that this variable inherently captures how LibreOffice based
2611 converters work. LibreOffice maps documents of various formats
2612 to classes like Text, Web, Spreadsheet, Presentation etc and
2613 allow document of a given class (irrespective of it's source
2614 format) to be converted to any of the export formats associated
2615 with that class.
2617 See default setting of this variable for an typical
2618 configuration."
2619 :group 'org-export-e-odt
2620 :version "24.1"
2621 :type
2622 '(choice
2623 (const :tag "None" nil)
2624 (alist :tag "Capabilities"
2625 :key-type (string :tag "Document Class")
2626 :value-type
2627 (group (repeat :tag "Input formats" (string :tag "Input format"))
2628 (alist :tag "Output formats"
2629 :key-type (string :tag "Output format")
2630 :value-type
2631 (group (string :tag "Output file extension")
2632 (choice
2633 (const :tag "None" nil)
2634 (string :tag "Extra options"))))))))
2636 ;;;; Debugging
2639 ;;;; Document
2641 ;;;; Document Header (Styles)
2643 ;;;; Document Header (Scripts)
2645 ;;;; Document Header (Mathjax)
2647 ;;;; Preamble
2649 ;;;; Postamble
2651 ;;;; Emphasis
2653 ;;;; Todos
2655 ;;;; Tags
2657 ;;;; Time-stamps
2658 ;;;; Statistics Cookie
2659 ;;;; Subscript
2660 ;;;; Superscript
2662 ;;;; Inline images
2664 ;;;; Block
2665 ;;;; Comment
2666 ;;;; Comment Block
2667 ;;;; Drawer
2668 ;;;; Dynamic Block
2669 ;;;; Emphasis
2670 ;;;; Entity
2671 ;;;; Example Block
2672 ;;;; Export Snippet
2673 ;;;; Export Block
2674 ;;;; Fixed Width
2675 ;;;; Footnotes
2677 ;;;; Headline
2678 ;;;; Horizontal Rule
2679 ;;;; Inline Babel Call
2680 ;;;; Inline Src Block
2681 ;;;; Inlinetask
2682 ;;;; Item
2683 ;;;; Keyword
2684 ;;;; Latex Environment
2685 ;;;; Latex Fragment
2686 ;;;; Line Break
2687 ;;;; Link
2688 ;;;; Babel Call
2689 ;;;; Macro
2690 ;;;; Paragraph
2691 ;;;; Plain List
2692 ;;;; Plain Text
2693 ;;;; Property Drawer
2694 ;;;; Quote Block
2695 ;;;; Quote Section
2696 ;;;; Section
2697 ;;;; Radio Target
2698 ;;;; Special Block
2699 ;;;; Src Block
2701 ;;;; Table
2703 ;;;; Target
2704 ;;;; Time-stamp
2706 ;;;; Verbatim
2707 ;;;; Verse Block
2708 ;;;; Headline
2710 ;;;; Links
2711 ;;;; Drawers
2712 ;;;; Inlinetasks
2713 ;;;; Publishing
2715 ;;;; Compilation
2719 ;;; User Configurable Variables (MAYBE)
2721 ;;;; Preamble
2723 ;;;; Headline
2725 ;;;; Emphasis
2727 (defcustom org-e-odt-format-headline-function nil
2728 "Function to format headline text.
2730 This function will be called with 5 arguments:
2731 TODO the todo keyword \(string or nil\).
2732 TODO-TYPE the type of todo \(symbol: `todo', `done', nil\)
2733 PRIORITY the priority of the headline \(integer or nil\)
2734 TEXT the main headline text \(string\).
2735 TAGS the tags string, separated with colons \(string or nil\).
2737 The function result will be used in the section format string.
2739 As an example, one could set the variable to the following, in
2740 order to reproduce the default set-up:
2742 \(defun org-e-odt-format-headline \(todo todo-type priority text tags\)
2743 \"Default format function for an headline.\"
2744 \(concat \(when todo
2745 \(format \"\\\\textbf{\\\\textsc{\\\\textsf{%s}}} \" todo\)\)
2746 \(when priority
2747 \(format \"\\\\framebox{\\\\#%c} \" priority\)\)
2748 text
2749 \(when tags \(format \"\\\\hfill{}\\\\textsc{%s}\" tags\)\)\)\)"
2750 :group 'org-export-e-odt
2751 :type 'function)
2753 ;;;; Footnotes
2755 ;;;; Time-stamps
2757 (defcustom org-e-odt-active-timestamp-format "\\textit{%s}"
2758 "A printf format string to be applied to active time-stamps."
2759 :group 'org-export-e-odt
2760 :type 'string)
2762 (defcustom org-e-odt-inactive-timestamp-format "\\textit{%s}"
2763 "A printf format string to be applied to inactive time-stamps."
2764 :group 'org-export-e-odt
2765 :type 'string)
2767 (defcustom org-e-odt-diary-timestamp-format "\\textit{%s}"
2768 "A printf format string to be applied to diary time-stamps."
2769 :group 'org-export-e-odt
2770 :type 'string)
2773 ;;;; Links
2775 (defcustom org-e-odt-image-default-option "width=.9\\linewidth"
2776 "Default option for images."
2777 :group 'org-export-e-odt
2778 :type 'string)
2780 (defcustom org-e-odt-default-figure-position "htb"
2781 "Default position for latex figures."
2782 :group 'org-export-e-odt
2783 :type 'string)
2785 (defcustom org-e-odt-inline-image-rules
2786 '(("file" . "\\.\\(pdf\\|jpeg\\|jpg\\|png\\|ps\\|eps\\)\\'"))
2787 "Rules characterizing image files that can be inlined into HTML.
2789 A rule consists in an association whose key is the type of link
2790 to consider, and value is a regexp that will be matched against
2791 link's path.
2793 Note that, by default, the image extension *actually* allowed
2794 depend on the way the HTML file is processed. When used with
2795 pdflatex, pdf, jpg and png images are OK. When processing
2796 through dvi to Postscript, only ps and eps are allowed. The
2797 default we use here encompasses both."
2798 :group 'org-export-e-odt
2799 :type '(alist :key-type (string :tag "Type")
2800 :value-type (regexp :tag "Path")))
2802 ;;;; Tables
2804 (defcustom org-e-odt-table-caption-above t
2805 "When non-nil, place caption string at the beginning of the table.
2806 Otherwise, place it near the end."
2807 :group 'org-export-e-odt
2808 :type 'boolean)
2810 ;;;; Drawers
2812 (defcustom org-e-odt-format-drawer-function nil
2813 "Function called to format a drawer in HTML code.
2815 The function must accept two parameters:
2816 NAME the drawer name, like \"LOGBOOK\"
2817 CONTENTS the contents of the drawer.
2819 The function should return the string to be exported.
2821 For example, the variable could be set to the following function
2822 in order to mimic default behaviour:
2824 \(defun org-e-odt-format-drawer-default \(name contents\)
2825 \"Format a drawer element for HTML export.\"
2826 contents\)"
2827 :group 'org-export-e-odt
2828 :type 'function)
2831 ;;;; Inlinetasks
2833 (defcustom org-e-odt-format-inlinetask-function nil
2834 "Function called to format an inlinetask in HTML code.
2836 The function must accept six parameters:
2837 TODO the todo keyword, as a string
2838 TODO-TYPE the todo type, a symbol among `todo', `done' and nil.
2839 PRIORITY the inlinetask priority, as a string
2840 NAME the inlinetask name, as a string.
2841 TAGS the inlinetask tags, as a string.
2842 CONTENTS the contents of the inlinetask, as a string.
2844 The function should return the string to be exported.
2846 For example, the variable could be set to the following function
2847 in order to mimic default behaviour:
2849 \(defun org-e-odt-format-inlinetask \(todo type priority name tags contents\)
2850 \"Format an inline task element for HTML export.\"
2851 \(let \(\(full-title
2852 \(concat
2853 \(when todo
2854 \(format \"\\\\textbf{\\\\textsf{\\\\textsc{%s}}} \" todo\)\)
2855 \(when priority \(format \"\\\\framebox{\\\\#%c} \" priority\)\)
2856 title
2857 \(when tags \(format \"\\\\hfill{}\\\\textsc{%s}\" tags\)\)\)\)\)
2858 \(format \(concat \"\\\\begin{center}\\n\"
2859 \"\\\\fbox{\\n\"
2860 \"\\\\begin{minipage}[c]{.6\\\\textwidth}\\n\"
2861 \"%s\\n\\n\"
2862 \"\\\\rule[.8em]{\\\\textwidth}{2pt}\\n\\n\"
2863 \"%s\"
2864 \"\\\\end{minipage}}\"
2865 \"\\\\end{center}\"\)
2866 full-title contents\)\)"
2867 :group 'org-export-e-odt
2868 :type 'function)
2871 ;; Src blocks
2873 ;;;; Plain text
2875 (defcustom org-e-odt-quotes
2876 '(("fr" ("\\(\\s-\\|[[(]\\)\"" . "«~") ("\\(\\S-\\)\"" . "~»") ("\\(\\s-\\|(\\)'" . "'"))
2877 ("en" ("\\(\\s-\\|[[(]\\)\"" . "``") ("\\(\\S-\\)\"" . "''") ("\\(\\s-\\|(\\)'" . "`")))
2878 "Alist for quotes to use when converting english double-quotes.
2880 The CAR of each item in this alist is the language code.
2881 The CDR of each item in this alist is a list of three CONS:
2882 - the first CONS defines the opening quote;
2883 - the second CONS defines the closing quote;
2884 - the last CONS defines single quotes.
2886 For each item in a CONS, the first string is a regexp
2887 for allowed characters before/after the quote, the second
2888 string defines the replacement string for this quote."
2889 :group 'org-export-e-odt
2890 :type '(list
2891 (cons :tag "Opening quote"
2892 (string :tag "Regexp for char before")
2893 (string :tag "Replacement quote "))
2894 (cons :tag "Closing quote"
2895 (string :tag "Regexp for char after ")
2896 (string :tag "Replacement quote "))
2897 (cons :tag "Single quote"
2898 (string :tag "Regexp for char before")
2899 (string :tag "Replacement quote "))))
2902 ;;;; Compilation
2906 ;;; Internal Functions (HTML)
2908 ;; (defun org-e-odt-format-inline-image (path &optional caption label attr)
2909 ;; ;; FIXME: alt text missing here?
2910 ;; (let ((inline-image (format "<img src=\"%s\" alt=\"%s\"/>"
2911 ;; path (file-name-nondirectory path))))
2912 ;; (if (not label) inline-image
2913 ;; (org-e-odt-format-section inline-image "figure" label))))
2915 (defun org-e-odt-format-image (src)
2916 "Create image tag with source and attributes."
2917 (save-match-data
2918 (let* ((caption (org-find-text-property-in-string 'org-caption src))
2919 (attr (org-find-text-property-in-string 'org-attributes src))
2920 (label (org-find-text-property-in-string 'org-label src))
2921 (caption (and caption (org-xml-encode-org-text caption)))
2922 (img-extras (if (string-match "^ltxpng/" src)
2923 (format " alt=\"%s\""
2924 (org-find-text-property-in-string
2925 'org-latex-src src))
2926 (if (string-match "\\<alt=" (or attr ""))
2927 (concat " " attr )
2928 (concat " " attr " alt=\"" src "\""))))
2929 (img (format "<img src=\"%s\"%s />" src img-extras))
2930 (extra (concat
2931 (and label
2932 (format "id=\"%s\" " (org-solidify-link-text label)))
2933 "class=\"figure\"")))
2934 (if caption
2935 (with-temp-buffer
2936 (with-org-lparse-preserve-paragraph-state
2937 (insert
2938 (org-lparse-format
2939 '("<div %s>" . "\n</div>")
2940 (concat
2941 (org-lparse-format '("\n<p>" . "</p>") img)
2942 (org-lparse-format '("\n<p>" . "</p>") caption))
2943 extra)))
2944 (buffer-string))
2945 img))))
2947 ;;;; Bibliography
2949 (defun org-e-odt-bibliography ()
2950 "Find bibliography, cut it out and return it."
2951 (catch 'exit
2952 (let (beg end (cnt 1) bib)
2953 (save-excursion
2954 (goto-char (point-min))
2955 (when (re-search-forward
2956 "^[ \t]*<div \\(id\\|class\\)=\"bibliography\"" nil t)
2957 (setq beg (match-beginning 0))
2958 (while (re-search-forward "</?div\\>" nil t)
2959 (setq cnt (+ cnt (if (string= (match-string 0) "<div") +1 -1)))
2960 (when (= cnt 0)
2961 (and (looking-at ">") (forward-char 1))
2962 (setq bib (buffer-substring beg (point)))
2963 (delete-region beg (point))
2964 (throw 'exit bib))))
2965 nil))))
2967 ;;;; Table
2969 (defun org-e-odt-format-table (lines olines)
2970 (let ((org-e-odt-format-table-no-css nil))
2971 (org-lparse-format-table lines olines)))
2973 (defun org-e-odt-splice-attributes (tag attributes)
2974 "Read attributes in string ATTRIBUTES, add and replace in HTML tag TAG."
2975 (if (not attributes)
2977 (let (oldatt newatt)
2978 (setq oldatt (org-extract-attributes-from-string tag)
2979 tag (pop oldatt)
2980 newatt (cdr (org-extract-attributes-from-string attributes)))
2981 (while newatt
2982 (setq oldatt (plist-put oldatt (pop newatt) (pop newatt))))
2983 (if (string-match ">" tag)
2984 (setq tag
2985 (replace-match (concat (org-attributes-to-string oldatt) ">")
2986 t t tag)))
2987 tag)))
2989 (defun org-export-splice-style (style extra)
2990 "Splice EXTRA into STYLE, just before \"</style>\"."
2991 (if (and (stringp extra)
2992 (string-match "\\S-" extra)
2993 (string-match "</style>" style))
2994 (concat (substring style 0 (match-beginning 0))
2995 "\n" extra "\n"
2996 (substring style (match-beginning 0)))
2997 style))
2999 ;; (defun org-e-odt-format-toc-entry (snumber todo headline tags href)
3000 ;; (setq headline (concat
3001 ;; ;; section number
3002 ;; (and org-export-with-section-numbers (concat snumber " "))
3003 ;; ;; headline
3004 ;; headline
3005 ;; ;; tags
3006 ;; (and tags (concat
3007 ;; (org-e-odt-format-spaces 3)
3008 ;; (org-e-odt-format-fontify tags "tag")))))
3009 ;; ;; fontify headline based on TODO keyword
3010 ;; (when todo (setq headline (org-e-odt-format-fontify headline "todo")))
3011 ;; (org-e-odt-format-link headline (concat "#" href)))
3013 (defun org-e-odt-toc-entry-formatter
3014 (level snumber todo todo-type priority
3015 headline tags target extra-targets extra-class)
3016 (org-e-odt-format-toc-entry snumber todo headline tags target))
3018 (defun org-e-odt-make-string (n string)
3019 (let (out) (dotimes (i n out) (setq out (concat string out)))))
3021 (defun org-e-odt-toc-text (toc-entries)
3022 (let* ((prev-level (1- (nth 1 (car toc-entries))))
3023 (start-level prev-level))
3024 (mapconcat
3025 (lambda (entry)
3026 (let ((headline (nth 0 entry))
3027 (level (nth 1 entry)))
3028 (prog1 (org-e-odt-format-toc-item headline level prev-level)
3029 (setq prev-level level))))
3030 toc-entries "")))
3032 (defun org-e-odt-toc (depth info)
3033 (assert (wholenump depth))
3034 (let* ((headlines (org-export-collect-headlines info depth))
3035 (toc-entries
3036 (loop for headline in headlines collect
3037 (list (org-e-odt-headline-text
3038 headline info 'org-e-odt-toc-entry-formatter)
3039 (org-export-get-relative-level headline info)))))
3040 (when toc-entries
3041 (let* ((lang-specific-heading "Table of Contents")) ; FIXME
3042 (concat
3043 (org-e-odt-begin-toc lang-specific-heading depth)
3044 (org-e-odt-toc-text toc-entries)
3045 (org-e-odt-end-toc))))))
3047 (defun org-e-odt-begin-outline (level1 snumber title tags
3048 target extra-targets extra-class)
3049 (let* ((class (format "outline-%d" level1))
3050 (class (if extra-class (concat class " " extra-class) class))
3051 (id (format "outline-container-%s"
3052 (org-lparse-suffix-from-snumber snumber)))
3053 (extra (concat (when id (format " id=\"%s\"" id))
3054 (when class (format " class=\"%s\"" class)))))
3055 (org-lparse-insert-tag "<div%s>" extra)
3056 (insert
3057 (org-lparse-format 'HEADING
3058 (org-lparse-format
3059 'HEADLINE title extra-targets tags snumber level1)
3060 level1 target))))
3062 (defun org-e-odt-end-outline ()
3063 (org-lparse-insert-tag "</div>"))
3065 (defun org-e-odt-suffix-from-snumber (snumber)
3066 (let* ((snu (replace-regexp-in-string "\\." "-" snumber))
3067 (href (cdr (assoc (concat "sec-" snu)
3068 org-export-preferred-target-alist))))
3069 (org-solidify-link-text (or href snu))))
3071 (defun org-e-odt-format-outline (contents level1 snumber title
3072 tags target extra-targets extra-class)
3073 (concat
3074 (org-e-odt-format-heading
3075 (org-e-odt-format-headline title extra-targets tags snumber level1)
3076 level1 target)
3077 contents))
3079 ;; (defun org-e-odt-format-line (line)
3080 ;; (case org-lparse-dyn-current-environment
3081 ;; ((quote fixedwidth) (concat (org-e-odt-encode-plain-text line) "\n"))
3082 ;; (t (concat line "\n"))))
3084 (defun org-e-odt-fix-class-name (kwd) ; audit callers of this function
3085 "Turn todo keyword into a valid class name.
3086 Replaces invalid characters with \"_\"."
3087 (save-match-data
3088 (while (string-match "[^a-zA-Z0-9_]" kwd)
3089 (setq kwd (replace-match "_" t t kwd))))
3090 kwd)
3092 (defun org-e-odt-format-internal-link (text href &optional extra)
3093 (org-e-odt-format-link text (concat "#" href) extra))
3095 (defun org-e-odt-format-extra-targets (extra-targets)
3096 (if (not extra-targets) ""
3097 (mapconcat (lambda (x)
3098 (when x
3099 (setq x (org-solidify-link-text
3100 (if (org-uuidgen-p x) (concat "ID-" x) x)))
3101 (org-e-odt-format-anchor "" x))) extra-targets "")))
3103 (defun org-e-odt-format-org-tags (tags)
3104 (if (not tags) ""
3105 (org-e-odt-format-fontify
3106 (mapconcat
3107 (lambda (x)
3108 (org-e-odt-format-fontify
3109 x (concat "" ;; org-e-odt-tag-class-prefix
3110 (org-e-odt-fix-class-name x))))
3111 (org-split-string tags ":")
3112 (org-e-odt-format-spaces 1)) "tag")))
3114 (defun org-e-odt-format-section-number (&optional snumber level)
3115 ;; FIXME
3116 (and nil org-export-with-section-numbers
3117 ;; (not org-lparse-body-only)
3118 snumber level
3119 (org-e-odt-format-fontify snumber (format "section-number-%d" level))))
3121 ;; (defun org-e-odt-format-headline (title extra-targets tags
3122 ;; &optional snumber level)
3123 ;; (concat
3124 ;; (org-e-odt-format-extra-targets extra-targets)
3125 ;; (concat (org-e-odt-format-section-number snumber level) " ")
3126 ;; title
3127 ;; (and tags (concat (org-e-odt-format-spaces 3)
3128 ;; (org-e-odt-format-org-tags tags)))))
3130 (defun org-e-odt-get-coding-system-for-write ()
3131 (or org-e-odt-coding-system
3132 (and (boundp 'buffer-file-coding-system) buffer-file-coding-system)))
3134 (defun org-e-odt-get-coding-system-for-save ()
3135 (or org-e-odt-coding-system
3136 (and (boundp 'buffer-file-coding-system) buffer-file-coding-system)))
3138 ;; (defun org-e-odt-format-date (info)
3139 ;; (let ((date (plist-get info :date)))
3140 ;; (cond
3141 ;; ((and date (string-match "%" date))
3142 ;; (format-time-string date))
3143 ;; (date date)
3144 ;; (t (format-time-string "%Y-%m-%d %T %Z")))))
3148 ;;; Internal Functions (Ngz)
3150 (defun org-e-odt--caption/label-string (caption label info)
3151 "Return caption and label HTML string for floats.
3153 CAPTION is a cons cell of secondary strings, the car being the
3154 standard caption and the cdr its short form. LABEL is a string
3155 representing the label. INFO is a plist holding contextual
3156 information.
3158 If there's no caption nor label, return the empty string.
3160 For non-floats, see `org-e-odt--wrap-label'."
3161 (setq label nil) ;; FIXME
3163 (let ((label-str (if label (format "\\label{%s}" label) "")))
3164 (cond
3165 ((and (not caption) (not label)) "")
3166 ((not caption) (format "\\label{%s}\n" label))
3167 ;; Option caption format with short name.
3168 ((cdr caption)
3169 (format "\\caption[%s]{%s%s}\n"
3170 (org-export-secondary-string (cdr caption) 'e-odt info)
3171 label-str
3172 (org-export-secondary-string (car caption) 'e-odt info)))
3173 ;; Standard caption format.
3174 ;; (t (format "\\caption{%s%s}\n"
3175 ;; label-str
3176 ;; (org-export-secondary-string (car caption) 'e-odt info)))
3178 (t (org-export-secondary-string (car caption) 'e-odt info)))))
3180 (defun org-e-odt--find-verb-separator (s)
3181 "Return a character not used in string S.
3182 This is used to choose a separator for constructs like \\verb."
3183 (let ((ll "~,./?;':\"|!@#%^&-_=+abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ<>()[]{}"))
3184 (loop for c across ll
3185 when (not (string-match (regexp-quote (char-to-string c)) s))
3186 return (char-to-string c))))
3188 (defun org-e-odt--make-option-string (options)
3189 "Return a comma separated string of keywords and values.
3190 OPTIONS is an alist where the key is the options keyword as
3191 a string, and the value a list containing the keyword value, or
3192 nil."
3193 (mapconcat (lambda (pair)
3194 (concat (first pair)
3195 (when (> (length (second pair)) 0)
3196 (concat "=" (second pair)))))
3197 options
3198 ","))
3200 (defun org-e-odt--quotation-marks (text info)
3201 "Export quotation marks depending on language conventions.
3202 TEXT is a string containing quotation marks to be replaced. INFO
3203 is a plist used as a communication channel."
3204 (mapc (lambda(l)
3205 (let ((start 0))
3206 (while (setq start (string-match (car l) text start))
3207 (let ((new-quote (concat (match-string 1 text) (cdr l))))
3208 (setq text (replace-match new-quote t t text))))))
3209 (cdr (or (assoc (plist-get info :language) org-e-odt-quotes)
3210 ;; Falls back on English.
3211 (assoc "en" org-e-odt-quotes))))
3212 text)
3214 (defun org-e-odt--wrap-label (element output)
3215 "Wrap label associated to ELEMENT around OUTPUT, if appropriate.
3216 This function shouldn't be used for floats. See
3217 `org-e-odt--caption/label-string'."
3218 ;; (let ((label (org-element-property :name element)))
3219 ;; (if (or (not output) (not label) (string= output "") (string= label ""))
3220 ;; output
3221 ;; (concat (format "\\label{%s}\n" label) output)))
3222 output)
3226 ;;; Transcode Helpers
3228 ;;;; Src Code
3230 (defun org-e-odt-htmlfontify-string (line)
3231 (let* ((hfy-html-quote-regex "\\([<\"&> ]\\)")
3232 (hfy-html-quote-map '(("\"" "&quot;")
3233 ("<" "&lt;")
3234 ("&" "&amp;")
3235 (">" "&gt;")
3236 (" " "<text:s/>")
3237 (" " "<text:tab/>")))
3238 (hfy-face-to-css 'org-e-odt-hfy-face-to-css)
3239 (hfy-optimisations-1 (copy-seq hfy-optimisations))
3240 (hfy-optimisations (add-to-list 'hfy-optimisations-1
3241 'body-text-only))
3242 (hfy-begin-span-handler
3243 (lambda (style text-block text-id text-begins-block-p)
3244 (insert (format "<text:span text:style-name=\"%s\">" style))))
3245 (hfy-end-span-handler (lambda nil (insert "</text:span>"))))
3246 (htmlfontify-string line)))
3248 (defun org-e-odt-do-format-code
3249 (code &optional lang refs retain-labels num-start)
3250 (let* ((lang (or (assoc-default lang org-src-lang-modes) lang))
3251 (lang-mode (and lang (intern (format "%s-mode" lang))))
3252 (code-lines (org-split-string code "\n"))
3253 (code-length (length code-lines))
3254 (use-htmlfontify-p (and (functionp lang-mode)
3255 org-export-e-odt-fontify-srcblocks
3256 (require 'htmlfontify nil t)
3257 (fboundp 'htmlfontify-string)))
3258 (code (if (not use-htmlfontify-p) code
3259 (with-temp-buffer
3260 (insert code)
3261 (funcall lang-mode)
3262 (font-lock-fontify-buffer)
3263 (buffer-string))))
3264 (fontifier (if use-htmlfontify-p 'org-e-odt-htmlfontify-string
3265 'org-e-odt-encode-plain-text))
3266 (par-style (if use-htmlfontify-p "OrgSrcBlock"
3267 "OrgFixedWidthBlock"))
3268 (i 0))
3269 (assert (= code-length (length (org-split-string code "\n"))))
3270 (setq code
3271 (org-export-format-code
3272 code
3273 (lambda (loc line-num ref)
3274 (setq par-style
3275 (concat par-style (and (= (incf i) code-length) "LastLine")))
3277 (setq loc (concat loc (and ref retain-labels (format " (%s)" ref))))
3278 (setq loc (funcall fontifier loc))
3279 (when ref
3280 (setq loc (org-e-odt-format-target loc (concat "coderef-" ref))))
3281 (setq loc (org-e-odt-format-stylized-paragraph par-style loc))
3282 (if (not line-num) loc
3283 (org-e-odt-format-tags
3284 '("<text:list-item>" . "</text:list-item>") loc)))
3285 num-start refs))
3286 (cond
3287 ((not num-start) code)
3288 ((equal num-start 0)
3289 (org-e-odt-format-tags
3290 '("<text:list text:style-name=\"OrgSrcBlockNumberedLine\"%s>"
3291 . "</text:list>") code " text:continue-numbering=\"false\""))
3292 (t (org-e-odt-format-tags
3293 '("<text:list text:style-name=\"OrgSrcBlockNumberedLine\"%s>"
3294 . "</text:list>") code " text:continue-numbering=\"true\"")))))
3296 (defun org-e-odt-format-code (element info)
3297 (let* ((lang (org-element-property :language element))
3298 ;; Extract code and references.
3299 (code-info (org-export-unravel-code element))
3300 (code (car code-info))
3301 (refs (cdr code-info))
3302 ;; Does the src block contain labels?
3303 (retain-labels (org-element-property :retain-labels element))
3304 ;; Does it have line numbers?
3305 (num-start (case (org-element-property :number-lines element)
3306 (continued (org-export-get-loc element info))
3307 (new 0))))
3308 (org-e-odt-do-format-code code lang refs retain-labels num-start)))
3312 ;;; Template
3314 (defun org-e-odt-template (contents info)
3315 "Return complete document string after HTML conversion.
3316 CONTENTS is the transcoded contents string. RAW-DATA is the
3317 original parsed data. INFO is a plist holding export options."
3320 ;; write meta file
3321 (org-e-odt-update-meta-file info)
3324 (with-temp-buffer
3325 (insert-file-contents
3326 (or org-export-e-odt-content-template-file
3327 (expand-file-name "OrgOdtContentTemplate.xml"
3328 org-e-odt-styles-dir)))
3329 (goto-char (point-min))
3330 (re-search-forward "</office:text>" nil nil)
3331 (goto-char (match-beginning 0))
3333 ;; Title
3334 (insert (org-e-odt-format-preamble info))
3335 ;; Table of Contents
3336 (let ((depth (plist-get info :with-toc)))
3337 (when (wholenump depth) (org-e-odt-toc depth info)))
3339 ;; Contents
3340 (insert contents)
3341 (buffer-substring-no-properties (point-min) (point-max))))
3345 ;;; Transcode Functions
3347 ;;;; Block
3349 (defun org-e-odt-center-block (center-block contents info)
3350 "Transcode a CENTER-BLOCK element from Org to HTML.
3351 CONTENTS holds the contents of the block. INFO is a plist
3352 holding contextual information."
3353 (org-e-odt--wrap-label center-block contents))
3356 ;;;; Comment
3358 ;; Comments are ignored.
3361 ;;;; Comment Block
3363 ;; Comment Blocks are ignored.
3366 ;;;; Drawer
3368 (defun org-e-odt-drawer (drawer contents info)
3369 "Transcode a DRAWER element from Org to HTML.
3370 CONTENTS holds the contents of the block. INFO is a plist
3371 holding contextual information."
3372 (let* ((name (org-element-property :drawer-name drawer))
3373 (output (if (functionp org-e-odt-format-drawer-function)
3374 (funcall org-e-odt-format-drawer-function
3375 name contents)
3376 ;; If there's no user defined function: simply
3377 ;; display contents of the drawer.
3378 contents)))
3379 (org-e-odt--wrap-label drawer output)))
3382 ;;;; Dynamic Block
3384 (defun org-e-odt-dynamic-block (dynamic-block contents info)
3385 "Transcode a DYNAMIC-BLOCK element from Org to HTML.
3386 CONTENTS holds the contents of the block. INFO is a plist
3387 holding contextual information. See
3388 `org-export-data'."
3389 (org-e-odt--wrap-label dynamic-block contents))
3392 ;;;; Emphasis
3394 (defun org-e-odt-emphasis (emphasis contents info)
3395 "Transcode EMPHASIS from Org to HTML.
3396 CONTENTS is the contents of the emphasized text. INFO is a plist
3397 holding contextual information.."
3398 ;; (format (cdr (assoc (org-element-property :marker emphasis)
3399 ;; org-e-odt-emphasis-alist))
3400 ;; contents)
3401 (org-e-odt-format-fontify
3402 contents (cadr (assoc
3403 (org-element-property :marker emphasis)
3404 '(("*" bold)
3405 ("/" emphasis)
3406 ("_" underline)
3407 ("=" code)
3408 ("~" verbatim)
3409 ("+" strike))))))
3412 ;;;; Entity
3414 (defun org-e-odt-entity (entity contents info)
3415 "Transcode an ENTITY object from Org to HTML.
3416 CONTENTS are the definition itself. INFO is a plist holding
3417 contextual information."
3418 ;; (let ((ent (org-element-property :latex entity)))
3419 ;; (if (org-element-property :latex-math-p entity)
3420 ;; (format "$%s$" ent)
3421 ;; ent))
3422 (org-element-property :utf-8 entity))
3425 ;;;; Example Block
3427 (defun org-e-odt-example-block (example-block contents info)
3428 "Transcode a EXAMPLE-BLOCK element from Org to HTML.
3429 CONTENTS is nil. INFO is a plist holding contextual information."
3430 (let* ((options (or (org-element-property :options example-block) ""))
3431 (value (org-export-handle-code example-block info nil nil t)))
3432 (org-e-odt--wrap-label
3433 example-block (org-e-odt-format-source-code-or-example value nil))))
3436 ;;;; Export Snippet
3438 (defun org-e-odt-export-snippet (export-snippet contents info)
3439 "Transcode a EXPORT-SNIPPET object from Org to HTML.
3440 CONTENTS is nil. INFO is a plist holding contextual information."
3441 (when (eq (org-export-snippet-backend export-snippet) 'e-odt)
3442 (org-element-property :value export-snippet)))
3445 ;;;; Export Block
3447 (defun org-e-odt-export-block (export-block contents info)
3448 "Transcode a EXPORT-BLOCK element from Org to HTML.
3449 CONTENTS is nil. INFO is a plist holding contextual information."
3450 (when (string= (org-element-property :type export-block) "latex")
3451 (org-remove-indentation (org-element-property :value export-block))))
3454 ;;;; Fixed Width
3456 (defun org-e-odt-fixed-width (fixed-width contents info)
3457 "Transcode a FIXED-WIDTH element from Org to HTML.
3458 CONTENTS is nil. INFO is a plist holding contextual information."
3459 (let* ((value (org-element-normalize-string
3460 (replace-regexp-in-string
3461 "^[ \t]*: ?" ""
3462 (org-element-property :value fixed-width)))))
3463 (org-e-odt--wrap-label
3464 fixed-width (org-e-odt-format-source-code-or-example value nil))))
3467 ;;;; Footnote Definition
3469 ;; Footnote Definitions are ignored.
3472 ;;;; Footnote Reference
3474 (defun org-e-odt-footnote-def (raw info) ; FIXME
3475 (if (equal (org-element-type raw) 'org-data)
3476 (org-trim (org-export-data raw 'e-odt info)) ; fix paragraph
3477 ; style
3478 (org-odt-format-stylized-paragraph
3479 'footnote (org-trim (org-export-secondary-string raw 'e-odt info)))))
3481 (defvar org-e-odt-footnote-separator
3482 (org-e-odt-format-fontify "," 'superscript))
3484 (defun org-e-odt-footnote-reference (footnote-reference contents info)
3485 "Transcode a FOOTNOTE-REFERENCE element from Org to HTML.
3486 CONTENTS is nil. INFO is a plist holding contextual information."
3487 (concat
3488 ;; Insert separator between two footnotes in a row.
3489 (let ((prev (org-export-get-previous-element footnote-reference info)))
3490 (when (eq (org-element-type prev) 'footnote-reference)
3491 org-e-odt-footnote-separator))
3492 (cond
3493 ((not (org-export-footnote-first-reference-p footnote-reference info))
3494 (let* ((n (org-export-get-footnote-number footnote-reference info)))
3495 (org-e-odt-format-footnote-reference n "IGNORED" 100)))
3496 ;; Inline definitions are secondary strings.
3497 ((eq (org-element-property :type footnote-reference) 'inline)
3498 (let* ((raw (org-export-get-footnote-definition footnote-reference info))
3499 (n (org-export-get-footnote-number footnote-reference info))
3500 (def (org-e-odt-footnote-def raw info)))
3501 (org-e-odt-format-footnote-reference n def 1)))
3502 ;; Non-inline footnotes definitions are full Org data.
3504 (let* ((raw (org-export-get-footnote-definition footnote-reference info))
3505 (n (org-export-get-footnote-number footnote-reference info))
3506 (def (org-e-odt-footnote-def raw info)))
3507 (org-e-odt-format-footnote-reference n def 1))))))
3510 ;;;; Headline
3512 (defun org-e-odt-todo (todo)
3513 (when todo
3514 (org-e-odt-format-fontify
3515 (concat
3516 "" ; org-e-odt-todo-kwd-class-prefix
3517 (org-e-odt-fix-class-name todo))
3518 (list (if (member todo org-done-keywords) "done" "todo")
3519 todo))))
3521 (defun org-e-odt-headline-text (headline info &optional formatter)
3522 "Transcode an HEADLINE element from Org to HTML.
3523 CONTENTS holds the contents of the headline. INFO is a plist
3524 holding contextual information."
3525 (let* ((numberedp (org-export-numbered-headline-p headline info))
3526 (level (org-export-get-relative-level headline info))
3527 (todo (and (plist-get info :with-todo-keywords)
3528 (let ((todo (org-element-property
3529 :todo-keyword headline)))
3530 (and todo
3531 (org-export-secondary-string todo 'e-odt info)))))
3532 (todo-type (and todo (org-element-property :todo-type headline)))
3533 (priority (and (plist-get info :with-priority)
3534 (org-element-property :priority headline)))
3535 (text (org-export-secondary-string
3536 (org-element-property :title headline) 'e-odt info))
3537 (tags (and (plist-get info :with-tags)
3538 (org-element-property :tags headline)))
3540 (headline-no (org-export-get-headline-number headline info))
3541 (headline-label
3542 (format "sec-%s" (mapconcat 'number-to-string headline-no "-")))
3543 (headline-labels (list headline-label))
3544 (headline-no (org-export-get-headline-number headline info))
3545 (section-no (mapconcat 'number-to-string headline-no "."))
3546 (primary-target (car (last headline-labels)))
3547 (secondary-targets (butlast headline-labels))
3548 (extra-class nil)
3549 (formatter (or (and (functionp formatter) formatter)
3550 org-e-odt-headline-formatter)))
3551 (funcall formatter level section-no todo todo-type priority
3552 text tags primary-target secondary-targets extra-class)))
3554 (defun org-e-odt-headline (headline contents info)
3555 "Transcode an HEADLINE element from Org to HTML.
3556 CONTENTS holds the contents of the headline. INFO is a plist
3557 holding contextual information."
3558 (let* ((class (plist-get info :latex-class))
3559 (numberedp (org-export-numbered-headline-p headline info))
3560 ;; Get level relative to current parsed data.
3561 (level (org-export-get-relative-level headline info))
3562 ;; (class-sectionning (assoc class org-e-odt-classes))
3563 ;; Section formatting will set two placeholders: one for the
3564 ;; title and the other for the contents.
3565 ;; (section-fmt
3566 ;; (let ((sec (if (and (symbolp (nth 2 class-sectionning))
3567 ;; (fboundp (nth 2 class-sectionning)))
3568 ;; (funcall (nth 2 class-sectionning) level numberedp)
3569 ;; (nth (1+ level) class-sectionning))))
3570 ;; (cond
3571 ;; ;; No section available for that LEVEL.
3572 ;; ((not sec) nil)
3573 ;; ;; Section format directly returned by a function.
3574 ;; ((stringp sec) sec)
3575 ;; ;; (numbered-section . unnumbered-section)
3576 ;; ((not (consp (cdr sec)))
3577 ;; (concat (funcall (if numberedp #'car #'cdr) sec) "\n%s"))
3578 ;; ;; (numbered-open numbered-close)
3579 ;; ((= (length sec) 2)
3580 ;; (when numberedp (concat (car sec) "\n%s" (nth 1 sec))))
3581 ;; ;; (num-in num-out no-num-in no-num-out)
3582 ;; ((= (length sec) 4)
3583 ;; (if numberedp
3584 ;; (concat (car sec) "\n%s" (nth 1 sec))
3585 ;; (concat (nth 2 sec) "\n%s" (nth 3 sec)))))))
3586 (text (org-export-secondary-string
3587 (org-element-property :title headline) 'e-odt info))
3588 (todo (and (plist-get info :with-todo-keywords)
3589 (let ((todo (org-element-property
3590 :todo-keyword headline)))
3591 (and todo
3592 (org-export-secondary-string todo 'e-odt info)))))
3593 (todo-type (and todo (org-element-property :todo-type headline)))
3594 (tags (and (plist-get info :with-tags)
3595 (org-element-property :tags headline)))
3596 (priority (and (plist-get info :with-priority)
3597 (org-element-property :priority headline)))
3598 ;; Create the headline text.
3599 (full-text (if (functionp org-e-odt-format-headline-function)
3600 ;; User-defined formatting function.
3601 (funcall org-e-odt-format-headline-function
3602 todo todo-type priority text tags)
3603 ;; Default formatting.
3604 (concat
3605 ;; (when todo
3606 ;; (format "\\textbf{\\textsf{\\textsc{%s}}} " todo))
3607 (org-e-odt-todo todo) " "
3608 (when priority (format "\\framebox{\\#%c} " priority))
3609 text
3610 ;; (when tags (format "\\hfill{}\\textsc{%s}" tags))
3612 ;; Associate some \label to the headline for internal links.
3613 ;; (headline-label
3614 ;; (format "\\label{sec-%s}\n"
3615 ;; (mapconcat 'number-to-string
3616 ;; (org-export-get-headline-number headline info)
3617 ;; "-")))
3619 ;; FIXME - begin
3620 (headline-no (org-export-get-headline-number headline info))
3621 (headline-label
3622 (format "sec-%s" (mapconcat 'number-to-string headline-no "-")))
3623 (headline-labels (list headline-label))
3624 (headline-no (org-export-get-headline-number headline info))
3625 (section-no (mapconcat 'number-to-string headline-no "."))
3626 ;; FIXME - end
3628 (pre-blanks (make-string
3629 (org-element-property :pre-blank headline) 10)))
3630 (cond
3631 ;; Case 1: This is a footnote section: ignore it.
3632 ((org-element-property :footnote-section-p headline) nil)
3633 ;; Case 2. This is a deep sub-tree: export it as a list item.
3634 ;; Also export as items headlines for which no section
3635 ;; format has been found.
3636 ((org-export-low-level-p headline info) ; FIXME (or (not section-fmt))
3637 ;; Build the real contents of the sub-tree.
3638 (let* ((type (if numberedp 'unordered 'unordered)) ; FIXME
3639 (itemized-body (org-e-odt-format-list-item
3640 contents type nil nil full-text)))
3641 (concat
3642 (and (org-export-first-sibling-p headline info)
3643 (org-e-odt-begin-plain-list type))
3644 itemized-body
3645 (and (org-export-last-sibling-p headline info)
3646 (org-e-odt-end-plain-list type)))))
3647 ;; Case 3. Standard headline. Export it as a section.
3649 ;; (format section-fmt full-text
3650 ;; (concat headline-label pre-blanks contents))
3652 (org-e-odt-format-outline contents level section-no full-text tags
3653 (car (last headline-labels))
3654 (butlast headline-labels) nil)))))
3657 ;;;; Horizontal Rule
3659 (defun org-e-odt-horizontal-rule (horizontal-rule contents info)
3660 "Transcode an HORIZONTAL-RULE object from Org to HTML.
3661 CONTENTS is nil. INFO is a plist holding contextual information."
3662 (let ((attr (mapconcat #'identity
3663 (org-element-property :attr_odt horizontal-rule)
3664 " ")))
3665 (org-e-odt--wrap-label horizontal-rule
3666 (org-e-odt-format-horizontal-line))))
3669 ;;;; Inline Babel Call
3671 ;; Inline Babel Calls are ignored.
3674 ;;;; Inline Src Block
3676 (defun org-e-odt-inline-src-block (inline-src-block contents info)
3677 "Transcode an INLINE-SRC-BLOCK element from Org to HTML.
3678 CONTENTS holds the contents of the item. INFO is a plist holding
3679 contextual information."
3680 (let* ((org-lang (org-element-property :language inline-src-block))
3681 (code (org-element-property :value inline-src-block))
3682 (separator (org-e-odt--find-verb-separator code)))
3683 (error "FIXME")))
3686 ;;;; Inlinetask
3688 (defun org-e-odt-format-section (text class &optional id)
3689 (let ((extra (concat (when id (format " id=\"%s\"" id)))))
3690 (concat (format "<div class=\"%s\"%s>\n" class extra) text "</div>\n")))
3692 (defun org-e-odt-inlinetask (inlinetask contents info)
3693 "Transcode an INLINETASK element from Org to HTML.
3694 CONTENTS holds the contents of the block. INFO is a plist
3695 holding contextual information."
3696 (let ((title (org-export-secondary-string
3697 (org-element-property :title inlinetask) 'e-odt info))
3698 (todo (and (plist-get info :with-todo-keywords)
3699 (let ((todo (org-element-property
3700 :todo-keyword inlinetask)))
3701 (and todo
3702 (org-export-secondary-string todo 'e-odt info)))))
3703 (todo-type (org-element-property :todo-type inlinetask))
3704 (tags (and (plist-get info :with-tags)
3705 (org-element-property :tags inlinetask)))
3706 (priority (and (plist-get info :with-priority)
3707 (org-element-property :priority inlinetask))))
3708 ;; If `org-e-odt-format-inlinetask-function' is provided, call it
3709 ;; with appropriate arguments.
3710 (if (functionp org-e-odt-format-inlinetask-function)
3711 (funcall org-e-odt-format-inlinetask-function
3712 todo todo-type priority title tags contents)
3713 ;; Otherwise, use a default template.
3714 (org-e-odt--wrap-label
3715 inlinetask
3716 (let ((full-title
3717 (concat
3718 (when todo (format "\\textbf{\\textsf{\\textsc{%s}}} " todo))
3719 (when priority (format "\\framebox{\\#%c} " priority))
3720 title
3721 (when tags (format "\\hfill{}\\textsc{%s}" tags)))))
3722 (format (concat "\\begin{center}\n"
3723 "\\fbox{\n"
3724 "\\begin{minipage}[c]{.6\\textwidth}\n"
3725 "%s\n\n"
3726 "\\rule[.8em]{\\textwidth}{2pt}\n\n"
3727 "%s"
3728 "\\end{minipage}\n"
3729 "}\n"
3730 "\\end{center}")
3731 full-title contents))))))
3734 ;;;; Item
3736 (defun org-e-odt-format-list-item (contents type checkbox
3737 &optional term-counter-id
3738 headline)
3739 (when checkbox
3740 (setq checkbox
3741 (org-e-odt-format-fontify (case checkbox
3742 (on "[X]")
3743 (off "[&nbsp;]")
3744 (trans "[-]")) 'code)))
3745 (concat
3746 (org-e-odt-begin-list-item type term-counter-id headline)
3747 ;; FIXME checkbox (and checkbox " ")
3748 contents
3749 (org-e-odt-end-list-item type)))
3751 (defun org-e-odt-item (item contents info)
3752 "Transcode an ITEM element from Org to HTML.
3753 CONTENTS holds the contents of the item. INFO is a plist holding
3754 contextual information."
3755 ;; Grab `:level' from plain-list properties, which is always the
3756 ;; first element above current item.
3757 (let* ((plain-list (org-export-get-parent item info))
3758 (type (org-element-property :type plain-list))
3759 (level (org-element-property :level plain-list))
3760 (counter (org-element-property :counter item))
3761 (checkbox (org-element-property :checkbox item))
3762 (tag (let ((tag (org-element-property :tag item)))
3763 (and tag (org-export-secondary-string tag 'e-odt info)))))
3764 (org-e-odt-format-list-item
3765 contents type checkbox (or tag counter))))
3768 ;;;; Keyword
3770 (defun org-e-odt-keyword (keyword contents info)
3771 "Transcode a KEYWORD element from Org to HTML.
3772 CONTENTS is nil. INFO is a plist holding contextual information."
3773 (let ((key (downcase (org-element-property :key keyword)))
3774 (value (org-element-property :value keyword)))
3775 (cond
3776 ((string= key "latex") value)
3777 ((string= key "index") (format "\\index{%s}" value))
3778 ((string= key "target") nil ; FIXME
3779 ;; (format "\\label{%s}" (org-export-solidify-link-text value))
3781 ((string= key "toc")
3782 (let ((value (downcase value)))
3783 (cond
3784 ((string-match "\\<headlines\\>" value)
3785 (let ((depth (or (and (string-match "[0-9]+" value)
3786 (string-to-number (match-string 0 value)))
3787 (plist-get info :with-toc))))
3788 (when (wholenump depth) (org-e-odt-toc depth info))))
3789 ((string= "tables" value) "FIXME")
3790 ((string= "figures" value) "FIXME")
3791 ((string= "listings" value)
3792 (cond
3793 ;; At the moment, src blocks with a caption are wrapped
3794 ;; into a figure environment.
3795 (t "FIXME")))))))))
3798 ;;;; Latex Environment
3800 (defun org-e-odt-format-latex (latex-frag processing-type)
3801 (let* ((prefix (case processing-type
3802 (dvipng "ltxpng/")
3803 (mathml "ltxmathml/")))
3804 (cache-relpath
3805 (concat prefix (file-name-sans-extension
3806 (file-name-nondirectory (buffer-file-name)))))
3807 (cache-dir (file-name-directory (buffer-file-name )))
3808 (display-msg (case processing-type
3809 (dvipng "Creating LaTeX Image...")
3810 (mathml "Creating MathML snippet..."))))
3811 (with-temp-buffer
3812 (insert latex-frag)
3813 (org-format-latex cache-relpath cache-dir nil display-msg
3814 nil nil processing-type)
3815 (buffer-string))))
3817 (defun org-e-odt-latex-environment (latex-environment contents info)
3818 "Transcode a LATEX-ENVIRONMENT element from Org to HTML.
3819 CONTENTS is nil. INFO is a plist holding contextual information."
3820 (org-e-odt--wrap-label
3821 latex-environment
3822 (let ((latex-frag
3823 (org-remove-indentation
3824 (org-element-property :value latex-environment)))
3825 (processing-type (plist-get info :LaTeX-fragments)))
3826 (cond
3827 ((member processing-type '(t mathjax))
3828 (org-e-odt-format-latex latex-frag 'mathml))
3829 ((equal processing-type 'dvipng)
3830 (let* ((formula-link (org-e-odt-format-latex
3831 latex-frag processing-type)))
3832 (when (and formula-link
3833 (string-match "file:\\([^]]*\\)" formula-link))
3834 (org-e-odt-format-inline-image (match-string 1 formula-link)))))
3836 latex-frag)))))
3839 ;;;; Latex Fragment
3841 (defun org-e-odt-latex-fragment (latex-fragment contents info)
3842 "Transcode a LATEX-FRAGMENT object from Org to HTML.
3843 CONTENTS is nil. INFO is a plist holding contextual information."
3844 ;; (org-element-property :value latex-fragment)
3845 (let* ((latex-frag (org-element-property :value latex-fragment)))
3846 (cond
3847 ((string-match "\\\\ref{\\([^{}\n]+\\)}" latex-frag)
3848 (let* ((label (match-string 1 latex-frag))
3849 (href (and label (org-export-solidify-link-text label)))
3850 (text (if (string-match "\\`[a-z]\\{1,10\\}:\\(.+\\)" label)
3851 (substring label (match-beginning 1))
3852 label)))
3853 (org-e-odt-format-internal-link text href)))
3854 (t (let ((processing-type (plist-get info :LaTeX-fragments)))
3855 (cond
3856 ((member processing-type '(t mathjax))
3857 (org-e-odt-format-latex latex-frag 'mathjax))
3858 ((equal processing-type 'dvipng)
3859 (let* ((formula-link (org-e-odt-format-latex
3860 latex-frag processing-type)))
3861 (when (and formula-link
3862 (string-match "file:\\([^]]*\\)" formula-link))
3863 (org-e-odt-format-inline-image
3864 (match-string 1 formula-link)))))
3865 (t latex-frag)))))))
3868 ;;;; Line Break
3870 (defun org-e-odt-line-break (line-break contents info)
3871 "Transcode a LINE-BREAK object from Org to HTML.
3872 CONTENTS is nil. INFO is a plist holding contextual information."
3873 "<text:line-break/>\n")
3876 ;;;; Link
3878 (defun org-e-odt-link--inline-image (link info)
3879 "Return HTML code for an inline image.
3880 LINK is the link pointing to the inline image. INFO is a plist
3881 used as a communication channel."
3882 (let* ((parent (org-export-get-parent-paragraph link info))
3883 (path (let ((raw-path (org-element-property :path link)))
3884 (if (not (file-name-absolute-p raw-path)) raw-path
3885 (expand-file-name raw-path))))
3886 (caption (org-e-odt--caption/label-string
3887 (org-element-property :caption parent)
3888 (org-element-property :name parent)
3889 info))
3890 (label (org-element-property :name parent))
3891 ;; Retrieve latex attributes from the element around.
3892 (attr (let ((raw-attr
3893 (mapconcat #'identity
3894 (org-element-property :attr_odt parent)
3895 " ")))
3896 (unless (string= raw-attr "") raw-attr))))
3897 ;; Now clear ATTR from any special keyword and set a default
3898 ;; value if nothing is left.
3899 (setq attr (if (not attr) "" (org-trim attr)))
3900 ;; Return proper string, depending on DISPOSITION.
3901 (let ((href (and label (org-export-solidify-link-text label))))
3902 (org-e-odt-format-inline-image path caption href attr))))
3904 (defun org-e-odt-link (link desc info)
3905 "Transcode a LINK object from Org to HTML.
3907 DESC is the description part of the link, or the empty string.
3908 INFO is a plist holding contextual information. See
3909 `org-export-data'."
3910 (let* ((type (org-element-property :type link))
3911 (raw-path (org-element-property :path link))
3912 ;; Ensure DESC really exists, or set it to nil.
3913 (desc (and (not (string= desc "")) desc))
3914 (imagep (org-export-inline-image-p
3915 link org-e-odt-inline-image-rules))
3916 (path (cond
3917 ((member type '("http" "https" "ftp" "mailto"))
3918 (concat type ":" raw-path))
3919 ((string= type "file")
3920 (when (string-match "\\(.+\\)::.+" raw-path)
3921 (setq raw-path (match-string 1 raw-path)))
3922 (if (file-name-absolute-p raw-path)
3923 (concat "file://" (expand-file-name raw-path))
3924 ;; TODO: Not implemented yet. Concat also:
3925 ;; (org-export-directory :HTML info)
3926 (concat "file://" raw-path)))
3927 (t raw-path)))
3928 protocol)
3929 (cond
3930 ;; Image file.
3931 (imagep (org-e-odt-link--inline-image link info))
3932 ;; Radioed target: Target's name is obtained from original raw
3933 ;; link. Path is parsed and transcoded in order to have a proper
3934 ;; display of the contents.
3935 ((string= type "radio")
3936 (org-e-odt-format-internal-link
3937 (org-export-secondary-string
3938 (org-element-parse-secondary-string
3939 path (cdr (assq 'radio-target org-element-object-restrictions)))
3940 'e-odt info)
3941 (org-export-solidify-link-text path)))
3942 ;; Links pointing to an headline: Find destination and build
3943 ;; appropriate referencing command.
3944 ((member type '("custom-id" "fuzzy" "id"))
3945 (let ((destination (if (string= type "fuzzy")
3946 (org-export-resolve-fuzzy-link link info)
3947 (org-export-resolve-id-link link info))))
3948 (case (org-element-type destination)
3949 ;; Fuzzy link points nowhere.
3950 ('nil
3951 (org-e-odt-format-fontify
3952 (or desc (org-export-secondary-string
3953 (org-element-property :raw-link link)
3954 'e-odt info)) 'emphasis))
3955 ;; Fuzzy link points to an invisible target.
3956 (keyword nil)
3957 ;; LINK points to an headline. If headlines are numbered
3958 ;; and the link has no description, display headline's
3959 ;; number. Otherwise, display description or headline's
3960 ;; title.
3961 (headline
3962 (let* ((headline-no (org-export-get-headline-number destination info))
3963 (label (format "sec-%s" (mapconcat 'number-to-string
3964 headline-no "-")))
3965 (section-no (mapconcat 'number-to-string headline-no ".")))
3966 (setq desc
3967 (cond
3968 (desc desc)
3969 ((plist-get info :section-numbers) section-no)
3970 (t (org-export-secondary-string
3971 (org-element-property :title destination)
3972 'e-odt info))))
3973 (org-e-odt-format-internal-link desc label)))
3974 ;; Fuzzy link points to a target. Do as above.
3975 (otherwise
3976 (let ((path (org-export-solidify-link-text path)))
3977 (unless desc
3978 (setq desc (let ((number (org-export-get-ordinal
3979 destination info)))
3980 (when number
3981 (if (atom number) (number-to-string number)
3982 (mapconcat 'number-to-string number "."))))))
3983 (org-e-odt-format-internal-link (or desc "FIXME") path))))))
3984 ;; Coderef: replace link with the reference name or the
3985 ;; equivalent line number.
3986 ((string= type "coderef")
3987 (let* ((fmt (org-export-get-coderef-format path (or desc "%s")))
3988 (res (org-export-resolve-coderef path info))
3989 (org-e-odt-suppress-xref nil)
3990 (href (org-xml-format-href (concat "#coderef-" path))))
3991 (format fmt (org-e-odt-format-link res href))))
3992 ;; Link type is handled by a special function.
3993 ((functionp (setq protocol (nth 2 (assoc type org-link-protocols))))
3994 (funcall protocol (org-link-unescape path) desc 'html))
3995 ;; External link with a description part.
3996 ((and path desc) (org-e-odt-format-link desc path))
3997 ;; External link without a description part.
3998 (path (org-e-odt-format-link path path))
3999 ;; No path, only description. Try to do something useful.
4000 (t (org-e-odt-format-fontify desc 'emphasis)))))
4003 ;;;; Babel Call
4005 ;; Babel Calls are ignored.
4008 ;;;; Macro
4010 (defun org-e-odt-macro (macro contents info)
4011 "Transcode a MACRO element from Org to HTML.
4012 CONTENTS is nil. INFO is a plist holding contextual information."
4013 ;; Use available tools.
4014 (org-export-expand-macro macro info))
4017 ;;;; Paragraph
4019 (defun org-e-odt-paragraph (paragraph contents info)
4020 "Transcode a PARAGRAPH element from Org to HTML.
4021 CONTENTS is the contents of the paragraph, as a string. INFO is
4022 the plist used as a communication channel."
4023 (let* ((style nil) ; FIXME
4024 (class (cdr (assoc style '((footnote . "footnote")
4025 (verse . nil)))))
4026 (extra (if class (format " class=\"%s\"" class) ""))
4027 (parent (org-export-get-parent paragraph info))
4028 (parent-type (org-element-type parent))
4029 (style (case parent-type
4030 (quote-block 'quote)
4031 (center-block 'center)
4032 (t nil))))
4033 (org-e-odt-format-stylized-paragraph style contents)))
4036 ;;;; Plain List
4038 (defun org-e-odt-plain-list (plain-list contents info)
4039 "Transcode a PLAIN-LIST element from Org to HTML.
4040 CONTENTS is the contents of the list. INFO is a plist holding
4041 contextual information."
4042 (let* (arg1 ;; FIXME
4043 (type (org-element-property :type plain-list))
4044 (attr (mapconcat #'identity
4045 (org-element-property :attr_odt plain-list)
4046 " ")))
4047 (org-e-odt--wrap-label
4048 plain-list (format "%s\n%s%s"
4049 (org-e-odt-begin-plain-list type)
4050 contents (org-e-odt-end-plain-list type)))))
4052 ;;;; Plain Text
4054 (defun org-e-odt-convert-special-strings (string)
4055 "Convert special characters in STRING to ODT."
4056 (let ((all org-export-e-odt-special-string-regexps)
4057 e a re rpl start)
4058 (while (setq a (pop all))
4059 (setq re (car a) rpl (cdr a) start 0)
4060 (while (string-match re string start)
4061 (setq string (replace-match rpl t nil string))))
4062 string))
4064 ;; (defun org-e-odt-encode-plain-text (s)
4065 ;; "Convert plain text characters to HTML equivalent.
4066 ;; Possible conversions are set in `org-export-html-protect-char-alist'."
4067 ;; (let ((cl org-e-odt-protect-char-alist) c)
4068 ;; (while (setq c (pop cl))
4069 ;; (let ((start 0))
4070 ;; (while (string-match (car c) s start)
4071 ;; (setq s (replace-match (cdr c) t t s)
4072 ;; start (1+ (match-beginning 0))))))
4073 ;; s))
4075 (defun org-e-odt-plain-text (text info)
4076 "Transcode a TEXT string from Org to HTML.
4077 TEXT is the string to transcode. INFO is a plist holding
4078 contextual information."
4079 (setq text (org-e-odt-encode-plain-text text t))
4080 ;; Protect %, #, &, $, ~, ^, _, { and }.
4081 ;; (while (string-match "\\([^\\]\\|^\\)\\([%$#&{}~^_]\\)" text)
4082 ;; (setq text
4083 ;; (replace-match (format "\\%s" (match-string 2 text)) nil t text 2)))
4084 ;; Protect \
4085 ;; (setq text (replace-regexp-in-string
4086 ;; "\\(?:[^\\]\\|^\\)\\(\\\\\\)\\(?:[^%$#&{}~^_\\]\\|$\\)"
4087 ;; "$\\backslash$" text nil t 1))
4088 ;; HTML into \HTML{} and TeX into \TeX{}.
4089 ;; (let ((case-fold-search nil)
4090 ;; (start 0))
4091 ;; (while (string-match "\\<\\(\\(?:La\\)?TeX\\)\\>" text start)
4092 ;; (setq text (replace-match
4093 ;; (format "\\%s{}" (match-string 1 text)) nil t text)
4094 ;; start (match-end 0))))
4095 ;; Handle quotation marks
4096 ;; (setq text (org-e-odt--quotation-marks text info))
4097 ;; Convert special strings.
4098 ;; (when (plist-get info :with-special-strings)
4099 ;; (while (string-match (regexp-quote "...") text)
4100 ;; (setq text (replace-match "\\ldots{}" nil t text))))
4101 (when (plist-get info :with-special-strings)
4102 (setq text (org-e-odt-convert-special-strings text)))
4103 ;; Handle break preservation if required.
4104 (when (plist-get info :preserve-breaks)
4105 (setq text (replace-regexp-in-string "\\(\\\\\\\\\\)?[ \t]*\n" " \\\\\\\\\n"
4106 text)))
4107 ;; Return value.
4108 text)
4111 ;;;; Property Drawer
4113 (defun org-e-odt-property-drawer (property-drawer contents info)
4114 "Transcode a PROPERTY-DRAWER element from Org to HTML.
4115 CONTENTS is nil. INFO is a plist holding contextual
4116 information."
4117 ;; The property drawer isn't exported but we want separating blank
4118 ;; lines nonetheless.
4122 ;;;; Quote Block
4124 (defun org-e-odt-quote-block (quote-block contents info)
4125 "Transcode a QUOTE-BLOCK element from Org to HTML.
4126 CONTENTS holds the contents of the block. INFO is a plist
4127 holding contextual information."
4128 (org-e-odt--wrap-label quote-block contents))
4131 ;;;; Quote Section
4133 (defun org-e-odt-quote-section (quote-section contents info)
4134 "Transcode a QUOTE-SECTION element from Org to HTML.
4135 CONTENTS is nil. INFO is a plist holding contextual information."
4136 (let ((value (org-remove-indentation
4137 (org-element-property :value quote-section))))
4138 (when value (org-e-odt-format-source-code-or-example value nil))))
4141 ;;;; Section
4143 (defun org-e-odt-section (section contents info) ; FIXME
4144 "Transcode a SECTION element from Org to HTML.
4145 CONTENTS holds the contents of the section. INFO is a plist
4146 holding contextual information."
4147 contents)
4149 ;;;; Radio Target
4151 (defun org-e-odt-radio-target (radio-target text info)
4152 "Transcode a RADIO-TARGET object from Org to HTML.
4153 TEXT is the text of the target. INFO is a plist holding
4154 contextual information."
4155 (org-e-odt-format-anchor
4156 text (org-export-solidify-link-text
4157 (org-element-property :raw-value radio-target))))
4160 ;;;; Special Block
4162 (defun org-e-odt-special-block (special-block contents info)
4163 "Transcode a SPECIAL-BLOCK element from Org to HTML.
4164 CONTENTS holds the contents of the block. INFO is a plist
4165 holding contextual information."
4166 (let ((type (downcase (org-element-property :type special-block))))
4167 (org-e-odt--wrap-label
4168 special-block
4169 (format "\\begin{%s}\n%s\\end{%s}" type contents type))))
4172 ;;;; Src Block
4174 (defun org-e-odt-src-block (src-block contents info)
4175 "Transcode a SRC-BLOCK element from Org to HTML.
4176 CONTENTS holds the contents of the item. INFO is a plist holding
4177 contextual information."
4178 (let* ((lang (org-element-property :language src-block))
4179 (caption (org-element-property :caption src-block))
4180 (label (org-element-property :name src-block)))
4181 ;; FIXME: Handle caption
4183 ;; caption-str (when caption)
4184 ;; (main (org-export-secondary-string (car caption) 'e-odt info))
4185 ;; (secondary (org-export-secondary-string (cdr caption) 'e-odt info))
4186 ;; (caption-str (org-e-odt--caption/label-string caption label info))
4187 (org-e-odt-format-code src-block info)))
4190 ;;;; Statistics Cookie
4192 (defun org-e-odt-statistics-cookie (statistics-cookie contents info)
4193 "Transcode a STATISTICS-COOKIE object from Org to HTML.
4194 CONTENTS is nil. INFO is a plist holding contextual information."
4195 (let ((cookie-value (org-element-property :value statistics-cookie)))
4196 (org-e-odt-format-fontify cookie-value 'code)))
4199 ;;;; Subscript
4201 (defun org-e-odt-subscript (subscript contents info)
4202 "Transcode a SUBSCRIPT object from Org to HTML.
4203 CONTENTS is the contents of the object. INFO is a plist holding
4204 contextual information."
4205 ;; (format (if (= (length contents) 1) "$_%s$" "$_{\\mathrm{%s}}$") contents)
4206 (org-e-odt-format-fontify contents 'subscript))
4209 ;;;; Superscript
4211 (defun org-e-odt-superscript (superscript contents info)
4212 "Transcode a SUPERSCRIPT object from Org to HTML.
4213 CONTENTS is the contents of the object. INFO is a plist holding
4214 contextual information."
4215 ;; (format (if (= (length contents) 1) "$^%s$" "$^{\\mathrm{%s}}$") contents)
4216 (org-e-odt-format-fontify contents 'superscript))
4219 ;;;; Table
4221 (defun org-e-odt-get-colwidth (c)
4222 (let ((col-widths (plist-get table-info :width)))
4223 (or (and org-lparse-table-is-styled (aref col-widths c)) 0)))
4225 (defun org-e-odt-table-row (fields &optional text-for-empty-fields)
4226 (incf org-e-odt-table-rownum)
4227 (let ((i -1))
4228 (org-e-odt-format-table-row
4229 (mapconcat
4230 (lambda (x)
4231 (when (and (string= x "") text-for-empty-fields)
4232 (setq x text-for-empty-fields))
4233 (incf i)
4234 (let ((horiz-span (org-e-odt-get-colwidth i)))
4235 (org-e-odt-format-table-cell
4236 x org-e-odt-table-rownum i horiz-span)))
4237 fields "\n"))))
4239 (defun org-e-odt-table-preamble ()
4240 (let ((colgroup-vector (plist-get table-info :column-groups)) ;; FIXME
4241 c gr colgropen preamble)
4242 (unless (aref colgroup-vector 0)
4243 (setf (aref colgroup-vector 0) 'start))
4244 (dotimes (c columns-number preamble)
4245 (setq gr (aref colgroup-vector c))
4246 (setq preamble
4247 (concat
4248 preamble
4249 (when (memq gr '(start start-end))
4250 (prog1 (if colgropen "</colgroup>\n<colgroup>" "\n<colgroup>")
4251 (setq colgropen t)))
4252 (let* ((colalign-vector (plist-get table-info :alignment)) ;; FIXME
4253 (align (cdr (assoc (aref colalign-vector c)
4254 '(("l" . "left")
4255 ("r" . "right")
4256 ("c" . "center")))))
4257 (alignspec (if (and (boundp 'org-e-odt-format-table-no-css)
4258 org-e-odt-format-table-no-css)
4259 " align=\"%s\"" " class=\"%s\""))
4260 (extra (format alignspec align)))
4261 (format "<col%s />" extra))
4262 (when (memq gr '(end start-end))
4263 (setq colgropen nil)
4264 "</colgroup>"))))
4265 (concat preamble (if colgropen "</colgroup>"))))
4267 (defun org-e-odt-list-table (lines caption label attributes)
4268 (setq lines (org-e-odt-org-table-to-list-table lines))
4269 (let* ((splice nil) head
4270 (org-e-odt-table-rownum -1)
4271 i (cnt 0)
4272 fields line
4273 org-e-odt-table-cur-rowgrp-is-hdr
4274 org-e-odt-table-rowgrp-open
4276 (org-lparse-table-style 'org-table)
4277 org-lparse-table-is-styled)
4278 (cond
4279 (splice
4280 (setq org-lparse-table-is-styled nil)
4281 (mapconcat 'org-e-odt-table-row lines "\n"))
4283 (setq org-lparse-table-is-styled t)
4285 (concat
4286 (org-e-odt-begin-table caption label attributes)
4287 ;; FIXME (org-e-odt-table-preamble)
4288 (org-e-odt-begin-table-rowgroup head)
4290 (mapconcat
4291 (lambda (line)
4292 (cond
4293 ((equal line 'hline) (org-e-odt-begin-table-rowgroup))
4294 (t (org-e-odt-table-row line))))
4295 lines "\n")
4297 (org-e-odt-end-table-rowgroup)
4298 (org-e-odt-end-table))))))
4300 (defun org-e-odt-transcode-table-row (row)
4301 (if (string-match org-table-hline-regexp row) 'hline
4302 (mapcar
4303 (lambda (cell)
4304 (org-export-secondary-string
4305 (let ((cell (org-element-parse-secondary-string
4306 cell
4307 (cdr (assq 'table org-element-string-restrictions)))))
4308 cell)
4309 'e-odt info))
4310 (org-split-string row "[ \t]*|[ \t]*"))))
4312 (defun org-e-odt-org-table-to-list-table (lines &optional splice)
4313 "Convert org-table to list-table.
4314 LINES is a list of the form (ROW1 ROW2 ROW3 ...) where each
4315 element is a `string' representing a single row of org-table.
4316 Thus each ROW has vertical separators \"|\" separating the table
4317 fields. A ROW could also be a row-group separator of the form
4318 \"|---...|\". Return a list of the form (ROW1 ROW2 ROW3
4319 ...). ROW could either be symbol `'hline' or a list of the
4320 form (FIELD1 FIELD2 FIELD3 ...) as appropriate."
4321 (let (line lines-1)
4322 (cond
4323 (splice
4324 (while (setq line (pop lines))
4325 (unless (string-match "^[ \t]*|-" line)
4326 (push (org-e-odt-transcode-table-row line) lines-1))))
4327 (t (while (setq line (pop lines))
4328 (cond
4329 ((string-match "^[ \t]*|-" line)
4330 (when lines (push 'hline lines-1)))
4331 (t (push (org-e-odt-transcode-table-row line) lines-1))))))
4332 (nreverse lines-1)))
4334 (defun org-e-odt-table-table (raw-table)
4335 (require 'table)
4336 (with-current-buffer (get-buffer-create "*org-export-table*")
4337 (erase-buffer))
4338 (let ((output (with-temp-buffer
4339 (insert raw-table)
4340 (goto-char 1)
4341 (re-search-forward "^[ \t]*|[^|]" nil t)
4342 (table-generate-source 'html "*org-export-table*")
4343 (with-current-buffer "*org-export-table*"
4344 (org-trim (buffer-string))))))
4345 (kill-buffer (get-buffer "*org-export-table*"))
4346 output))
4348 (defun org-e-odt-table (table contents info)
4349 "Transcode a TABLE element from Org to HTML.
4350 CONTENTS is nil. INFO is a plist holding contextual information."
4351 (let* ((label (org-element-property :name table))
4352 (caption (org-e-odt--caption/label-string
4353 (org-element-property :caption table) label info))
4354 (attr (mapconcat #'identity
4355 (org-element-property :attr_odt table)
4356 " "))
4357 (raw-table (org-element-property :raw-table table))
4358 (table-type (org-element-property :type table)))
4359 (case table-type
4360 (table.el
4361 ;; (org-e-odt-table-table raw-table)
4364 (let* ((table-info (org-export-table-format-info raw-table))
4365 (columns-number (length (plist-get table-info :alignment)))
4366 (lines (org-split-string
4367 (org-export-clean-table
4368 raw-table (plist-get table-info :special-column-p)) "\n"))
4370 (genealogy (org-export-get-genealogy table info))
4371 (parent (car genealogy))
4372 (parent-type (org-element-type parent)))
4373 (org-e-odt-list-table lines caption label attr))))))
4376 ;;;; Target
4378 (defun org-e-odt-target (target contents info)
4379 "Transcode a TARGET object from Org to HTML.
4380 CONTENTS is nil. INFO is a plist holding contextual
4381 information."
4382 (org-e-odt-format-anchor
4383 "" (org-export-solidify-link-text (org-element-property :value target))))
4386 ;;;; Time-stamp
4388 (defun org-e-odt-time-stamp (time-stamp contents info)
4389 "Transcode a TIME-STAMP object from Org to HTML.
4390 CONTENTS is nil. INFO is a plist holding contextual
4391 information."
4392 ;; (let ((value (org-element-property :value time-stamp))
4393 ;; (type (org-element-property :type time-stamp))
4394 ;; (appt-type (org-element-property :appt-type time-stamp)))
4395 ;; (concat (cond ((eq appt-type 'scheduled)
4396 ;; (format "\\textbf{\\textsc{%s}} " org-scheduled-string))
4397 ;; ((eq appt-type 'deadline)
4398 ;; (format "\\textbf{\\textsc{%s}} " org-deadline-string))
4399 ;; ((eq appt-type 'closed)
4400 ;; (format "\\textbf{\\textsc{%s}} " org-closed-string)))
4401 ;; (cond ((memq type '(active active-range))
4402 ;; (format org-e-odt-active-timestamp-format value))
4403 ;; ((memq type '(inactive inactive-range))
4404 ;; (format org-e-odt-inactive-timestamp-format value))
4405 ;; (t
4406 ;; (format org-e-odt-diary-timestamp-format value)))))
4407 (let ((value (org-element-property :value time-stamp))
4408 (type (org-element-property :type time-stamp))
4409 (appt-type (org-element-property :appt-type time-stamp)))
4410 (setq value (org-export-secondary-string value 'e-odt info))
4411 (org-e-odt-format-fontify
4412 (concat
4413 (org-e-odt-format-fontify
4414 (cond ((eq appt-type 'scheduled) org-scheduled-string)
4415 ((eq appt-type 'deadline) org-deadline-string)
4416 ((eq appt-type 'closed) org-closed-string)) "timestamp-kwd")
4417 ;; FIXME: (org-translate-time value)
4418 (org-e-odt-format-fontify value "timestamp"))
4419 "timestamp-wrapper")))
4422 ;;;; Verbatim
4424 (defun org-e-odt-verbatim (verbatim contents info)
4425 "Transcode a VERBATIM object from Org to HTML.
4426 CONTENTS is nil. INFO is a plist used as a communication
4427 channel."
4428 (org-e-odt-emphasis
4429 verbatim (org-element-property :value verbatim) info))
4432 ;;;; Verse Block
4434 (defun org-e-odt-verse-block (verse-block contents info)
4435 "Transcode a VERSE-BLOCK element from Org to HTML.
4436 CONTENTS is nil. INFO is a plist holding contextual information."
4437 ;; Replace each newline character with line break. Also replace
4438 ;; each blank line with a line break.
4439 (setq contents (replace-regexp-in-string
4440 "^ *\\\\\\\\$" "<br/>\n"
4441 (replace-regexp-in-string
4442 "\\(\\\\\\\\\\)?[ \t]*\n" " <br/>\n"
4443 (org-remove-indentation
4444 (org-export-secondary-string
4445 (org-element-property :value verse-block)
4446 'e-odt info)))))
4448 ;; Replace each white space at beginning of a line with a
4449 ;; non-breaking space.
4450 (while (string-match "^[ \t]+" contents)
4451 (let ((new-str (org-e-odt-format-spaces
4452 (length (match-string 0 contents)))))
4453 (setq contents (replace-match new-str nil t contents))))
4455 (org-e-odt--wrap-label
4456 verse-block (format "<p class=\"verse\">\n%s</p>" contents)))
4461 ;;; Filter Functions
4463 ;;;; Filter Settings
4464 ;;;; Filters
4466 ;;; Interactive functions
4468 (defun org-e-odt-export-to-odt
4469 (&optional subtreep visible-only body-only ext-plist pub-dir)
4470 "Export current buffer to a HTML file.
4472 If narrowing is active in the current buffer, only export its
4473 narrowed part.
4475 If a region is active, export that region.
4477 When optional argument SUBTREEP is non-nil, export the sub-tree
4478 at point, extracting information from the headline properties
4479 first.
4481 When optional argument VISIBLE-ONLY is non-nil, don't export
4482 contents of hidden elements.
4484 When optional argument BODY-ONLY is non-nil, only write code
4485 between \"\\begin{document}\" and \"\\end{document}\".
4487 EXT-PLIST, when provided, is a property list with external
4488 parameters overriding Org default settings, but still inferior to
4489 file-local settings.
4491 When optional argument PUB-DIR is set, use it as the publishing
4492 directory.
4494 Return output file's name."
4495 (interactive)
4497 ;; FIXME
4498 (with-current-buffer (get-buffer-create "*debug*")
4499 (erase-buffer))
4501 ;; (let* ((outfile (org-export-output-file-name ".html" subtreep pub-dir))
4502 ;; (outfile "content.xml"))
4503 ;; (org-export-to-file
4504 ;; 'e-odt outfile subtreep visible-only body-only ext-plist))
4506 (let* ((outbuf (org-e-odt-init-outfile))
4507 (target (org-export-output-file-name ".odt" subtreep pub-dir))
4508 (outdir (file-name-directory (buffer-file-name outbuf)))
4509 (default-directory outdir))
4511 ;; FIXME: for copying embedded images
4512 (setq org-current-export-file
4513 (file-name-directory
4514 (org-export-output-file-name ".odt" subtreep nil)))
4516 (org-export-to-buffer
4517 'e-odt outbuf
4518 (memq 'subtree optns) (memq 'visible optns) (memq 'body optns))
4520 (setq org-lparse-opt-plist nil) ; FIXME
4521 (org-e-odt-save-as-outfile target ;; info
4525 ;; return outfile
4526 target))
4531 ;;; FIXMES, TODOS, FOR REVIEW etc
4533 ;;;; org-format-table-html
4534 ;;;; org-format-org-table-html
4535 ;;;; org-format-table-table-html
4536 ;;;; org-table-number-fraction
4537 ;;;; org-table-number-regexp
4538 ;;;; org-e-odt-table-caption-above
4540 ;;;; org-whitespace
4541 ;;;; "<span style=\"visibility:hidden;\">%s</span>"
4542 ;;;; Remove display properties
4543 ;;;; org-e-odt-final-hook
4545 ;;;; org-e-odt-with-timestamp
4546 ;;;; org-e-odt-html-helper-timestamp
4548 ;;;; org-export-as-html-and-open
4549 ;;;; org-export-as-html-batch
4550 ;;;; org-export-as-html-to-buffer
4551 ;;;; org-replace-region-by-html
4552 ;;;; org-export-region-as-html
4553 ;;;; org-export-as-html
4555 ;;;; (org-export-directory :html opt-plist)
4556 ;;;; (plist-get opt-plist :html-extension)
4557 ;;;; org-e-odt-toplevel-hlevel
4558 ;;;; org-e-odt-special-string-regexps
4559 ;;;; org-e-odt-coding-system
4560 ;;;; org-e-odt-coding-system
4561 ;;;; org-e-odt-inline-images
4562 ;;;; org-e-odt-inline-image-extensions
4563 ;;;; org-e-odt-protect-char-alist
4564 ;;;; org-e-odt-table-use-header-tags-for-first-column
4565 ;;;; org-e-odt-todo-kwd-class-prefix
4566 ;;;; org-e-odt-tag-class-prefix
4567 ;;;; org-e-odt-footnote-separator
4570 ;;; Library Initializations
4572 (mapc
4573 (lambda (desc)
4574 ;; Let Org open all OpenDocument files using system-registered app
4575 (add-to-list 'org-file-apps
4576 (cons (concat "\\." (car desc) "\\'") 'system))
4577 ;; Let Emacs open all OpenDocument files in archive mode
4578 (add-to-list 'auto-mode-alist
4579 (cons (concat "\\." (car desc) "\\'") 'archive-mode)))
4580 org-e-odt-file-extensions)
4582 ;; FIXME
4583 ;; (eval-after-load 'org-exp
4584 ;; '(add-to-list 'org-export-inbuffer-options-extra
4585 ;; '("ODT_STYLES_FILE" :odt-styles-file)))
4587 (provide 'org-e-odt)
4589 ;;; org-e-odt.el ends here