Merge branch 'maint'
[org-mode.git] / EXPERIMENTAL / org-e-odt.el
blob9cbf9299e551caa0a9af79c613f7607b3e7022ff
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))
627 (defun org-e-odt-format-source-line-with-line-number-and-label
628 (line fontifier par-style)
629 (let (;; (keep-label (not (numberp rpllbl)))
630 (ref (org-find-text-property-in-string 'org-coderef line))
631 (num (org-find-text-property-in-string 'org-loc line)))
632 (setq line (concat line (and ref (format "(%s)" ref))))
633 (setq line (funcall fontifier line))
634 (when ref
635 (setq line (org-e-odt-format-target line (concat "coderef-" ref))))
636 (setq line (org-e-odt-format-stylized-paragraph par-style line))
637 (if (not num) line
638 (org-e-odt-format-tags
639 '("<text:list-item>" . "</text:list-item>") line))))
641 (defun org-e-odt-format-source-code-or-example-plain
642 (lines lang caption textareap cols rows num cont rpllbl fmt)
643 "Format source or example blocks much like fixedwidth blocks.
644 Use this when `org-export-e-odt-fontify-srcblocks' option is turned
645 off."
646 (let* ((lines (org-split-string lines "[\r\n]"))
647 (line-count (length lines))
648 (i 0))
649 (mapconcat
650 (lambda (line)
651 (incf i)
652 (org-e-odt-format-source-line-with-line-number-and-label
653 line 'org-e-odt-encode-plain-text
654 (if (= i line-count) "OrgFixedWidthBlockLastLine"
655 "OrgFixedWidthBlock")))
656 lines "\n")))
658 (defun org-e-odt-hfy-face-to-css (fn)
659 "Create custom style for face FN.
660 When FN is the default face, use it's foreground and background
661 properties to create \"OrgSrcBlock\" paragraph style. Otherwise
662 use it's color attribute to create a character style whose name
663 is obtained from FN. Currently all attributes of FN other than
664 color are ignored.
666 The style name for a face FN is derived using the following
667 operations on the face name in that order - de-dash, CamelCase
668 and prefix with \"OrgSrc\". For example,
669 `font-lock-function-name-face' is associated with
670 \"OrgSrcFontLockFunctionNameFace\"."
671 (let* ((css-list (hfy-face-to-style fn))
672 (style-name ((lambda (fn)
673 (concat "OrgSrc"
674 (mapconcat
675 'capitalize (split-string
676 (hfy-face-or-def-to-name fn) "-")
677 ""))) fn))
678 (color-val (cdr (assoc "color" css-list)))
679 (background-color-val (cdr (assoc "background" css-list)))
680 (style (and org-export-e-odt-create-custom-styles-for-srcblocks
681 (cond
682 ((eq fn 'default)
683 (format org-src-block-paragraph-format
684 background-color-val color-val))
686 (format
688 <style:style style:name=\"%s\" style:family=\"text\">
689 <style:text-properties fo:color=\"%s\"/>
690 </style:style>" style-name color-val))))))
691 (cons style-name style)))
693 (defun org-e-odt-insert-custom-styles-for-srcblocks (styles)
694 "Save STYLES used for colorizing of source blocks.
695 Update styles.xml with styles that were collected as part of
696 `org-e-odt-hfy-face-to-css' callbacks."
697 (when styles
698 (with-current-buffer
699 (find-file-noselect (expand-file-name "styles.xml") t)
700 (goto-char (point-min))
701 (when (re-search-forward "</office:styles>" nil t)
702 (goto-char (match-beginning 0))
703 (insert "\n<!-- Org Htmlfontify Styles -->\n" styles "\n")))))
705 (defun org-e-odt-format-source-code-or-example-colored (lines lang caption)
706 "Format source or example blocks using `htmlfontify-string'.
707 Use this routine when `org-export-e-odt-fontify-srcblocks' option
708 is turned on."
709 (let* ((lang-m (and lang (or (cdr (assoc lang org-src-lang-modes)) lang)))
710 (mode (and lang-m (intern (concat (if (symbolp lang-m)
711 (symbol-name lang-m)
712 lang-m) "-mode"))))
713 (org-inhibit-startup t)
714 (org-startup-folded nil)
715 (lines (with-temp-buffer
716 (insert lines)
717 (if (functionp mode) (funcall mode) (fundamental-mode))
718 (font-lock-fontify-buffer)
719 (buffer-string)))
720 (hfy-html-quote-regex "\\([<\"&> ]\\)")
721 (hfy-html-quote-map '(("\"" "&quot;")
722 ("<" "&lt;")
723 ("&" "&amp;")
724 (">" "&gt;")
725 (" " "<text:s/>")
726 (" " "<text:tab/>")))
727 (hfy-face-to-css 'org-e-odt-hfy-face-to-css)
728 (hfy-optimisations-1 (copy-seq hfy-optimisations))
729 (hfy-optimisations (add-to-list 'hfy-optimisations-1
730 'body-text-only))
731 (hfy-begin-span-handler
732 (lambda (style text-block text-id text-begins-block-p)
733 (insert (format "<text:span text:style-name=\"%s\">" style))))
734 (hfy-end-span-handler (lambda nil (insert "</text:span>"))))
735 (when (fboundp 'htmlfontify-string)
736 (let* ((lines (org-split-string lines "[\r\n]"))
737 (line-count (length lines))
738 (i 0))
739 (mapconcat
740 (lambda (line)
741 (incf i)
742 (org-e-odt-format-source-line-with-line-number-and-label
743 line 'htmlfontify-string
744 (if (= i line-count) "OrgSrcBlockLastLine" "OrgSrcBlock")))
745 lines "\n")))))
747 (defun org-e-odt-format-source-code-or-example (lines lang
748 &optional caption ; FIXME
750 "Format source or example blocks for export.
751 Use `org-e-odt-format-source-code-or-example-plain' or
752 `org-e-odt-format-source-code-or-example-colored' depending on the
753 value of `org-export-e-odt-fontify-srcblocks."
754 (setq ;; lines (org-export-number-lines
755 ;; lines 0 0 num cont rpllbl fmt 'preprocess) FIXME
756 lines (funcall
757 (or (and org-export-e-odt-fontify-srcblocks
758 (or (featurep 'htmlfontify)
759 ;; htmlfontify.el was introduced in Emacs 23.2
760 ;; So load it with some caution
761 (require 'htmlfontify nil t))
762 (fboundp 'htmlfontify-string)
763 'org-e-odt-format-source-code-or-example-colored)
764 'org-e-odt-format-source-code-or-example-plain)
765 lines lang caption))
766 (let ((num (org-find-text-property-in-string 'org-loc lines)))
767 (if (not num) lines
768 (let* ((cont (not (equal num 1)))
769 (extra (format " text:continue-numbering=\"%s\""
770 (if cont "true" "false"))))
771 (org-e-odt-format-tags
772 '("<text:list text:style-name=\"OrgSrcBlockNumberedLine\"%s>"
773 . "</text:list>") lines extra)))))
775 (defun org-e-odt-remap-stylenames (style-name)
777 (cdr (assoc style-name '(("timestamp-wrapper" . "OrgTimestampWrapper")
778 ("timestamp" . "OrgTimestamp")
779 ("timestamp-kwd" . "OrgTimestampKeyword")
780 ("tag" . "OrgTag")
781 ("todo" . "OrgTodo")
782 ("done" . "OrgDone")
783 ("target" . "OrgTarget"))))
784 style-name))
786 (defun org-e-odt-format-fontify (text style &optional id)
787 (let* ((style-name
788 (cond
789 ((stringp style)
790 (org-e-odt-remap-stylenames style))
791 ((symbolp style)
792 (org-e-odt-get-style-name-for-entity 'character style))
793 ((listp style)
794 (assert (< 1 (length style)))
795 (let ((parent-style (pop style)))
796 (mapconcat (lambda (s)
797 ;; (assert (stringp s) t)
798 (org-e-odt-remap-stylenames s)) style "")
799 (org-e-odt-remap-stylenames parent-style)))
800 (t (error "Don't how to handle style %s" style)))))
801 (org-e-odt-format-tags
802 '("<text:span text:style-name=\"%s\">" . "</text:span>")
803 text style-name)))
805 (defun org-e-odt-relocate-relative-path (path dir)
806 (if (file-name-absolute-p path) path
807 (file-relative-name (expand-file-name path dir)
808 (expand-file-name "eyecandy" dir))))
810 (defun org-e-odt-format-inline-image (thefile
811 &optional caption label attrs ; FIXME - CLA
813 (let* ((thelink (if (file-name-absolute-p thefile) thefile
814 (org-xml-format-href
815 (org-e-odt-relocate-relative-path
816 thefile org-current-export-file))))
817 (href
818 (org-e-odt-format-tags
819 "<draw:image xlink:href=\"%s\" xlink:type=\"simple\" xlink:show=\"embed\" xlink:actuate=\"onLoad\"/>" ""
820 (if org-export-e-odt-embed-images
821 (org-e-odt-copy-image-file thefile) thelink))))
822 (org-export-e-odt-format-image thefile href)))
824 (defun org-export-e-odt-format-formula (src href)
825 (save-match-data
826 (let* ((caption (org-find-text-property-in-string 'org-caption src))
827 (caption (and caption (org-xml-format-desc caption)))
828 (label (org-find-text-property-in-string 'org-label src))
829 (latex-frag (org-find-text-property-in-string 'org-latex-src src))
830 (embed-as (or (and latex-frag
831 (org-find-text-property-in-string
832 'org-latex-src-embed-type src))
833 (if (or caption label) 'paragraph 'character)))
834 width height)
835 (when latex-frag
836 (setq href (org-propertize href :title "LaTeX Fragment"
837 :description latex-frag)))
838 (cond
839 ((eq embed-as 'character)
840 (org-e-odt-format-entity "InlineFormula" href width height))
842 (org-lparse-end-paragraph)
843 (org-lparse-insert-list-table
844 `((,(org-e-odt-format-entity
845 (if caption "CaptionedDisplayFormula" "DisplayFormula")
846 href width height :caption caption :label nil)
847 ,(if (not label) ""
848 (org-e-odt-format-entity-caption label nil "__MathFormula__"))))
849 nil nil nil ":style \"OrgEquation\"" nil '((1 "c" 8) (2 "c" 1)))
850 (throw 'nextline nil))))))
852 (defun org-e-odt-copy-formula-file (path)
853 "Returns the internal name of the file"
854 (let* ((src-file (expand-file-name
855 path (file-name-directory org-current-export-file)))
856 (target-dir (format "Formula-%04d/"
857 (incf org-e-odt-embedded-formulas-count)))
858 (target-file (concat target-dir "content.xml")))
859 (message "Embedding %s as %s ..."
860 (substring-no-properties path) target-file)
862 (make-directory target-dir)
863 (org-e-odt-create-manifest-file-entry
864 "application/vnd.oasis.opendocument.formula" target-dir "1.2")
866 (case (org-e-odt-is-formula-link-p src-file)
867 (mathml
868 (copy-file src-file target-file 'overwrite))
869 (odf
870 (org-e-odt-zip-extract-one src-file "content.xml" target-dir))
872 (error "%s is not a formula file" src-file)))
874 (org-e-odt-create-manifest-file-entry "text/xml" target-file)
875 target-file))
877 (defun org-e-odt-format-inline-formula (thefile)
878 (let* ((thelink (if (file-name-absolute-p thefile) thefile
879 (org-xml-format-href
880 (org-e-odt-relocate-relative-path
881 thefile org-current-export-file))))
882 (href
883 (org-e-odt-format-tags
884 "<draw:object xlink:href=\"%s\" xlink:type=\"simple\" xlink:show=\"embed\" xlink:actuate=\"onLoad\"/>" ""
885 (file-name-directory (org-e-odt-copy-formula-file thefile)))))
886 (org-export-e-odt-format-formula thefile href)))
888 (defun org-e-odt-is-formula-link-p (file)
889 (let ((case-fold-search nil))
890 (cond
891 ((string-match "\\.\\(mathml\\|mml\\)\\'" file)
892 'mathml)
893 ((string-match "\\.odf\\'" file)
894 'odf))))
896 (defun org-e-odt-format-org-link (opt-plist type-1 path fragment desc attr
897 descp)
898 "Make a OpenDocument link.
899 OPT-PLIST is an options list.
900 TYPE-1 is the device-type of the link (THIS://foo.html).
901 PATH is the path of the link (http://THIS#location).
902 FRAGMENT is the fragment part of the link, if any (foo.html#THIS).
903 DESC is the link description, if any.
904 ATTR is a string of other attributes of the a element."
905 (declare (special org-lparse-par-open))
906 (save-match-data
907 (let* ((may-inline-p
908 (and (member type-1 '("http" "https" "file"))
909 (org-lparse-should-inline-p path descp)
910 (not fragment)))
911 (type (if (equal type-1 "id") "file" type-1))
912 (filename path)
913 (thefile path))
914 (cond
915 ;; check for inlined images
916 ((and (member type '("file"))
917 (not fragment)
918 (org-file-image-p
919 filename org-export-e-odt-inline-image-extensions)
920 (or (eq t org-export-e-odt-inline-images)
921 (and org-export-e-odt-inline-images (not descp))))
922 (org-e-odt-format-inline-image thefile))
923 ;; check for embedded formulas
924 ((and (member type '("file"))
925 (not fragment)
926 (org-e-odt-is-formula-link-p filename)
927 (or (not descp)))
928 (org-e-odt-format-inline-formula thefile))
929 ((string= type "coderef")
930 (let* ((ref fragment)
931 (lineno-or-ref (cdr (assoc ref org-export-code-refs)))
932 (desc (and descp desc))
933 (org-e-odt-suppress-xref nil)
934 (href (org-xml-format-href (concat "#coderef-" ref))))
935 (cond
936 ((and (numberp lineno-or-ref) (not desc))
937 (org-e-odt-format-link lineno-or-ref href))
938 ((and (numberp lineno-or-ref) desc
939 (string-match (regexp-quote (concat "(" ref ")")) desc))
940 (format (replace-match "%s" t t desc)
941 (org-e-odt-format-link lineno-or-ref href)))
943 (setq desc (format
944 (if (and desc (string-match
945 (regexp-quote (concat "(" ref ")"))
946 desc))
947 (replace-match "%s" t t desc)
948 (or desc "%s"))
949 lineno-or-ref))
950 (org-e-odt-format-link (org-xml-format-desc desc) href)))))
952 (when (string= type "file")
953 (setq thefile
954 (cond
955 ((file-name-absolute-p path)
956 (concat "file://" (expand-file-name path)))
957 (t (org-e-odt-relocate-relative-path
958 thefile org-current-export-file)))))
960 (when (and (member type '("" "http" "https" "file")) fragment)
961 (setq thefile (concat thefile "#" fragment)))
963 (setq thefile (org-xml-format-href thefile))
965 (when (not (member type '("" "file")))
966 (setq thefile (concat type ":" thefile)))
968 (let ((org-e-odt-suppress-xref nil))
969 (org-e-odt-format-link
970 (org-xml-format-desc desc) thefile attr)))))))
972 (defun org-e-odt-format-heading (text level &optional id)
973 (let* ((text (if id (org-e-odt-format-target text id) text)))
974 (org-e-odt-format-tags
975 '("<text:h text:style-name=\"Heading_20_%s\" text:outline-level=\"%s\">" .
976 "</text:h>") text level level)))
978 (defun org-e-odt-format-headline (title extra-targets tags
979 &optional snumber level)
980 (concat
981 (org-e-odt-format-extra-targets extra-targets)
983 ;; No need to generate section numbers. They are auto-generated by
984 ;; the application
986 ;; (concat (org-lparse-format 'SECTION-NUMBER snumber level) " ")
987 title
988 (and tags (concat (org-e-odt-format-spaces 3)
989 (org-e-odt-format-org-tags tags)))))
991 (defun org-e-odt-format-anchor (text name &optional class)
992 (org-e-odt-format-target text name))
994 (defun org-e-odt-format-bookmark (text id)
995 (if id
996 (org-e-odt-format-tags "<text:bookmark text:name=\"%s\"/>" text id)
997 text))
999 (defun org-e-odt-format-target (text id)
1000 (let ((name (concat org-export-e-odt-bookmark-prefix id)))
1001 (concat
1002 (and id (org-e-odt-format-tags
1003 "<text:bookmark-start text:name=\"%s\"/>" "" name))
1004 (org-e-odt-format-bookmark text id)
1005 (and id (org-e-odt-format-tags
1006 "<text:bookmark-end text:name=\"%s\"/>" "" name)))))
1008 (defun org-e-odt-format-footnote (n def)
1009 (setq n (format "%d" n))
1010 (let ((id (concat "fn" n))
1011 (note-class "footnote")
1012 (par-style "Footnote"))
1013 (org-e-odt-format-tags
1014 '("<text:note text:id=\"%s\" text:note-class=\"%s\">" .
1015 "</text:note>")
1016 (concat
1017 (org-e-odt-format-tags
1018 '("<text:note-citation>" . "</text:note-citation>")
1020 (org-e-odt-format-tags
1021 '("<text:note-body>" . "</text:note-body>")
1022 def))
1023 id note-class)))
1025 (defun org-e-odt-format-footnote-reference (n def refcnt)
1026 (if (= refcnt 1)
1027 (org-e-odt-format-footnote n def)
1028 (org-e-odt-format-footnote-ref n)))
1030 (defun org-e-odt-format-footnote-ref (n)
1031 (setq n (format "%d" n))
1032 (let ((note-class "footnote")
1033 (ref-format "text")
1034 (ref-name (concat "fn" n)))
1035 (org-e-odt-format-tags
1036 '("<text:span text:style-name=\"%s\">" . "</text:span>")
1037 (org-e-odt-format-tags
1038 '("<text:note-ref text:note-class=\"%s\" text:reference-format=\"%s\" text:ref-name=\"%s\">" . "</text:note-ref>")
1039 n note-class ref-format ref-name)
1040 "OrgSuperscript")))
1042 (defun org-e-odt-get-image-name (file-name)
1043 (require 'sha1)
1044 (file-relative-name
1045 (expand-file-name
1046 (concat (sha1 file-name) "." (file-name-extension file-name)) "Pictures")))
1048 (defun org-export-e-odt-format-image (src href)
1049 "Create image tag with source and attributes."
1050 (save-match-data
1051 (let* ((caption (org-find-text-property-in-string 'org-caption src))
1052 (caption (and caption (org-xml-format-desc caption)))
1053 (attr (org-find-text-property-in-string 'org-attributes src))
1054 (label (org-find-text-property-in-string 'org-label src))
1055 (latex-frag (org-find-text-property-in-string
1056 'org-latex-src src))
1057 (category (and latex-frag "__DvipngImage__"))
1058 (attr-plist (org-lparse-get-block-params attr))
1059 (user-frame-anchor
1060 (car (assoc-string (plist-get attr-plist :anchor)
1061 '(("as-char") ("paragraph") ("page")) t)))
1062 (user-frame-style
1063 (and user-frame-anchor (plist-get attr-plist :style)))
1064 (user-frame-attrs
1065 (and user-frame-anchor (plist-get attr-plist :attributes)))
1066 (user-frame-params
1067 (list user-frame-style user-frame-attrs user-frame-anchor))
1068 (embed-as (cond
1069 (latex-frag
1070 (symbol-name
1071 (case (org-find-text-property-in-string
1072 'org-latex-src-embed-type src)
1073 (paragraph 'paragraph)
1074 (t 'as-char))))
1075 (user-frame-anchor)
1076 (t "paragraph")))
1077 (size (org-e-odt-image-size-from-file
1078 src (plist-get attr-plist :width)
1079 (plist-get attr-plist :height)
1080 (plist-get attr-plist :scale) nil embed-as))
1081 (width (car size)) (height (cdr size)))
1082 (when latex-frag
1083 (setq href (org-propertize href :title "LaTeX Fragment"
1084 :description latex-frag)))
1085 (let ((frame-style-handle (concat (and (or caption label) "Captioned")
1086 embed-as "Image")))
1087 (org-e-odt-format-entity
1088 frame-style-handle href width height
1089 :caption caption :label label :category category
1090 :user-frame-params user-frame-params)))))
1092 (defun org-e-odt-format-object-description (title description)
1093 (concat (and title (org-e-odt-format-tags
1094 '("<svg:title>" . "</svg:title>")
1095 (org-e-odt-encode-plain-text title t)))
1096 (and description (org-e-odt-format-tags
1097 '("<svg:desc>" . "</svg:desc>")
1098 (org-e-odt-encode-plain-text description t)))))
1100 (defun org-e-odt-format-frame (text width height style &optional
1101 extra anchor-type)
1102 (let ((frame-attrs
1103 (concat
1104 (if width (format " svg:width=\"%0.2fcm\"" width) "")
1105 (if height (format " svg:height=\"%0.2fcm\"" height) "")
1106 extra
1107 (format " text:anchor-type=\"%s\"" (or anchor-type "paragraph")))))
1108 (org-e-odt-format-tags
1109 '("<draw:frame draw:style-name=\"%s\"%s>" . "</draw:frame>")
1110 (concat text (org-e-odt-format-object-description
1111 (get-text-property 0 :title text)
1112 (get-text-property 0 :description text)))
1113 style frame-attrs)))
1115 (defun org-e-odt-format-textbox (text width height style &optional
1116 extra anchor-type)
1117 (org-e-odt-format-frame
1118 (org-e-odt-format-tags
1119 '("<draw:text-box %s>" . "</draw:text-box>")
1120 text (concat (format " fo:min-height=\"%0.2fcm\"" (or height .2))
1121 (unless width
1122 (format " fo:min-width=\"%0.2fcm\"" (or width .2)))))
1123 width nil style extra anchor-type))
1125 (defun org-e-odt-format-inlinetask (heading content
1126 &optional todo priority tags)
1127 (org-e-odt-format-stylized-paragraph
1128 nil (org-e-odt-format-textbox
1129 (concat (org-e-odt-format-stylized-paragraph
1130 "OrgInlineTaskHeading"
1131 (org-lparse-format
1132 'HEADLINE (concat (org-lparse-format-todo todo) " " heading)
1133 nil tags))
1134 content) nil nil "OrgInlineTaskFrame" " style:rel-width=\"100%\"")))
1137 (defun org-e-odt-merge-frame-params(default-frame-params user-frame-params)
1138 (if (not user-frame-params) default-frame-params
1139 (assert (= (length default-frame-params) 3))
1140 (assert (= (length user-frame-params) 3))
1141 (loop for user-frame-param in user-frame-params
1142 for default-frame-param in default-frame-params
1143 collect (or user-frame-param default-frame-param))))
1145 (defun* org-e-odt-format-entity (entity href width height
1146 &key caption label category
1147 user-frame-params)
1148 (let* ((entity-style (assoc-string entity org-e-odt-entity-frame-styles t))
1149 default-frame-params frame-params)
1150 (cond
1151 ((not (or caption label))
1152 (setq default-frame-params (nth 2 entity-style))
1153 (setq frame-params (org-e-odt-merge-frame-params
1154 default-frame-params user-frame-params))
1155 (apply 'org-e-odt-format-frame href width height frame-params))
1157 (setq default-frame-params (nth 3 entity-style))
1158 (setq frame-params (org-e-odt-merge-frame-params
1159 default-frame-params user-frame-params))
1160 (apply 'org-e-odt-format-textbox
1161 (org-e-odt-format-stylized-paragraph
1162 'illustration
1163 (concat
1164 (apply 'org-e-odt-format-frame href width height
1165 (nth 2 entity-style))
1166 (org-e-odt-format-entity-caption
1167 label caption (or category (nth 1 entity-style)))))
1168 width height frame-params)))))
1170 (defun org-e-odt-copy-image-file (path)
1171 "Returns the internal name of the file"
1172 (let* ((image-type (file-name-extension path))
1173 (media-type (format "image/%s" image-type))
1174 (src-file (expand-file-name
1175 path (file-name-directory org-current-export-file)))
1176 (target-dir "Images/")
1177 (target-file
1178 (format "%s%04d.%s" target-dir
1179 (incf org-e-odt-embedded-images-count) image-type)))
1180 (message "Embedding %s as %s ..."
1181 (substring-no-properties path) target-file)
1183 (when (= 1 org-e-odt-embedded-images-count)
1184 (make-directory target-dir)
1185 (org-e-odt-create-manifest-file-entry "" target-dir))
1187 (copy-file src-file target-file 'overwrite)
1188 (org-e-odt-create-manifest-file-entry media-type target-file)
1189 target-file))
1191 (defun org-e-odt-do-image-size (probe-method file &optional dpi anchor-type)
1192 (setq dpi (or dpi org-export-e-odt-pixels-per-inch))
1193 (setq anchor-type (or anchor-type "paragraph"))
1194 (flet ((size-in-cms (size-in-pixels)
1195 (flet ((pixels-to-cms (pixels)
1196 (let* ((cms-per-inch 2.54)
1197 (inches (/ pixels dpi)))
1198 (* cms-per-inch inches))))
1199 (and size-in-pixels
1200 (cons (pixels-to-cms (car size-in-pixels))
1201 (pixels-to-cms (cdr size-in-pixels)))))))
1202 (case probe-method
1203 (emacs
1204 (size-in-cms (ignore-errors ; Emacs could be in batch mode
1205 (clear-image-cache)
1206 (image-size (create-image file) 'pixels))))
1207 (imagemagick
1208 (size-in-cms
1209 (let ((dim (shell-command-to-string
1210 (format "identify -format \"%%w:%%h\" \"%s\"" file))))
1211 (when (string-match "\\([0-9]+\\):\\([0-9]+\\)" dim)
1212 (cons (string-to-number (match-string 1 dim))
1213 (string-to-number (match-string 2 dim)))))))
1215 (cdr (assoc-string anchor-type
1216 org-export-e-odt-default-image-sizes-alist))))))
1218 (defun org-e-odt-image-size-from-file (file &optional user-width
1219 user-height scale dpi embed-as)
1220 (unless (file-name-absolute-p file)
1221 (setq file (expand-file-name
1222 file (file-name-directory org-current-export-file))))
1223 (let* (size width height)
1224 (unless (and user-height user-width)
1225 (loop for probe-method in org-export-e-odt-image-size-probe-method
1226 until size
1227 do (setq size (org-e-odt-do-image-size
1228 probe-method file dpi embed-as)))
1229 (or size (error "Cannot determine Image size. Aborting ..."))
1230 (setq width (car size) height (cdr size)))
1231 (cond
1232 (scale
1233 (setq width (* width scale) height (* height scale)))
1234 ((and user-height user-width)
1235 (setq width user-width height user-height))
1236 (user-height
1237 (setq width (* user-height (/ width height)) height user-height))
1238 (user-width
1239 (setq height (* user-width (/ height width)) width user-width))
1240 (t (ignore)))
1241 ;; ensure that an embedded image fits comfortably within a page
1242 (let ((max-width (car org-export-e-odt-max-image-size))
1243 (max-height (cdr org-export-e-odt-max-image-size)))
1244 (when (or (> width max-width) (> height max-height))
1245 (let* ((scale1 (/ max-width width))
1246 (scale2 (/ max-height height))
1247 (scale (min scale1 scale2)))
1248 (setq width (* scale width) height (* scale height)))))
1249 (cons width height)))
1251 (defun org-e-odt-get-label-category-and-style (label default-category)
1252 "See `org-export-e-odt-get-category-from-label'."
1253 (let ((default-category-map
1254 (assoc default-category org-e-odt-category-map-alist))
1255 user-category user-category-map category)
1256 (cond
1257 ((not org-export-e-odt-get-category-from-label)
1258 default-category-map)
1259 ((not (setq user-category
1260 (save-match-data
1261 (and (string-match "\\`\\(.*\\):.+" label)
1262 (match-string 1 label)))))
1263 default-category-map)
1265 (setq user-category-map
1266 (or (assoc user-category org-e-odt-category-map-alist)
1267 (list nil user-category "category-and-value"))
1268 category (nth 1 user-category-map))
1269 (if (member category org-export-e-odt-user-categories)
1270 user-category-map
1271 default-category-map)))))
1273 (defun org-e-odt-add-label-definition (label default-category)
1274 "Create an entry in `org-e-odt-entity-labels-alist' and return it."
1275 (setq label (substring-no-properties label))
1276 (let* ((label-props (org-e-odt-get-label-category-and-style
1277 label default-category))
1278 (category (nth 1 label-props))
1279 (counter category)
1280 (label-style (nth 2 label-props))
1281 (sequence-var (intern (mapconcat
1282 'downcase
1283 (org-split-string counter) "-")))
1284 (seqno (1+ (or (plist-get org-e-odt-entity-counts-plist sequence-var)
1285 0)))
1286 (label-props (list label category seqno label-style)))
1287 (setq org-e-odt-entity-counts-plist
1288 (plist-put org-e-odt-entity-counts-plist sequence-var seqno))
1289 (push label-props org-e-odt-entity-labels-alist)
1290 label-props))
1292 (defun org-e-odt-format-label-definition (caption label category seqno label-style)
1293 (assert label)
1294 (format-spec
1295 (cadr (assoc-string label-style org-e-odt-label-styles t))
1296 `((?e . ,category)
1297 (?n . ,(org-e-odt-format-tags
1298 '("<text:sequence text:ref-name=\"%s\" text:name=\"%s\" text:formula=\"ooow:%s+1\" style:num-format=\"1\">" . "</text:sequence>")
1299 (format "%d" seqno) label category category))
1300 (?c . ,(or (and caption (concat ": " caption)) "")))))
1302 (defun org-e-odt-format-label-reference (label category seqno label-style)
1303 (assert label)
1304 (save-match-data
1305 (let* ((fmt (cddr (assoc-string label-style org-e-odt-label-styles t)))
1306 (fmt1 (car fmt))
1307 (fmt2 (cadr fmt)))
1308 (org-e-odt-format-tags
1309 '("<text:sequence-ref text:reference-format=\"%s\" text:ref-name=\"%s\">"
1310 . "</text:sequence-ref>")
1311 (format-spec fmt2 `((?e . ,category)
1312 (?n . ,(format "%d" seqno)))) fmt1 label))))
1314 (defun org-e-odt-fixup-label-references ()
1315 (goto-char (point-min))
1316 (while (re-search-forward
1317 "<text:sequence-ref text:ref-name=\"\\([^\"]+\\)\">[ \t\n]*</text:sequence-ref>"
1318 nil t)
1319 (let* ((label (match-string 1))
1320 (label-def (assoc label org-e-odt-entity-labels-alist))
1321 (rpl (and label-def
1322 (apply 'org-e-odt-format-label-reference label-def))))
1323 (if rpl (replace-match rpl t t)
1324 (org-lparse-warn
1325 (format "Unable to resolve reference to label \"%s\"" label))))))
1327 (defun org-e-odt-format-entity-caption (label caption category)
1328 (or (and label
1329 (apply 'org-e-odt-format-label-definition
1330 caption (org-e-odt-add-label-definition label category)))
1331 caption ""))
1333 (defun org-e-odt-format-tags-1 (tag text prefix suffix &rest args)
1334 (cond
1335 ((consp tag)
1336 (concat prefix (apply 'format (car tag) args) text suffix
1337 (format (cdr tag))))
1338 ((stringp tag) ; singleton tag
1339 (concat prefix (apply 'format tag args) text))))
1341 (defun org-e-odt-format-tags (tag text &rest args)
1342 (apply 'org-e-odt-format-tags-1 tag text "\n" "\n" args))
1344 (defun org-e-odt-format-tags-simple (tag text &rest args)
1345 (apply 'org-e-odt-format-tags-1 tag text nil nil args))
1347 (defun org-e-odt-init-outfile ()
1348 (unless (executable-find "zip")
1349 ;; Not at all OSes ship with zip by default
1350 (error "Executable \"zip\" needed for creating OpenDocument files"))
1352 (let* ((outdir (make-temp-file
1353 (format org-export-e-odt-tmpdir-prefix org-lparse-backend) t))
1354 (content-file (expand-file-name "content.xml" outdir)))
1356 ;; reset variables
1357 (setq org-e-odt-manifest-file-entries nil
1358 org-e-odt-embedded-images-count 0
1359 org-e-odt-embedded-formulas-count 0
1360 org-e-odt-section-count 0
1361 org-e-odt-entity-labels-alist nil
1362 org-e-odt-list-stack-stashed nil
1363 org-e-odt-automatic-styles nil
1364 org-e-odt-object-counters nil
1365 org-e-odt-entity-counts-plist nil)
1367 ;; let `htmlfontify' know that we are interested in collecting
1368 ;; styles - FIXME
1370 (setq hfy-user-sheet-assoc nil)
1372 ;; init conten.xml
1373 (with-current-buffer
1374 (find-file-noselect content-file t)
1375 (current-buffer))))
1379 (defun org-e-odt-save-as-outfile (target opt-plist)
1380 ;; write automatic styles
1381 (org-e-odt-write-automatic-styles)
1383 ;; write styles file
1384 ;; (when (equal org-lparse-backend 'odt) FIXME
1385 ;; )
1387 (org-e-odt-update-styles-file opt-plist)
1389 ;; create mimetype file
1390 (let ((mimetype (org-e-odt-write-mimetype-file ;; org-lparse-backend FIXME
1391 'odt)))
1392 (org-e-odt-create-manifest-file-entry mimetype "/" "1.2"))
1394 ;; create a manifest entry for content.xml
1395 (org-e-odt-create-manifest-file-entry "text/xml" "content.xml")
1397 ;; write out the manifest entries before zipping
1398 (org-e-odt-write-manifest-file)
1400 (let ((xml-files '("mimetype" "META-INF/manifest.xml" "content.xml"
1401 "meta.xml"))
1402 (zipdir default-directory))
1403 (when (or t (equal org-lparse-backend 'odt)) ; FIXME
1404 (push "styles.xml" xml-files))
1405 (message "Switching to directory %s" (expand-file-name zipdir))
1407 ;; save all xml files
1408 (mapc (lambda (file)
1409 (with-current-buffer
1410 (find-file-noselect (expand-file-name file) t)
1411 ;; prettify output if needed
1412 (when org-export-e-odt-prettify-xml
1413 (indent-region (point-min) (point-max)))
1414 (save-buffer 0)))
1415 xml-files)
1417 (let* ((target-name (file-name-nondirectory target))
1418 (target-dir (file-name-directory target))
1419 (cmds `(("zip" "-mX0" ,target-name "mimetype")
1420 ("zip" "-rmTq" ,target-name "."))))
1421 (when (file-exists-p target)
1422 ;; FIXME: If the file is locked this throws a cryptic error
1423 (delete-file target))
1425 (let ((coding-system-for-write 'no-conversion) exitcode err-string)
1426 (message "Creating odt file...")
1427 (mapc
1428 (lambda (cmd)
1429 (message "Running %s" (mapconcat 'identity cmd " "))
1430 (setq err-string
1431 (with-output-to-string
1432 (setq exitcode
1433 (apply 'call-process (car cmd)
1434 nil standard-output nil (cdr cmd)))))
1435 (or (zerop exitcode)
1436 (ignore (message "%s" err-string))
1437 (error "Unable to create odt file (%S)" exitcode)))
1438 cmds))
1440 ;; move the file from outdir to target-dir
1441 (rename-file target-name target-dir)
1443 ;; kill all xml buffers
1444 (mapc (lambda (file)
1445 (kill-buffer
1446 (find-file-noselect (expand-file-name file zipdir) t)))
1447 xml-files)
1449 (delete-directory zipdir)))
1450 (message "Created %s" target)
1451 (set-buffer (find-file-noselect target t)))
1454 (defun org-e-odt-create-manifest-file-entry (&rest args)
1455 (push args org-e-odt-manifest-file-entries))
1457 (defun org-e-odt-write-manifest-file ()
1458 (make-directory "META-INF")
1459 (let ((manifest-file (expand-file-name "META-INF/manifest.xml")))
1460 (with-current-buffer
1461 (find-file-noselect manifest-file t)
1462 (insert
1463 "<?xml version=\"1.0\" encoding=\"UTF-8\"?>
1464 <manifest:manifest xmlns:manifest=\"urn:oasis:names:tc:opendocument:xmlns:manifest:1.0\" manifest:version=\"1.2\">\n")
1465 (mapc
1466 (lambda (file-entry)
1467 (let* ((version (nth 2 file-entry))
1468 (extra (if version
1469 (format " manifest:version=\"%s\"" version)
1470 "")))
1471 (insert
1472 (format org-e-odt-manifest-file-entry-tag
1473 (nth 0 file-entry) (nth 1 file-entry) extra))))
1474 org-e-odt-manifest-file-entries)
1475 (insert "\n</manifest:manifest>"))))
1477 (defun org-e-odt-update-meta-file (info) ; FIXME opt-plist
1478 (let ((date (org-e-odt-format-date (plist-get info :date)))
1479 (author (or (plist-get info :author) ""))
1480 (email (plist-get info :email))
1481 (keywords (plist-get info :keywords))
1482 (description (plist-get info :description))
1483 (title (plist-get info :title)))
1484 (write-region
1485 (concat
1486 "<?xml version=\"1.0\" encoding=\"UTF-8\"?>
1487 <office:document-meta
1488 xmlns:office=\"urn:oasis:names:tc:opendocument:xmlns:office:1.0\"
1489 xmlns:xlink=\"http://www.w3.org/1999/xlink\"
1490 xmlns:dc=\"http://purl.org/dc/elements/1.1/\"
1491 xmlns:meta=\"urn:oasis:names:tc:opendocument:xmlns:meta:1.0\"
1492 xmlns:ooo=\"http://openoffice.org/2004/office\"
1493 office:version=\"1.2\">
1494 <office:meta>\n"
1495 (org-e-odt-format-author author) "\n"
1496 (format "<meta:initial-creator>%s</meta:initial-creator>\n" author)
1497 (format "<dc:date>%s</dc:date>\n" date)
1498 (format "<meta:creation-date>%s</meta:creation-date>\n" date)
1499 (format "<meta:generator>%s</meta:generator>\n"
1500 (when org-export-creator-info
1501 (format "Org-%s/Emacs-%s"
1502 org-version emacs-version)))
1503 (format "<meta:keyword>%s</meta:keyword>\n" keywords)
1504 (format "<dc:subject>%s</dc:subject>\n" description)
1505 (format "<dc:title>%s</dc:title>\n" title)
1506 "\n"
1507 " </office:meta>\n" "</office:document-meta>")
1508 nil (expand-file-name "meta.xml")))
1510 ;; create a manifest entry for meta.xml
1511 (org-e-odt-create-manifest-file-entry "text/xml" "meta.xml"))
1513 (defun org-e-odt-update-styles-file (opt-plist)
1514 ;; write styles file
1515 (let ((styles-file (plist-get opt-plist :odt-styles-file)))
1516 (org-e-odt-copy-styles-file (and styles-file
1517 (read (org-trim styles-file)))))
1519 ;; Update styles.xml - take care of outline numbering
1520 (with-current-buffer
1521 (find-file-noselect (expand-file-name "styles.xml") t)
1522 ;; Don't make automatic backup of styles.xml file. This setting
1523 ;; prevents the backed-up styles.xml file from being zipped in to
1524 ;; odt file. This is more of a hackish fix. Better alternative
1525 ;; would be to fix the zip command so that the output odt file
1526 ;; includes only the needed files and excludes any auto-generated
1527 ;; extra files like backups and auto-saves etc etc. Note that
1528 ;; currently the zip command zips up the entire temp directory so
1529 ;; that any auto-generated files created under the hood ends up in
1530 ;; the resulting odt file.
1531 (set (make-local-variable 'backup-inhibited) t)
1533 ;; Import local setting of `org-export-with-section-numbers'
1534 (org-e-odt-configure-outline-numbering
1535 (if org-export-with-section-numbers org-export-headline-levels 0)))
1537 ;; Write custom styles for source blocks
1538 (org-e-odt-insert-custom-styles-for-srcblocks
1539 (mapconcat
1540 (lambda (style)
1541 (format " %s\n" (cddr style)))
1542 hfy-user-sheet-assoc "")))
1544 (defun org-e-odt-write-mimetype-file (format)
1545 ;; create mimetype file
1546 (let ((mimetype
1547 (case format
1548 (odt "application/vnd.oasis.opendocument.text")
1549 (odf "application/vnd.oasis.opendocument.formula")
1550 (t (error "Unknown OpenDocument backend %S" org-lparse-backend)))))
1551 (write-region mimetype nil (expand-file-name "mimetype"))
1552 mimetype))
1554 (defun org-e-odt-finalize-outfile ()
1555 (org-e-odt-delete-empty-paragraphs))
1557 (defun org-e-odt-delete-empty-paragraphs ()
1558 (goto-char (point-min))
1559 (let ((open "<text:p[^>]*>")
1560 (close "</text:p>"))
1561 (while (re-search-forward (format "%s[ \r\n\t]*%s" open close) nil t)
1562 (replace-match ""))))
1564 (declare-function org-create-math-formula "org"
1565 (latex-frag &optional mathml-file))
1567 ;;;###autoload
1568 (defun org-export-e-odt-convert (&optional in-file out-fmt prefix-arg)
1569 "Convert IN-FILE to format OUT-FMT using a command line converter.
1570 IN-FILE is the file to be converted. If unspecified, it defaults
1571 to variable `buffer-file-name'. OUT-FMT is the desired output
1572 format. Use `org-export-e-odt-convert-process' as the converter.
1573 If PREFIX-ARG is non-nil then the newly converted file is opened
1574 using `org-open-file'."
1575 (interactive
1576 (append (org-lparse-convert-read-params) current-prefix-arg))
1577 (org-lparse-do-convert in-file out-fmt prefix-arg))
1579 (defun org-e-odt-get (what &optional opt-plist)
1580 (case what
1581 (BACKEND 'odt)
1582 (EXPORT-DIR (org-export-directory :html opt-plist))
1583 (FILE-NAME-EXTENSION "odt")
1584 (EXPORT-BUFFER-NAME "*Org ODT Export*")
1585 (ENTITY-CONTROL org-e-odt-entity-control-callbacks-alist)
1586 (ENTITY-FORMAT org-e-odt-entity-format-callbacks-alist)
1587 (INIT-METHOD 'org-e-odt-init-outfile)
1588 (FINAL-METHOD 'org-e-odt-finalize-outfile)
1589 (SAVE-METHOD 'org-e-odt-save-as-outfile)
1590 (CONVERT-METHOD
1591 (and org-export-e-odt-convert-process
1592 (cadr (assoc-string org-export-e-odt-convert-process
1593 org-export-e-odt-convert-processes t))))
1594 (CONVERT-CAPABILITIES
1595 (and org-export-e-odt-convert-process
1596 (cadr (assoc-string org-export-e-odt-convert-process
1597 org-export-e-odt-convert-processes t))
1598 org-export-e-odt-convert-capabilities))
1599 (TOPLEVEL-HLEVEL 1)
1600 (SPECIAL-STRING-REGEXPS org-export-e-odt-special-string-regexps)
1601 (INLINE-IMAGES 'maybe)
1602 (INLINE-IMAGE-EXTENSIONS '("png" "jpeg" "jpg" "gif" "svg"))
1603 (PLAIN-TEXT-MAP '(("&" . "&amp;") ("<" . "&lt;") (">" . "&gt;")))
1604 (TABLE-FIRST-COLUMN-AS-LABELS nil)
1605 (FOOTNOTE-SEPARATOR )
1606 (CODING-SYSTEM-FOR-WRITE 'utf-8)
1607 (CODING-SYSTEM-FOR-SAVE 'utf-8)
1608 (t (error "Unknown property: %s" what))))
1610 (defun org-export-e-odt-do-preprocess-latex-fragments ()
1611 "Convert LaTeX fragments to images."
1612 (let* ((latex-frag-opt (plist-get org-lparse-opt-plist :LaTeX-fragments))
1613 (latex-frag-opt ; massage the options
1614 (or (and (member latex-frag-opt '(mathjax t))
1615 (not (and (fboundp 'org-format-latex-mathml-available-p)
1616 (org-format-latex-mathml-available-p)))
1617 (prog1 org-lparse-latex-fragment-fallback
1618 (org-lparse-warn
1619 (concat
1620 "LaTeX to MathML converter not available. "
1621 (format "Using %S instead."
1622 org-lparse-latex-fragment-fallback)))))
1623 latex-frag-opt))
1624 cache-dir display-msg)
1625 (cond
1626 ((eq latex-frag-opt 'dvipng)
1627 (setq cache-dir "ltxpng/")
1628 (setq display-msg "Creating LaTeX image %s"))
1629 ((member latex-frag-opt '(mathjax t))
1630 (setq latex-frag-opt 'mathml)
1631 (setq cache-dir "ltxmathml/")
1632 (setq display-msg "Creating MathML formula %s")))
1633 (when (and org-current-export-file)
1634 (org-format-latex
1635 (concat cache-dir (file-name-sans-extension
1636 (file-name-nondirectory org-current-export-file)))
1637 org-current-export-dir nil display-msg
1638 nil nil latex-frag-opt))))
1640 (defadvice org-format-latex-as-mathml
1641 (after org-e-odt-protect-latex-fragment activate)
1642 "Encode LaTeX fragment as XML.
1643 Do this when translation to MathML fails."
1644 (when (or (not (> (length ad-return-value) 0))
1645 (get-text-property 0 'org-protected ad-return-value))
1646 (setq ad-return-value
1647 (org-propertize (org-e-odt-encode-plain-text (ad-get-arg 0))
1648 'org-protected t))))
1650 (defun org-export-e-odt-preprocess-latex-fragments ()
1651 (when (equal org-export-current-backend 'odt)
1652 (org-export-e-odt-do-preprocess-latex-fragments)))
1654 (defun org-export-e-odt-preprocess-label-references ()
1655 (goto-char (point-min))
1656 (let (label label-components category value pretty-label)
1657 (while (re-search-forward "\\\\ref{\\([^{}\n]+\\)}" nil t)
1658 (org-if-unprotected-at (match-beginning 1)
1659 (replace-match
1660 (let ((org-lparse-encode-pending t)
1661 (label (match-string 1)))
1662 ;; markup generated below is mostly an eye-candy. At
1663 ;; pre-processing stage, there is no information on which
1664 ;; entity a label reference points to. The actual markup
1665 ;; is generated as part of `org-e-odt-fixup-label-references'
1666 ;; which gets called at the fag end of export. By this
1667 ;; time we would have seen and collected all the label
1668 ;; definitions in `org-e-odt-entity-labels-alist'.
1669 (org-e-odt-format-tags
1670 '("<text:sequence-ref text:ref-name=\"%s\">" .
1671 "</text:sequence-ref>")
1672 "" (org-add-props label '(org-protected t)))) t t)))))
1674 ;; process latex fragments as part of
1675 ;; `org-export-preprocess-after-blockquote-hook'. Note that this hook
1676 ;; is the one that is closest and well before the call to
1677 ;; `org-export-attach-captions-and-attributes' in
1678 ;; `org-export-preprocess-string'. The above arrangement permits
1679 ;; captions, labels and attributes to be attached to png images
1680 ;; generated out of latex equations.
1681 (add-hook 'org-export-preprocess-after-blockquote-hook
1682 'org-export-e-odt-preprocess-latex-fragments)
1684 (defun org-export-e-odt-preprocess (parameters)
1685 (org-export-e-odt-preprocess-label-references))
1688 (defun org-e-odt-zip-extract-one (archive member &optional target)
1689 (require 'arc-mode)
1690 (let* ((target (or target default-directory))
1691 (archive (expand-file-name archive))
1692 (archive-zip-extract
1693 (list "unzip" "-qq" "-o" "-d" target))
1694 exit-code command-output)
1695 (setq command-output
1696 (with-temp-buffer
1697 (setq exit-code (archive-zip-extract archive member))
1698 (buffer-string)))
1699 (unless (zerop exit-code)
1700 (message command-output)
1701 (error "Extraction failed"))))
1703 (defun org-e-odt-zip-extract (archive members &optional target)
1704 (when (atom members) (setq members (list members)))
1705 (mapc (lambda (member)
1706 (org-e-odt-zip-extract-one archive member target))
1707 members))
1709 (defun org-e-odt-copy-styles-file (&optional styles-file)
1710 ;; Non-availability of styles.xml is not a critical error. For now
1711 ;; throw an error purely for aesthetic reasons.
1712 (setq styles-file (or styles-file
1713 org-export-e-odt-styles-file
1714 (expand-file-name "OrgOdtStyles.xml"
1715 org-e-odt-styles-dir)
1716 (error "org-e-odt: Missing styles file?")))
1717 (cond
1718 ((listp styles-file)
1719 (let ((archive (nth 0 styles-file))
1720 (members (nth 1 styles-file)))
1721 (org-e-odt-zip-extract archive members)
1722 (mapc
1723 (lambda (member)
1724 (when (org-file-image-p member)
1725 (let* ((image-type (file-name-extension member))
1726 (media-type (format "image/%s" image-type)))
1727 (org-e-odt-create-manifest-file-entry media-type member))))
1728 members)))
1729 ((and (stringp styles-file) (file-exists-p styles-file))
1730 (let ((styles-file-type (file-name-extension styles-file)))
1731 (cond
1732 ((string= styles-file-type "xml")
1733 (copy-file styles-file "styles.xml" t))
1734 ((member styles-file-type '("odt" "ott"))
1735 (org-e-odt-zip-extract styles-file "styles.xml")))))
1737 (error (format "Invalid specification of styles.xml file: %S"
1738 org-export-e-odt-styles-file))))
1740 ;; create a manifest entry for styles.xml
1741 (org-e-odt-create-manifest-file-entry "text/xml" "styles.xml"))
1743 (defun org-e-odt-configure-outline-numbering (level)
1744 "Outline numbering is retained only upto LEVEL.
1745 To disable outline numbering pass a LEVEL of 0."
1746 (goto-char (point-min))
1747 (let ((regex
1748 "<text:outline-level-style\\([^>]*\\)text:level=\"\\([^\"]*\\)\"\\([^>]*\\)>")
1749 (replacement
1750 "<text:outline-level-style\\1text:level=\"\\2\" style:num-format=\"\">"))
1751 (while (re-search-forward regex nil t)
1752 (when (> (string-to-number (match-string 2)) level)
1753 (replace-match replacement t nil))))
1754 (save-buffer 0))
1756 ;;;###autoload
1757 (defun org-export-as-odf (latex-frag &optional odf-file)
1758 "Export LATEX-FRAG as OpenDocument formula file ODF-FILE.
1759 Use `org-create-math-formula' to convert LATEX-FRAG first to
1760 MathML. When invoked as an interactive command, use
1761 `org-latex-regexps' to infer LATEX-FRAG from currently active
1762 region. If no LaTeX fragments are found, prompt for it. Push
1763 MathML source to kill ring, if `org-export-copy-to-kill-ring' is
1764 non-nil."
1765 (interactive
1766 `(,(let (frag)
1767 (setq frag (and (setq frag (and (region-active-p)
1768 (buffer-substring (region-beginning)
1769 (region-end))))
1770 (loop for e in org-latex-regexps
1771 thereis (when (string-match (nth 1 e) frag)
1772 (match-string (nth 2 e) frag)))))
1773 (read-string "LaTeX Fragment: " frag nil frag))
1774 ,(let ((odf-filename (expand-file-name
1775 (concat
1776 (file-name-sans-extension
1777 (or (file-name-nondirectory buffer-file-name)))
1778 "." "odf")
1779 (file-name-directory buffer-file-name))))
1780 (read-file-name "ODF filename: " nil odf-filename nil
1781 (file-name-nondirectory odf-filename)))))
1782 (let* ((org-lparse-backend 'odf)
1783 org-lparse-opt-plist
1784 (filename (or odf-file
1785 (expand-file-name
1786 (concat
1787 (file-name-sans-extension
1788 (or (file-name-nondirectory buffer-file-name)))
1789 "." "odf")
1790 (file-name-directory buffer-file-name))))
1791 (buffer (find-file-noselect (org-e-odt-init-outfile filename)))
1792 (coding-system-for-write 'utf-8)
1793 (save-buffer-coding-system 'utf-8))
1794 (set-buffer buffer)
1795 (set-buffer-file-coding-system coding-system-for-write)
1796 (let ((mathml (org-create-math-formula latex-frag)))
1797 (unless mathml (error "No Math formula created"))
1798 (insert mathml)
1799 (or (org-export-push-to-kill-ring
1800 (upcase (symbol-name org-lparse-backend)))
1801 (message "Exporting... done")))
1802 (org-e-odt-save-as-outfile filename nil ; FIXME
1805 ;;;###autoload
1806 (defun org-export-as-odf-and-open ()
1807 "Export LaTeX fragment as OpenDocument formula and immediately open it.
1808 Use `org-export-as-odf' to read LaTeX fragment and OpenDocument
1809 formula file."
1810 (interactive)
1811 (org-lparse-and-open
1812 nil nil nil (call-interactively 'org-export-as-odf)))
1817 ;;; Driver Starts here
1818 ;;; Dependencies
1820 (require 'format-spec)
1821 (eval-when-compile (require 'cl) (require 'table))
1825 ;;; Hooks
1827 (defvar org-e-odt-after-blockquotes-hook nil
1828 "Hook run during HTML export, after blockquote, verse, center are done.")
1830 (defvar org-e-odt-final-hook nil
1831 "Hook run at the end of HTML export, in the new buffer.")
1833 ;; FIXME: it already exists in org-e-odt.el
1834 ;;; Function Declarations
1836 (declare-function org-element-property "org-element" (property element))
1837 (declare-function org-element-normalize-string "org-element" (s))
1838 (declare-function org-element-parse-secondary-string
1839 "org-element" (string restriction &optional buffer))
1840 (defvar org-element-string-restrictions)
1842 (declare-function org-export-clean-table "org-export" (table specialp))
1843 (declare-function org-export-data "org-export" (data backend info))
1844 (declare-function org-export-directory "org-export" (type plist))
1845 (declare-function org-export-expand-macro "org-export" (macro info))
1846 (declare-function org-export-first-sibling-p "org-export" (headline info))
1847 (declare-function org-export-footnote-first-reference-p "org-export"
1848 (footnote-reference info))
1849 (declare-function org-export-get-coderef-format "org-export" (path desc))
1850 (declare-function org-export-get-footnote-definition "org-export"
1851 (footnote-reference info))
1852 (declare-function org-export-get-footnote-number "org-export" (footnote info))
1853 (declare-function org-export-get-previous-element "org-export" (blob info))
1854 (declare-function org-export-get-relative-level "org-export" (headline info))
1855 (declare-function org-export-handle-code
1856 "org-export" (element info &optional num-fmt ref-fmt delayed))
1857 (declare-function org-export-included-file "org-export" (keyword backend info))
1858 (declare-function org-export-inline-image-p "org-export"
1859 (link &optional extensions))
1860 (declare-function org-export-last-sibling-p "org-export" (headline info))
1861 (declare-function org-export-low-level-p "org-export" (headline info))
1862 (declare-function org-export-output-file-name
1863 "org-export" (extension &optional subtreep pub-dir))
1864 (declare-function org-export-resolve-coderef "org-export" (ref info))
1865 (declare-function org-export-resolve-fuzzy-link "org-export" (link info))
1866 (declare-function org-export-secondary-string "org-export"
1867 (secondary backend info))
1868 (declare-function org-export-solidify-link-text "org-export" (s))
1869 (declare-function org-export-table-format-info "org-export" (table))
1870 (declare-function
1871 org-export-to-buffer "org-export"
1872 (backend buffer &optional subtreep visible-only body-only ext-plist))
1873 (declare-function
1874 org-export-to-file "org-export"
1875 (backend file &optional subtreep visible-only body-only ext-plist))
1877 (declare-function org-id-find-id-file "org-id" (id))
1878 (declare-function htmlize-region "ext:htmlize" (beg end))
1879 (declare-function org-pop-to-buffer-same-window
1880 "org-compat" (&optional buffer-or-name norecord label))
1886 (declare-function hfy-face-to-style "htmlfontify" (fn))
1887 (declare-function hfy-face-or-def-to-name "htmlfontify" (fn))
1888 (declare-function archive-zip-extract "arc-mode.el" (archive name))
1890 ;;; Internal Variables
1892 ;;;; ODT Internal Variables
1894 (defconst org-e-odt-lib-dir
1895 (file-name-directory load-file-name)
1896 "Location of ODT exporter.
1897 Use this to infer values of `org-e-odt-styles-dir' and
1898 `org-export-e-odt-schema-dir'.")
1900 (defvar org-e-odt-data-dir
1901 (expand-file-name "../etc/" org-e-odt-lib-dir)
1902 "Data directory for ODT exporter.
1903 Use this to infer values of `org-e-odt-styles-dir' and
1904 `org-export-e-odt-schema-dir'.")
1909 (defconst org-export-e-odt-special-string-regexps
1910 '(("\\\\-" . "&#x00ad;\\1") ; shy
1911 ("---\\([^-]\\)" . "&#x2014;\\1") ; mdash
1912 ("--\\([^-]\\)" . "&#x2013;\\1") ; ndash
1913 ("\\.\\.\\." . "&#x2026;")) ; hellip
1914 "Regular expressions for special string conversion.")
1916 (defconst org-e-odt-schema-dir-list
1917 (list
1918 (and org-e-odt-data-dir
1919 (expand-file-name "./schema/" org-e-odt-data-dir)) ; bail out
1920 (eval-when-compile
1921 (and (boundp 'org-e-odt-data-dir) org-e-odt-data-dir ; see make install
1922 (expand-file-name "./schema/" org-e-odt-data-dir)))
1923 (expand-file-name "../contrib/odt/etc/schema/" org-e-odt-lib-dir) ; git
1925 "List of directories to search for OpenDocument schema files.
1926 Use this list to set the default value of
1927 `org-export-e-odt-schema-dir'. The entries in this list are
1928 populated heuristically based on the values of `org-e-odt-lib-dir'
1929 and `org-e-odt-data-dir'.")
1932 (defconst org-e-odt-styles-dir-list
1933 (list
1934 (and org-e-odt-data-dir
1935 (expand-file-name "./styles/" org-e-odt-data-dir)) ; bail out
1936 (eval-when-compile
1937 (and (boundp 'org-e-odt-data-dir) org-e-odt-data-dir ; see make install
1938 (expand-file-name "./styles/" org-e-odt-data-dir)))
1939 (expand-file-name "../etc/styles/" org-e-odt-lib-dir) ; git
1940 (expand-file-name "./etc/styles/" org-e-odt-lib-dir) ; elpa
1941 (expand-file-name "./org/" data-directory) ; system
1943 "List of directories to search for OpenDocument styles files.
1944 See `org-e-odt-styles-dir'. The entries in this list are populated
1945 heuristically based on the values of `org-e-odt-lib-dir' and
1946 `org-e-odt-data-dir'.")
1948 (defconst org-e-odt-styles-dir
1949 (let* ((styles-dir
1950 (catch 'styles-dir
1951 (message "Debug (org-e-odt): Searching for OpenDocument styles files...")
1952 (mapc (lambda (styles-dir)
1953 (when styles-dir
1954 (message "Debug (org-e-odt): Trying %s..." styles-dir)
1955 (when (and (file-readable-p
1956 (expand-file-name
1957 "OrgOdtContentTemplate.xml" styles-dir))
1958 (file-readable-p
1959 (expand-file-name
1960 "OrgOdtStyles.xml" styles-dir)))
1961 (message "Debug (org-e-odt): Using styles under %s"
1962 styles-dir)
1963 (throw 'styles-dir styles-dir))))
1964 org-e-odt-styles-dir-list)
1965 nil)))
1966 (unless styles-dir
1967 (error "Error (org-e-odt): Cannot find factory styles files. Aborting."))
1968 styles-dir)
1969 "Directory that holds auxiliary XML files used by the ODT exporter.
1971 This directory contains the following XML files -
1972 \"OrgOdtStyles.xml\" and \"OrgOdtContentTemplate.xml\". These
1973 XML files are used as the default values of
1974 `org-export-e-odt-styles-file' and
1975 `org-export-e-odt-content-template-file'.
1977 The default value of this variable varies depending on the
1978 version of org in use and is initialized from
1979 `org-e-odt-styles-dir-list'. Note that the user could be using org
1980 from one of: org's own private git repository, GNU ELPA tar or
1981 standard Emacs.")
1983 (defconst org-export-e-odt-tmpdir-prefix "%s-")
1984 (defconst org-export-e-odt-bookmark-prefix "OrgXref.")
1986 (defconst org-e-odt-manifest-file-entry-tag
1988 <manifest:file-entry manifest:media-type=\"%s\" manifest:full-path=\"%s\"%s/>")
1992 (defvar org-lparse-dyn-first-heading-pos) ; let bound during org-do-lparse
1994 (defvar org-e-odt-suppress-xref nil)
1995 (defvar org-e-odt-file-extensions
1996 '(("odt" . "OpenDocument Text")
1997 ("ott" . "OpenDocument Text Template")
1998 ("odm" . "OpenDocument Master Document")
1999 ("ods" . "OpenDocument Spreadsheet")
2000 ("ots" . "OpenDocument Spreadsheet Template")
2001 ("odg" . "OpenDocument Drawing (Graphics)")
2002 ("otg" . "OpenDocument Drawing Template")
2003 ("odp" . "OpenDocument Presentation")
2004 ("otp" . "OpenDocument Presentation Template")
2005 ("odi" . "OpenDocument Image")
2006 ("odf" . "OpenDocument Formula")
2007 ("odc" . "OpenDocument Chart")))
2009 (defvar org-export-e-odt-embed-images t
2010 "Should the images be copied in to the odt file or just linked?")
2012 (defvar org-export-e-odt-inline-images 'maybe)
2013 (defvar org-export-e-odt-default-org-styles-alist
2014 '((paragraph . ((default . "Text_20_body")
2015 (fixedwidth . "OrgFixedWidthBlock")
2016 (verse . "OrgVerse")
2017 (quote . "Quotations")
2018 (blockquote . "Quotations")
2019 (center . "OrgCenter")
2020 (left . "OrgLeft")
2021 (right . "OrgRight")
2022 (title . "OrgTitle")
2023 (subtitle . "OrgSubtitle")
2024 (footnote . "Footnote")
2025 (src . "OrgSrcBlock")
2026 (illustration . "Illustration")
2027 (table . "Table")
2028 (definition-term . "Text_20_body_20_bold")
2029 (horizontal-line . "Horizontal_20_Line")))
2030 (character . ((bold . "Bold")
2031 (emphasis . "Emphasis")
2032 (code . "OrgCode")
2033 (verbatim . "OrgCode")
2034 (strike . "Strikethrough")
2035 (underline . "Underline")
2036 (subscript . "OrgSubscript")
2037 (superscript . "OrgSuperscript")))
2038 (list . ((ordered . "OrgNumberedList")
2039 (unordered . "OrgBulletedList")
2040 (descriptive . "OrgDescriptionList"))))
2041 "Default styles for various entities.")
2043 (defvar org-export-e-odt-org-styles-alist org-export-e-odt-default-org-styles-alist)
2045 ;;;_. callbacks
2046 ;;;_. control callbacks
2047 ;;;_ , document body
2049 (defvar org-lparse-body-only) ; let bound during org-do-lparse
2050 (defvar org-lparse-opt-plist) ; bound during org-do-lparse
2051 (defvar org-lparse-list-stack) ; dynamically bound in org-do-lparse
2052 (defvar org-e-odt-list-stack-stashed)
2053 (defvar org-lparse-table-ncols)
2054 (defvar org-e-odt-table-rowgrp-open)
2055 (defvar org-e-odt-table-rownum)
2056 (defvar org-e-odt-table-cur-rowgrp-is-hdr)
2057 (defvar org-lparse-table-is-styled)
2058 (defvar org-lparse-table-rowgrp-info)
2059 (defvar org-lparse-table-colalign-vector)
2061 (defvar org-e-odt-table-style nil
2062 "Table style specified by \"#+ATTR_ODT: <style-name>\" line.
2063 This is set during `org-e-odt-begin-table'.")
2065 (defvar org-e-odt-table-style-spec nil
2066 "Entry for `org-e-odt-table-style' in `org-export-e-odt-table-styles'.")
2069 (defvar org-e-odt-table-style-format
2071 <style:style style:name=\"%s\" style:family=\"table\">
2072 <style:table-properties style:rel-width=\"%d%%\" fo:margin-top=\"0cm\" fo:margin-bottom=\"0.20cm\" table:align=\"center\"/>
2073 </style:style>
2075 "Template for auto-generated Table styles.")
2077 (defvar org-e-odt-automatic-styles '()
2078 "Registry of automatic styles for various OBJECT-TYPEs.
2079 The variable has the following form:
2080 \(\(OBJECT-TYPE-A
2081 \(\(OBJECT-NAME-A.1 OBJECT-PROPS-A.1\)
2082 \(OBJECT-NAME-A.2 OBJECT-PROPS-A.2\) ...\)\)
2083 \(OBJECT-TYPE-B
2084 \(\(OBJECT-NAME-B.1 OBJECT-PROPS-B.1\)
2085 \(OBJECT-NAME-B.2 OBJECT-PROPS-B.2\) ...\)\)
2086 ...\).
2088 OBJECT-TYPEs could be \"Section\", \"Table\", \"Figure\" etc.
2089 OBJECT-PROPS is (typically) a plist created by passing
2090 \"#+ATTR_ODT: \" option to `org-lparse-get-block-params'.
2092 Use `org-e-odt-add-automatic-style' to add update this variable.'")
2094 (defvar org-e-odt-object-counters nil
2095 "Running counters for various OBJECT-TYPEs.
2096 Use this to generate automatic names and style-names. See
2097 `org-e-odt-add-automatic-style'.")
2099 (defvar org-e-odt-table-indentedp nil)
2100 (defvar org-lparse-table-colalign-info)
2101 (defvar org-lparse-link-description-is-image nil)
2104 (defvar org-src-block-paragraph-format
2105 "<style:style style:name=\"OrgSrcBlock\" style:family=\"paragraph\" style:parent-style-name=\"Preformatted_20_Text\">
2106 <style:paragraph-properties fo:background-color=\"%s\" fo:padding=\"0.049cm\" fo:border=\"0.51pt solid #000000\" style:shadow=\"none\">
2107 <style:background-image/>
2108 </style:paragraph-properties>
2109 <style:text-properties fo:color=\"%s\"/>
2110 </style:style>"
2111 "Custom paragraph style for colorized source and example blocks.
2112 This style is much the same as that of \"OrgFixedWidthBlock\"
2113 except that the foreground and background colors are set
2114 according to the default face identified by the `htmlfontify'.")
2116 (defvar hfy-optimisations)
2117 (defvar org-e-odt-embedded-formulas-count 0)
2118 (defvar org-e-odt-entity-frame-styles
2119 '(("As-CharImage" "__Figure__" ("OrgInlineImage" nil "as-char"))
2120 ("ParagraphImage" "__Figure__" ("OrgDisplayImage" nil "paragraph"))
2121 ("PageImage" "__Figure__" ("OrgPageImage" nil "page"))
2122 ("CaptionedAs-CharImage" "__Figure__"
2123 ("OrgCaptionedImage"
2124 " style:rel-width=\"100%\" style:rel-height=\"scale\"" "paragraph")
2125 ("OrgInlineImage" nil "as-char"))
2126 ("CaptionedParagraphImage" "__Figure__"
2127 ("OrgCaptionedImage"
2128 " style:rel-width=\"100%\" style:rel-height=\"scale\"" "paragraph")
2129 ("OrgImageCaptionFrame" nil "paragraph"))
2130 ("CaptionedPageImage" "__Figure__"
2131 ("OrgCaptionedImage"
2132 " style:rel-width=\"100%\" style:rel-height=\"scale\"" "paragraph")
2133 ("OrgPageImageCaptionFrame" nil "page"))
2134 ("InlineFormula" "__MathFormula__" ("OrgInlineFormula" nil "as-char"))
2135 ("DisplayFormula" "__MathFormula__" ("OrgDisplayFormula" nil "as-char"))
2136 ("CaptionedDisplayFormula" "__MathFormula__"
2137 ("OrgCaptionedFormula" nil "paragraph")
2138 ("OrgFormulaCaptionFrame" nil "as-char"))))
2140 (defvar org-e-odt-embedded-images-count 0)
2142 (defvar org-export-e-odt-image-size-probe-method
2143 (append (and (executable-find "identify") '(imagemagick)) ; See Bug#10675
2144 '(emacs fixed))
2145 "Ordered list of methods for determining image sizes.")
2147 (defvar org-export-e-odt-default-image-sizes-alist
2148 '(("as-char" . (5 . 0.4))
2149 ("paragraph" . (5 . 5)))
2150 "Hardcoded image dimensions one for each of the anchor
2151 methods.")
2153 ;; A4 page size is 21.0 by 29.7 cms
2154 ;; The default page settings has 2cm margin on each of the sides. So
2155 ;; the effective text area is 17.0 by 25.7 cm
2156 (defvar org-export-e-odt-max-image-size '(17.0 . 20.0)
2157 "Limiting dimensions for an embedded image.")
2159 (defvar org-e-odt-entity-labels-alist nil
2160 "Associate Labels with the Labeled entities.
2161 Each element of the alist is of the form (LABEL-NAME
2162 CATEGORY-NAME SEQNO LABEL-STYLE-NAME). LABEL-NAME is same as
2163 that specified by \"#+LABEL: ...\" line. CATEGORY-NAME is the
2164 type of the entity that LABEL-NAME is attached to. CATEGORY-NAME
2165 can be one of \"Table\", \"Figure\" or \"Equation\". SEQNO is
2166 the unique number assigned to the referenced entity on a
2167 per-CATEGORY basis. It is generated sequentially and is 1-based.
2168 LABEL-STYLE-NAME is a key `org-e-odt-label-styles'.
2170 See `org-e-odt-add-label-definition' and
2171 `org-e-odt-fixup-label-references'.")
2173 (defvar org-e-odt-entity-counts-plist nil
2174 "Plist of running counters of SEQNOs for each of the CATEGORY-NAMEs.
2175 See `org-e-odt-entity-labels-alist' for known CATEGORY-NAMEs.")
2177 (defvar org-e-odt-label-styles
2178 '(("text" "(%n)" "text" "(%n)")
2179 ("category-and-value" "%e %n%c" "category-and-value" "%e %n")
2180 ("value" "%e %n%c" "value" "%n"))
2181 "Specify how labels are applied and referenced.
2182 This is an alist where each element is of the
2183 form (LABEL-STYLE-NAME LABEL-ATTACH-FMT LABEL-REF-MODE
2184 LABEL-REF-FMT).
2186 LABEL-ATTACH-FMT controls how labels and captions are attached to
2187 an entity. It may contain following specifiers - %e, %n and %c.
2188 %e is replaced with the CATEGORY-NAME. %n is replaced with
2189 \"<text:sequence ...> SEQNO </text:sequence>\". %c is replaced
2190 with CAPTION. See `org-e-odt-format-label-definition'.
2192 LABEL-REF-MODE and LABEL-REF-FMT controls how label references
2193 are generated. The following XML is generated for a label
2194 reference - \"<text:sequence-ref
2195 text:reference-format=\"LABEL-REF-MODE\" ...> LABEL-REF-FMT
2196 </text:sequence-ref>\". LABEL-REF-FMT may contain following
2197 specifiers - %e and %n. %e is replaced with the CATEGORY-NAME.
2198 %n is replaced with SEQNO. See
2199 `org-e-odt-format-label-reference'.")
2201 (defvar org-e-odt-category-map-alist
2202 '(("__Table__" "Table" "value")
2203 ("__Figure__" "Figure" "value")
2204 ("__MathFormula__" "Equation" "text")
2205 ("__DvipngImage__" "Equation" "value")
2206 ;; ("__Table__" "Table" "category-and-value")
2207 ;; ("__Figure__" "Figure" "category-and-value")
2208 ;; ("__DvipngImage__" "Equation" "category-and-value")
2210 "Map a CATEGORY-HANDLE to CATEGORY-NAME and LABEL-STYLE.
2211 This is an alist where each element is of the form
2212 \\(CATEGORY-HANDLE CATEGORY-NAME LABEL-STYLE\\). CATEGORY_HANDLE
2213 could either be one of the internal handles (as seen above) or be
2214 derived from the \"#+LABEL:<label-name>\" specification. See
2215 `org-export-e-odt-get-category-from-label'. CATEGORY-NAME and
2216 LABEL-STYLE are used for generating ODT labels. See
2217 `org-e-odt-label-styles'.")
2219 (defvar org-export-e-odt-user-categories
2220 '("Illustration" "Table" "Text" "Drawing" "Equation" "Figure"))
2222 (defvar org-export-e-odt-get-category-from-label nil
2223 "Should category of label be inferred from label itself.
2224 When this option is non-nil, a label is parsed in to two
2225 component parts delimited by a \":\" (colon) as shown here -
2226 #+LABEL:[CATEGORY-HANDLE:]EXTRA. The CATEGORY-HANDLE is mapped
2227 to a CATEGORY-NAME and LABEL-STYLE using
2228 `org-e-odt-category-map-alist'. (If no such map is provided and
2229 CATEGORY-NAME is set to CATEGORY-HANDLE and LABEL-STYLE is set to
2230 \"category-and-value\"). If CATEGORY-NAME so obtained is listed
2231 under `org-export-e-odt-user-categories' then the user specified
2232 styles are used. Otherwise styles as determined by the internal
2233 CATEGORY-HANDLE is used. See
2234 `org-e-odt-get-label-category-and-style' for details.")
2236 (defvar org-e-odt-manifest-file-entries nil)
2237 (defvar hfy-user-sheet-assoc) ; bound during org-do-lparse
2238 (defvar org-lparse-latex-fragment-fallback) ; set by org-do-lparse
2241 ;;;; HTML Internal Variables
2243 (defvar org-e-odt-option-alist
2245 ;; (:agenda-style nil nil org-agenda-export-html-style)
2246 ;; (:convert-org-links nil nil org-e-odt-link-org-files-as-html)
2247 ;; ;; FIXME Use (org-xml-encode-org-text-skip-links s) ??
2248 ;; ;; (:expand-quoted-html nil "@" org-e-odt-expand)
2249 ;; (:inline-images nil nil org-e-odt-inline-images)
2250 ;; ;; (:link-home nil nil org-e-odt-link-home) FIXME
2251 ;; ;; (:link-up nil nil org-e-odt-link-up) FIXME
2252 ;; (:style nil nil org-e-odt-style)
2253 ;; (:style-extra nil nil org-e-odt-style-extra)
2254 ;; (:style-include-default nil nil org-e-odt-style-include-default)
2255 ;; (:style-include-scripts nil nil org-e-odt-style-include-scripts)
2256 ;; ;; (:timestamp nil nil org-e-odt-with-timestamp)
2257 ;; (:html-extension nil nil org-e-odt-extension)
2258 ;; (:html-postamble nil nil org-e-odt-postamble)
2259 ;; (:html-preamble nil nil org-e-odt-preamble)
2260 ;; (:html-table-tag nil nil org-e-odt-table-tag)
2261 ;; (:xml-declaration nil nil org-e-odt-xml-declaration)
2262 (:LaTeX-fragments nil "LaTeX" org-export-with-LaTeX-fragments))
2263 "Alist between export properties and ways to set them.
2265 The car of the alist is the property name, and the cdr is a list
2266 like \(KEYWORD OPTION DEFAULT BEHAVIOUR\) where:
2268 KEYWORD is a string representing a buffer keyword, or nil.
2269 OPTION is a string that could be found in an #+OPTIONS: line.
2270 DEFAULT is the default value for the property.
2271 BEHAVIOUR determine how Org should handle multiple keywords for
2272 the same property. It is a symbol among:
2273 nil Keep old value and discard the new one.
2274 t Replace old value with the new one.
2275 `space' Concatenate the values, separating them with a space.
2276 `newline' Concatenate the values, separating them with
2277 a newline.
2278 `split' Split values at white spaces, and cons them to the
2279 previous list.
2281 KEYWORD and OPTION have precedence over DEFAULT.
2283 All these properties should be back-end agnostic. For back-end
2284 specific properties, define a similar variable named
2285 `org-BACKEND-option-alist', replacing BACKEND with the name of
2286 the appropriate back-end. You can also redefine properties
2287 there, as they have precedence over these.")
2289 (defvar html-table-tag nil) ; dynamically scoped into this.
2291 ;; FIXME: it already exists in org-e-odt.el
2292 (defconst org-e-odt-cvt-link-fn
2294 "Function to convert link URLs to exportable URLs.
2295 Takes two arguments, TYPE and PATH.
2296 Returns exportable url as (TYPE PATH), or nil to signal that it
2297 didn't handle this case.
2298 Intended to be locally bound around a call to `org-export-as-html'." )
2303 (defvar org-e-odt-format-table-no-css)
2304 (defvar htmlize-buffer-places) ; from htmlize.el
2305 (defvar body-only) ; dynamically scoped into this.
2307 (defvar org-e-odt-table-rowgrp-open)
2308 (defvar org-e-odt-table-rownum)
2309 (defvar org-e-odt-table-cur-rowgrp-is-hdr)
2310 (defvar org-lparse-table-is-styled)
2313 (defvar org-e-odt-headline-formatter
2314 (lambda (level snumber todo todo-type priority
2315 title tags target extra-targets extra-class)
2316 (concat snumber " " title)))
2320 ;;; User Configuration Variables
2322 (defgroup org-export-e-odt nil
2323 "Options for exporting Org mode files to HTML."
2324 :tag "Org Export HTML"
2325 :group 'org-export)
2327 (defcustom org-e-odt-protect-char-alist
2328 '(("&" . "&amp;")
2329 ("<" . "&lt;")
2330 (">" . "&gt;"))
2331 "Alist of characters to be converted by `org-e-html-protect'."
2332 :group 'org-export-e-html
2333 :type '(repeat (cons (string :tag "Character")
2334 (string :tag "ODT equivalent"))))
2335 (defcustom org-export-e-odt-schema-dir
2336 (let* ((schema-dir
2337 (catch 'schema-dir
2338 (message "Debug (org-e-odt): Searching for OpenDocument schema files...")
2339 (mapc
2340 (lambda (schema-dir)
2341 (when schema-dir
2342 (message "Debug (org-e-odt): Trying %s..." schema-dir)
2343 (when (and (file-readable-p
2344 (expand-file-name "od-manifest-schema-v1.2-cs01.rnc"
2345 schema-dir))
2346 (file-readable-p
2347 (expand-file-name "od-schema-v1.2-cs01.rnc"
2348 schema-dir))
2349 (file-readable-p
2350 (expand-file-name "schemas.xml" schema-dir)))
2351 (message "Debug (org-e-odt): Using schema files under %s"
2352 schema-dir)
2353 (throw 'schema-dir schema-dir))))
2354 org-e-odt-schema-dir-list)
2355 (message "Debug (org-e-odt): No OpenDocument schema files installed")
2356 nil)))
2357 schema-dir)
2358 "Directory that contains OpenDocument schema files.
2360 This directory contains:
2361 1. rnc files for OpenDocument schema
2362 2. a \"schemas.xml\" file that specifies locating rules needed
2363 for auto validation of OpenDocument XML files.
2365 Use the customize interface to set this variable. This ensures
2366 that `rng-schema-locating-files' is updated and auto-validation
2367 of OpenDocument XML takes place based on the value
2368 `rng-nxml-auto-validate-flag'.
2370 The default value of this variable varies depending on the
2371 version of org in use and is initialized from
2372 `org-e-odt-schema-dir-list'. The OASIS schema files are available
2373 only in the org's private git repository. It is *not* bundled
2374 with GNU ELPA tar or standard Emacs distribution."
2375 :type '(choice
2376 (const :tag "Not set" nil)
2377 (directory :tag "Schema directory"))
2378 :group 'org-export-e-odt
2379 :version "24.1"
2380 :set
2381 (lambda (var value)
2382 "Set `org-export-e-odt-schema-dir'.
2383 Also add it to `rng-schema-locating-files'."
2384 (let ((schema-dir value))
2385 (set var
2386 (if (and
2387 (file-readable-p
2388 (expand-file-name "od-manifest-schema-v1.2-cs01.rnc" schema-dir))
2389 (file-readable-p
2390 (expand-file-name "od-schema-v1.2-cs01.rnc" schema-dir))
2391 (file-readable-p
2392 (expand-file-name "schemas.xml" schema-dir)))
2393 schema-dir
2394 (when value
2395 (message "Error (org-e-odt): %s has no OpenDocument schema files"
2396 value))
2397 nil)))
2398 (when org-export-e-odt-schema-dir
2399 (eval-after-load 'rng-loc
2400 '(add-to-list 'rng-schema-locating-files
2401 (expand-file-name "schemas.xml"
2402 org-export-e-odt-schema-dir))))))
2404 (defcustom org-export-e-odt-content-template-file nil
2405 "Template file for \"content.xml\".
2406 The exporter embeds the exported content just before
2407 \"</office:text>\" element.
2409 If unspecified, the file named \"OrgOdtContentTemplate.xml\"
2410 under `org-e-odt-styles-dir' is used."
2411 :type 'file
2412 :group 'org-export-e-odt
2413 :version "24.1")
2415 (defcustom org-export-e-odt-styles-file nil
2416 "Default styles file for use with ODT export.
2417 Valid values are one of:
2418 1. nil
2419 2. path to a styles.xml file
2420 3. path to a *.odt or a *.ott file
2421 4. list of the form (ODT-OR-OTT-FILE (FILE-MEMBER-1 FILE-MEMBER-2
2422 ...))
2424 In case of option 1, an in-built styles.xml is used. See
2425 `org-e-odt-styles-dir' for more information.
2427 In case of option 3, the specified file is unzipped and the
2428 styles.xml embedded therein is used.
2430 In case of option 4, the specified ODT-OR-OTT-FILE is unzipped
2431 and FILE-MEMBER-1, FILE-MEMBER-2 etc are copied in to the
2432 generated odt file. Use relative path for specifying the
2433 FILE-MEMBERS. styles.xml must be specified as one of the
2434 FILE-MEMBERS.
2436 Use options 1, 2 or 3 only if styles.xml alone suffices for
2437 achieving the desired formatting. Use option 4, if the styles.xml
2438 references additional files like header and footer images for
2439 achieving the desired formatting.
2441 Use \"#+ODT_STYLES_FILE: ...\" directive to set this variable on
2442 a per-file basis. For example,
2444 #+ODT_STYLES_FILE: \"/path/to/styles.xml\" or
2445 #+ODT_STYLES_FILE: (\"/path/to/file.ott\" (\"styles.xml\" \"image/hdr.png\"))."
2446 :group 'org-export-e-odt
2447 :version "24.1"
2448 :type
2449 '(choice
2450 (const :tag "Factory settings" nil)
2451 (file :must-match t :tag "styles.xml")
2452 (file :must-match t :tag "ODT or OTT file")
2453 (list :tag "ODT or OTT file + Members"
2454 (file :must-match t :tag "ODF Text or Text Template file")
2455 (cons :tag "Members"
2456 (file :tag " Member" "styles.xml")
2457 (repeat (file :tag "Member"))))))
2460 (defcustom org-export-e-odt-inline-image-extensions
2461 '("png" "jpeg" "jpg" "gif")
2462 "Extensions of image files that can be inlined into HTML."
2463 :type '(repeat (string :tag "Extension"))
2464 :group 'org-export-e-odt
2465 :version "24.1")
2467 (defcustom org-export-e-odt-pixels-per-inch display-pixels-per-inch
2468 "Scaling factor for converting images pixels to inches.
2469 Use this for sizing of embedded images. See Info node `(org)
2470 Images in ODT export' for more information."
2471 :type 'float
2472 :group 'org-export-e-odt
2473 :version "24.1")
2475 (defcustom org-export-e-odt-create-custom-styles-for-srcblocks t
2476 "Whether custom styles for colorized source blocks be automatically created.
2477 When this option is turned on, the exporter creates custom styles
2478 for source blocks based on the advice of `htmlfontify'. Creation
2479 of custom styles happen as part of `org-e-odt-hfy-face-to-css'.
2481 When this option is turned off exporter does not create such
2482 styles.
2484 Use the latter option if you do not want the custom styles to be
2485 based on your current display settings. It is necessary that the
2486 styles.xml already contains needed styles for colorizing to work.
2488 This variable is effective only if
2489 `org-export-e-odt-fontify-srcblocks' is turned on."
2490 :group 'org-export-e-odt
2491 :version "24.1"
2492 :type 'boolean)
2494 (defcustom org-export-e-odt-preferred-output-format nil
2495 "Automatically post-process to this format after exporting to \"odt\".
2496 Interactive commands `org-export-as-e-odt' and
2497 `org-export-as-e-odt-and-open' export first to \"odt\" format and
2498 then use `org-export-e-odt-convert-process' to convert the
2499 resulting document to this format. During customization of this
2500 variable, the list of valid values are populated based on
2501 `org-export-e-odt-convert-capabilities'."
2502 :group 'org-export-e-odt
2503 :version "24.1"
2504 :type '(choice :convert-widget
2505 (lambda (w)
2506 (apply 'widget-convert (widget-type w)
2507 (eval (car (widget-get w :args)))))
2508 `((const :tag "None" nil)
2509 ,@(mapcar (lambda (c)
2510 `(const :tag ,c ,c))
2511 (org-lparse-reachable-formats "odt")))))
2513 (defcustom org-export-e-odt-table-styles
2514 '(("OrgEquation" "OrgEquation"
2515 ((use-first-column-styles . t)
2516 (use-last-column-styles . t))))
2517 "Specify how Table Styles should be derived from a Table Template.
2518 This is a list where each element is of the
2519 form (TABLE-STYLE-NAME TABLE-TEMPLATE-NAME TABLE-CELL-OPTIONS).
2521 TABLE-STYLE-NAME is the style associated with the table through
2522 `org-e-odt-table-style'.
2524 TABLE-TEMPLATE-NAME is a set of - upto 9 - automatic
2525 TABLE-CELL-STYLE-NAMEs and PARAGRAPH-STYLE-NAMEs (as defined
2526 below) that is included in
2527 `org-export-e-odt-content-template-file'.
2529 TABLE-CELL-STYLE-NAME := TABLE-TEMPLATE-NAME + TABLE-CELL-TYPE +
2530 \"TableCell\"
2531 PARAGRAPH-STYLE-NAME := TABLE-TEMPLATE-NAME + TABLE-CELL-TYPE +
2532 \"TableParagraph\"
2533 TABLE-CELL-TYPE := \"FirstRow\" | \"LastColumn\" |
2534 \"FirstRow\" | \"LastRow\" |
2535 \"EvenRow\" | \"OddRow\" |
2536 \"EvenColumn\" | \"OddColumn\" | \"\"
2537 where \"+\" above denotes string concatenation.
2539 TABLE-CELL-OPTIONS is an alist where each element is of the
2540 form (TABLE-CELL-STYLE-SELECTOR . ON-OR-OFF).
2541 TABLE-CELL-STYLE-SELECTOR := `use-first-row-styles' |
2542 `use-last-row-styles' |
2543 `use-first-column-styles' |
2544 `use-last-column-styles' |
2545 `use-banding-rows-styles' |
2546 `use-banding-columns-styles' |
2547 `use-first-row-styles'
2548 ON-OR-OFF := `t' | `nil'
2550 For example, with the following configuration
2552 \(setq org-export-e-odt-table-styles
2553 '\(\(\"TableWithHeaderRowsAndColumns\" \"Custom\"
2554 \(\(use-first-row-styles . t\)
2555 \(use-first-column-styles . t\)\)\)
2556 \(\"TableWithHeaderColumns\" \"Custom\"
2557 \(\(use-first-column-styles . t\)\)\)\)\)
2559 1. A table associated with \"TableWithHeaderRowsAndColumns\"
2560 style will use the following table-cell styles -
2561 \"CustomFirstRowTableCell\", \"CustomFirstColumnTableCell\",
2562 \"CustomTableCell\" and the following paragraph styles
2563 \"CustomFirstRowTableParagraph\",
2564 \"CustomFirstColumnTableParagraph\", \"CustomTableParagraph\"
2565 as appropriate.
2567 2. A table associated with \"TableWithHeaderColumns\" style will
2568 use the following table-cell styles -
2569 \"CustomFirstColumnTableCell\", \"CustomTableCell\" and the
2570 following paragraph styles
2571 \"CustomFirstColumnTableParagraph\", \"CustomTableParagraph\"
2572 as appropriate..
2574 Note that TABLE-TEMPLATE-NAME corresponds to the
2575 \"<table:table-template>\" elements contained within
2576 \"<office:styles>\". The entries (TABLE-STYLE-NAME
2577 TABLE-TEMPLATE-NAME TABLE-CELL-OPTIONS) correspond to
2578 \"table:template-name\" and \"table:use-first-row-styles\" etc
2579 attributes of \"<table:table>\" element. Refer ODF-1.2
2580 specification for more information. Also consult the
2581 implementation filed under `org-e-odt-get-table-cell-styles'.
2583 The TABLE-STYLE-NAME \"OrgEquation\" is used internally for
2584 formatting of numbered display equations. Do not delete this
2585 style from the list."
2586 :group 'org-export-e-odt
2587 :version "24.1"
2588 :type '(choice
2589 (const :tag "None" nil)
2590 (repeat :tag "Table Styles"
2591 (list :tag "Table Style Specification"
2592 (string :tag "Table Style Name")
2593 (string :tag "Table Template Name")
2594 (alist :options (use-first-row-styles
2595 use-last-row-styles
2596 use-first-column-styles
2597 use-last-column-styles
2598 use-banding-rows-styles
2599 use-banding-columns-styles)
2600 :key-type symbol
2601 :value-type (const :tag "True" t))))))
2602 (defcustom org-export-e-odt-fontify-srcblocks t
2603 "Specify whether or not source blocks need to be fontified.
2604 Turn this option on if you want to colorize the source code
2605 blocks in the exported file. For colorization to work, you need
2606 to make available an enhanced version of `htmlfontify' library."
2607 :type 'boolean
2608 :group 'org-export-e-odt
2609 :version "24.1")
2611 (defcustom org-export-e-odt-prettify-xml t ; FIXME
2612 "Specify whether or not the xml output should be prettified.
2613 When this option is turned on, `indent-region' is run on all
2614 component xml buffers before they are saved. Turn this off for
2615 regular use. Turn this on if you need to examine the xml
2616 visually."
2617 :group 'org-export-e-odt
2618 :version "24.1"
2619 :type 'boolean)
2621 (defcustom org-export-e-odt-convert-processes
2622 '(("LibreOffice"
2623 "soffice --headless --convert-to %f%x --outdir %d %i")
2624 ("unoconv"
2625 "unoconv -f %f -o %d %i"))
2626 "Specify a list of document converters and their usage.
2627 The converters in this list are offered as choices while
2628 customizing `org-export-e-odt-convert-process'.
2630 This variable is a list where each element is of the
2631 form (CONVERTER-NAME CONVERTER-CMD). CONVERTER-NAME is the name
2632 of the converter. CONVERTER-CMD is the shell command for the
2633 converter and can contain format specifiers. These format
2634 specifiers are interpreted as below:
2636 %i input file name in full
2637 %I input file name as a URL
2638 %f format of the output file
2639 %o output file name in full
2640 %O output file name as a URL
2641 %d output dir in full
2642 %D output dir as a URL.
2643 %x extra options as set in `org-export-e-odt-convert-capabilities'."
2644 :group 'org-export-e-odt
2645 :version "24.1"
2646 :type
2647 '(choice
2648 (const :tag "None" nil)
2649 (alist :tag "Converters"
2650 :key-type (string :tag "Converter Name")
2651 :value-type (group (string :tag "Command line")))))
2653 (defcustom org-export-e-odt-convert-process "LibreOffice"
2654 "Use this converter to convert from \"odt\" format to other formats.
2655 During customization, the list of converter names are populated
2656 from `org-export-e-odt-convert-processes'."
2657 :group 'org-export-e-odt
2658 :version "24.1"
2659 :type '(choice :convert-widget
2660 (lambda (w)
2661 (apply 'widget-convert (widget-type w)
2662 (eval (car (widget-get w :args)))))
2663 `((const :tag "None" nil)
2664 ,@(mapcar (lambda (c)
2665 `(const :tag ,(car c) ,(car c)))
2666 org-export-e-odt-convert-processes))))
2668 (defcustom org-export-e-odt-convert-capabilities
2669 '(("Text"
2670 ("odt" "ott" "doc" "rtf" "docx")
2671 (("pdf" "pdf") ("odt" "odt") ("rtf" "rtf") ("ott" "ott")
2672 ("doc" "doc" ":\"MS Word 97\"") ("docx" "docx") ("html" "html")))
2673 ("Web"
2674 ("html")
2675 (("pdf" "pdf") ("odt" "odt") ("html" "html")))
2676 ("Spreadsheet"
2677 ("ods" "ots" "xls" "csv" "xlsx")
2678 (("pdf" "pdf") ("ots" "ots") ("html" "html") ("csv" "csv") ("ods" "ods")
2679 ("xls" "xls") ("xlsx" "xlsx")))
2680 ("Presentation"
2681 ("odp" "otp" "ppt" "pptx")
2682 (("pdf" "pdf") ("swf" "swf") ("odp" "odp") ("otp" "otp") ("ppt" "ppt")
2683 ("pptx" "pptx") ("odg" "odg"))))
2684 "Specify input and output formats of `org-export-e-odt-convert-process'.
2685 More correctly, specify the set of input and output formats that
2686 the user is actually interested in.
2688 This variable is an alist where each element is of the
2689 form (DOCUMENT-CLASS INPUT-FMT-LIST OUTPUT-FMT-ALIST).
2690 INPUT-FMT-LIST is a list of INPUT-FMTs. OUTPUT-FMT-ALIST is an
2691 alist where each element is of the form (OUTPUT-FMT
2692 OUTPUT-FILE-EXTENSION EXTRA-OPTIONS).
2694 The variable is interpreted as follows:
2695 `org-export-e-odt-convert-process' can take any document that is in
2696 INPUT-FMT-LIST and produce any document that is in the
2697 OUTPUT-FMT-LIST. A document converted to OUTPUT-FMT will have
2698 OUTPUT-FILE-EXTENSION as the file name extension. OUTPUT-FMT
2699 serves dual purposes:
2700 - It is used for populating completion candidates during
2701 `org-export-e-odt-convert' commands.
2702 - It is used as the value of \"%f\" specifier in
2703 `org-export-e-odt-convert-process'.
2705 EXTRA-OPTIONS is used as the value of \"%x\" specifier in
2706 `org-export-e-odt-convert-process'.
2708 DOCUMENT-CLASS is used to group a set of file formats in
2709 INPUT-FMT-LIST in to a single class.
2711 Note that this variable inherently captures how LibreOffice based
2712 converters work. LibreOffice maps documents of various formats
2713 to classes like Text, Web, Spreadsheet, Presentation etc and
2714 allow document of a given class (irrespective of it's source
2715 format) to be converted to any of the export formats associated
2716 with that class.
2718 See default setting of this variable for an typical
2719 configuration."
2720 :group 'org-export-e-odt
2721 :version "24.1"
2722 :type
2723 '(choice
2724 (const :tag "None" nil)
2725 (alist :tag "Capabilities"
2726 :key-type (string :tag "Document Class")
2727 :value-type
2728 (group (repeat :tag "Input formats" (string :tag "Input format"))
2729 (alist :tag "Output formats"
2730 :key-type (string :tag "Output format")
2731 :value-type
2732 (group (string :tag "Output file extension")
2733 (choice
2734 (const :tag "None" nil)
2735 (string :tag "Extra options"))))))))
2737 ;;;; Debugging
2740 ;;;; Document
2742 ;;;; Document Header (Styles)
2744 ;;;; Document Header (Scripts)
2746 ;;;; Document Header (Mathjax)
2748 ;;;; Preamble
2750 ;;;; Postamble
2752 ;;;; Emphasis
2754 ;;;; Todos
2756 ;;;; Tags
2758 ;;;; Time-stamps
2759 ;;;; Statistics Cookie
2760 ;;;; Subscript
2761 ;;;; Superscript
2763 ;;;; Inline images
2765 ;;;; Block
2766 ;;;; Comment
2767 ;;;; Comment Block
2768 ;;;; Drawer
2769 ;;;; Dynamic Block
2770 ;;;; Emphasis
2771 ;;;; Entity
2772 ;;;; Example Block
2773 ;;;; Export Snippet
2774 ;;;; Export Block
2775 ;;;; Fixed Width
2776 ;;;; Footnotes
2778 ;;;; Headline
2779 ;;;; Horizontal Rule
2780 ;;;; Inline Babel Call
2781 ;;;; Inline Src Block
2782 ;;;; Inlinetask
2783 ;;;; Item
2784 ;;;; Keyword
2785 ;;;; Latex Environment
2786 ;;;; Latex Fragment
2787 ;;;; Line Break
2788 ;;;; Link
2789 ;;;; Babel Call
2790 ;;;; Macro
2791 ;;;; Paragraph
2792 ;;;; Plain List
2793 ;;;; Plain Text
2794 ;;;; Property Drawer
2795 ;;;; Quote Block
2796 ;;;; Quote Section
2797 ;;;; Section
2798 ;;;; Radio Target
2799 ;;;; Special Block
2800 ;;;; Src Block
2802 ;;;; Table
2804 ;;;; Target
2805 ;;;; Time-stamp
2807 ;;;; Verbatim
2808 ;;;; Verse Block
2809 ;;;; Headline
2811 ;;;; Links
2812 ;;;; Drawers
2813 ;;;; Inlinetasks
2814 ;;;; Publishing
2816 ;;;; Compilation
2820 ;;; User Configurable Variables (MAYBE)
2822 ;;;; Preamble
2824 ;;;; Headline
2826 ;;;; Emphasis
2828 (defcustom org-e-odt-format-headline-function nil
2829 "Function to format headline text.
2831 This function will be called with 5 arguments:
2832 TODO the todo keyword \(string or nil\).
2833 TODO-TYPE the type of todo \(symbol: `todo', `done', nil\)
2834 PRIORITY the priority of the headline \(integer or nil\)
2835 TEXT the main headline text \(string\).
2836 TAGS the tags string, separated with colons \(string or nil\).
2838 The function result will be used in the section format string.
2840 As an example, one could set the variable to the following, in
2841 order to reproduce the default set-up:
2843 \(defun org-e-odt-format-headline \(todo todo-type priority text tags\)
2844 \"Default format function for an headline.\"
2845 \(concat \(when todo
2846 \(format \"\\\\textbf{\\\\textsc{\\\\textsf{%s}}} \" todo\)\)
2847 \(when priority
2848 \(format \"\\\\framebox{\\\\#%c} \" priority\)\)
2849 text
2850 \(when tags \(format \"\\\\hfill{}\\\\textsc{%s}\" tags\)\)\)\)"
2851 :group 'org-export-e-odt
2852 :type 'function)
2854 ;;;; Footnotes
2856 ;;;; Time-stamps
2858 (defcustom org-e-odt-active-timestamp-format "\\textit{%s}"
2859 "A printf format string to be applied to active time-stamps."
2860 :group 'org-export-e-odt
2861 :type 'string)
2863 (defcustom org-e-odt-inactive-timestamp-format "\\textit{%s}"
2864 "A printf format string to be applied to inactive time-stamps."
2865 :group 'org-export-e-odt
2866 :type 'string)
2868 (defcustom org-e-odt-diary-timestamp-format "\\textit{%s}"
2869 "A printf format string to be applied to diary time-stamps."
2870 :group 'org-export-e-odt
2871 :type 'string)
2874 ;;;; Links
2876 (defcustom org-e-odt-image-default-option "width=.9\\linewidth"
2877 "Default option for images."
2878 :group 'org-export-e-odt
2879 :type 'string)
2881 (defcustom org-e-odt-default-figure-position "htb"
2882 "Default position for latex figures."
2883 :group 'org-export-e-odt
2884 :type 'string)
2886 (defcustom org-e-odt-inline-image-rules
2887 '(("file" . "\\.\\(pdf\\|jpeg\\|jpg\\|png\\|ps\\|eps\\)\\'"))
2888 "Rules characterizing image files that can be inlined into HTML.
2890 A rule consists in an association whose key is the type of link
2891 to consider, and value is a regexp that will be matched against
2892 link's path.
2894 Note that, by default, the image extension *actually* allowed
2895 depend on the way the HTML file is processed. When used with
2896 pdflatex, pdf, jpg and png images are OK. When processing
2897 through dvi to Postscript, only ps and eps are allowed. The
2898 default we use here encompasses both."
2899 :group 'org-export-e-odt
2900 :type '(alist :key-type (string :tag "Type")
2901 :value-type (regexp :tag "Path")))
2903 ;;;; Tables
2905 (defcustom org-e-odt-table-caption-above t
2906 "When non-nil, place caption string at the beginning of the table.
2907 Otherwise, place it near the end."
2908 :group 'org-export-e-odt
2909 :type 'boolean)
2911 ;;;; Drawers
2913 (defcustom org-e-odt-format-drawer-function nil
2914 "Function called to format a drawer in HTML code.
2916 The function must accept two parameters:
2917 NAME the drawer name, like \"LOGBOOK\"
2918 CONTENTS the contents of the drawer.
2920 The function should return the string to be exported.
2922 For example, the variable could be set to the following function
2923 in order to mimic default behaviour:
2925 \(defun org-e-odt-format-drawer-default \(name contents\)
2926 \"Format a drawer element for HTML export.\"
2927 contents\)"
2928 :group 'org-export-e-odt
2929 :type 'function)
2932 ;;;; Inlinetasks
2934 (defcustom org-e-odt-format-inlinetask-function nil
2935 "Function called to format an inlinetask in HTML code.
2937 The function must accept six parameters:
2938 TODO the todo keyword, as a string
2939 TODO-TYPE the todo type, a symbol among `todo', `done' and nil.
2940 PRIORITY the inlinetask priority, as a string
2941 NAME the inlinetask name, as a string.
2942 TAGS the inlinetask tags, as a string.
2943 CONTENTS the contents of the inlinetask, as a string.
2945 The function should return the string to be exported.
2947 For example, the variable could be set to the following function
2948 in order to mimic default behaviour:
2950 \(defun org-e-odt-format-inlinetask \(todo type priority name tags contents\)
2951 \"Format an inline task element for HTML export.\"
2952 \(let \(\(full-title
2953 \(concat
2954 \(when todo
2955 \(format \"\\\\textbf{\\\\textsf{\\\\textsc{%s}}} \" todo\)\)
2956 \(when priority \(format \"\\\\framebox{\\\\#%c} \" priority\)\)
2957 title
2958 \(when tags \(format \"\\\\hfill{}\\\\textsc{%s}\" tags\)\)\)\)\)
2959 \(format \(concat \"\\\\begin{center}\\n\"
2960 \"\\\\fbox{\\n\"
2961 \"\\\\begin{minipage}[c]{.6\\\\textwidth}\\n\"
2962 \"%s\\n\\n\"
2963 \"\\\\rule[.8em]{\\\\textwidth}{2pt}\\n\\n\"
2964 \"%s\"
2965 \"\\\\end{minipage}}\"
2966 \"\\\\end{center}\"\)
2967 full-title contents\)\)"
2968 :group 'org-export-e-odt
2969 :type 'function)
2972 ;; Src blocks
2974 ;;;; Plain text
2976 (defcustom org-e-odt-quotes
2977 '(("fr" ("\\(\\s-\\|[[(]\\)\"" . "«~") ("\\(\\S-\\)\"" . "~»") ("\\(\\s-\\|(\\)'" . "'"))
2978 ("en" ("\\(\\s-\\|[[(]\\)\"" . "``") ("\\(\\S-\\)\"" . "''") ("\\(\\s-\\|(\\)'" . "`")))
2979 "Alist for quotes to use when converting english double-quotes.
2981 The CAR of each item in this alist is the language code.
2982 The CDR of each item in this alist is a list of three CONS:
2983 - the first CONS defines the opening quote;
2984 - the second CONS defines the closing quote;
2985 - the last CONS defines single quotes.
2987 For each item in a CONS, the first string is a regexp
2988 for allowed characters before/after the quote, the second
2989 string defines the replacement string for this quote."
2990 :group 'org-export-e-odt
2991 :type '(list
2992 (cons :tag "Opening quote"
2993 (string :tag "Regexp for char before")
2994 (string :tag "Replacement quote "))
2995 (cons :tag "Closing quote"
2996 (string :tag "Regexp for char after ")
2997 (string :tag "Replacement quote "))
2998 (cons :tag "Single quote"
2999 (string :tag "Regexp for char before")
3000 (string :tag "Replacement quote "))))
3003 ;;;; Compilation
3007 ;;; Internal Functions (HTML)
3009 ;; (defun org-e-odt-format-inline-image (path &optional caption label attr)
3010 ;; ;; FIXME: alt text missing here?
3011 ;; (let ((inline-image (format "<img src=\"%s\" alt=\"%s\"/>"
3012 ;; path (file-name-nondirectory path))))
3013 ;; (if (not label) inline-image
3014 ;; (org-e-odt-format-section inline-image "figure" label))))
3016 (defun org-e-odt-format-image (src)
3017 "Create image tag with source and attributes."
3018 (save-match-data
3019 (let* ((caption (org-find-text-property-in-string 'org-caption src))
3020 (attr (org-find-text-property-in-string 'org-attributes src))
3021 (label (org-find-text-property-in-string 'org-label src))
3022 (caption (and caption (org-xml-encode-org-text caption)))
3023 (img-extras (if (string-match "^ltxpng/" src)
3024 (format " alt=\"%s\""
3025 (org-find-text-property-in-string
3026 'org-latex-src src))
3027 (if (string-match "\\<alt=" (or attr ""))
3028 (concat " " attr )
3029 (concat " " attr " alt=\"" src "\""))))
3030 (img (format "<img src=\"%s\"%s />" src img-extras))
3031 (extra (concat
3032 (and label
3033 (format "id=\"%s\" " (org-solidify-link-text label)))
3034 "class=\"figure\"")))
3035 (if caption
3036 (with-temp-buffer
3037 (with-org-lparse-preserve-paragraph-state
3038 (insert
3039 (org-lparse-format
3040 '("<div %s>" . "\n</div>")
3041 (concat
3042 (org-lparse-format '("\n<p>" . "</p>") img)
3043 (org-lparse-format '("\n<p>" . "</p>") caption))
3044 extra)))
3045 (buffer-string))
3046 img))))
3048 ;;;; Bibliography
3050 (defun org-e-odt-bibliography ()
3051 "Find bibliography, cut it out and return it."
3052 (catch 'exit
3053 (let (beg end (cnt 1) bib)
3054 (save-excursion
3055 (goto-char (point-min))
3056 (when (re-search-forward
3057 "^[ \t]*<div \\(id\\|class\\)=\"bibliography\"" nil t)
3058 (setq beg (match-beginning 0))
3059 (while (re-search-forward "</?div\\>" nil t)
3060 (setq cnt (+ cnt (if (string= (match-string 0) "<div") +1 -1)))
3061 (when (= cnt 0)
3062 (and (looking-at ">") (forward-char 1))
3063 (setq bib (buffer-substring beg (point)))
3064 (delete-region beg (point))
3065 (throw 'exit bib))))
3066 nil))))
3068 ;;;; Table
3070 (defun org-e-odt-format-table (lines olines)
3071 (let ((org-e-odt-format-table-no-css nil))
3072 (org-lparse-format-table lines olines)))
3074 (defun org-e-odt-splice-attributes (tag attributes)
3075 "Read attributes in string ATTRIBUTES, add and replace in HTML tag TAG."
3076 (if (not attributes)
3078 (let (oldatt newatt)
3079 (setq oldatt (org-extract-attributes-from-string tag)
3080 tag (pop oldatt)
3081 newatt (cdr (org-extract-attributes-from-string attributes)))
3082 (while newatt
3083 (setq oldatt (plist-put oldatt (pop newatt) (pop newatt))))
3084 (if (string-match ">" tag)
3085 (setq tag
3086 (replace-match (concat (org-attributes-to-string oldatt) ">")
3087 t t tag)))
3088 tag)))
3090 (defun org-export-splice-style (style extra)
3091 "Splice EXTRA into STYLE, just before \"</style>\"."
3092 (if (and (stringp extra)
3093 (string-match "\\S-" extra)
3094 (string-match "</style>" style))
3095 (concat (substring style 0 (match-beginning 0))
3096 "\n" extra "\n"
3097 (substring style (match-beginning 0)))
3098 style))
3100 ;; (defun org-e-odt-format-toc-entry (snumber todo headline tags href)
3101 ;; (setq headline (concat
3102 ;; ;; section number
3103 ;; (and org-export-with-section-numbers (concat snumber " "))
3104 ;; ;; headline
3105 ;; headline
3106 ;; ;; tags
3107 ;; (and tags (concat
3108 ;; (org-e-odt-format-spaces 3)
3109 ;; (org-e-odt-format-fontify tags "tag")))))
3110 ;; ;; fontify headline based on TODO keyword
3111 ;; (when todo (setq headline (org-e-odt-format-fontify headline "todo")))
3112 ;; (org-e-odt-format-link headline (concat "#" href)))
3114 (defun org-e-odt-toc-entry-formatter
3115 (level snumber todo todo-type priority
3116 headline tags target extra-targets extra-class)
3117 (org-e-odt-format-toc-entry snumber todo headline tags target))
3119 (defun org-e-odt-make-string (n string)
3120 (let (out) (dotimes (i n out) (setq out (concat string out)))))
3122 (defun org-e-odt-toc-text (toc-entries)
3123 (let* ((prev-level (1- (nth 1 (car toc-entries))))
3124 (start-level prev-level))
3125 (mapconcat
3126 (lambda (entry)
3127 (let ((headline (nth 0 entry))
3128 (level (nth 1 entry)))
3129 (prog1 (org-e-odt-format-toc-item headline level prev-level)
3130 (setq prev-level level))))
3131 toc-entries "")))
3133 (defun org-e-odt-toc (depth info)
3134 (assert (wholenump depth))
3135 (let* ((headlines (org-export-collect-headlines info depth))
3136 (toc-entries
3137 (loop for headline in headlines collect
3138 (list (org-e-odt-headline-text
3139 headline info 'org-e-odt-toc-entry-formatter)
3140 (org-export-get-relative-level headline info)))))
3141 (when toc-entries
3142 (let* ((lang-specific-heading "Table of Contents")) ; FIXME
3143 (concat
3144 (org-e-odt-begin-toc lang-specific-heading depth)
3145 (org-e-odt-toc-text toc-entries)
3146 (org-e-odt-end-toc))))))
3148 (defun org-e-odt-begin-outline (level1 snumber title tags
3149 target extra-targets extra-class)
3150 (let* ((class (format "outline-%d" level1))
3151 (class (if extra-class (concat class " " extra-class) class))
3152 (id (format "outline-container-%s"
3153 (org-lparse-suffix-from-snumber snumber)))
3154 (extra (concat (when id (format " id=\"%s\"" id))
3155 (when class (format " class=\"%s\"" class)))))
3156 (org-lparse-insert-tag "<div%s>" extra)
3157 (insert
3158 (org-lparse-format 'HEADING
3159 (org-lparse-format
3160 'HEADLINE title extra-targets tags snumber level1)
3161 level1 target))))
3163 (defun org-e-odt-end-outline ()
3164 (org-lparse-insert-tag "</div>"))
3166 (defun org-e-odt-suffix-from-snumber (snumber)
3167 (let* ((snu (replace-regexp-in-string "\\." "-" snumber))
3168 (href (cdr (assoc (concat "sec-" snu)
3169 org-export-preferred-target-alist))))
3170 (org-solidify-link-text (or href snu))))
3172 (defun org-e-odt-format-outline (contents level1 snumber title
3173 tags target extra-targets extra-class)
3174 (concat
3175 (org-e-odt-format-heading
3176 (org-e-odt-format-headline title extra-targets tags snumber level1)
3177 level1 target)
3178 contents))
3180 ;; (defun org-e-odt-format-line (line)
3181 ;; (case org-lparse-dyn-current-environment
3182 ;; ((quote fixedwidth) (concat (org-e-odt-encode-plain-text line) "\n"))
3183 ;; (t (concat line "\n"))))
3185 (defun org-e-odt-fix-class-name (kwd) ; audit callers of this function
3186 "Turn todo keyword into a valid class name.
3187 Replaces invalid characters with \"_\"."
3188 (save-match-data
3189 (while (string-match "[^a-zA-Z0-9_]" kwd)
3190 (setq kwd (replace-match "_" t t kwd))))
3191 kwd)
3193 (defun org-e-odt-format-internal-link (text href &optional extra)
3194 (org-e-odt-format-link text (concat "#" href) extra))
3196 (defun org-e-odt-format-extra-targets (extra-targets)
3197 (if (not extra-targets) ""
3198 (mapconcat (lambda (x)
3199 (when x
3200 (setq x (org-solidify-link-text
3201 (if (org-uuidgen-p x) (concat "ID-" x) x)))
3202 (org-e-odt-format-anchor "" x))) extra-targets "")))
3204 (defun org-e-odt-format-org-tags (tags)
3205 (if (not tags) ""
3206 (org-e-odt-format-fontify
3207 (mapconcat
3208 (lambda (x)
3209 (org-e-odt-format-fontify
3210 x (concat "" ;; org-e-odt-tag-class-prefix
3211 (org-e-odt-fix-class-name x))))
3212 (org-split-string tags ":")
3213 (org-e-odt-format-spaces 1)) "tag")))
3215 (defun org-e-odt-format-section-number (&optional snumber level)
3216 ;; FIXME
3217 (and nil org-export-with-section-numbers
3218 ;; (not org-lparse-body-only)
3219 snumber level
3220 (org-e-odt-format-fontify snumber (format "section-number-%d" level))))
3222 ;; (defun org-e-odt-format-headline (title extra-targets tags
3223 ;; &optional snumber level)
3224 ;; (concat
3225 ;; (org-e-odt-format-extra-targets extra-targets)
3226 ;; (concat (org-e-odt-format-section-number snumber level) " ")
3227 ;; title
3228 ;; (and tags (concat (org-e-odt-format-spaces 3)
3229 ;; (org-e-odt-format-org-tags tags)))))
3231 (defun org-e-odt-get-coding-system-for-write ()
3232 (or org-e-odt-coding-system
3233 (and (boundp 'buffer-file-coding-system) buffer-file-coding-system)))
3235 (defun org-e-odt-get-coding-system-for-save ()
3236 (or org-e-odt-coding-system
3237 (and (boundp 'buffer-file-coding-system) buffer-file-coding-system)))
3239 ;; (defun org-e-odt-format-date (info)
3240 ;; (let ((date (plist-get info :date)))
3241 ;; (cond
3242 ;; ((and date (string-match "%" date))
3243 ;; (format-time-string date))
3244 ;; (date date)
3245 ;; (t (format-time-string "%Y-%m-%d %T %Z")))))
3249 ;;; Internal Functions (Ngz)
3251 (defun org-e-odt--caption/label-string (caption label info)
3252 "Return caption and label HTML string for floats.
3254 CAPTION is a cons cell of secondary strings, the car being the
3255 standard caption and the cdr its short form. LABEL is a string
3256 representing the label. INFO is a plist holding contextual
3257 information.
3259 If there's no caption nor label, return the empty string.
3261 For non-floats, see `org-e-odt--wrap-label'."
3262 (setq label nil) ;; FIXME
3264 (let ((label-str (if label (format "\\label{%s}" label) "")))
3265 (cond
3266 ((and (not caption) (not label)) "")
3267 ((not caption) (format "\\label{%s}\n" label))
3268 ;; Option caption format with short name.
3269 ((cdr caption)
3270 (format "\\caption[%s]{%s%s}\n"
3271 (org-export-secondary-string (cdr caption) 'e-odt info)
3272 label-str
3273 (org-export-secondary-string (car caption) 'e-odt info)))
3274 ;; Standard caption format.
3275 ;; (t (format "\\caption{%s%s}\n"
3276 ;; label-str
3277 ;; (org-export-secondary-string (car caption) 'e-odt info)))
3279 (t (org-export-secondary-string (car caption) 'e-odt info)))))
3281 (defun org-e-odt--find-verb-separator (s)
3282 "Return a character not used in string S.
3283 This is used to choose a separator for constructs like \\verb."
3284 (let ((ll "~,./?;':\"|!@#%^&-_=+abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ<>()[]{}"))
3285 (loop for c across ll
3286 when (not (string-match (regexp-quote (char-to-string c)) s))
3287 return (char-to-string c))))
3289 (defun org-e-odt--make-option-string (options)
3290 "Return a comma separated string of keywords and values.
3291 OPTIONS is an alist where the key is the options keyword as
3292 a string, and the value a list containing the keyword value, or
3293 nil."
3294 (mapconcat (lambda (pair)
3295 (concat (first pair)
3296 (when (> (length (second pair)) 0)
3297 (concat "=" (second pair)))))
3298 options
3299 ","))
3301 (defun org-e-odt--quotation-marks (text info)
3302 "Export quotation marks depending on language conventions.
3303 TEXT is a string containing quotation marks to be replaced. INFO
3304 is a plist used as a communication channel."
3305 (mapc (lambda(l)
3306 (let ((start 0))
3307 (while (setq start (string-match (car l) text start))
3308 (let ((new-quote (concat (match-string 1 text) (cdr l))))
3309 (setq text (replace-match new-quote t t text))))))
3310 (cdr (or (assoc (plist-get info :language) org-e-odt-quotes)
3311 ;; Falls back on English.
3312 (assoc "en" org-e-odt-quotes))))
3313 text)
3315 (defun org-e-odt--wrap-label (element output)
3316 "Wrap label associated to ELEMENT around OUTPUT, if appropriate.
3317 This function shouldn't be used for floats. See
3318 `org-e-odt--caption/label-string'."
3319 ;; (let ((label (org-element-property :name element)))
3320 ;; (if (or (not output) (not label) (string= output "") (string= label ""))
3321 ;; output
3322 ;; (concat (format "\\label{%s}\n" label) output)))
3323 output)
3327 ;;; Template
3329 (defun org-e-odt-template (contents info)
3330 "Return complete document string after HTML conversion.
3331 CONTENTS is the transcoded contents string. RAW-DATA is the
3332 original parsed data. INFO is a plist holding export options."
3335 ;; write meta file
3336 (org-e-odt-update-meta-file info)
3339 (with-temp-buffer
3340 (insert-file-contents
3341 (or org-export-e-odt-content-template-file
3342 (expand-file-name "OrgOdtContentTemplate.xml"
3343 org-e-odt-styles-dir)))
3344 (goto-char (point-min))
3345 (re-search-forward "</office:text>" nil nil)
3346 (goto-char (match-beginning 0))
3348 ;; Title
3349 (insert (org-e-odt-format-preamble info))
3350 ;; Table of Contents
3351 (let ((depth (plist-get info :with-toc)))
3352 (when (wholenump depth) (org-e-odt-toc depth info)))
3354 ;; Contents
3355 (insert contents)
3356 (buffer-substring-no-properties (point-min) (point-max))))
3360 ;;; Transcode Functions
3362 ;;;; Block
3364 (defun org-e-odt-center-block (center-block contents info)
3365 "Transcode a CENTER-BLOCK element from Org to HTML.
3366 CONTENTS holds the contents of the block. INFO is a plist
3367 holding contextual information."
3368 (org-e-odt--wrap-label center-block contents))
3371 ;;;; Comment
3373 ;; Comments are ignored.
3376 ;;;; Comment Block
3378 ;; Comment Blocks are ignored.
3381 ;;;; Drawer
3383 (defun org-e-odt-drawer (drawer contents info)
3384 "Transcode a DRAWER element from Org to HTML.
3385 CONTENTS holds the contents of the block. INFO is a plist
3386 holding contextual information."
3387 (let* ((name (org-element-property :drawer-name drawer))
3388 (output (if (functionp org-e-odt-format-drawer-function)
3389 (funcall org-e-odt-format-drawer-function
3390 name contents)
3391 ;; If there's no user defined function: simply
3392 ;; display contents of the drawer.
3393 contents)))
3394 (org-e-odt--wrap-label drawer output)))
3397 ;;;; Dynamic Block
3399 (defun org-e-odt-dynamic-block (dynamic-block contents info)
3400 "Transcode a DYNAMIC-BLOCK element from Org to HTML.
3401 CONTENTS holds the contents of the block. INFO is a plist
3402 holding contextual information. See
3403 `org-export-data'."
3404 (org-e-odt--wrap-label dynamic-block contents))
3407 ;;;; Emphasis
3409 (defun org-e-odt-emphasis (emphasis contents info)
3410 "Transcode EMPHASIS from Org to HTML.
3411 CONTENTS is the contents of the emphasized text. INFO is a plist
3412 holding contextual information.."
3413 ;; (format (cdr (assoc (org-element-property :marker emphasis)
3414 ;; org-e-odt-emphasis-alist))
3415 ;; contents)
3416 (org-e-odt-format-fontify
3417 contents (cadr (assoc
3418 (org-element-property :marker emphasis)
3419 '(("*" bold)
3420 ("/" emphasis)
3421 ("_" underline)
3422 ("=" code)
3423 ("~" verbatim)
3424 ("+" strike))))))
3427 ;;;; Entity
3429 (defun org-e-odt-entity (entity contents info)
3430 "Transcode an ENTITY object from Org to HTML.
3431 CONTENTS are the definition itself. INFO is a plist holding
3432 contextual information."
3433 ;; (let ((ent (org-element-property :latex entity)))
3434 ;; (if (org-element-property :latex-math-p entity)
3435 ;; (format "$%s$" ent)
3436 ;; ent))
3437 (org-element-property :utf-8 entity))
3440 ;;;; Example Block
3442 (defun org-e-odt-example-block (example-block contents info)
3443 "Transcode a EXAMPLE-BLOCK element from Org to HTML.
3444 CONTENTS is nil. INFO is a plist holding contextual information."
3445 (let* ((options (or (org-element-property :options example-block) ""))
3446 (value (org-export-handle-code example-block info nil nil t)))
3447 (org-e-odt--wrap-label
3448 example-block (org-e-odt-format-source-code-or-example value nil))))
3451 ;;;; Export Snippet
3453 (defun org-e-odt-export-snippet (export-snippet contents info)
3454 "Transcode a EXPORT-SNIPPET object from Org to HTML.
3455 CONTENTS is nil. INFO is a plist holding contextual information."
3456 (when (eq (org-export-snippet-backend export-snippet) 'e-odt)
3457 (org-element-property :value export-snippet)))
3460 ;;;; Export Block
3462 (defun org-e-odt-export-block (export-block contents info)
3463 "Transcode a EXPORT-BLOCK element from Org to HTML.
3464 CONTENTS is nil. INFO is a plist holding contextual information."
3465 (when (string= (org-element-property :type export-block) "latex")
3466 (org-remove-indentation (org-element-property :value export-block))))
3469 ;;;; Fixed Width
3471 (defun org-e-odt-fixed-width (fixed-width contents info)
3472 "Transcode a FIXED-WIDTH element from Org to HTML.
3473 CONTENTS is nil. INFO is a plist holding contextual information."
3474 (let* ((value (org-element-normalize-string
3475 (replace-regexp-in-string
3476 "^[ \t]*: ?" ""
3477 (org-element-property :value fixed-width)))))
3478 (org-e-odt--wrap-label
3479 fixed-width (org-e-odt-format-source-code-or-example value nil))))
3482 ;;;; Footnote Definition
3484 ;; Footnote Definitions are ignored.
3487 ;;;; Footnote Reference
3489 (defun org-e-odt-footnote-def (raw info) ; FIXME
3490 (if (equal (org-element-type raw) 'org-data)
3491 (org-trim (org-export-data raw 'e-odt info))
3492 (org-odt-format-stylized-paragraph
3493 'footnote (org-trim (org-export-secondary-string raw 'e-odt info)))))
3495 (defvar org-e-odt-footnote-separator
3496 (org-e-odt-format-fontify "," 'superscript))
3498 (defun org-e-odt-footnote-reference (footnote-reference contents info)
3499 "Transcode a FOOTNOTE-REFERENCE element from Org to HTML.
3500 CONTENTS is nil. INFO is a plist holding contextual information."
3501 (concat
3502 ;; Insert separator between two footnotes in a row.
3503 (let ((prev (org-export-get-previous-element footnote-reference info)))
3504 (when (and (listp prev) (eq (car prev) 'footnote-reference))
3505 org-e-odt-footnote-separator))
3506 (cond
3507 ((not (org-export-footnote-first-reference-p footnote-reference info))
3508 (let* ((n (org-export-get-footnote-number footnote-reference info)))
3509 (org-e-odt-format-footnote-reference n "IGNORED" 100)))
3510 ;; Inline definitions are secondary strings.
3511 ((eq (org-element-property :type footnote-reference) 'inline)
3512 (let* ((raw (org-export-get-footnote-definition footnote-reference info))
3513 (n (org-export-get-footnote-number footnote-reference info))
3514 (def (org-e-odt-footnote-def raw info)))
3515 (org-e-odt-format-footnote-reference n def 1)))
3516 ;; Non-inline footnotes definitions are full Org data.
3518 (let* ((raw (org-export-get-footnote-definition footnote-reference info))
3519 (n (org-export-get-footnote-number footnote-reference info))
3520 (def (org-e-odt-footnote-def raw info)))
3521 (org-e-odt-format-footnote-reference n def 1))))))
3524 ;;;; Headline
3526 (defun org-e-odt-todo (todo)
3527 (when todo
3528 (org-e-odt-format-fontify
3529 (concat
3530 "" ; org-e-odt-todo-kwd-class-prefix
3531 (org-e-odt-fix-class-name todo))
3532 (list (if (member todo org-done-keywords) "done" "todo")
3533 todo))))
3535 (defun org-e-odt-headline-text (headline info &optional formatter)
3536 "Transcode an HEADLINE element from Org to HTML.
3537 CONTENTS holds the contents of the headline. INFO is a plist
3538 holding contextual information."
3539 (let* ((numberedp (plist-get info :section-numbers))
3540 (level (org-export-get-relative-level headline info))
3541 (todo (and (plist-get info :with-todo-keywords)
3542 (let ((todo (org-element-property
3543 :todo-keyword headline)))
3544 (and todo
3545 (org-export-secondary-string todo 'e-odt info)))))
3546 (todo-type (and todo (org-element-property :todo-type headline)))
3547 (priority (and (plist-get info :with-priority)
3548 (org-element-property :priority headline)))
3549 (text (org-export-secondary-string
3550 (org-element-property :title headline) 'e-odt info))
3551 (tags (and (plist-get info :with-tags)
3552 (org-element-property :tags headline)))
3554 (headline-no (org-export-get-headline-number headline info))
3555 (headline-label
3556 (format "sec-%s" (mapconcat 'number-to-string headline-no "-")))
3557 (headline-labels (list headline-label))
3558 (headline-no (org-export-get-headline-number headline info))
3559 (section-no (mapconcat 'number-to-string headline-no "."))
3560 (primary-target (car (last headline-labels)))
3561 (secondary-targets (butlast headline-labels))
3562 (extra-class nil)
3563 (formatter (or (and (functionp formatter) formatter)
3564 org-e-odt-headline-formatter)))
3565 (funcall formatter level section-no todo todo-type priority
3566 text tags primary-target secondary-targets extra-class)))
3568 (defun org-e-odt-headline (headline contents info)
3569 "Transcode an HEADLINE element from Org to HTML.
3570 CONTENTS holds the contents of the headline. INFO is a plist
3571 holding contextual information."
3572 (let* ((class (plist-get info :latex-class))
3573 (numberedp (plist-get info :section-numbers))
3574 ;; Get level relative to current parsed data.
3575 (level (org-export-get-relative-level headline info))
3576 ;; (class-sectionning (assoc class org-e-odt-classes))
3577 ;; Section formatting will set two placeholders: one for the
3578 ;; title and the other for the contents.
3579 ;; (section-fmt
3580 ;; (let ((sec (if (and (symbolp (nth 2 class-sectionning))
3581 ;; (fboundp (nth 2 class-sectionning)))
3582 ;; (funcall (nth 2 class-sectionning) level numberedp)
3583 ;; (nth (1+ level) class-sectionning))))
3584 ;; (cond
3585 ;; ;; No section available for that LEVEL.
3586 ;; ((not sec) nil)
3587 ;; ;; Section format directly returned by a function.
3588 ;; ((stringp sec) sec)
3589 ;; ;; (numbered-section . unnumbered-section)
3590 ;; ((not (consp (cdr sec)))
3591 ;; (concat (funcall (if numberedp #'car #'cdr) sec) "\n%s"))
3592 ;; ;; (numbered-open numbered-close)
3593 ;; ((= (length sec) 2)
3594 ;; (when numberedp (concat (car sec) "\n%s" (nth 1 sec))))
3595 ;; ;; (num-in num-out no-num-in no-num-out)
3596 ;; ((= (length sec) 4)
3597 ;; (if numberedp
3598 ;; (concat (car sec) "\n%s" (nth 1 sec))
3599 ;; (concat (nth 2 sec) "\n%s" (nth 3 sec)))))))
3600 (text (org-export-secondary-string
3601 (org-element-property :title headline) 'e-odt info))
3602 (todo (and (plist-get info :with-todo-keywords)
3603 (let ((todo (org-element-property
3604 :todo-keyword headline)))
3605 (and todo
3606 (org-export-secondary-string todo 'e-odt info)))))
3607 (todo-type (and todo (org-element-property :todo-type headline)))
3608 (tags (and (plist-get info :with-tags)
3609 (org-element-property :tags headline)))
3610 (priority (and (plist-get info :with-priority)
3611 (org-element-property :priority headline)))
3612 ;; Create the headline text.
3613 (full-text (if (functionp org-e-odt-format-headline-function)
3614 ;; User-defined formatting function.
3615 (funcall org-e-odt-format-headline-function
3616 todo todo-type priority text tags)
3617 ;; Default formatting.
3618 (concat
3619 ;; (when todo
3620 ;; (format "\\textbf{\\textsf{\\textsc{%s}}} " todo))
3621 (org-e-odt-todo todo) " "
3622 (when priority (format "\\framebox{\\#%c} " priority))
3623 text
3624 ;; (when tags (format "\\hfill{}\\textsc{%s}" tags))
3626 ;; Associate some \label to the headline for internal links.
3627 ;; (headline-label
3628 ;; (format "\\label{sec-%s}\n"
3629 ;; (mapconcat 'number-to-string
3630 ;; (org-export-get-headline-number headline info)
3631 ;; "-")))
3633 ;; FIXME - begin
3634 (headline-no (org-export-get-headline-number headline info))
3635 (headline-label
3636 (format "sec-%s" (mapconcat 'number-to-string headline-no "-")))
3637 (headline-labels (list headline-label))
3638 (headline-no (org-export-get-headline-number headline info))
3639 (section-no (mapconcat 'number-to-string headline-no "."))
3640 ;; FIXME - end
3642 (pre-blanks (make-string
3643 (org-element-property :pre-blank headline) 10)))
3644 (cond
3645 ;; Case 1: This is a footnote section: ignore it.
3646 ((org-element-property :footnote-section-p headline) nil)
3647 ;; Case 2. This is a deep sub-tree: export it as a list item.
3648 ;; Also export as items headlines for which no section
3649 ;; format has been found.
3650 ((org-export-low-level-p headline info) ; FIXME (or (not section-fmt))
3651 ;; Build the real contents of the sub-tree.
3652 (let* ((type (if numberedp 'unordered 'unordered)) ; FIXME
3653 (itemized-body (org-e-odt-format-list-item
3654 contents type nil nil full-text)))
3655 (concat
3656 (and (org-export-first-sibling-p headline info)
3657 (org-e-odt-begin-plain-list type))
3658 itemized-body
3659 (and (org-export-last-sibling-p headline info)
3660 (org-e-odt-end-plain-list type)))))
3661 ;; Case 3. Standard headline. Export it as a section.
3663 ;; (format section-fmt full-text
3664 ;; (concat headline-label pre-blanks contents))
3666 (org-e-odt-format-outline contents level section-no full-text tags
3667 (car (last headline-labels))
3668 (butlast headline-labels) nil)))))
3671 ;;;; Horizontal Rule
3673 (defun org-e-odt-horizontal-rule (horizontal-rule contents info)
3674 "Transcode an HORIZONTAL-RULE object from Org to HTML.
3675 CONTENTS is nil. INFO is a plist holding contextual information."
3676 (let ((attr (mapconcat #'identity
3677 (org-element-property :attr_odt horizontal-rule)
3678 " ")))
3679 (org-e-odt--wrap-label horizontal-rule
3680 (org-e-odt-format-horizontal-line))))
3683 ;;;; Inline Babel Call
3685 ;; Inline Babel Calls are ignored.
3688 ;;;; Inline Src Block
3690 (defun org-e-odt-inline-src-block (inline-src-block contents info)
3691 "Transcode an INLINE-SRC-BLOCK element from Org to HTML.
3692 CONTENTS holds the contents of the item. INFO is a plist holding
3693 contextual information."
3694 (let* ((org-lang (org-element-property :language inline-src-block))
3695 (code (org-element-property :value inline-src-block))
3696 (separator (org-e-odt--find-verb-separator code)))
3697 (error "FIXME")))
3700 ;;;; Inlinetask
3702 (defun org-e-odt-format-section (text class &optional id)
3703 (let ((extra (concat (when id (format " id=\"%s\"" id)))))
3704 (concat (format "<div class=\"%s\"%s>\n" class extra) text "</div>\n")))
3706 (defun org-e-odt-inlinetask (inlinetask contents info)
3707 "Transcode an INLINETASK element from Org to HTML.
3708 CONTENTS holds the contents of the block. INFO is a plist
3709 holding contextual information."
3710 (let ((title (org-export-secondary-string
3711 (org-element-property :title inlinetask) 'e-odt info))
3712 (todo (and (plist-get info :with-todo-keywords)
3713 (let ((todo (org-element-property
3714 :todo-keyword inlinetask)))
3715 (and todo
3716 (org-export-secondary-string todo 'e-odt info)))))
3717 (todo-type (org-element-property :todo-type inlinetask))
3718 (tags (and (plist-get info :with-tags)
3719 (org-element-property :tags inlinetask)))
3720 (priority (and (plist-get info :with-priority)
3721 (org-element-property :priority inlinetask))))
3722 ;; If `org-e-odt-format-inlinetask-function' is provided, call it
3723 ;; with appropriate arguments.
3724 (if (functionp org-e-odt-format-inlinetask-function)
3725 (funcall org-e-odt-format-inlinetask-function
3726 todo todo-type priority title tags contents)
3727 ;; Otherwise, use a default template.
3728 (org-e-odt--wrap-label
3729 inlinetask
3730 (let ((full-title
3731 (concat
3732 (when todo (format "\\textbf{\\textsf{\\textsc{%s}}} " todo))
3733 (when priority (format "\\framebox{\\#%c} " priority))
3734 title
3735 (when tags (format "\\hfill{}\\textsc{%s}" tags)))))
3736 (format (concat "\\begin{center}\n"
3737 "\\fbox{\n"
3738 "\\begin{minipage}[c]{.6\\textwidth}\n"
3739 "%s\n\n"
3740 "\\rule[.8em]{\\textwidth}{2pt}\n\n"
3741 "%s"
3742 "\\end{minipage}\n"
3743 "}\n"
3744 "\\end{center}")
3745 full-title contents))))))
3748 ;;;; Item
3750 (defun org-e-odt-format-list-item (contents type checkbox
3751 &optional term-counter-id
3752 headline)
3753 (when checkbox
3754 (setq checkbox
3755 (org-e-odt-format-fontify (case checkbox
3756 (on "[X]")
3757 (off "[&nbsp;]")
3758 (trans "[-]")) 'code)))
3759 (concat
3760 (org-e-odt-begin-list-item type term-counter-id headline)
3761 ;; FIXME checkbox (and checkbox " ")
3762 contents
3763 (org-e-odt-end-list-item type)))
3765 (defun org-e-odt-item (item contents info)
3766 "Transcode an ITEM element from Org to HTML.
3767 CONTENTS holds the contents of the item. INFO is a plist holding
3768 contextual information."
3769 ;; Grab `:level' from plain-list properties, which is always the
3770 ;; first element above current item.
3771 (let* ((plain-list (org-export-get-parent item info))
3772 (type (org-element-property :type plain-list))
3773 (level (org-element-property :level plain-list))
3774 (counter (org-element-property :counter item))
3775 (checkbox (org-element-property :checkbox item))
3776 (tag (let ((tag (org-element-property :tag item)))
3777 (and tag (org-export-secondary-string tag 'e-odt info)))))
3778 (org-e-odt-format-list-item
3779 contents type checkbox (or tag counter))))
3782 ;;;; Keyword
3784 (defun org-e-odt-keyword (keyword contents info)
3785 "Transcode a KEYWORD element from Org to HTML.
3786 CONTENTS is nil. INFO is a plist holding contextual information."
3787 (let ((key (downcase (org-element-property :key keyword)))
3788 (value (org-element-property :value keyword)))
3789 (cond
3790 ((string= key "latex") value)
3791 ((string= key "index") (format "\\index{%s}" value))
3792 ((string= key "target")
3793 (format "\\label{%s}" (org-export-solidify-link-text value)))
3794 ((string= key "toc")
3795 (let ((value (downcase value)))
3796 (cond
3797 ((string-match "\\<headlines\\>" value)
3798 (let ((depth (or (and (string-match "[0-9]+" value)
3799 (string-to-number (match-string 0 value)))
3800 (plist-get info :with-toc))))
3801 (when (wholenump depth) (org-e-odt-toc depth info))))
3802 ((string= "tables" value) "FIXME")
3803 ((string= "figures" value) "FIXME")
3804 ((string= "listings" value)
3805 (cond
3806 ;; At the moment, src blocks with a caption are wrapped
3807 ;; into a figure environment.
3808 (t "FIXME")))))))))
3811 ;;;; Latex Environment
3813 (defun org-e-odt-format-latex (latex-frag processing-type)
3814 (let* ((prefix (case processing-type
3815 (dvipng "ltxpng/")
3816 (mathml "ltxmathml/")))
3817 (cache-relpath
3818 (concat prefix (file-name-sans-extension
3819 (file-name-nondirectory (buffer-file-name)))))
3820 (cache-dir (file-name-directory (buffer-file-name )))
3821 (display-msg (case processing-type
3822 (dvipng "Creating LaTeX Image...")
3823 (mathml "Creating MathML snippet..."))))
3824 (with-temp-buffer
3825 (insert latex-frag)
3826 (org-format-latex cache-relpath cache-dir nil display-msg
3827 nil nil processing-type)
3828 (buffer-string))))
3830 (defun org-e-odt-latex-environment (latex-environment contents info)
3831 "Transcode a LATEX-ENVIRONMENT element from Org to HTML.
3832 CONTENTS is nil. INFO is a plist holding contextual information."
3833 (org-e-odt--wrap-label
3834 latex-environment
3835 (let ((latex-frag
3836 (org-remove-indentation
3837 (org-element-property :value latex-environment)))
3838 (processing-type (plist-get info :LaTeX-fragments)))
3839 (cond
3840 ((member processing-type '(t mathjax))
3841 (org-e-odt-format-latex latex-frag 'mathml))
3842 ((equal processing-type 'dvipng)
3843 (let* ((formula-link (org-e-odt-format-latex
3844 latex-frag processing-type)))
3845 (when (and formula-link
3846 (string-match "file:\\([^]]*\\)" formula-link))
3847 (org-e-odt-format-inline-image (match-string 1 formula-link)))))
3849 latex-frag)))))
3852 ;;;; Latex Fragment
3854 (defun org-e-odt-latex-fragment (latex-fragment contents info)
3855 "Transcode a LATEX-FRAGMENT object from Org to HTML.
3856 CONTENTS is nil. INFO is a plist holding contextual information."
3857 ;; (org-element-property :value latex-fragment)
3858 (let* ((latex-frag (org-element-property :value latex-fragment)))
3859 (cond
3860 ((string-match "\\\\ref{\\([^{}\n]+\\)}" latex-frag)
3861 (let* ((label (match-string 1 latex-frag))
3862 (href (and label (org-export-solidify-link-text label)))
3863 (text (if (string-match "\\`[a-z]\\{1,10\\}:\\(.+\\)" label)
3864 (substring label (match-beginning 1))
3865 label)))
3866 (org-e-odt-format-internal-link text href)))
3867 (t (let ((processing-type (plist-get info :LaTeX-fragments)))
3868 (cond
3869 ((member processing-type '(t mathjax))
3870 (org-e-odt-format-latex latex-frag 'mathjax))
3871 ((equal processing-type 'dvipng)
3872 (let* ((formula-link (org-e-odt-format-latex
3873 latex-frag processing-type)))
3874 (when (and formula-link
3875 (string-match "file:\\([^]]*\\)" formula-link))
3876 (org-e-odt-format-inline-image
3877 (match-string 1 formula-link)))))
3878 (t latex-frag)))))))
3881 ;;;; Line Break
3883 (defun org-e-odt-line-break (line-break contents info)
3884 "Transcode a LINE-BREAK object from Org to HTML.
3885 CONTENTS is nil. INFO is a plist holding contextual information."
3886 "<text:line-break/>\n")
3889 ;;;; Link
3891 (defun org-e-odt-link--inline-image (link info)
3892 "Return HTML code for an inline image.
3893 LINK is the link pointing to the inline image. INFO is a plist
3894 used as a communication channel."
3895 (let* ((parent (org-export-get-parent-paragraph link info))
3896 (path (let ((raw-path (org-element-property :path link)))
3897 (if (not (file-name-absolute-p raw-path)) raw-path
3898 (expand-file-name raw-path))))
3899 (caption (org-e-odt--caption/label-string
3900 (org-element-property :caption parent)
3901 (org-element-property :name parent)
3902 info))
3903 (label (org-element-property :name parent))
3904 ;; Retrieve latex attributes from the element around.
3905 (attr (let ((raw-attr
3906 (mapconcat #'identity
3907 (org-element-property :attr_odt parent)
3908 " ")))
3909 (unless (string= raw-attr "") raw-attr))))
3910 ;; Now clear ATTR from any special keyword and set a default
3911 ;; value if nothing is left.
3912 (setq attr (if (not attr) "" (org-trim attr)))
3913 ;; Return proper string, depending on DISPOSITION.
3914 (let ((href (and label (org-export-solidify-link-text label))))
3915 (org-e-odt-format-inline-image path caption href attr))))
3917 (defun org-e-odt-link (link desc info)
3918 "Transcode a LINK object from Org to HTML.
3920 DESC is the description part of the link, or the empty string.
3921 INFO is a plist holding contextual information. See
3922 `org-export-data'."
3923 (let* ((type (org-element-property :type link))
3924 (raw-path (org-element-property :path link))
3925 ;; Ensure DESC really exists, or set it to nil.
3926 (desc (and (not (string= desc "")) desc))
3927 (imagep (org-export-inline-image-p
3928 link org-e-odt-inline-image-rules))
3929 (path (cond
3930 ((member type '("http" "https" "ftp" "mailto"))
3931 (concat type ":" raw-path))
3932 ((string= type "file")
3933 (when (string-match "\\(.+\\)::.+" raw-path)
3934 (setq raw-path (match-string 1 raw-path)))
3935 (if (file-name-absolute-p raw-path)
3936 (concat "file://" (expand-file-name raw-path))
3937 ;; TODO: Not implemented yet. Concat also:
3938 ;; (org-export-directory :HTML info)
3939 (concat "file://" raw-path)))
3940 (t raw-path)))
3941 protocol)
3942 (cond
3943 ;; Image file.
3944 (imagep (org-e-odt-link--inline-image link info))
3945 ;; Target or radioed target: replace link with the normalized
3946 ;; custom-id/target name.
3947 ((member type '("target" "radio"))
3948 (org-e-odt-format-internal-link
3949 (or desc (org-export-secondary-string path 'e-odt info))
3950 (org-export-solidify-link-text path)))
3951 ;; Links pointing to an headline: Find destination and build
3952 ;; appropriate referencing commanding.
3953 ((member type '("custom-id" "fuzzy" "id"))
3954 (let ((destination (if (string= type "fuzzy")
3955 (org-export-resolve-fuzzy-link link info)
3956 (org-export-resolve-id-link link info))))
3957 ;; Fuzzy link points to a target. Do as above.
3958 (case (org-element-type destination)
3959 (target
3960 (org-e-odt-format-internal-link
3961 (or desc
3962 (org-export-secondary-string
3963 (org-element-property :raw-link link)
3964 'e-odt info))
3965 (org-export-solidify-link-text
3966 (org-element-property :raw-value destination))))
3967 ;; Fuzzy link points to an headline. If headlines are
3968 ;; numbered and the link has no description, display
3969 ;; headline's number. Otherwise, display description or
3970 ;; headline's title.
3971 (headline
3972 (let ((label
3973 (format "sec-%s"
3974 (mapconcat
3975 'number-to-string
3976 (org-export-get-headline-number destination info)
3977 "-"))))
3978 (if (and (plist-get info :section-numbers) (not desc))
3979 (format "\\ref{%s}" label)
3980 (org-e-odt-format-internal-link
3981 (or desc
3982 (org-export-secondary-string
3983 (org-element-property :title destination)
3984 'e-odt info)) label))))
3985 ;; Fuzzy link points nowhere.
3986 (otherwise
3987 (org-e-odt-format-fontify
3988 (or desc
3989 (org-export-secondary-string
3990 (org-element-property :raw-link link)
3991 'e-odt info)) 'emphasis)))))
3992 ;; Coderef: replace link with the reference name or the
3993 ;; equivalent line number.
3994 ((string= type "coderef")
3995 (let* ((fmt (org-export-get-coderef-format path (or desc "%s")))
3996 (res (org-export-resolve-coderef path info))
3997 (org-e-odt-suppress-xref nil)
3998 (href (org-xml-format-href (concat "#coderef-" path))))
3999 (format fmt (org-e-odt-format-link res href))))
4000 ;; Link type is handled by a special function.
4001 ((functionp (setq protocol (nth 2 (assoc type org-link-protocols))))
4002 (funcall protocol (org-link-unescape path) desc 'html))
4003 ;; External link with a description part.
4004 ((and path desc) (org-e-odt-format-link desc path))
4005 ;; External link without a description part.
4006 (path (org-e-odt-format-link path path))
4007 ;; No path, only description. Try to do something useful.
4008 (t (org-e-odt-format-fontify desc 'emphasis)))))
4011 ;;;; Babel Call
4013 ;; Babel Calls are ignored.
4016 ;;;; Macro
4018 (defun org-e-odt-macro (macro contents info)
4019 "Transcode a MACRO element from Org to HTML.
4020 CONTENTS is nil. INFO is a plist holding contextual information."
4021 ;; Use available tools.
4022 (org-export-expand-macro macro info))
4025 ;;;; Paragraph
4027 (defun org-e-odt-paragraph (paragraph contents info)
4028 "Transcode a PARAGRAPH element from Org to HTML.
4029 CONTENTS is the contents of the paragraph, as a string. INFO is
4030 the plist used as a communication channel."
4031 (let* ((style nil) ; FIXME
4032 (class (cdr (assoc style '((footnote . "footnote")
4033 (verse . nil)))))
4034 (extra (if class (format " class=\"%s\"" class) ""))
4035 (parent (car (org-export-get-genealogy paragraph info)))
4036 (parent-type (org-element-type parent))
4037 (style (case parent-type
4038 (quote-block 'quote)
4039 (center-block 'center)
4040 (t nil))))
4041 (org-e-odt-format-stylized-paragraph style contents)))
4044 ;;;; Plain List
4046 (defun org-e-odt-plain-list (plain-list contents info)
4047 "Transcode a PLAIN-LIST element from Org to HTML.
4048 CONTENTS is the contents of the list. INFO is a plist holding
4049 contextual information."
4050 (let* (arg1 ;; FIXME
4051 (type (org-element-property :type plain-list))
4052 (attr (mapconcat #'identity
4053 (org-element-property :attr_odt plain-list)
4054 " ")))
4055 (org-e-odt--wrap-label
4056 plain-list (format "%s\n%s%s"
4057 (org-e-odt-begin-plain-list type)
4058 contents (org-e-odt-end-plain-list type)))))
4060 ;;;; Plain Text
4062 (defun org-e-odt-convert-special-strings (string)
4063 "Convert special characters in STRING to ODT."
4064 (let ((all org-export-e-odt-special-string-regexps)
4065 e a re rpl start)
4066 (while (setq a (pop all))
4067 (setq re (car a) rpl (cdr a) start 0)
4068 (while (string-match re string start)
4069 (setq string (replace-match rpl t nil string))))
4070 string))
4072 ;; (defun org-e-odt-encode-plain-text (s)
4073 ;; "Convert plain text characters to HTML equivalent.
4074 ;; Possible conversions are set in `org-export-html-protect-char-alist'."
4075 ;; (let ((cl org-e-odt-protect-char-alist) c)
4076 ;; (while (setq c (pop cl))
4077 ;; (let ((start 0))
4078 ;; (while (string-match (car c) s start)
4079 ;; (setq s (replace-match (cdr c) t t s)
4080 ;; start (1+ (match-beginning 0))))))
4081 ;; s))
4083 (defun org-e-odt-plain-text (text info)
4084 "Transcode a TEXT string from Org to HTML.
4085 TEXT is the string to transcode. INFO is a plist holding
4086 contextual information."
4087 (setq text (org-e-odt-encode-plain-text text t))
4088 ;; Protect %, #, &, $, ~, ^, _, { and }.
4089 ;; (while (string-match "\\([^\\]\\|^\\)\\([%$#&{}~^_]\\)" text)
4090 ;; (setq text
4091 ;; (replace-match (format "\\%s" (match-string 2 text)) nil t text 2)))
4092 ;; Protect \
4093 ;; (setq text (replace-regexp-in-string
4094 ;; "\\(?:[^\\]\\|^\\)\\(\\\\\\)\\(?:[^%$#&{}~^_\\]\\|$\\)"
4095 ;; "$\\backslash$" text nil t 1))
4096 ;; HTML into \HTML{} and TeX into \TeX{}.
4097 ;; (let ((case-fold-search nil)
4098 ;; (start 0))
4099 ;; (while (string-match "\\<\\(\\(?:La\\)?TeX\\)\\>" text start)
4100 ;; (setq text (replace-match
4101 ;; (format "\\%s{}" (match-string 1 text)) nil t text)
4102 ;; start (match-end 0))))
4103 ;; Handle quotation marks
4104 ;; (setq text (org-e-odt--quotation-marks text info))
4105 ;; Convert special strings.
4106 ;; (when (plist-get info :with-special-strings)
4107 ;; (while (string-match (regexp-quote "...") text)
4108 ;; (setq text (replace-match "\\ldots{}" nil t text))))
4109 (when (plist-get info :with-special-strings)
4110 (setq text (org-e-odt-convert-special-strings text)))
4111 ;; Handle break preservation if required.
4112 (when (plist-get info :preserve-breaks)
4113 (setq text (replace-regexp-in-string "\\(\\\\\\\\\\)?[ \t]*\n" " \\\\\\\\\n"
4114 text)))
4115 ;; Return value.
4116 text)
4119 ;;;; Property Drawer
4121 (defun org-e-odt-property-drawer (property-drawer contents info)
4122 "Transcode a PROPERTY-DRAWER element from Org to HTML.
4123 CONTENTS is nil. INFO is a plist holding contextual
4124 information."
4125 ;; The property drawer isn't exported but we want separating blank
4126 ;; lines nonetheless.
4130 ;;;; Quote Block
4132 (defun org-e-odt-quote-block (quote-block contents info)
4133 "Transcode a QUOTE-BLOCK element from Org to HTML.
4134 CONTENTS holds the contents of the block. INFO is a plist
4135 holding contextual information."
4136 (org-e-odt--wrap-label quote-block contents))
4139 ;;;; Quote Section
4141 (defun org-e-odt-quote-section (quote-section contents info)
4142 "Transcode a QUOTE-SECTION element from Org to HTML.
4143 CONTENTS is nil. INFO is a plist holding contextual information."
4144 (let ((value (org-remove-indentation
4145 (org-element-property :value quote-section))))
4146 (when value (org-e-odt-format-source-code-or-example value nil))))
4149 ;;;; Section
4151 (defun org-e-odt-section (section contents info) ; FIXME
4152 "Transcode a SECTION element from Org to HTML.
4153 CONTENTS holds the contents of the section. INFO is a plist
4154 holding contextual information."
4155 contents)
4157 ;;;; Radio Target
4159 (defun org-e-odt-radio-target (radio-target text info)
4160 "Transcode a RADIO-TARGET object from Org to HTML.
4161 TEXT is the text of the target. INFO is a plist holding
4162 contextual information."
4163 (org-e-odt-format-anchor
4164 text (org-export-solidify-link-text
4165 (org-element-property :raw-value radio-target))))
4168 ;;;; Special Block
4170 (defun org-e-odt-special-block (special-block contents info)
4171 "Transcode a SPECIAL-BLOCK element from Org to HTML.
4172 CONTENTS holds the contents of the block. INFO is a plist
4173 holding contextual information."
4174 (let ((type (downcase (org-element-property :type special-block))))
4175 (org-e-odt--wrap-label
4176 special-block
4177 (format "\\begin{%s}\n%s\\end{%s}" type contents type))))
4180 ;;;; Src Block
4182 (defun org-e-odt-src-block (src-block contents info)
4183 "Transcode a SRC-BLOCK element from Org to HTML.
4184 CONTENTS holds the contents of the item. INFO is a plist holding
4185 contextual information."
4186 (let* ((lang (org-element-property :language src-block))
4187 (code (org-export-handle-code src-block info nil nil t))
4188 (caption (org-element-property :caption src-block))
4189 (label (org-element-property :name src-block)))
4190 ;; FIXME: Handle caption
4192 ;; caption-str (when caption)
4193 ;; (main (org-export-secondary-string (car caption) 'e-odt info))
4194 ;; (secondary (org-export-secondary-string (cdr caption) 'e-odt info))
4195 ;; (caption-str (org-e-odt--caption/label-string caption label info))
4196 (org-e-odt-format-source-code-or-example code lang)))
4199 ;;;; Statistics Cookie
4201 (defun org-e-odt-statistics-cookie (statistics-cookie contents info)
4202 "Transcode a STATISTICS-COOKIE object from Org to HTML.
4203 CONTENTS is nil. INFO is a plist holding contextual information."
4204 (let ((cookie-value (org-element-property :value statistics-cookie)))
4205 (org-e-odt-format-fontify cookie-value 'code)))
4208 ;;;; Subscript
4210 (defun org-e-odt-subscript (subscript contents info)
4211 "Transcode a SUBSCRIPT object from Org to HTML.
4212 CONTENTS is the contents of the object. INFO is a plist holding
4213 contextual information."
4214 ;; (format (if (= (length contents) 1) "$_%s$" "$_{\\mathrm{%s}}$") contents)
4215 (org-e-odt-format-fontify contents 'subscript))
4218 ;;;; Superscript
4220 (defun org-e-odt-superscript (superscript contents info)
4221 "Transcode a SUPERSCRIPT object from Org to HTML.
4222 CONTENTS is the contents of the object. INFO is a plist holding
4223 contextual information."
4224 ;; (format (if (= (length contents) 1) "$^%s$" "$^{\\mathrm{%s}}$") contents)
4225 (org-e-odt-format-fontify contents 'superscript))
4228 ;;;; Table
4230 (defun org-e-odt-get-colwidth (c)
4231 (let ((col-widths (plist-get table-info :width)))
4232 (or (and org-lparse-table-is-styled (aref col-widths c)) 0)))
4234 (defun org-e-odt-table-row (fields &optional text-for-empty-fields)
4235 (incf org-e-odt-table-rownum)
4236 (let ((i -1))
4237 (org-e-odt-format-table-row
4238 (mapconcat
4239 (lambda (x)
4240 (when (and (string= x "") text-for-empty-fields)
4241 (setq x text-for-empty-fields))
4242 (incf i)
4243 (let ((horiz-span (org-e-odt-get-colwidth i)))
4244 (org-e-odt-format-table-cell
4245 x org-e-odt-table-rownum i horiz-span)))
4246 fields "\n"))))
4248 (defun org-e-odt-table-preamble ()
4249 (let ((colgroup-vector (plist-get table-info :column-groups)) ;; FIXME
4250 c gr colgropen preamble)
4251 (unless (aref colgroup-vector 0)
4252 (setf (aref colgroup-vector 0) 'start))
4253 (dotimes (c columns-number preamble)
4254 (setq gr (aref colgroup-vector c))
4255 (setq preamble
4256 (concat
4257 preamble
4258 (when (memq gr '(start start-end))
4259 (prog1 (if colgropen "</colgroup>\n<colgroup>" "\n<colgroup>")
4260 (setq colgropen t)))
4261 (let* ((colalign-vector (plist-get table-info :alignment)) ;; FIXME
4262 (align (cdr (assoc (aref colalign-vector c)
4263 '(("l" . "left")
4264 ("r" . "right")
4265 ("c" . "center")))))
4266 (alignspec (if (and (boundp 'org-e-odt-format-table-no-css)
4267 org-e-odt-format-table-no-css)
4268 " align=\"%s\"" " class=\"%s\""))
4269 (extra (format alignspec align)))
4270 (format "<col%s />" extra))
4271 (when (memq gr '(end start-end))
4272 (setq colgropen nil)
4273 "</colgroup>"))))
4274 (concat preamble (if colgropen "</colgroup>"))))
4276 (defun org-e-odt-list-table (lines caption label attributes)
4277 (setq lines (org-e-odt-org-table-to-list-table lines))
4278 (let* ((splice nil) head
4279 (org-e-odt-table-rownum -1)
4280 i (cnt 0)
4281 fields line
4282 org-e-odt-table-cur-rowgrp-is-hdr
4283 org-e-odt-table-rowgrp-open
4285 (org-lparse-table-style 'org-table)
4286 org-lparse-table-is-styled)
4287 (cond
4288 (splice
4289 (setq org-lparse-table-is-styled nil)
4290 (mapconcat 'org-e-odt-table-row lines "\n"))
4292 (setq org-lparse-table-is-styled t)
4294 (concat
4295 (org-e-odt-begin-table caption label attributes)
4296 ;; FIXME (org-e-odt-table-preamble)
4297 (org-e-odt-begin-table-rowgroup head)
4299 (mapconcat
4300 (lambda (line)
4301 (cond
4302 ((equal line 'hline) (org-e-odt-begin-table-rowgroup))
4303 (t (org-e-odt-table-row line))))
4304 lines "\n")
4306 (org-e-odt-end-table-rowgroup)
4307 (org-e-odt-end-table))))))
4309 (defun org-e-odt-transcode-table-row (row)
4310 (if (string-match org-table-hline-regexp row) 'hline
4311 (mapcar
4312 (lambda (cell)
4313 (org-export-secondary-string
4314 (let ((cell (org-element-parse-secondary-string
4315 cell
4316 (cdr (assq 'table org-element-string-restrictions)))))
4317 cell)
4318 'e-odt info))
4319 (org-split-string row "[ \t]*|[ \t]*"))))
4321 (defun org-e-odt-org-table-to-list-table (lines &optional splice)
4322 "Convert org-table to list-table.
4323 LINES is a list of the form (ROW1 ROW2 ROW3 ...) where each
4324 element is a `string' representing a single row of org-table.
4325 Thus each ROW has vertical separators \"|\" separating the table
4326 fields. A ROW could also be a row-group separator of the form
4327 \"|---...|\". Return a list of the form (ROW1 ROW2 ROW3
4328 ...). ROW could either be symbol `'hline' or a list of the
4329 form (FIELD1 FIELD2 FIELD3 ...) as appropriate."
4330 (let (line lines-1)
4331 (cond
4332 (splice
4333 (while (setq line (pop lines))
4334 (unless (string-match "^[ \t]*|-" line)
4335 (push (org-e-odt-transcode-table-row line) lines-1))))
4336 (t (while (setq line (pop lines))
4337 (cond
4338 ((string-match "^[ \t]*|-" line)
4339 (when lines (push 'hline lines-1)))
4340 (t (push (org-e-odt-transcode-table-row line) lines-1))))))
4341 (nreverse lines-1)))
4343 (defun org-e-odt-table-table (raw-table)
4344 (require 'table)
4345 (with-current-buffer (get-buffer-create "*org-export-table*")
4346 (erase-buffer))
4347 (let ((output (with-temp-buffer
4348 (insert raw-table)
4349 (goto-char 1)
4350 (re-search-forward "^[ \t]*|[^|]" nil t)
4351 (table-generate-source 'html "*org-export-table*")
4352 (with-current-buffer "*org-export-table*"
4353 (org-trim (buffer-string))))))
4354 (kill-buffer (get-buffer "*org-export-table*"))
4355 output))
4357 (defun org-e-odt-table (table contents info)
4358 "Transcode a TABLE element from Org to HTML.
4359 CONTENTS is nil. INFO is a plist holding contextual information."
4360 (let* ((label (org-element-property :name table))
4361 (caption (org-e-odt--caption/label-string
4362 (org-element-property :caption table) label info))
4363 (attr (mapconcat #'identity
4364 (org-element-property :attr_odt table)
4365 " "))
4366 (raw-table (org-element-property :raw-table table))
4367 (table-type (org-element-property :type table)))
4368 (case table-type
4369 (table.el
4370 ;; (org-e-odt-table-table raw-table)
4373 (let* ((table-info (org-export-table-format-info raw-table))
4374 (columns-number (length (plist-get table-info :alignment)))
4375 (lines (org-split-string
4376 (org-export-clean-table
4377 raw-table (plist-get table-info :special-column-p)) "\n"))
4379 (genealogy (org-export-get-genealogy table info))
4380 (parent (car genealogy))
4381 (parent-type (org-element-type parent)))
4382 (org-e-odt-list-table lines caption label attr))))))
4385 ;;;; Target
4387 (defun org-e-odt-target (target text info)
4388 "Transcode a TARGET object from Org to HTML.
4389 TEXT is the text of the target. INFO is a plist holding
4390 contextual information."
4391 (org-e-odt-format-anchor
4392 text (org-export-solidify-link-text
4393 (org-element-property :raw-value target))))
4396 ;;;; Time-stamp
4398 (defun org-e-odt-time-stamp (time-stamp contents info)
4399 "Transcode a TIME-STAMP object from Org to HTML.
4400 CONTENTS is nil. INFO is a plist holding contextual
4401 information."
4402 ;; (let ((value (org-element-property :value time-stamp))
4403 ;; (type (org-element-property :type time-stamp))
4404 ;; (appt-type (org-element-property :appt-type time-stamp)))
4405 ;; (concat (cond ((eq appt-type 'scheduled)
4406 ;; (format "\\textbf{\\textsc{%s}} " org-scheduled-string))
4407 ;; ((eq appt-type 'deadline)
4408 ;; (format "\\textbf{\\textsc{%s}} " org-deadline-string))
4409 ;; ((eq appt-type 'closed)
4410 ;; (format "\\textbf{\\textsc{%s}} " org-closed-string)))
4411 ;; (cond ((memq type '(active active-range))
4412 ;; (format org-e-odt-active-timestamp-format value))
4413 ;; ((memq type '(inactive inactive-range))
4414 ;; (format org-e-odt-inactive-timestamp-format value))
4415 ;; (t
4416 ;; (format org-e-odt-diary-timestamp-format value)))))
4417 (let ((value (org-element-property :value time-stamp))
4418 (type (org-element-property :type time-stamp))
4419 (appt-type (org-element-property :appt-type time-stamp)))
4420 (setq value (org-export-secondary-string value 'e-odt info))
4421 (org-e-odt-format-fontify
4422 (concat
4423 (org-e-odt-format-fontify
4424 (cond ((eq appt-type 'scheduled) org-scheduled-string)
4425 ((eq appt-type 'deadline) org-deadline-string)
4426 ((eq appt-type 'closed) org-closed-string)) "timestamp-kwd")
4427 ;; FIXME: (org-translate-time value)
4428 (org-e-odt-format-fontify value "timestamp"))
4429 "timestamp-wrapper")))
4432 ;;;; Verbatim
4434 (defun org-e-odt-verbatim (verbatim contents info)
4435 "Transcode a VERBATIM object from Org to HTML.
4436 CONTENTS is nil. INFO is a plist used as a communication
4437 channel."
4438 (org-e-odt-emphasis
4439 verbatim (org-element-property :value verbatim) info))
4442 ;;;; Verse Block
4444 (defun org-e-odt-verse-block (verse-block contents info)
4445 "Transcode a VERSE-BLOCK element from Org to HTML.
4446 CONTENTS is nil. INFO is a plist holding contextual information."
4447 ;; Replace each newline character with line break. Also replace
4448 ;; each blank line with a line break.
4449 (setq contents (replace-regexp-in-string
4450 "^ *\\\\\\\\$" "<br/>\n"
4451 (replace-regexp-in-string
4452 "\\(\\\\\\\\\\)?[ \t]*\n" " <br/>\n"
4453 (org-remove-indentation
4454 (org-export-secondary-string
4455 (org-element-property :value verse-block)
4456 'e-odt info)))))
4458 ;; Replace each white space at beginning of a line with a
4459 ;; non-breaking space.
4460 (while (string-match "^[ \t]+" contents)
4461 (let ((new-str (org-e-odt-format-spaces
4462 (length (match-string 0 contents)))))
4463 (setq contents (replace-match new-str nil t contents))))
4465 (org-e-odt--wrap-label
4466 verse-block (format "<p class=\"verse\">\n%s</p>" contents)))
4471 ;;; Filter Functions
4473 ;;;; Filter Settings
4474 ;;;; Filters
4476 ;;; Interactive functions
4478 (defun org-e-odt-export-to-odt
4479 (&optional subtreep visible-only body-only ext-plist pub-dir)
4480 "Export current buffer to a HTML file.
4482 If narrowing is active in the current buffer, only export its
4483 narrowed part.
4485 If a region is active, export that region.
4487 When optional argument SUBTREEP is non-nil, export the sub-tree
4488 at point, extracting information from the headline properties
4489 first.
4491 When optional argument VISIBLE-ONLY is non-nil, don't export
4492 contents of hidden elements.
4494 When optional argument BODY-ONLY is non-nil, only write code
4495 between \"\\begin{document}\" and \"\\end{document}\".
4497 EXT-PLIST, when provided, is a property list with external
4498 parameters overriding Org default settings, but still inferior to
4499 file-local settings.
4501 When optional argument PUB-DIR is set, use it as the publishing
4502 directory.
4504 Return output file's name."
4505 (interactive)
4507 ;; FIXME
4508 (with-current-buffer (get-buffer-create "*debug*")
4509 (erase-buffer))
4511 ;; (let* ((outfile (org-export-output-file-name ".html" subtreep pub-dir))
4512 ;; (outfile "content.xml"))
4513 ;; (org-export-to-file
4514 ;; 'e-odt outfile subtreep visible-only body-only ext-plist))
4516 (let* ((outbuf (org-e-odt-init-outfile))
4517 (target (org-export-output-file-name ".odt" subtreep pub-dir))
4518 (outdir (file-name-directory (buffer-file-name outbuf)))
4519 (default-directory outdir))
4521 ;; FIXME: for copying embedded images
4522 (setq org-current-export-file
4523 (file-name-directory
4524 (org-export-output-file-name ".odt" subtreep nil)))
4526 (org-export-to-buffer
4527 'e-odt outbuf
4528 (memq 'subtree optns) (memq 'visible optns) (memq 'body optns))
4530 (setq org-lparse-opt-plist nil) ; FIXME
4531 (org-e-odt-save-as-outfile target ;; info
4535 ;; return outfile
4536 target))
4541 ;;; FIXMES, TODOS, FOR REVIEW etc
4543 ;;;; org-format-table-html
4544 ;;;; org-format-org-table-html
4545 ;;;; org-format-table-table-html
4546 ;;;; org-table-number-fraction
4547 ;;;; org-table-number-regexp
4548 ;;;; org-e-odt-table-caption-above
4550 ;;;; org-whitespace
4551 ;;;; "<span style=\"visibility:hidden;\">%s</span>"
4552 ;;;; Remove display properties
4553 ;;;; org-e-odt-final-hook
4555 ;;;; org-e-odt-with-timestamp
4556 ;;;; org-e-odt-html-helper-timestamp
4558 ;;;; org-export-as-html-and-open
4559 ;;;; org-export-as-html-batch
4560 ;;;; org-export-as-html-to-buffer
4561 ;;;; org-replace-region-by-html
4562 ;;;; org-export-region-as-html
4563 ;;;; org-export-as-html
4565 ;;;; (org-export-directory :html opt-plist)
4566 ;;;; (plist-get opt-plist :html-extension)
4567 ;;;; org-e-odt-toplevel-hlevel
4568 ;;;; org-e-odt-special-string-regexps
4569 ;;;; org-e-odt-coding-system
4570 ;;;; org-e-odt-coding-system
4571 ;;;; org-e-odt-inline-images
4572 ;;;; org-e-odt-inline-image-extensions
4573 ;;;; org-e-odt-protect-char-alist
4574 ;;;; org-e-odt-table-use-header-tags-for-first-column
4575 ;;;; org-e-odt-todo-kwd-class-prefix
4576 ;;;; org-e-odt-tag-class-prefix
4577 ;;;; org-e-odt-footnote-separator
4580 ;;; Library Initializations
4582 (mapc
4583 (lambda (desc)
4584 ;; Let Org open all OpenDocument files using system-registered app
4585 (add-to-list 'org-file-apps
4586 (cons (concat "\\." (car desc) "\\'") 'system))
4587 ;; Let Emacs open all OpenDocument files in archive mode
4588 (add-to-list 'auto-mode-alist
4589 (cons (concat "\\." (car desc) "\\'") 'archive-mode)))
4590 org-e-odt-file-extensions)
4592 ;; FIXME
4593 ;; (eval-after-load 'org-exp
4594 ;; '(add-to-list 'org-export-inbuffer-options-extra
4595 ;; '("ODT_STYLES_FILE" :odt-styles-file)))
4597 (provide 'org-e-odt)
4599 ;;; org-e-odt.el ends here