org-export: Fix some small bugs, include tests
[org-mode.git] / EXPERIMENTAL / org-e-odt.el
blob3437a5e8cd10114c7de8c1739e4c08444faab514
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))
29 (require 'org-lparse)
31 (defgroup org-export-e-odt nil
32 "Options specific for ODT export of Org-mode files."
33 :tag "Org Export ODT"
34 :group 'org-export
35 :version "24.1")
37 ;; (defun org-e-odt-unload-function ()
38 ;; (org-lparse-unregister-backend 'odt)
39 ;; (remove-hook 'org-export-preprocess-after-blockquote-hook
40 ;; 'org-export-e-odt-preprocess-latex-fragments)
41 ;; nil)
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 ;;;###autoload
55 (defun org-export-as-e-odt-and-open (arg)
56 "Export the outline as ODT and immediately open it with a browser.
57 If there is an active region, export only the region.
58 The prefix ARG specifies how many levels of the outline should become
59 headlines. The default is 3. Lower levels will become bulleted lists."
60 (interactive "P")
61 (org-lparse-and-open
62 (or org-export-e-odt-preferred-output-format "odt") "odt" arg))
64 ;;;###autoload
65 (defun org-export-as-e-odt-batch ()
66 "Call the function `org-lparse-batch'.
67 This function can be used in batch processing as:
68 emacs --batch
69 --load=$HOME/lib/emacs/org.el
70 --eval \"(setq org-export-headline-levels 2)\"
71 --visit=MyFile --funcall org-export-as-e-odt-batch"
72 (org-lparse-batch "odt"))
74 ;;; org-export-as-e-odt
75 ;;;###autoload
76 (defun org-export-as-e-odt (arg &optional hidden ext-plist
77 to-buffer body-only pub-dir)
78 "Export the outline as a OpenDocumentText file.
79 If there is an active region, export only the region. The prefix
80 ARG specifies how many levels of the outline should become
81 headlines. The default is 3. Lower levels will become bulleted
82 lists. HIDDEN is obsolete and does nothing.
83 EXT-PLIST is a property list with external parameters overriding
84 org-mode's default settings, but still inferior to file-local
85 settings. When TO-BUFFER is non-nil, create a buffer with that
86 name and export to that buffer. If TO-BUFFER is the symbol
87 `string', don't leave any buffer behind but just return the
88 resulting XML as a string. When BODY-ONLY is set, don't produce
89 the file header and footer, simply return the content of
90 <body>...</body>, without even the body tags themselves. When
91 PUB-DIR is set, use this as the publishing directory."
92 (interactive "P")
93 (org-lparse (or org-export-e-odt-preferred-output-format "odt")
94 "odt" arg hidden ext-plist to-buffer body-only pub-dir))
98 ;; Following variable is let bound when `org-do-lparse' is in
99 ;; progress. See org-html.el.
101 (defun org-e-odt-format-preamble (info)
102 (let* ((title (plist-get info :title))
103 (author (plist-get info :author))
104 (date (plist-get info :date))
105 (iso-date (org-e-odt-format-date date))
106 (date (org-e-odt-format-date date "%d %b %Y"))
107 (email (plist-get info :email))
108 ;; switch on or off above vars based on user settings
109 (author (and (plist-get info :with-author) (or author email)))
110 (email (and (plist-get info :with-email) email))
111 ;; (date (and (plist-get info :time-stamp-file) date))
113 (concat
114 ;; title
115 (when title
116 (concat
117 (org-e-odt-format-stylized-paragraph
118 'title (format "\n<text:title>%s</text:title>" title))
119 ;; separator
120 "\n<text:p text:style-name=\"OrgTitle\"/>"))
121 (cond
122 ((and author (not email))
123 ;; author only
124 (concat
125 (org-e-odt-format-stylized-paragraph
126 'subtitle
127 (format "<text:initial-creator>%s</text:initial-creator>" author))
128 ;; separator
129 "\n<text:p text:style-name=\"OrgSubtitle\"/>"))
130 ((and author email)
131 ;; author and email
132 (concat
133 (org-e-odt-format-stylized-paragraph
134 'subtitle
135 (org-e-odt-format-link
136 (format "<text:initial-creator>%s</text:initial-creator>" author)
137 (concat "mailto:" email)))
138 ;; separator
139 "\n<text:p text:style-name=\"OrgSubtitle\"/>")))
140 ;; date
141 (when date
142 (concat
143 (org-e-odt-format-stylized-paragraph
144 'subtitle
145 (org-odt-format-tags
146 '("<text:date style:data-style-name=\"%s\" text:date-value=\"%s\">"
147 . "</text:date>")
148 date "N75" iso-date))
149 ;; separator
150 "<text:p text:style-name=\"OrgSubtitle\"/>")))))
152 (defun org-e-odt-begin-section (style &optional name)
153 (let ((default-name (car (org-e-odt-add-automatic-style "Section"))))
154 (format "<text:section text:style-name=\"%s\" text:name=\"%s\">"
155 style (or name default-name))))
157 (defun org-e-odt-end-section ()
158 "</text:section>")
160 (defun org-e-odt-begin-paragraph (&optional style)
161 (format "<text:p%s>" (org-e-odt-get-extra-attrs-for-paragraph-style style)))
163 (defun org-e-odt-end-paragraph ()
164 "</text:p>")
166 (defun org-e-odt-get-extra-attrs-for-paragraph-style (style)
167 (let (style-name)
168 (setq style-name
169 (cond
170 ((stringp style) style)
171 ((symbolp style) (org-e-odt-get-style-name-for-entity
172 'paragraph style))))
173 (unless style-name
174 (error "Don't know how to handle paragraph style %s" style))
175 (format " text:style-name=\"%s\"" style-name)))
177 (defun org-e-odt-format-stylized-paragraph (style text)
178 (format "\n<text:p%s>%s</text:p>"
179 (org-e-odt-get-extra-attrs-for-paragraph-style style)
180 text))
182 (defun org-e-odt-format-author (&optional author )
183 (when (setq author (or author (plist-get org-lparse-opt-plist :author)))
184 (format "<dc:creator>%s</dc:creator>" author)))
186 (defun org-e-odt-format-date (&optional org-ts fmt)
187 (save-match-data
188 (let* ((time
189 (and (stringp org-ts)
190 (string-match org-ts-regexp0 org-ts)
191 (apply 'encode-time
192 (org-fix-decoded-time
193 (org-parse-time-string (match-string 0 org-ts) t)))))
194 date)
195 (cond
196 (fmt (format-time-string fmt time))
197 (t (setq date (format-time-string "%Y-%m-%dT%H:%M:%S%z" time))
198 (format "%s:%s" (substring date 0 -2) (substring date -2)))))))
200 (defun org-e-odt-begin-annotation (&optional author date)
201 (org-lparse-insert-tag "<office:annotation>")
202 (when (setq author (org-e-odt-format-author author))
203 (insert author))
204 (insert (org-e-odt-format-tags
205 '("<dc:date>" . "</dc:date>")
206 (org-e-odt-format-date
207 (or date (plist-get org-lparse-opt-plist :date)))))
208 (org-lparse-begin-paragraph))
210 (defun org-e-odt-end-annotation ()
211 (org-lparse-insert-tag "</office:annotation>"))
213 (defun org-e-odt-begin-environment (style env-options-plist)
214 (case style
215 (annotation
216 (org-lparse-stash-save-paragraph-state)
217 (org-e-odt-begin-annotation (plist-get env-options-plist 'author)
218 (plist-get env-options-plist 'date)))
219 ((blockquote verse center quote)
220 (org-lparse-begin-paragraph style)
221 (list))
222 ((fixedwidth native)
223 (org-lparse-end-paragraph)
224 (list))
225 (t (error "Unknown environment %s" style))))
227 (defun org-e-odt-end-environment (style env-options-plist)
228 (case style
229 (annotation
230 (org-lparse-end-paragraph)
231 (org-e-odt-end-annotation)
232 (org-lparse-stash-pop-paragraph-state))
233 ((blockquote verse center quote)
234 (org-lparse-end-paragraph)
235 (list))
236 ((fixedwidth native)
237 (org-lparse-begin-paragraph)
238 (list))
239 (t (error "Unknown environment %s" style))))
241 (defun org-e-odt-begin-plain-list (ltype)
242 ;; (setq ltype (or (org-lparse-html-list-type-to-canonical-list-type ltype)
243 ;; ltype))
244 (let* ((style-name (org-e-odt-get-style-name-for-entity 'list ltype))
245 (extra (concat
246 ;; (if (or org-lparse-list-table-p
247 ;; (and (= 1 (length org-lparse-list-stack))
248 ;; (null org-e-odt-list-stack-stashed)))
249 ;; " text:continue-numbering=\"false\""
250 ;; " text:continue-numbering=\"true\"")
252 " text:continue-numbering=\"true\""
254 (when style-name
255 (format " text:style-name=\"%s\"" style-name)))))
256 (case ltype
257 ((ordered unordered descriptive)
258 (concat
259 ;; (org-e-odt-end-paragraph)
260 (format "<text:list%s>" extra)))
261 (t (error "Unknown list type: %s" ltype)))))
263 (defun org-e-odt-end-plain-list (ltype)
264 ;; (setq ltype (or (org-lparse-html-list-type-to-canonical-list-type ltype)
265 ;; ltype))
266 (if ltype "</text:list>"
267 (error "Unknown list type: %s" ltype)))
269 (defun org-e-odt-begin-list-item (ltype &optional arg headline)
270 (setq ltype (or (org-lparse-html-list-type-to-canonical-list-type ltype)
271 ltype))
272 (case ltype
273 (ordered
274 (assert (not headline) t)
275 (let* ((counter arg) (extra ""))
276 (concat "<text:list-item>" ;; (org-e-odt-begin-paragraph)
278 ;; (if (= (length org-lparse-list-stack)
279 ;; (length org-e-odt-list-stack-stashed))
280 ;; "<text:list-header>" "<text:list-item>")
282 (unordered
283 (let* ((id arg) (extra ""))
284 (concat
285 "<text:list-item>"
286 ;; (org-e-odt-begin-paragraph)
287 (if headline (org-e-odt-format-target headline id)
288 (org-e-odt-format-bookmark "" id)))
289 ;; (if (= (length org-lparse-list-stack)
290 ;; (length org-e-odt-list-stack-stashed))
291 ;; "<text:list-header>" "<text:list-item>")
293 (descriptive
294 (assert (not headline) t)
295 (let ((term (or arg "(no term)")))
296 (concat
297 (org-e-odt-format-tags
298 '("<text:list-item>" . "</text:list-item>")
299 (org-e-odt-format-stylized-paragraph 'definition-term term))
300 (org-e-odt-begin-list-item 'unordered)
301 (org-e-odt-begin-plain-list 'descriptive)
302 (org-e-odt-begin-list-item 'unordered))))
303 (t (error "Unknown list type"))))
305 (defun org-e-odt-end-list-item (ltype)
306 ;; (setq ltype (or (org-lparse-html-list-type-to-canonical-list-type ltype)
307 ;; ltype))
308 (case ltype
309 ((ordered unordered)
310 ;; (org-lparse-insert-tag
311 ;; (if (= (length org-lparse-list-stack)
312 ;; (length org-e-odt-list-stack-stashed))
313 ;; (prog1 "</text:list-header>"
314 ;; (setq org-e-odt-list-stack-stashed nil))
315 ;; "</text:list-item>")
316 "</text:list-item>"
317 ;; )
319 (descriptive
320 (concat
321 (org-e-odt-end-list-item 'unordered)
322 (org-e-odt-end-plain-list 'descriptive)
323 (org-e-odt-end-list-item 'unordered)
325 (t (error "Unknown list type"))))
327 (defun org-e-odt-discontinue-list ()
328 (let ((stashed-stack org-lparse-list-stack))
329 (loop for list-type in stashed-stack
330 do (org-lparse-end-list-item-1 list-type)
331 (org-lparse-end-list list-type))
332 (setq org-e-odt-list-stack-stashed stashed-stack)))
334 (defun org-e-odt-continue-list ()
335 (setq org-e-odt-list-stack-stashed (nreverse org-e-odt-list-stack-stashed))
336 (loop for list-type in org-e-odt-list-stack-stashed
337 do (org-lparse-begin-list list-type)
338 (org-lparse-begin-list-item list-type)))
340 ;; Following variables are let bound when table emission is in
341 ;; progress. See org-lparse.el.
342 (defun org-e-odt-write-automatic-styles ()
343 "Write automatic styles to \"content.xml\"."
344 (with-current-buffer
345 (find-file-noselect (expand-file-name "content.xml") t)
346 ;; position the cursor
347 (goto-char (point-min))
348 (re-search-forward " </office:automatic-styles>" nil t)
349 (goto-char (match-beginning 0))
350 ;; write automatic table styles
351 (loop for (style-name props) in
352 (plist-get org-e-odt-automatic-styles 'Table) do
353 (when (setq props (or (plist-get props :rel-width) 96))
354 (insert (format org-e-odt-table-style-format style-name props))))))
356 (defun org-e-odt-add-automatic-style (object-type &optional object-props)
357 "Create an automatic style of type OBJECT-TYPE with param OBJECT-PROPS.
358 OBJECT-PROPS is (typically) a plist created by passing
359 \"#+ATTR_ODT: \" option of the object in question to
360 `org-lparse-get-block-params'.
362 Use `org-e-odt-object-counters' to generate an automatic
363 OBJECT-NAME and STYLE-NAME. If OBJECT-PROPS is non-nil, add a
364 new entry in `org-e-odt-automatic-styles'. Return (OBJECT-NAME
365 . STYLE-NAME)."
366 (assert (stringp object-type))
367 (let* ((object (intern object-type))
368 (seqvar object)
369 (seqno (1+ (or (plist-get org-e-odt-object-counters seqvar) 0)))
370 (object-name (format "%s%d" object-type seqno)) style-name)
371 (setq org-e-odt-object-counters
372 (plist-put org-e-odt-object-counters seqvar seqno))
373 (when object-props
374 (setq style-name (format "Org%s" object-name))
375 (setq org-e-odt-automatic-styles
376 (plist-put org-e-odt-automatic-styles object
377 (append (list (list style-name object-props))
378 (plist-get org-e-odt-automatic-styles object)))))
379 (cons object-name style-name)))
381 (defun org-e-odt-format-table-columns ()
382 (let* ((num-cols (length (plist-get table-info :alignment)))
383 (col-nos (loop for i from 1 below num-cols collect i))
384 (levels )
385 (col-widths (plist-get table-info :width))
386 (style (or (nth 1 org-e-odt-table-style-spec) "OrgTable")))
387 (mapconcat
388 (lambda (c)
389 (let* ((width (or (and org-lparse-table-is-styled (aref col-widths c))
390 0)))
391 (org-e-odt-make-string
392 (1+ width)
393 (org-e-odt-format-tags
394 "<table:table-column table:style-name=\"%sColumn\"/>" "" style))))
395 col-nos "\n")))
398 (defun org-e-odt-begin-table (caption label attributes)
399 ;; (setq org-e-odt-table-indentedp (not (null org-lparse-list-stack)))
400 (setq org-e-odt-table-indentedp nil) ; FIXME
401 (when org-e-odt-table-indentedp
402 ;; Within the Org file, the table is appearing within a list item.
403 ;; OpenDocument doesn't allow table to appear within list items.
404 ;; Temporarily terminate the list, emit the table and then
405 ;; re-continue the list.
406 (org-e-odt-discontinue-list)
407 ;; Put the Table in an indented section.
408 (let ((level (length org-e-odt-list-stack-stashed)))
409 (org-e-odt-begin-section (format "OrgIndentedSection-Level-%d" level))))
410 (setq attributes (org-lparse-get-block-params attributes))
411 (setq org-e-odt-table-style (plist-get attributes :style))
412 (setq org-e-odt-table-style-spec
413 (assoc org-e-odt-table-style org-export-e-odt-table-styles))
414 (concat
415 (org-e-odt-format-stylized-paragraph
416 'table (org-e-odt-format-entity-caption label caption "__Table__"))
417 (let ((name-and-style (org-e-odt-add-automatic-style "Table" attributes)))
418 (format
419 "\n<table:table table:name=\"%s\" table:style-name=\"%s\">\n"
420 (car name-and-style) (or (nth 1 org-e-odt-table-style-spec)
421 (cdr name-and-style) "OrgTable")))
422 (org-e-odt-format-table-columns) "\n")
424 ;; (org-e-html-pp table-info)
426 ;; (setq org-lparse-table-begin-marker (point))
429 (defun org-e-odt-end-table ()
430 ;; fill style attributes for table cells
431 (when org-lparse-table-is-styled
432 (while (re-search-forward "@@\\(table-cell:p\\|table-cell:style-name\\)@@\\([0-9]+\\)@@\\([0-9]+\\)@@" nil t)
433 (let* (;; (spec (match-string 1))
434 ;; (r (string-to-number (match-string 2)))
435 ;; (c (string-to-number (match-string 3)))
436 (cell-styles (org-e-odt-get-table-cell-styles
437 r c org-e-odt-table-style-spec))
438 (table-cell-style (car cell-styles))
439 (table-cell-paragraph-style (cdr cell-styles)))
440 (cond
441 ((equal spec "table-cell:p")
442 (replace-match table-cell-paragraph-style t t))
443 ((equal spec "table-cell:style-name")
444 (replace-match table-cell-style t t))))))
445 (goto-char (point-max))
447 (concat
448 "</table:table>"
449 ;; (when org-e-odt-table-indentedp
450 ;; (org-e-odt-end-section)
451 ;; (org-e-odt-continue-list))
454 (defun org-e-odt-begin-table-rowgroup (&optional is-header-row)
455 (prog1
456 (concat (when org-e-odt-table-rowgrp-open
457 (org-e-odt-end-table-rowgroup))
458 (if is-header-row "<table:table-header-rows>"
459 "<table:table-rows>"))
460 (setq org-e-odt-table-rowgrp-open t)
461 (setq org-e-odt-table-cur-rowgrp-is-hdr is-header-row)))
463 (defun org-e-odt-end-table-rowgroup ()
464 (when org-e-odt-table-rowgrp-open
465 (setq org-e-odt-table-rowgrp-open nil)
466 (if org-e-odt-table-cur-rowgrp-is-hdr
467 "</table:table-header-rows>" "</table:table-rows>")))
469 (defun org-e-odt-format-table-row (row)
470 (org-e-odt-format-tags
471 '("<table:table-row>" . "</table:table-row>") row))
473 (defun org-e-odt-get-column-alignment (c)
474 (let ((colalign-vector (plist-get table-info :alignment)))
475 ;; FIXME
476 (assoc-default (aref colalign-vector c)
477 '(("l" . "left")
478 ("r" . "right")
479 ("c" . "center")))))
481 (defun org-e-odt-get-table-cell-styles (r c &optional style-spec)
482 "Retrieve styles applicable to a table cell.
483 R and C are (zero-based) row and column numbers of the table
484 cell. STYLE-SPEC is an entry in `org-export-e-odt-table-styles'
485 applicable to the current table. It is `nil' if the table is not
486 associated with any style attributes.
488 Return a cons of (TABLE-CELL-STYLE-NAME . PARAGRAPH-STYLE-NAME).
490 When STYLE-SPEC is nil, style the table cell the conventional way
491 - choose cell borders based on row and column groupings and
492 choose paragraph alignment based on `org-col-cookies' text
493 property. See also
494 `org-e-odt-get-paragraph-style-cookie-for-table-cell'.
496 When STYLE-SPEC is non-nil, ignore the above cookie and return
497 styles congruent with the ODF-1.2 specification."
498 (cond
499 (style-spec
501 ;; LibreOffice - particularly the Writer - honors neither table
502 ;; templates nor custom table-cell styles. Inorder to retain
503 ;; inter-operability with LibreOffice, only automatic styles are
504 ;; used for styling of table-cells. The current implementation is
505 ;; congruent with ODF-1.2 specification and hence is
506 ;; future-compatible.
508 ;; Additional Note: LibreOffice's AutoFormat facility for tables -
509 ;; which recognizes as many as 16 different cell types - is much
510 ;; richer. Unfortunately it is NOT amenable to easy configuration
511 ;; by hand.
513 (let* ((template-name (nth 1 style-spec))
514 (cell-style-selectors (nth 2 style-spec))
515 (cell-type
516 (cond
517 ((and (cdr (assoc 'use-first-column-styles cell-style-selectors))
518 (= c 0)) "FirstColumn")
519 ((and (cdr (assoc 'use-last-column-styles cell-style-selectors))
520 (= c (1- org-lparse-table-ncols))) "LastColumn")
521 ((and (cdr (assoc 'use-first-row-styles cell-style-selectors))
522 (= r 0)) "FirstRow")
523 ((and (cdr (assoc 'use-last-row-styles cell-style-selectors))
524 (= r org-e-odt-table-rownum))
525 "LastRow")
526 ((and (cdr (assoc 'use-banding-rows-styles cell-style-selectors))
527 (= (% r 2) 1)) "EvenRow")
528 ((and (cdr (assoc 'use-banding-rows-styles cell-style-selectors))
529 (= (% r 2) 0)) "OddRow")
530 ((and (cdr (assoc 'use-banding-columns-styles cell-style-selectors))
531 (= (% c 2) 1)) "EvenColumn")
532 ((and (cdr (assoc 'use-banding-columns-styles cell-style-selectors))
533 (= (% c 2) 0)) "OddColumn")
534 (t ""))))
535 (cons
536 (concat template-name cell-type "TableCell")
537 (concat template-name cell-type "TableParagraph"))))
539 (cons
540 (concat
541 "OrgTblCell"
542 (cond
543 ((= r 0) "T")
544 ((eq (cdr (assoc r nil ;; org-lparse-table-rowgrp-info FIXME
545 )) :start) "T")
546 (t ""))
547 (when (= r org-e-odt-table-rownum) "B")
548 (cond
549 ((= c 0) "")
550 ((or (memq (nth c org-table-colgroup-info) '(:start :startend))
551 (memq (nth (1- c) org-table-colgroup-info) '(:end :startend))) "L")
552 (t "")))
553 (capitalize (org-e-odt-get-column-alignment c))))))
555 (defun org-e-odt-get-paragraph-style-cookie-for-table-cell (r c)
556 (concat
557 (and (not org-e-odt-table-style-spec)
558 (cond
559 (org-e-odt-table-cur-rowgrp-is-hdr "OrgTableHeading")
560 ((and (= c 0) nil
561 ;; (org-lparse-get 'TABLE-FIRST-COLUMN-AS-LABELS)
563 "OrgTableHeading")
564 (t "OrgTableContents")))
565 (and org-lparse-table-is-styled
566 (cdr (org-e-odt-get-table-cell-styles
567 r c org-e-odt-table-style-spec)))))
569 (defun org-e-odt-get-style-name-cookie-for-table-cell (r c)
570 (when org-lparse-table-is-styled
571 (let* ((cell-styles (org-e-odt-get-table-cell-styles
572 r c org-e-odt-table-style-spec))
573 (table-cell-style (car cell-styles)))
574 table-cell-style)))
576 (defun org-e-odt-format-table-cell (data r c horiz-span)
577 (concat
578 (let* ((paragraph-style-cookie
579 (org-e-odt-get-paragraph-style-cookie-for-table-cell r c))
580 (style-name-cookie
581 (org-e-odt-get-style-name-cookie-for-table-cell r c))
582 (extra (and style-name-cookie
583 (format " table:style-name=\"%s\"" style-name-cookie)))
584 (extra (concat extra
585 (and (> horiz-span 0)
586 (format " table:number-columns-spanned=\"%d\""
587 (1+ horiz-span))))))
588 (org-e-odt-format-tags
589 '("<table:table-cell%s>" . "</table:table-cell>")
590 (if org-lparse-list-table-p data
591 (org-e-odt-format-stylized-paragraph paragraph-style-cookie data)) extra))
592 (let (s)
593 (dotimes (i horiz-span)
594 (setq s (concat s "\n<table:covered-table-cell/>"))) s)
595 "\n"))
597 (defun org-e-odt-begin-footnote-definition (n)
598 (org-lparse-begin-paragraph 'footnote))
600 (defun org-e-odt-end-footnote-definition (n)
601 (org-lparse-end-paragraph))
603 (defun org-e-odt-begin-toc (lang-specific-heading max-level)
604 (concat
605 (format "
606 <text:table-of-content text:style-name=\"Sect2\" text:protected=\"true\" text:name=\"Table of Contents1\">
607 <text:table-of-content-source text:outline-level=\"%d\">
608 <text:index-title-template text:style-name=\"Contents_20_Heading\">%s</text:index-title-template>
609 " max-level lang-specific-heading)
611 (let ((entry-templates ""))
612 (loop for level from 1 upto 10
613 do (setq entry-templates
614 (concat entry-templates
615 (format
617 <text:table-of-content-entry-template text:outline-level=\"%d\" text:style-name=\"Contents_20_%d\">
618 <text:index-entry-link-start text:style-name=\"Internet_20_link\"/>
619 <text:index-entry-chapter/>
620 <text:index-entry-text/>
621 <text:index-entry-link-end/>
622 </text:table-of-content-entry-template>
623 " level level))))
624 entry-templates)
626 (format "
627 </text:table-of-content-source>
629 <text:index-body>
630 <text:index-title text:style-name=\"Sect1\" text:name=\"Table of Contents1_Head\">
631 <text:p text:style-name=\"Contents_20_Heading\">%s</text:p>
632 </text:index-title>
633 " lang-specific-heading)))
635 (defun org-e-odt-end-toc ()
636 (format "
637 </text:index-body>
638 </text:table-of-content>
641 (defun org-e-odt-format-toc-entry (snumber todo headline tags href)
643 ;; FIXME
644 (setq headline (concat
645 (and org-export-with-section-numbers
646 (concat snumber ". "))
647 headline
648 (and tags
649 (concat
650 (org-e-odt-format-spaces 3)
651 (org-e-odt-format-fontify tags "tag")))))
652 (when todo
653 (setq headline (org-e-odt-format-fontify headline "todo")))
655 (let ((org-e-odt-suppress-xref t))
656 (org-e-odt-format-link headline (concat "#" href))))
658 (defun org-e-odt-format-toc-item (toc-entry level org-last-level)
659 (let ((style (format "Contents_20_%d"
660 (+ level (or ;; (org-lparse-get 'TOPLEVEL-HLEVEL)
662 1) -1))))
663 (concat "\n" (org-e-odt-format-stylized-paragraph style toc-entry) "\n")))
665 ;; Following variable is let bound during 'ORG-LINK callback. See
666 ;; org-html.el
668 (defun org-e-odt-format-link (desc href &optional attr)
669 (cond
670 ((and (= (string-to-char href) ?#) (not org-e-odt-suppress-xref))
671 (setq href (concat org-export-e-odt-bookmark-prefix (substring href 1)))
672 (let ((xref-format "text"))
673 (when (numberp desc)
674 (setq desc (format "%d" desc) xref-format "number"))
675 (org-e-odt-format-tags
676 '("<text:bookmark-ref text:reference-format=\"%s\" text:ref-name=\"%s\">" .
677 "</text:bookmark-ref>")
678 desc xref-format href)))
679 (org-lparse-link-description-is-image
680 (org-e-odt-format-tags
681 '("<draw:a xlink:type=\"simple\" xlink:href=\"%s\" %s>" . "</draw:a>")
682 desc href (or attr "")))
684 (org-e-odt-format-tags
685 '("<text:a xlink:type=\"simple\" xlink:href=\"%s\" %s>" . "</text:a>")
686 desc href (or attr "")))))
688 (defun org-e-odt-format-spaces (n)
689 (cond
690 ((= n 1) " ")
691 ((> n 1) (concat
692 " " (org-e-odt-format-tags "<text:s text:c=\"%d\"/>" "" (1- n))))
693 (t "")))
695 (defun org-e-odt-format-tabs (&optional n)
696 (let ((tab "<text:tab/>")
697 (n (or n 1)))
698 (insert tab)))
700 (defun org-e-odt-format-line-break ()
701 (org-e-odt-format-tags "<text:line-break/>" ""))
703 (defun org-e-odt-format-horizontal-line ()
704 (org-e-odt-format-stylized-paragraph 'horizontal-line ""))
706 (defun org-e-odt-encode-plain-text (line &optional no-whitespace-filling)
707 (setq line (org-e-html-encode-plain-text line))
708 (if no-whitespace-filling line
709 (org-e-odt-fill-tabs-and-spaces line)))
711 (defun org-e-odt-format-line (line)
712 (case org-lparse-dyn-current-environment
713 (fixedwidth (concat
714 (org-e-odt-format-stylized-paragraph
715 'fixedwidth (org-e-odt-encode-plain-text line)) "\n"))
716 (t (concat line "\n"))))
718 (defun org-e-odt-format-comment (fmt &rest args)
719 (let ((comment (apply 'format fmt args)))
720 (format "\n<!-- %s -->\n" comment)))
722 (defun org-e-odt-format-org-entity (wd)
723 (org-entity-get-representation wd 'utf8))
725 (defun org-e-odt-fill-tabs-and-spaces (line)
726 (replace-regexp-in-string
727 "\\([\t]\\|\\([ ]+\\)\\)" (lambda (s)
728 (cond
729 ((string= s "\t") (org-e-odt-format-tabs))
730 (t (org-e-odt-format-spaces (length s))))) line))
733 (defun org-e-odt-format-source-line-with-line-number-and-label
734 (line rpllbl num fontifier par-style)
736 (let ((keep-label (not (numberp rpllbl)))
737 (ref (org-find-text-property-in-string 'org-coderef line)))
738 (setq line (concat line (and keep-label ref (format "(%s)" ref))))
739 (setq line (funcall fontifier line))
740 (when ref
741 (setq line (org-e-odt-format-target line (concat "coderef-" ref))))
742 (setq line (org-e-odt-format-stylized-paragraph par-style line))
743 (if (not num) line
744 (org-e-odt-format-tags '("<text:list-item>" . "</text:list-item>") line))))
746 (defun org-e-odt-format-source-code-or-example-plain
747 (lines lang caption textareap cols rows num cont rpllbl fmt)
748 "Format source or example blocks much like fixedwidth blocks.
749 Use this when `org-export-e-odt-fontify-srcblocks' option is turned
750 off."
751 (let* ((lines (org-split-string lines "[\r\n]"))
752 (line-count (length lines))
753 (i 0))
754 (mapconcat
755 (lambda (line)
756 (incf i)
757 (org-e-odt-format-source-line-with-line-number-and-label
758 line rpllbl num 'org-e-odt-encode-plain-text
759 (if (= i line-count) "OrgFixedWidthBlockLastLine"
760 "OrgFixedWidthBlock")))
761 lines "\n")))
763 (defun org-e-odt-hfy-face-to-css (fn)
764 "Create custom style for face FN.
765 When FN is the default face, use it's foreground and background
766 properties to create \"OrgSrcBlock\" paragraph style. Otherwise
767 use it's color attribute to create a character style whose name
768 is obtained from FN. Currently all attributes of FN other than
769 color are ignored.
771 The style name for a face FN is derived using the following
772 operations on the face name in that order - de-dash, CamelCase
773 and prefix with \"OrgSrc\". For example,
774 `font-lock-function-name-face' is associated with
775 \"OrgSrcFontLockFunctionNameFace\"."
776 (let* ((css-list (hfy-face-to-style fn))
777 (style-name ((lambda (fn)
778 (concat "OrgSrc"
779 (mapconcat
780 'capitalize (split-string
781 (hfy-face-or-def-to-name fn) "-")
782 ""))) fn))
783 (color-val (cdr (assoc "color" css-list)))
784 (background-color-val (cdr (assoc "background" css-list)))
785 (style (and org-export-e-odt-create-custom-styles-for-srcblocks
786 (cond
787 ((eq fn 'default)
788 (format org-src-block-paragraph-format
789 background-color-val color-val))
791 (format
793 <style:style style:name=\"%s\" style:family=\"text\">
794 <style:text-properties fo:color=\"%s\"/>
795 </style:style>" style-name color-val))))))
796 (cons style-name style)))
798 (defun org-e-odt-insert-custom-styles-for-srcblocks (styles)
799 "Save STYLES used for colorizing of source blocks.
800 Update styles.xml with styles that were collected as part of
801 `org-e-odt-hfy-face-to-css' callbacks."
802 (when styles
803 (with-current-buffer
804 (find-file-noselect (expand-file-name "styles.xml") t)
805 (goto-char (point-min))
806 (when (re-search-forward "</office:styles>" nil t)
807 (goto-char (match-beginning 0))
808 (insert "\n<!-- Org Htmlfontify Styles -->\n" styles "\n")))))
810 (defun org-e-odt-format-source-code-or-example-colored
811 (lines lang caption textareap cols rows num cont rpllbl fmt)
812 "Format source or example blocks using `htmlfontify-string'.
813 Use this routine when `org-export-e-odt-fontify-srcblocks' option
814 is turned on."
815 (let* ((lang-m (and lang (or (cdr (assoc lang org-src-lang-modes)) lang)))
816 (mode (and lang-m (intern (concat (if (symbolp lang-m)
817 (symbol-name lang-m)
818 lang-m) "-mode"))))
819 (org-inhibit-startup t)
820 (org-startup-folded nil)
821 (lines (with-temp-buffer
822 (insert lines)
823 (if (functionp mode) (funcall mode) (fundamental-mode))
824 (font-lock-fontify-buffer)
825 (buffer-string)))
826 (hfy-html-quote-regex "\\([<\"&> ]\\)")
827 (hfy-html-quote-map '(("\"" "&quot;")
828 ("<" "&lt;")
829 ("&" "&amp;")
830 (">" "&gt;")
831 (" " "<text:s/>")
832 (" " "<text:tab/>")))
833 (hfy-face-to-css 'org-e-odt-hfy-face-to-css)
834 (hfy-optimisations-1 (copy-seq hfy-optimisations))
835 (hfy-optimisations (add-to-list 'hfy-optimisations-1
836 'body-text-only))
837 (hfy-begin-span-handler
838 (lambda (style text-block text-id text-begins-block-p)
839 (insert (format "<text:span text:style-name=\"%s\">" style))))
840 (hfy-end-span-handler (lambda nil (insert "</text:span>"))))
841 (when (fboundp 'htmlfontify-string)
842 (let* ((lines (org-split-string lines "[\r\n]"))
843 (line-count (length lines))
844 (i 0))
845 (mapconcat
846 (lambda (line)
847 (incf i)
848 (org-e-odt-format-source-line-with-line-number-and-label
849 line rpllbl num 'htmlfontify-string
850 (if (= i line-count) "OrgSrcBlockLastLine" "OrgSrcBlock")))
851 lines "\n")))))
853 (defun org-e-odt-format-source-code-or-example (lines lang
854 &optional
855 caption textareap
856 cols rows num cont
857 rpllbl fmt)
858 "Format source or example blocks for export.
859 Use `org-e-odt-format-source-code-or-example-plain' or
860 `org-e-odt-format-source-code-or-example-colored' depending on the
861 value of `org-export-e-odt-fontify-srcblocks."
862 (setq ;; lines (org-export-number-lines
863 ;; lines 0 0 num cont rpllbl fmt 'preprocess) FIXME
864 lines (funcall
865 (or (and org-export-e-odt-fontify-srcblocks
866 (or (featurep 'htmlfontify)
867 ;; htmlfontify.el was introduced in Emacs 23.2
868 ;; So load it with some caution
869 (require 'htmlfontify nil t))
870 (fboundp 'htmlfontify-string)
871 'org-e-odt-format-source-code-or-example-colored)
872 'org-e-odt-format-source-code-or-example-plain)
873 lines lang caption textareap cols rows num cont rpllbl fmt))
874 (if (not num) lines
875 (let ((extra (format " text:continue-numbering=\"%s\""
876 (if cont "true" "false"))))
877 (org-e-odt-format-tags
878 '("<text:list text:style-name=\"OrgSrcBlockNumberedLine\"%s>"
879 . "</text:list>") lines extra))))
881 (defun org-e-odt-remap-stylenames (style-name)
883 (cdr (assoc style-name '(("timestamp-wrapper" . "OrgTimestampWrapper")
884 ("timestamp" . "OrgTimestamp")
885 ("timestamp-kwd" . "OrgTimestampKeyword")
886 ("tag" . "OrgTag")
887 ("todo" . "OrgTodo")
888 ("done" . "OrgDone")
889 ("target" . "OrgTarget"))))
890 style-name))
892 (defun org-e-odt-format-fontify (text style &optional id)
893 (let* ((style-name
894 (cond
895 ((stringp style)
896 (org-e-odt-remap-stylenames style))
897 ((symbolp style)
898 (org-e-odt-get-style-name-for-entity 'character style))
899 ((listp style)
900 (assert (< 1 (length style)))
901 (let ((parent-style (pop style)))
902 (mapconcat (lambda (s)
903 ;; (assert (stringp s) t)
904 (org-e-odt-remap-stylenames s)) style "")
905 (org-e-odt-remap-stylenames parent-style)))
906 (t (error "Don't how to handle style %s" style)))))
907 (org-e-odt-format-tags
908 '("<text:span text:style-name=\"%s\">" . "</text:span>")
909 text style-name)))
911 (defun org-e-odt-relocate-relative-path (path dir)
912 (if (file-name-absolute-p path) path
913 (file-relative-name (expand-file-name path dir)
914 (expand-file-name "eyecandy" dir))))
916 (defun org-e-odt-format-inline-image (thefile
917 &optional caption label attrs ; FIXME - CLA
919 (let* ((thelink (if (file-name-absolute-p thefile) thefile
920 (org-xml-format-href
921 (org-e-odt-relocate-relative-path
922 thefile org-current-export-file))))
923 (href
924 (org-e-odt-format-tags
925 "<draw:image xlink:href=\"%s\" xlink:type=\"simple\" xlink:show=\"embed\" xlink:actuate=\"onLoad\"/>" ""
926 (if org-export-e-odt-embed-images
927 (org-e-odt-copy-image-file thefile) thelink))))
928 (org-export-e-odt-format-image thefile href)))
930 (defun org-export-e-odt-format-formula (src href)
931 (save-match-data
932 (let* ((caption (org-find-text-property-in-string 'org-caption src))
933 (caption (and caption (org-xml-format-desc caption)))
934 (label (org-find-text-property-in-string 'org-label src))
935 (latex-frag (org-find-text-property-in-string 'org-latex-src src))
936 (embed-as (or (and latex-frag
937 (org-find-text-property-in-string
938 'org-latex-src-embed-type src))
939 (if (or caption label) 'paragraph 'character)))
940 width height)
941 (when latex-frag
942 (setq href (org-propertize href :title "LaTeX Fragment"
943 :description latex-frag)))
944 (cond
945 ((eq embed-as 'character)
946 (org-e-odt-format-entity "InlineFormula" href width height))
948 (org-lparse-end-paragraph)
949 (org-lparse-insert-list-table
950 `((,(org-e-odt-format-entity
951 (if caption "CaptionedDisplayFormula" "DisplayFormula")
952 href width height :caption caption :label nil)
953 ,(if (not label) ""
954 (org-e-odt-format-entity-caption label nil "__MathFormula__"))))
955 nil nil nil ":style \"OrgEquation\"" nil '((1 "c" 8) (2 "c" 1)))
956 (throw 'nextline nil))))))
958 (defun org-e-odt-copy-formula-file (path)
959 "Returns the internal name of the file"
960 (let* ((src-file (expand-file-name
961 path (file-name-directory org-current-export-file)))
962 (target-dir (format "Formula-%04d/"
963 (incf org-e-odt-embedded-formulas-count)))
964 (target-file (concat target-dir "content.xml")))
965 (when (not org-lparse-to-buffer)
966 (message "Embedding %s as %s ..."
967 (substring-no-properties path) target-file)
969 (make-directory target-dir)
970 (org-e-odt-create-manifest-file-entry
971 "application/vnd.oasis.opendocument.formula" target-dir "1.2")
973 (case (org-e-odt-is-formula-link-p src-file)
974 (mathml
975 (copy-file src-file target-file 'overwrite))
976 (odf
977 (org-e-odt-zip-extract-one src-file "content.xml" target-dir))
979 (error "%s is not a formula file" src-file)))
981 (org-e-odt-create-manifest-file-entry "text/xml" target-file))
982 target-file))
984 (defun org-e-odt-format-inline-formula (thefile)
985 (let* ((thelink (if (file-name-absolute-p thefile) thefile
986 (org-xml-format-href
987 (org-e-odt-relocate-relative-path
988 thefile org-current-export-file))))
989 (href
990 (org-e-odt-format-tags
991 "<draw:object xlink:href=\"%s\" xlink:type=\"simple\" xlink:show=\"embed\" xlink:actuate=\"onLoad\"/>" ""
992 (file-name-directory (org-e-odt-copy-formula-file thefile)))))
993 (org-export-e-odt-format-formula thefile href)))
995 (defun org-e-odt-is-formula-link-p (file)
996 (let ((case-fold-search nil))
997 (cond
998 ((string-match "\\.\\(mathml\\|mml\\)\\'" file)
999 'mathml)
1000 ((string-match "\\.odf\\'" file)
1001 'odf))))
1003 (defun org-e-odt-format-org-link (opt-plist type-1 path fragment desc attr
1004 descp)
1005 "Make a OpenDocument link.
1006 OPT-PLIST is an options list.
1007 TYPE-1 is the device-type of the link (THIS://foo.html).
1008 PATH is the path of the link (http://THIS#location).
1009 FRAGMENT is the fragment part of the link, if any (foo.html#THIS).
1010 DESC is the link description, if any.
1011 ATTR is a string of other attributes of the a element."
1012 (declare (special org-lparse-par-open))
1013 (save-match-data
1014 (let* ((may-inline-p
1015 (and (member type-1 '("http" "https" "file"))
1016 (org-lparse-should-inline-p path descp)
1017 (not fragment)))
1018 (type (if (equal type-1 "id") "file" type-1))
1019 (filename path)
1020 (thefile path))
1021 (cond
1022 ;; check for inlined images
1023 ((and (member type '("file"))
1024 (not fragment)
1025 (org-file-image-p
1026 filename org-export-e-odt-inline-image-extensions)
1027 (or (eq t org-export-e-odt-inline-images)
1028 (and org-export-e-odt-inline-images (not descp))))
1029 (org-e-odt-format-inline-image thefile))
1030 ;; check for embedded formulas
1031 ((and (member type '("file"))
1032 (not fragment)
1033 (org-e-odt-is-formula-link-p filename)
1034 (or (not descp)))
1035 (org-e-odt-format-inline-formula thefile))
1036 ((string= type "coderef")
1037 (let* ((ref fragment)
1038 (lineno-or-ref (cdr (assoc ref org-export-code-refs)))
1039 (desc (and descp desc))
1040 (org-e-odt-suppress-xref nil)
1041 (href (org-xml-format-href (concat "#coderef-" ref))))
1042 (cond
1043 ((and (numberp lineno-or-ref) (not desc))
1044 (org-e-odt-format-link lineno-or-ref href))
1045 ((and (numberp lineno-or-ref) desc
1046 (string-match (regexp-quote (concat "(" ref ")")) desc))
1047 (format (replace-match "%s" t t desc)
1048 (org-e-odt-format-link lineno-or-ref href)))
1050 (setq desc (format
1051 (if (and desc (string-match
1052 (regexp-quote (concat "(" ref ")"))
1053 desc))
1054 (replace-match "%s" t t desc)
1055 (or desc "%s"))
1056 lineno-or-ref))
1057 (org-e-odt-format-link (org-xml-format-desc desc) href)))))
1059 (when (string= type "file")
1060 (setq thefile
1061 (cond
1062 ((file-name-absolute-p path)
1063 (concat "file://" (expand-file-name path)))
1064 (t (org-e-odt-relocate-relative-path
1065 thefile org-current-export-file)))))
1067 (when (and (member type '("" "http" "https" "file")) fragment)
1068 (setq thefile (concat thefile "#" fragment)))
1070 (setq thefile (org-xml-format-href thefile))
1072 (when (not (member type '("" "file")))
1073 (setq thefile (concat type ":" thefile)))
1075 (let ((org-e-odt-suppress-xref nil))
1076 (org-e-odt-format-link
1077 (org-xml-format-desc desc) thefile attr)))))))
1079 (defun org-e-odt-format-heading (text level &optional id)
1080 (let* ((text (if id (org-e-odt-format-target text id) text)))
1081 (org-e-odt-format-tags
1082 '("<text:h text:style-name=\"Heading_20_%s\" text:outline-level=\"%s\">" .
1083 "</text:h>") text level level)))
1085 (defun org-e-odt-format-headline (title extra-targets tags
1086 &optional snumber level)
1087 (concat
1088 (org-e-odt-format-extra-targets extra-targets)
1090 ;; No need to generate section numbers. They are auto-generated by
1091 ;; the application
1093 ;; (concat (org-lparse-format 'SECTION-NUMBER snumber level) " ")
1094 title
1095 (and tags (concat (org-e-odt-format-spaces 3)
1096 (org-e-odt-format-org-tags tags)))))
1098 (defun org-e-odt-format-anchor (text name &optional class)
1099 (org-e-odt-format-target text name))
1101 (defun org-e-odt-format-bookmark (text id)
1102 (if id
1103 (org-e-odt-format-tags "<text:bookmark text:name=\"%s\"/>" text id)
1104 text))
1106 (defun org-e-odt-format-target (text id)
1107 (let ((name (concat org-export-e-odt-bookmark-prefix id)))
1108 (concat
1109 (and id (org-e-odt-format-tags
1110 "<text:bookmark-start text:name=\"%s\"/>" "" name))
1111 (org-e-odt-format-bookmark text id)
1112 (and id (org-e-odt-format-tags
1113 "<text:bookmark-end text:name=\"%s\"/>" "" name)))))
1115 (defun org-e-odt-format-footnote (n def)
1116 (setq n (format "%d" n))
1117 (let ((id (concat "fn" n))
1118 (note-class "footnote")
1119 (par-style "Footnote"))
1120 (org-e-odt-format-tags
1121 '("<text:note text:id=\"%s\" text:note-class=\"%s\">" .
1122 "</text:note>")
1123 (concat
1124 (org-e-odt-format-tags
1125 '("<text:note-citation>" . "</text:note-citation>")
1127 (org-e-odt-format-tags
1128 '("<text:note-body>" . "</text:note-body>")
1129 def))
1130 id note-class)))
1132 (defun org-e-odt-format-footnote-reference (n def refcnt)
1133 (if (= refcnt 1)
1134 (org-e-odt-format-footnote n def)
1135 (org-e-odt-format-footnote-ref n)))
1137 (defun org-e-odt-format-footnote-ref (n)
1138 (setq n (format "%d" n))
1139 (let ((note-class "footnote")
1140 (ref-format "text")
1141 (ref-name (concat "fn" n)))
1142 (org-e-odt-format-tags
1143 '("<text:span text:style-name=\"%s\">" . "</text:span>")
1144 (org-e-odt-format-tags
1145 '("<text:note-ref text:note-class=\"%s\" text:reference-format=\"%s\" text:ref-name=\"%s\">" . "</text:note-ref>")
1146 n note-class ref-format ref-name)
1147 "OrgSuperscript")))
1149 (defun org-e-odt-get-image-name (file-name)
1150 (require 'sha1)
1151 (file-relative-name
1152 (expand-file-name
1153 (concat (sha1 file-name) "." (file-name-extension file-name)) "Pictures")))
1155 (defun org-export-e-odt-format-image (src href)
1156 "Create image tag with source and attributes."
1157 (save-match-data
1158 (let* ((caption (org-find-text-property-in-string 'org-caption src))
1159 (caption (and caption (org-xml-format-desc caption)))
1160 (attr (org-find-text-property-in-string 'org-attributes src))
1161 (label (org-find-text-property-in-string 'org-label src))
1162 (latex-frag (org-find-text-property-in-string
1163 'org-latex-src src))
1164 (category (and latex-frag "__DvipngImage__"))
1165 (attr-plist (org-lparse-get-block-params attr))
1166 (user-frame-anchor
1167 (car (assoc-string (plist-get attr-plist :anchor)
1168 '(("as-char") ("paragraph") ("page")) t)))
1169 (user-frame-style
1170 (and user-frame-anchor (plist-get attr-plist :style)))
1171 (user-frame-attrs
1172 (and user-frame-anchor (plist-get attr-plist :attributes)))
1173 (user-frame-params
1174 (list user-frame-style user-frame-attrs user-frame-anchor))
1175 (embed-as (cond
1176 (latex-frag
1177 (symbol-name
1178 (case (org-find-text-property-in-string
1179 'org-latex-src-embed-type src)
1180 (paragraph 'paragraph)
1181 (t 'as-char))))
1182 (user-frame-anchor)
1183 (t "paragraph")))
1184 (size (org-e-odt-image-size-from-file
1185 src (plist-get attr-plist :width)
1186 (plist-get attr-plist :height)
1187 (plist-get attr-plist :scale) nil embed-as))
1188 (width (car size)) (height (cdr size)))
1189 (when latex-frag
1190 (setq href (org-propertize href :title "LaTeX Fragment"
1191 :description latex-frag)))
1192 (let ((frame-style-handle (concat (and (or caption label) "Captioned")
1193 embed-as "Image")))
1194 (org-e-odt-format-entity
1195 frame-style-handle href width height
1196 :caption caption :label label :category category
1197 :user-frame-params user-frame-params)))))
1199 (defun org-e-odt-format-object-description (title description)
1200 (concat (and title (org-e-odt-format-tags
1201 '("<svg:title>" . "</svg:title>")
1202 (org-e-odt-encode-plain-text title t)))
1203 (and description (org-e-odt-format-tags
1204 '("<svg:desc>" . "</svg:desc>")
1205 (org-e-odt-encode-plain-text description t)))))
1207 (defun org-e-odt-format-frame (text width height style &optional
1208 extra anchor-type)
1209 (let ((frame-attrs
1210 (concat
1211 (if width (format " svg:width=\"%0.2fcm\"" width) "")
1212 (if height (format " svg:height=\"%0.2fcm\"" height) "")
1213 extra
1214 (format " text:anchor-type=\"%s\"" (or anchor-type "paragraph")))))
1215 (org-e-odt-format-tags
1216 '("<draw:frame draw:style-name=\"%s\"%s>" . "</draw:frame>")
1217 (concat text (org-e-odt-format-object-description
1218 (get-text-property 0 :title text)
1219 (get-text-property 0 :description text)))
1220 style frame-attrs)))
1222 (defun org-e-odt-format-textbox (text width height style &optional
1223 extra anchor-type)
1224 (org-e-odt-format-frame
1225 (org-e-odt-format-tags
1226 '("<draw:text-box %s>" . "</draw:text-box>")
1227 text (concat (format " fo:min-height=\"%0.2fcm\"" (or height .2))
1228 (unless width
1229 (format " fo:min-width=\"%0.2fcm\"" (or width .2)))))
1230 width nil style extra anchor-type))
1232 (defun org-e-odt-format-inlinetask (heading content
1233 &optional todo priority tags)
1234 (org-e-odt-format-stylized-paragraph
1235 nil (org-e-odt-format-textbox
1236 (concat (org-e-odt-format-stylized-paragraph
1237 "OrgInlineTaskHeading"
1238 (org-lparse-format
1239 'HEADLINE (concat (org-lparse-format-todo todo) " " heading)
1240 nil tags))
1241 content) nil nil "OrgInlineTaskFrame" " style:rel-width=\"100%\"")))
1244 (defun org-e-odt-merge-frame-params(default-frame-params user-frame-params)
1245 (if (not user-frame-params) default-frame-params
1246 (assert (= (length default-frame-params) 3))
1247 (assert (= (length user-frame-params) 3))
1248 (loop for user-frame-param in user-frame-params
1249 for default-frame-param in default-frame-params
1250 collect (or user-frame-param default-frame-param))))
1252 (defun* org-e-odt-format-entity (entity href width height
1253 &key caption label category
1254 user-frame-params)
1255 (let* ((entity-style (assoc-string entity org-e-odt-entity-frame-styles t))
1256 default-frame-params frame-params)
1257 (cond
1258 ((not (or caption label))
1259 (setq default-frame-params (nth 2 entity-style))
1260 (setq frame-params (org-e-odt-merge-frame-params
1261 default-frame-params user-frame-params))
1262 (apply 'org-e-odt-format-frame href width height frame-params))
1264 (setq default-frame-params (nth 3 entity-style))
1265 (setq frame-params (org-e-odt-merge-frame-params
1266 default-frame-params user-frame-params))
1267 (apply 'org-e-odt-format-textbox
1268 (org-e-odt-format-stylized-paragraph
1269 'illustration
1270 (concat
1271 (apply 'org-e-odt-format-frame href width height
1272 (nth 2 entity-style))
1273 (org-e-odt-format-entity-caption
1274 label caption (or category (nth 1 entity-style)))))
1275 width height frame-params)))))
1278 (defun org-e-odt-copy-image-file (path)
1279 "Returns the internal name of the file"
1280 (let* ((image-type (file-name-extension path))
1281 (media-type (format "image/%s" image-type))
1282 (src-file (expand-file-name
1283 path (file-name-directory org-current-export-file)))
1284 (target-dir "Images/")
1285 (target-file
1286 (format "%s%04d.%s" target-dir
1287 (incf org-e-odt-embedded-images-count) image-type)))
1288 (when (not org-lparse-to-buffer)
1289 (message "Embedding %s as %s ..."
1290 (substring-no-properties path) target-file)
1292 (when (= 1 org-e-odt-embedded-images-count)
1293 (make-directory target-dir)
1294 (org-e-odt-create-manifest-file-entry "" target-dir))
1296 (copy-file src-file target-file 'overwrite)
1297 (org-e-odt-create-manifest-file-entry media-type target-file))
1298 target-file))
1300 (defun org-e-odt-do-image-size (probe-method file &optional dpi anchor-type)
1301 (setq dpi (or dpi org-export-e-odt-pixels-per-inch))
1302 (setq anchor-type (or anchor-type "paragraph"))
1303 (flet ((size-in-cms (size-in-pixels)
1304 (flet ((pixels-to-cms (pixels)
1305 (let* ((cms-per-inch 2.54)
1306 (inches (/ pixels dpi)))
1307 (* cms-per-inch inches))))
1308 (and size-in-pixels
1309 (cons (pixels-to-cms (car size-in-pixels))
1310 (pixels-to-cms (cdr size-in-pixels)))))))
1311 (case probe-method
1312 (emacs
1313 (size-in-cms (ignore-errors ; Emacs could be in batch mode
1314 (clear-image-cache)
1315 (image-size (create-image file) 'pixels))))
1316 (imagemagick
1317 (size-in-cms
1318 (let ((dim (shell-command-to-string
1319 (format "identify -format \"%%w:%%h\" \"%s\"" file))))
1320 (when (string-match "\\([0-9]+\\):\\([0-9]+\\)" dim)
1321 (cons (string-to-number (match-string 1 dim))
1322 (string-to-number (match-string 2 dim)))))))
1324 (cdr (assoc-string anchor-type
1325 org-export-e-odt-default-image-sizes-alist))))))
1327 (defun org-e-odt-image-size-from-file (file &optional user-width
1328 user-height scale dpi embed-as)
1329 (unless (file-name-absolute-p file)
1330 (setq file (expand-file-name
1331 file (file-name-directory org-current-export-file))))
1332 (let* (size width height)
1333 (unless (and user-height user-width)
1334 (loop for probe-method in org-export-e-odt-image-size-probe-method
1335 until size
1336 do (setq size (org-e-odt-do-image-size
1337 probe-method file dpi embed-as)))
1338 (or size (error "Cannot determine Image size. Aborting ..."))
1339 (setq width (car size) height (cdr size)))
1340 (cond
1341 (scale
1342 (setq width (* width scale) height (* height scale)))
1343 ((and user-height user-width)
1344 (setq width user-width height user-height))
1345 (user-height
1346 (setq width (* user-height (/ width height)) height user-height))
1347 (user-width
1348 (setq height (* user-width (/ height width)) width user-width))
1349 (t (ignore)))
1350 ;; ensure that an embedded image fits comfortably within a page
1351 (let ((max-width (car org-export-e-odt-max-image-size))
1352 (max-height (cdr org-export-e-odt-max-image-size)))
1353 (when (or (> width max-width) (> height max-height))
1354 (let* ((scale1 (/ max-width width))
1355 (scale2 (/ max-height height))
1356 (scale (min scale1 scale2)))
1357 (setq width (* scale width) height (* scale height)))))
1358 (cons width height)))
1360 (defun org-e-odt-get-label-category-and-style (label default-category)
1361 "See `org-export-e-odt-get-category-from-label'."
1362 (let ((default-category-map
1363 (assoc default-category org-e-odt-category-map-alist))
1364 user-category user-category-map category)
1365 (cond
1366 ((not org-export-e-odt-get-category-from-label)
1367 default-category-map)
1368 ((not (setq user-category
1369 (save-match-data
1370 (and (string-match "\\`\\(.*\\):.+" label)
1371 (match-string 1 label)))))
1372 default-category-map)
1374 (setq user-category-map
1375 (or (assoc user-category org-e-odt-category-map-alist)
1376 (list nil user-category "category-and-value"))
1377 category (nth 1 user-category-map))
1378 (if (member category org-export-e-odt-user-categories)
1379 user-category-map
1380 default-category-map)))))
1382 (defun org-e-odt-add-label-definition (label default-category)
1383 "Create an entry in `org-e-odt-entity-labels-alist' and return it."
1384 (setq label (substring-no-properties label))
1385 (let* ((label-props (org-e-odt-get-label-category-and-style
1386 label default-category))
1387 (category (nth 1 label-props))
1388 (counter category)
1389 (label-style (nth 2 label-props))
1390 (sequence-var (intern (mapconcat
1391 'downcase
1392 (org-split-string counter) "-")))
1393 (seqno (1+ (or (plist-get org-e-odt-entity-counts-plist sequence-var)
1394 0)))
1395 (label-props (list label category seqno label-style)))
1396 (setq org-e-odt-entity-counts-plist
1397 (plist-put org-e-odt-entity-counts-plist sequence-var seqno))
1398 (push label-props org-e-odt-entity-labels-alist)
1399 label-props))
1401 (defun org-e-odt-format-label-definition (caption label category seqno label-style)
1402 (assert label)
1403 (format-spec
1404 (cadr (assoc-string label-style org-e-odt-label-styles t))
1405 `((?e . ,category)
1406 (?n . ,(org-e-odt-format-tags
1407 '("<text:sequence text:ref-name=\"%s\" text:name=\"%s\" text:formula=\"ooow:%s+1\" style:num-format=\"1\">" . "</text:sequence>")
1408 (format "%d" seqno) label category category))
1409 (?c . ,(or (and caption (concat ": " caption)) "")))))
1411 (defun org-e-odt-format-label-reference (label category seqno label-style)
1412 (assert label)
1413 (save-match-data
1414 (let* ((fmt (cddr (assoc-string label-style org-e-odt-label-styles t)))
1415 (fmt1 (car fmt))
1416 (fmt2 (cadr fmt)))
1417 (org-e-odt-format-tags
1418 '("<text:sequence-ref text:reference-format=\"%s\" text:ref-name=\"%s\">"
1419 . "</text:sequence-ref>")
1420 (format-spec fmt2 `((?e . ,category)
1421 (?n . ,(format "%d" seqno)))) fmt1 label))))
1423 (defun org-e-odt-fixup-label-references ()
1424 (goto-char (point-min))
1425 (while (re-search-forward
1426 "<text:sequence-ref text:ref-name=\"\\([^\"]+\\)\">[ \t\n]*</text:sequence-ref>"
1427 nil t)
1428 (let* ((label (match-string 1))
1429 (label-def (assoc label org-e-odt-entity-labels-alist))
1430 (rpl (and label-def
1431 (apply 'org-e-odt-format-label-reference label-def))))
1432 (if rpl (replace-match rpl t t)
1433 (org-lparse-warn
1434 (format "Unable to resolve reference to label \"%s\"" label))))))
1436 (defun org-e-odt-format-entity-caption (label caption category)
1437 (or (and label
1438 (apply 'org-e-odt-format-label-definition
1439 caption (org-e-odt-add-label-definition label category)))
1440 caption ""))
1442 (defun org-e-odt-format-tags-1 (tag text prefix suffix &rest args)
1443 (cond
1444 ((consp tag)
1445 (concat prefix (apply 'format (car tag) args) text suffix
1446 (format (cdr tag))))
1447 ((stringp tag) ; singleton tag
1448 (concat prefix (apply 'format tag args) text))))
1450 (defun org-e-odt-format-tags (tag text &rest args)
1451 (apply 'org-e-odt-format-tags-1 tag text "\n" "\n" args))
1453 (defun org-e-odt-init-outfile ()
1454 (unless (executable-find "zip")
1455 ;; Not at all OSes ship with zip by default
1456 (error "Executable \"zip\" needed for creating OpenDocument files"))
1458 (let* ((outdir (make-temp-file
1459 (format org-export-e-odt-tmpdir-prefix org-lparse-backend) t))
1460 (content-file (expand-file-name "content.xml" outdir)))
1462 ;; reset variables
1463 (setq org-e-odt-manifest-file-entries nil
1464 org-e-odt-embedded-images-count 0
1465 org-e-odt-embedded-formulas-count 0
1466 org-e-odt-section-count 0
1467 org-e-odt-entity-labels-alist nil
1468 org-e-odt-list-stack-stashed nil
1469 org-e-odt-automatic-styles nil
1470 org-e-odt-object-counters nil
1471 org-e-odt-entity-counts-plist nil)
1473 ;; init conten.xml
1474 (with-current-buffer
1475 (find-file-noselect content-file t)
1476 (current-buffer))))
1480 (defun org-e-odt-save-as-outfile (target opt-plist)
1481 ;; write automatic styles
1482 (org-e-odt-write-automatic-styles)
1484 ;; write styles file
1485 ;; (when (equal org-lparse-backend 'odt) FIXME
1486 ;; )
1488 (org-e-odt-update-styles-file opt-plist)
1490 ;; create mimetype file
1491 (let ((mimetype (org-e-odt-write-mimetype-file ;; org-lparse-backend FIXME
1492 'odt)))
1493 (org-e-odt-create-manifest-file-entry mimetype "/" "1.2"))
1495 ;; create a manifest entry for content.xml
1496 (org-e-odt-create-manifest-file-entry "text/xml" "content.xml")
1498 ;; write out the manifest entries before zipping
1499 (org-e-odt-write-manifest-file)
1501 (let ((xml-files '("mimetype" "META-INF/manifest.xml" "content.xml"
1502 "meta.xml"))
1503 (zipdir default-directory))
1504 (when (equal org-lparse-backend 'odt)
1505 (push "styles.xml" xml-files))
1506 (message "Switching to directory %s" (expand-file-name zipdir))
1508 ;; save all xml files
1509 (mapc (lambda (file)
1510 (with-current-buffer
1511 (find-file-noselect (expand-file-name file) t)
1512 ;; prettify output if needed
1513 (when org-export-e-odt-prettify-xml
1514 (indent-region (point-min) (point-max)))
1515 (save-buffer 0)))
1516 xml-files)
1518 (let* ((target-name (file-name-nondirectory target))
1519 (target-dir (file-name-directory target))
1520 (cmds `(("zip" "-mX0" ,target-name "mimetype")
1521 ("zip" "-rmTq" ,target-name "."))))
1522 (when (file-exists-p target)
1523 ;; FIXME: If the file is locked this throws a cryptic error
1524 (delete-file target))
1526 (let ((coding-system-for-write 'no-conversion) exitcode err-string)
1527 (message "Creating odt file...")
1528 (mapc
1529 (lambda (cmd)
1530 (message "Running %s" (mapconcat 'identity cmd " "))
1531 (setq err-string
1532 (with-output-to-string
1533 (setq exitcode
1534 (apply 'call-process (car cmd)
1535 nil standard-output nil (cdr cmd)))))
1536 (or (zerop exitcode)
1537 (ignore (message "%s" err-string))
1538 (error "Unable to create odt file (%S)" exitcode)))
1539 cmds))
1541 ;; move the file from outdir to target-dir
1542 (rename-file target-name target-dir)
1544 ;; kill all xml buffers
1545 (mapc (lambda (file)
1546 (kill-buffer
1547 (find-file-noselect (expand-file-name file zipdir) t)))
1548 xml-files)
1550 (delete-directory zipdir)))
1551 (message "Created %s" target)
1552 (set-buffer (find-file-noselect target t)))
1555 (defun org-e-odt-create-manifest-file-entry (&rest args)
1556 (push args org-e-odt-manifest-file-entries))
1558 (defun org-e-odt-write-manifest-file ()
1559 (make-directory "META-INF")
1560 (let ((manifest-file (expand-file-name "META-INF/manifest.xml")))
1561 (with-current-buffer
1562 (find-file-noselect manifest-file t)
1563 (insert
1564 "<?xml version=\"1.0\" encoding=\"UTF-8\"?>
1565 <manifest:manifest xmlns:manifest=\"urn:oasis:names:tc:opendocument:xmlns:manifest:1.0\" manifest:version=\"1.2\">\n")
1566 (mapc
1567 (lambda (file-entry)
1568 (let* ((version (nth 2 file-entry))
1569 (extra (if version
1570 (format " manifest:version=\"%s\"" version)
1571 "")))
1572 (insert
1573 (format org-e-odt-manifest-file-entry-tag
1574 (nth 0 file-entry) (nth 1 file-entry) extra))))
1575 org-e-odt-manifest-file-entries)
1576 (insert "\n</manifest:manifest>"))))
1578 (defun org-e-odt-update-meta-file (info) ; FIXME opt-plist
1579 (let ((date (org-e-odt-format-date (plist-get info :date)))
1580 (author (or (plist-get info :author) ""))
1581 (email (plist-get info :email))
1582 (keywords (plist-get info :keywords))
1583 (description (plist-get info :description))
1584 (title (plist-get info :title)))
1585 (write-region
1586 (concat
1587 "<?xml version=\"1.0\" encoding=\"UTF-8\"?>
1588 <office:document-meta
1589 xmlns:office=\"urn:oasis:names:tc:opendocument:xmlns:office:1.0\"
1590 xmlns:xlink=\"http://www.w3.org/1999/xlink\"
1591 xmlns:dc=\"http://purl.org/dc/elements/1.1/\"
1592 xmlns:meta=\"urn:oasis:names:tc:opendocument:xmlns:meta:1.0\"
1593 xmlns:ooo=\"http://openoffice.org/2004/office\"
1594 office:version=\"1.2\">
1595 <office:meta>\n"
1596 (org-e-odt-format-author author) "\n"
1597 (format "<meta:initial-creator>%s</meta:initial-creator>\n" author)
1598 (format "<dc:date>%s</dc:date>\n" date)
1599 (format "<meta:creation-date>%s</meta:creation-date>\n" date)
1600 (format "<meta:generator>%s</meta:generator>\n"
1601 (when org-export-creator-info
1602 (format "Org-%s/Emacs-%s"
1603 org-version emacs-version)))
1604 (format "<meta:keyword>%s</meta:keyword>\n" keywords)
1605 (format "<dc:subject>%s</dc:subject>\n" description)
1606 (format "<dc:title>%s</dc:title>\n" title)
1607 "\n"
1608 " </office:meta>\n" "</office:document-meta>")
1609 nil (expand-file-name "meta.xml")))
1611 ;; create a manifest entry for meta.xml
1612 (org-e-odt-create-manifest-file-entry "text/xml" "meta.xml"))
1614 (defun org-e-odt-update-styles-file (opt-plist)
1615 ;; write styles file
1616 (let ((styles-file (plist-get opt-plist :odt-styles-file)))
1617 (org-e-odt-copy-styles-file (and styles-file
1618 (read (org-trim styles-file)))))
1620 ;; Update styles.xml - take care of outline numbering
1621 (with-current-buffer
1622 (find-file-noselect (expand-file-name "styles.xml") t)
1623 ;; Don't make automatic backup of styles.xml file. This setting
1624 ;; prevents the backed-up styles.xml file from being zipped in to
1625 ;; odt file. This is more of a hackish fix. Better alternative
1626 ;; would be to fix the zip command so that the output odt file
1627 ;; includes only the needed files and excludes any auto-generated
1628 ;; extra files like backups and auto-saves etc etc. Note that
1629 ;; currently the zip command zips up the entire temp directory so
1630 ;; that any auto-generated files created under the hood ends up in
1631 ;; the resulting odt file.
1632 (set (make-local-variable 'backup-inhibited) t)
1634 ;; Import local setting of `org-export-with-section-numbers'
1635 (org-lparse-bind-local-variables opt-plist)
1636 (org-e-odt-configure-outline-numbering
1637 (if org-export-with-section-numbers org-export-headline-levels 0)))
1639 ;; Write custom styles for source blocks
1640 ;; (org-e-odt-insert-custom-styles-for-srcblocks FIXME
1641 ;; (mapconcat
1642 ;; (lambda (style)
1643 ;; (format " %s\n" (cddr style)))
1644 ;; hfy-user-sheet-assoc ""))
1647 (defun org-e-odt-write-mimetype-file (format)
1648 ;; create mimetype file
1649 (let ((mimetype
1650 (case format
1651 (odt "application/vnd.oasis.opendocument.text")
1652 (odf "application/vnd.oasis.opendocument.formula")
1653 (t (error "Unknown OpenDocument backend %S" org-lparse-backend)))))
1654 (write-region mimetype nil (expand-file-name "mimetype"))
1655 mimetype))
1657 (defun org-e-odt-finalize-outfile ()
1658 (org-e-odt-delete-empty-paragraphs))
1660 (defun org-e-odt-delete-empty-paragraphs ()
1661 (goto-char (point-min))
1662 (let ((open "<text:p[^>]*>")
1663 (close "</text:p>"))
1664 (while (re-search-forward (format "%s[ \r\n\t]*%s" open close) nil t)
1665 (replace-match ""))))
1667 (declare-function org-create-math-formula "org"
1668 (latex-frag &optional mathml-file))
1670 ;;;###autoload
1671 (defun org-export-e-odt-convert (&optional in-file out-fmt prefix-arg)
1672 "Convert IN-FILE to format OUT-FMT using a command line converter.
1673 IN-FILE is the file to be converted. If unspecified, it defaults
1674 to variable `buffer-file-name'. OUT-FMT is the desired output
1675 format. Use `org-export-e-odt-convert-process' as the converter.
1676 If PREFIX-ARG is non-nil then the newly converted file is opened
1677 using `org-open-file'."
1678 (interactive
1679 (append (org-lparse-convert-read-params) current-prefix-arg))
1680 (org-lparse-do-convert in-file out-fmt prefix-arg))
1682 (defun org-e-odt-get (what &optional opt-plist)
1683 (case what
1684 (BACKEND 'odt)
1685 (EXPORT-DIR (org-export-directory :html opt-plist))
1686 (FILE-NAME-EXTENSION "odt")
1687 (EXPORT-BUFFER-NAME "*Org ODT Export*")
1688 (ENTITY-CONTROL org-e-odt-entity-control-callbacks-alist)
1689 (ENTITY-FORMAT org-e-odt-entity-format-callbacks-alist)
1690 (INIT-METHOD 'org-e-odt-init-outfile)
1691 (FINAL-METHOD 'org-e-odt-finalize-outfile)
1692 (SAVE-METHOD 'org-e-odt-save-as-outfile)
1693 (CONVERT-METHOD
1694 (and org-export-e-odt-convert-process
1695 (cadr (assoc-string org-export-e-odt-convert-process
1696 org-export-e-odt-convert-processes t))))
1697 (CONVERT-CAPABILITIES
1698 (and org-export-e-odt-convert-process
1699 (cadr (assoc-string org-export-e-odt-convert-process
1700 org-export-e-odt-convert-processes t))
1701 org-export-e-odt-convert-capabilities))
1702 (TOPLEVEL-HLEVEL 1)
1703 (SPECIAL-STRING-REGEXPS org-export-e-odt-special-string-regexps)
1704 (INLINE-IMAGES 'maybe)
1705 (INLINE-IMAGE-EXTENSIONS '("png" "jpeg" "jpg" "gif" "svg"))
1706 (PLAIN-TEXT-MAP '(("&" . "&amp;") ("<" . "&lt;") (">" . "&gt;")))
1707 (TABLE-FIRST-COLUMN-AS-LABELS nil)
1708 (FOOTNOTE-SEPARATOR )
1709 (CODING-SYSTEM-FOR-WRITE 'utf-8)
1710 (CODING-SYSTEM-FOR-SAVE 'utf-8)
1711 (t (error "Unknown property: %s" what))))
1713 (defun org-export-e-odt-do-preprocess-latex-fragments ()
1714 "Convert LaTeX fragments to images."
1715 (let* ((latex-frag-opt (plist-get org-lparse-opt-plist :LaTeX-fragments))
1716 (latex-frag-opt ; massage the options
1717 (or (and (member latex-frag-opt '(mathjax t))
1718 (not (and (fboundp 'org-format-latex-mathml-available-p)
1719 (org-format-latex-mathml-available-p)))
1720 (prog1 org-lparse-latex-fragment-fallback
1721 (org-lparse-warn
1722 (concat
1723 "LaTeX to MathML converter not available. "
1724 (format "Using %S instead."
1725 org-lparse-latex-fragment-fallback)))))
1726 latex-frag-opt))
1727 cache-dir display-msg)
1728 (cond
1729 ((eq latex-frag-opt 'dvipng)
1730 (setq cache-dir "ltxpng/")
1731 (setq display-msg "Creating LaTeX image %s"))
1732 ((member latex-frag-opt '(mathjax t))
1733 (setq latex-frag-opt 'mathml)
1734 (setq cache-dir "ltxmathml/")
1735 (setq display-msg "Creating MathML formula %s")))
1736 (when (and org-current-export-file)
1737 (org-format-latex
1738 (concat cache-dir (file-name-sans-extension
1739 (file-name-nondirectory org-current-export-file)))
1740 org-current-export-dir nil display-msg
1741 nil nil latex-frag-opt))))
1743 (defadvice org-format-latex-as-mathml
1744 (after org-e-odt-protect-latex-fragment activate)
1745 "Encode LaTeX fragment as XML.
1746 Do this when translation to MathML fails."
1747 (when (or (not (> (length ad-return-value) 0))
1748 (get-text-property 0 'org-protected ad-return-value))
1749 (setq ad-return-value
1750 (org-propertize (org-e-odt-encode-plain-text (ad-get-arg 0))
1751 'org-protected t))))
1753 (defun org-export-e-odt-preprocess-latex-fragments ()
1754 (when (equal org-export-current-backend 'odt)
1755 (org-export-e-odt-do-preprocess-latex-fragments)))
1757 (defun org-export-e-odt-preprocess-label-references ()
1758 (goto-char (point-min))
1759 (let (label label-components category value pretty-label)
1760 (while (re-search-forward "\\\\ref{\\([^{}\n]+\\)}" nil t)
1761 (org-if-unprotected-at (match-beginning 1)
1762 (replace-match
1763 (let ((org-lparse-encode-pending t)
1764 (label (match-string 1)))
1765 ;; markup generated below is mostly an eye-candy. At
1766 ;; pre-processing stage, there is no information on which
1767 ;; entity a label reference points to. The actual markup
1768 ;; is generated as part of `org-e-odt-fixup-label-references'
1769 ;; which gets called at the fag end of export. By this
1770 ;; time we would have seen and collected all the label
1771 ;; definitions in `org-e-odt-entity-labels-alist'.
1772 (org-e-odt-format-tags
1773 '("<text:sequence-ref text:ref-name=\"%s\">" .
1774 "</text:sequence-ref>")
1775 "" (org-add-props label '(org-protected t)))) t t)))))
1777 ;; process latex fragments as part of
1778 ;; `org-export-preprocess-after-blockquote-hook'. Note that this hook
1779 ;; is the one that is closest and well before the call to
1780 ;; `org-export-attach-captions-and-attributes' in
1781 ;; `org-export-preprocess-string'. The above arrangement permits
1782 ;; captions, labels and attributes to be attached to png images
1783 ;; generated out of latex equations.
1784 (add-hook 'org-export-preprocess-after-blockquote-hook
1785 'org-export-e-odt-preprocess-latex-fragments)
1787 (defun org-export-e-odt-preprocess (parameters)
1788 (org-export-e-odt-preprocess-label-references))
1791 (defun org-e-odt-zip-extract-one (archive member &optional target)
1792 (require 'arc-mode)
1793 (let* ((target (or target default-directory))
1794 (archive (expand-file-name archive))
1795 (archive-zip-extract
1796 (list "unzip" "-qq" "-o" "-d" target))
1797 exit-code command-output)
1798 (setq command-output
1799 (with-temp-buffer
1800 (setq exit-code (archive-zip-extract archive member))
1801 (buffer-string)))
1802 (unless (zerop exit-code)
1803 (message command-output)
1804 (error "Extraction failed"))))
1806 (defun org-e-odt-zip-extract (archive members &optional target)
1807 (when (atom members) (setq members (list members)))
1808 (mapc (lambda (member)
1809 (org-e-odt-zip-extract-one archive member target))
1810 members))
1812 (defun org-e-odt-copy-styles-file (&optional styles-file)
1813 ;; Non-availability of styles.xml is not a critical error. For now
1814 ;; throw an error purely for aesthetic reasons.
1815 (setq styles-file (or styles-file
1816 org-export-e-odt-styles-file
1817 (expand-file-name "OrgOdtStyles.xml"
1818 org-e-odt-styles-dir)
1819 (error "org-e-odt: Missing styles file?")))
1820 (cond
1821 ((listp styles-file)
1822 (let ((archive (nth 0 styles-file))
1823 (members (nth 1 styles-file)))
1824 (org-e-odt-zip-extract archive members)
1825 (mapc
1826 (lambda (member)
1827 (when (org-file-image-p member)
1828 (let* ((image-type (file-name-extension member))
1829 (media-type (format "image/%s" image-type)))
1830 (org-e-odt-create-manifest-file-entry media-type member))))
1831 members)))
1832 ((and (stringp styles-file) (file-exists-p styles-file))
1833 (let ((styles-file-type (file-name-extension styles-file)))
1834 (cond
1835 ((string= styles-file-type "xml")
1836 (copy-file styles-file "styles.xml" t))
1837 ((member styles-file-type '("odt" "ott"))
1838 (org-e-odt-zip-extract styles-file "styles.xml")))))
1840 (error (format "Invalid specification of styles.xml file: %S"
1841 org-export-e-odt-styles-file))))
1843 ;; create a manifest entry for styles.xml
1844 (org-e-odt-create-manifest-file-entry "text/xml" "styles.xml"))
1846 (defun org-e-odt-configure-outline-numbering (level)
1847 "Outline numbering is retained only upto LEVEL.
1848 To disable outline numbering pass a LEVEL of 0."
1849 (goto-char (point-min))
1850 (let ((regex
1851 "<text:outline-level-style\\([^>]*\\)text:level=\"\\([^\"]*\\)\"\\([^>]*\\)>")
1852 (replacement
1853 "<text:outline-level-style\\1text:level=\"\\2\" style:num-format=\"\">"))
1854 (while (re-search-forward regex nil t)
1855 (when (> (string-to-number (match-string 2)) level)
1856 (replace-match replacement t nil))))
1857 (save-buffer 0))
1859 ;;;###autoload
1860 (defun org-export-as-odf (latex-frag &optional odf-file)
1861 "Export LATEX-FRAG as OpenDocument formula file ODF-FILE.
1862 Use `org-create-math-formula' to convert LATEX-FRAG first to
1863 MathML. When invoked as an interactive command, use
1864 `org-latex-regexps' to infer LATEX-FRAG from currently active
1865 region. If no LaTeX fragments are found, prompt for it. Push
1866 MathML source to kill ring, if `org-export-copy-to-kill-ring' is
1867 non-nil."
1868 (interactive
1869 `(,(let (frag)
1870 (setq frag (and (setq frag (and (region-active-p)
1871 (buffer-substring (region-beginning)
1872 (region-end))))
1873 (loop for e in org-latex-regexps
1874 thereis (when (string-match (nth 1 e) frag)
1875 (match-string (nth 2 e) frag)))))
1876 (read-string "LaTeX Fragment: " frag nil frag))
1877 ,(let ((odf-filename (expand-file-name
1878 (concat
1879 (file-name-sans-extension
1880 (or (file-name-nondirectory buffer-file-name)))
1881 "." "odf")
1882 (file-name-directory buffer-file-name))))
1883 (read-file-name "ODF filename: " nil odf-filename nil
1884 (file-name-nondirectory odf-filename)))))
1885 (let* ((org-lparse-backend 'odf)
1886 org-lparse-opt-plist
1887 (filename (or odf-file
1888 (expand-file-name
1889 (concat
1890 (file-name-sans-extension
1891 (or (file-name-nondirectory buffer-file-name)))
1892 "." "odf")
1893 (file-name-directory buffer-file-name))))
1894 (buffer (find-file-noselect (org-e-odt-init-outfile filename)))
1895 (coding-system-for-write 'utf-8)
1896 (save-buffer-coding-system 'utf-8))
1897 (set-buffer buffer)
1898 (set-buffer-file-coding-system coding-system-for-write)
1899 (let ((mathml (org-create-math-formula latex-frag)))
1900 (unless mathml (error "No Math formula created"))
1901 (insert mathml)
1902 (or (org-export-push-to-kill-ring
1903 (upcase (symbol-name org-lparse-backend)))
1904 (message "Exporting... done")))
1905 (org-e-odt-save-as-outfile filename nil ; FIXME
1908 ;;;###autoload
1909 (defun org-export-as-odf-and-open ()
1910 "Export LaTeX fragment as OpenDocument formula and immediately open it.
1911 Use `org-export-as-odf' to read LaTeX fragment and OpenDocument
1912 formula file."
1913 (interactive)
1914 (org-lparse-and-open
1915 nil nil nil (call-interactively 'org-export-as-odf)))
1920 ;;; Driver Starts here
1921 ;;; Dependencies
1923 (require 'format-spec)
1924 (eval-when-compile (require 'cl) (require 'table))
1928 ;;; Hooks
1930 (defvar org-e-odt-after-blockquotes-hook nil
1931 "Hook run during HTML export, after blockquote, verse, center are done.")
1933 (defvar org-e-odt-final-hook nil
1934 "Hook run at the end of HTML export, in the new buffer.")
1936 ;; FIXME: it already exists in org-e-odt.el
1937 ;;; Function Declarations
1939 (declare-function org-element-property "org-element" (property element))
1940 (declare-function org-element-normalize-string "org-element" (s))
1941 (declare-function org-element-parse-secondary-string
1942 "org-element" (string restriction &optional buffer))
1943 (defvar org-element-string-restrictions)
1945 (declare-function org-export-clean-table "org-export" (table specialp))
1946 (declare-function org-export-data "org-export" (data backend info))
1947 (declare-function org-export-directory "org-export" (type plist))
1948 (declare-function org-export-expand-macro "org-export" (macro info))
1949 (declare-function org-export-first-sibling-p "org-export" (headline info))
1950 (declare-function org-export-footnote-first-reference-p "org-export"
1951 (footnote-reference info))
1952 (declare-function org-export-get-coderef-format "org-export" (path desc))
1953 (declare-function org-export-get-footnote-definition "org-export"
1954 (footnote-reference info))
1955 (declare-function org-export-get-footnote-number "org-export" (footnote info))
1956 (declare-function org-export-get-previous-element "org-export" (blob info))
1957 (declare-function org-export-get-relative-level "org-export" (headline info))
1958 (declare-function org-export-handle-code
1959 "org-export" (element info &optional num-fmt ref-fmt delayed))
1960 (declare-function org-export-included-file "org-export" (keyword backend info))
1961 (declare-function org-export-inline-image-p "org-export"
1962 (link &optional extensions))
1963 (declare-function org-export-last-sibling-p "org-export" (headline info))
1964 (declare-function org-export-low-level-p "org-export" (headline info))
1965 (declare-function org-export-output-file-name
1966 "org-export" (extension &optional subtreep pub-dir))
1967 (declare-function org-export-resolve-coderef "org-export" (ref info))
1968 (declare-function org-export-resolve-fuzzy-link "org-export" (link info))
1969 (declare-function org-export-secondary-string "org-export"
1970 (secondary backend info))
1971 (declare-function org-export-solidify-link-text "org-export" (s))
1972 (declare-function org-export-table-format-info "org-export" (table))
1973 (declare-function
1974 org-export-to-buffer "org-export"
1975 (backend buffer &optional subtreep visible-only body-only ext-plist))
1976 (declare-function
1977 org-export-to-file "org-export"
1978 (backend file &optional subtreep visible-only body-only ext-plist))
1980 (declare-function org-id-find-id-file "org-id" (id))
1981 (declare-function htmlize-region "ext:htmlize" (beg end))
1982 (declare-function org-pop-to-buffer-same-window
1983 "org-compat" (&optional buffer-or-name norecord label))
1989 (declare-function hfy-face-to-style "htmlfontify" (fn))
1990 (declare-function hfy-face-or-def-to-name "htmlfontify" (fn))
1991 (declare-function archive-zip-extract "arc-mode.el" (archive name))
1993 ;;; Internal Variables
1995 ;;;; ODT Internal Variables
1997 (defconst org-e-odt-lib-dir
1998 (file-name-directory load-file-name)
1999 "Location of ODT exporter.
2000 Use this to infer values of `org-e-odt-styles-dir' and
2001 `org-export-e-odt-schema-dir'.")
2003 (defvar org-e-odt-data-dir
2004 (expand-file-name "../etc/" org-e-odt-lib-dir)
2005 "Data directory for ODT exporter.
2006 Use this to infer values of `org-e-odt-styles-dir' and
2007 `org-export-e-odt-schema-dir'.")
2012 (defconst org-export-e-odt-special-string-regexps
2013 '(("\\\\-" . "&#x00ad;\\1") ; shy
2014 ("---\\([^-]\\)" . "&#x2014;\\1") ; mdash
2015 ("--\\([^-]\\)" . "&#x2013;\\1") ; ndash
2016 ("\\.\\.\\." . "&#x2026;")) ; hellip
2017 "Regular expressions for special string conversion.")
2019 (defconst org-e-odt-schema-dir-list
2020 (list
2021 (and org-e-odt-data-dir
2022 (expand-file-name "./schema/" org-e-odt-data-dir)) ; bail out
2023 (eval-when-compile
2024 (and (boundp 'org-e-odt-data-dir) org-e-odt-data-dir ; see make install
2025 (expand-file-name "./schema/" org-e-odt-data-dir)))
2026 (expand-file-name "../contrib/odt/etc/schema/" org-e-odt-lib-dir) ; git
2028 "List of directories to search for OpenDocument schema files.
2029 Use this list to set the default value of
2030 `org-export-e-odt-schema-dir'. The entries in this list are
2031 populated heuristically based on the values of `org-e-odt-lib-dir'
2032 and `org-e-odt-data-dir'.")
2035 (defconst org-e-odt-styles-dir-list
2036 (list
2037 (and org-e-odt-data-dir
2038 (expand-file-name "./styles/" org-e-odt-data-dir)) ; bail out
2039 (eval-when-compile
2040 (and (boundp 'org-e-odt-data-dir) org-e-odt-data-dir ; see make install
2041 (expand-file-name "./styles/" org-e-odt-data-dir)))
2042 (expand-file-name "../etc/styles/" org-e-odt-lib-dir) ; git
2043 (expand-file-name "./etc/styles/" org-e-odt-lib-dir) ; elpa
2044 (expand-file-name "./org/" data-directory) ; system
2046 "List of directories to search for OpenDocument styles files.
2047 See `org-e-odt-styles-dir'. The entries in this list are populated
2048 heuristically based on the values of `org-e-odt-lib-dir' and
2049 `org-e-odt-data-dir'.")
2051 (defconst org-e-odt-styles-dir
2052 (let* ((styles-dir
2053 (catch 'styles-dir
2054 (message "Debug (org-e-odt): Searching for OpenDocument styles files...")
2055 (mapc (lambda (styles-dir)
2056 (when styles-dir
2057 (message "Debug (org-e-odt): Trying %s..." styles-dir)
2058 (when (and (file-readable-p
2059 (expand-file-name
2060 "OrgOdtContentTemplate.xml" styles-dir))
2061 (file-readable-p
2062 (expand-file-name
2063 "OrgOdtStyles.xml" styles-dir)))
2064 (message "Debug (org-e-odt): Using styles under %s"
2065 styles-dir)
2066 (throw 'styles-dir styles-dir))))
2067 org-e-odt-styles-dir-list)
2068 nil)))
2069 (unless styles-dir
2070 (error "Error (org-e-odt): Cannot find factory styles files. Aborting."))
2071 styles-dir)
2072 "Directory that holds auxiliary XML files used by the ODT exporter.
2074 This directory contains the following XML files -
2075 \"OrgOdtStyles.xml\" and \"OrgOdtContentTemplate.xml\". These
2076 XML files are used as the default values of
2077 `org-export-e-odt-styles-file' and
2078 `org-export-e-odt-content-template-file'.
2080 The default value of this variable varies depending on the
2081 version of org in use and is initialized from
2082 `org-e-odt-styles-dir-list'. Note that the user could be using org
2083 from one of: org's own private git repository, GNU ELPA tar or
2084 standard Emacs.")
2086 (defconst org-export-e-odt-tmpdir-prefix "%s-")
2087 (defconst org-export-e-odt-bookmark-prefix "OrgXref.")
2089 (defconst org-e-odt-manifest-file-entry-tag
2091 <manifest:file-entry manifest:media-type=\"%s\" manifest:full-path=\"%s\"%s/>")
2095 (defvar org-lparse-dyn-first-heading-pos) ; let bound during org-do-lparse
2097 (defvar org-e-odt-suppress-xref nil)
2098 (defvar org-e-odt-file-extensions
2099 '(("odt" . "OpenDocument Text")
2100 ("ott" . "OpenDocument Text Template")
2101 ("odm" . "OpenDocument Master Document")
2102 ("ods" . "OpenDocument Spreadsheet")
2103 ("ots" . "OpenDocument Spreadsheet Template")
2104 ("odg" . "OpenDocument Drawing (Graphics)")
2105 ("otg" . "OpenDocument Drawing Template")
2106 ("odp" . "OpenDocument Presentation")
2107 ("otp" . "OpenDocument Presentation Template")
2108 ("odi" . "OpenDocument Image")
2109 ("odf" . "OpenDocument Formula")
2110 ("odc" . "OpenDocument Chart")))
2112 (defvar org-export-e-odt-embed-images t
2113 "Should the images be copied in to the odt file or just linked?")
2115 (defvar org-export-e-odt-inline-images 'maybe)
2116 (defvar org-export-e-odt-default-org-styles-alist
2117 '((paragraph . ((default . "Text_20_body")
2118 (fixedwidth . "OrgFixedWidthBlock")
2119 (verse . "OrgVerse")
2120 (quote . "Quotations")
2121 (blockquote . "Quotations")
2122 (center . "OrgCenter")
2123 (left . "OrgLeft")
2124 (right . "OrgRight")
2125 (title . "OrgTitle")
2126 (subtitle . "OrgSubtitle")
2127 (footnote . "Footnote")
2128 (src . "OrgSrcBlock")
2129 (illustration . "Illustration")
2130 (table . "Table")
2131 (definition-term . "Text_20_body_20_bold")
2132 (horizontal-line . "Horizontal_20_Line")))
2133 (character . ((bold . "Bold")
2134 (emphasis . "Emphasis")
2135 (code . "OrgCode")
2136 (verbatim . "OrgCode")
2137 (strike . "Strikethrough")
2138 (underline . "Underline")
2139 (subscript . "OrgSubscript")
2140 (superscript . "OrgSuperscript")))
2141 (list . ((ordered . "OrgNumberedList")
2142 (unordered . "OrgBulletedList")
2143 (descriptive . "OrgDescriptionList"))))
2144 "Default styles for various entities.")
2146 (defvar org-export-e-odt-org-styles-alist org-export-e-odt-default-org-styles-alist)
2148 (defvar org-e-odt-entity-control-callbacks-alist
2149 `((EXPORT
2150 . (org-e-odt-begin-export org-e-odt-end-export))
2151 (DOCUMENT-CONTENT
2152 . (org-e-odt-begin-document-content org-e-odt-end-document-content))
2153 (DOCUMENT-BODY
2154 . (org-e-odt-begin-document-body org-e-odt-end-document-body))
2155 (TOC
2156 . (org-e-odt-begin-toc org-e-odt-end-toc))
2157 (ENVIRONMENT
2158 . (org-e-odt-begin-environment org-e-odt-end-environment))
2159 (FOOTNOTE-DEFINITION
2160 . (org-e-odt-begin-footnote-definition org-e-odt-end-footnote-definition))
2161 (TABLE
2162 . (org-e-odt-begin-table org-e-odt-end-table))
2163 (TABLE-ROWGROUP
2164 . (org-e-odt-begin-table-rowgroup org-e-odt-end-table-rowgroup))
2165 (LIST
2166 . (org-e-odt-begin-list org-e-odt-end-list))
2167 (LIST-ITEM
2168 . (org-e-odt-begin-list-item org-e-odt-end-list-item))
2169 (OUTLINE
2170 . (org-e-odt-begin-outline org-e-odt-end-outline))
2171 (OUTLINE-TEXT
2172 . (org-e-odt-begin-outline-text org-e-odt-end-outline-text))
2173 (PARAGRAPH
2174 . (org-e-odt-begin-paragraph org-e-odt-end-paragraph)))
2177 (defvar org-e-odt-entity-format-callbacks-alist
2178 `((EXTRA-TARGETS . org-lparse-format-extra-targets)
2179 (ORG-TAGS . org-lparse-format-org-tags)
2180 (SECTION-NUMBER . org-lparse-format-section-number)
2181 (HEADLINE . org-e-odt-format-headline)
2182 (TOC-ENTRY . org-e-odt-format-toc-entry)
2183 (TOC-ITEM . org-e-odt-format-toc-item)
2184 (TAGS . org-e-odt-format-tags)
2185 (SPACES . org-e-odt-format-spaces)
2186 (TABS . org-e-odt-format-tabs)
2187 (LINE-BREAK . org-e-odt-format-line-break)
2188 (FONTIFY . org-e-odt-format-fontify)
2189 (TODO . org-lparse-format-todo)
2190 (LINK . org-e-odt-format-link)
2191 (INLINE-IMAGE . org-e-odt-format-inline-image)
2192 (ORG-LINK . org-e-odt-format-org-link)
2193 (HEADING . org-e-odt-format-heading)
2194 (ANCHOR . org-e-odt-format-anchor)
2195 (TABLE . org-lparse-format-table)
2196 (TABLE-ROW . org-e-odt-format-table-row)
2197 (TABLE-CELL . org-e-odt-format-table-cell)
2198 (FOOTNOTES-SECTION . ignore)
2199 (FOOTNOTE-REFERENCE . org-e-odt-format-footnote-reference)
2200 (HORIZONTAL-LINE . org-e-odt-format-horizontal-line)
2201 (COMMENT . org-e-odt-format-comment)
2202 (LINE . org-e-odt-format-line)
2203 (ORG-ENTITY . org-e-odt-format-org-entity))
2206 ;;;_. callbacks
2207 ;;;_. control callbacks
2208 ;;;_ , document body
2210 (defvar org-lparse-toc)
2211 (defvar org-lparse-body-only) ; let bound during org-do-lparse
2212 (defvar org-lparse-to-buffer) ; let bound during org-do-lparse
2213 (defvar org-lparse-opt-plist) ; bound during org-do-lparse
2214 (defvar org-lparse-list-stack) ; dynamically bound in org-do-lparse
2215 (defvar org-e-odt-list-stack-stashed)
2216 (defvar org-lparse-table-begin-marker)
2217 (defvar org-lparse-table-ncols)
2218 (defvar org-e-odt-table-rowgrp-open)
2219 (defvar org-e-odt-table-rownum)
2220 (defvar org-e-odt-table-cur-rowgrp-is-hdr)
2221 (defvar org-lparse-table-is-styled)
2222 (defvar org-lparse-table-rowgrp-info)
2223 (defvar org-lparse-table-colalign-vector)
2225 (defvar org-e-odt-table-style nil
2226 "Table style specified by \"#+ATTR_ODT: <style-name>\" line.
2227 This is set during `org-e-odt-begin-table'.")
2229 (defvar org-e-odt-table-style-spec nil
2230 "Entry for `org-e-odt-table-style' in `org-export-e-odt-table-styles'.")
2233 (defvar org-e-odt-table-style-format
2235 <style:style style:name=\"%s\" style:family=\"table\">
2236 <style:table-properties style:rel-width=\"%d%%\" fo:margin-top=\"0cm\" fo:margin-bottom=\"0.20cm\" table:align=\"center\"/>
2237 </style:style>
2239 "Template for auto-generated Table styles.")
2241 (defvar org-e-odt-automatic-styles '()
2242 "Registry of automatic styles for various OBJECT-TYPEs.
2243 The variable has the following form:
2244 \(\(OBJECT-TYPE-A
2245 \(\(OBJECT-NAME-A.1 OBJECT-PROPS-A.1\)
2246 \(OBJECT-NAME-A.2 OBJECT-PROPS-A.2\) ...\)\)
2247 \(OBJECT-TYPE-B
2248 \(\(OBJECT-NAME-B.1 OBJECT-PROPS-B.1\)
2249 \(OBJECT-NAME-B.2 OBJECT-PROPS-B.2\) ...\)\)
2250 ...\).
2252 OBJECT-TYPEs could be \"Section\", \"Table\", \"Figure\" etc.
2253 OBJECT-PROPS is (typically) a plist created by passing
2254 \"#+ATTR_ODT: \" option to `org-lparse-get-block-params'.
2256 Use `org-e-odt-add-automatic-style' to add update this variable.'")
2258 (defvar org-e-odt-object-counters nil
2259 "Running counters for various OBJECT-TYPEs.
2260 Use this to generate automatic names and style-names. See
2261 `org-e-odt-add-automatic-style'.")
2263 (defvar org-e-odt-table-indentedp nil)
2264 (defvar org-lparse-table-colalign-info)
2265 (defvar org-lparse-link-description-is-image nil)
2268 (defvar org-src-block-paragraph-format
2269 "<style:style style:name=\"OrgSrcBlock\" style:family=\"paragraph\" style:parent-style-name=\"Preformatted_20_Text\">
2270 <style:paragraph-properties fo:background-color=\"%s\" fo:padding=\"0.049cm\" fo:border=\"0.51pt solid #000000\" style:shadow=\"none\">
2271 <style:background-image/>
2272 </style:paragraph-properties>
2273 <style:text-properties fo:color=\"%s\"/>
2274 </style:style>"
2275 "Custom paragraph style for colorized source and example blocks.
2276 This style is much the same as that of \"OrgFixedWidthBlock\"
2277 except that the foreground and background colors are set
2278 according to the default face identified by the `htmlfontify'.")
2280 (defvar hfy-optimisations)
2281 (defvar org-e-odt-embedded-formulas-count 0)
2282 (defvar org-e-odt-entity-frame-styles
2283 '(("As-CharImage" "__Figure__" ("OrgInlineImage" nil "as-char"))
2284 ("ParagraphImage" "__Figure__" ("OrgDisplayImage" nil "paragraph"))
2285 ("PageImage" "__Figure__" ("OrgPageImage" nil "page"))
2286 ("CaptionedAs-CharImage" "__Figure__"
2287 ("OrgCaptionedImage"
2288 " style:rel-width=\"100%\" style:rel-height=\"scale\"" "paragraph")
2289 ("OrgInlineImage" nil "as-char"))
2290 ("CaptionedParagraphImage" "__Figure__"
2291 ("OrgCaptionedImage"
2292 " style:rel-width=\"100%\" style:rel-height=\"scale\"" "paragraph")
2293 ("OrgImageCaptionFrame" nil "paragraph"))
2294 ("CaptionedPageImage" "__Figure__"
2295 ("OrgCaptionedImage"
2296 " style:rel-width=\"100%\" style:rel-height=\"scale\"" "paragraph")
2297 ("OrgPageImageCaptionFrame" nil "page"))
2298 ("InlineFormula" "__MathFormula__" ("OrgInlineFormula" nil "as-char"))
2299 ("DisplayFormula" "__MathFormula__" ("OrgDisplayFormula" nil "as-char"))
2300 ("CaptionedDisplayFormula" "__MathFormula__"
2301 ("OrgCaptionedFormula" nil "paragraph")
2302 ("OrgFormulaCaptionFrame" nil "as-char"))))
2304 (defvar org-e-odt-embedded-images-count 0)
2306 (defvar org-export-e-odt-image-size-probe-method
2307 (append (and (executable-find "identify") '(imagemagick)) ; See Bug#10675
2308 '(emacs fixed))
2309 "Ordered list of methods for determining image sizes.")
2311 (defvar org-export-e-odt-default-image-sizes-alist
2312 '(("as-char" . (5 . 0.4))
2313 ("paragraph" . (5 . 5)))
2314 "Hardcoded image dimensions one for each of the anchor
2315 methods.")
2317 ;; A4 page size is 21.0 by 29.7 cms
2318 ;; The default page settings has 2cm margin on each of the sides. So
2319 ;; the effective text area is 17.0 by 25.7 cm
2320 (defvar org-export-e-odt-max-image-size '(17.0 . 20.0)
2321 "Limiting dimensions for an embedded image.")
2323 (defvar org-e-odt-entity-labels-alist nil
2324 "Associate Labels with the Labeled entities.
2325 Each element of the alist is of the form (LABEL-NAME
2326 CATEGORY-NAME SEQNO LABEL-STYLE-NAME). LABEL-NAME is same as
2327 that specified by \"#+LABEL: ...\" line. CATEGORY-NAME is the
2328 type of the entity that LABEL-NAME is attached to. CATEGORY-NAME
2329 can be one of \"Table\", \"Figure\" or \"Equation\". SEQNO is
2330 the unique number assigned to the referenced entity on a
2331 per-CATEGORY basis. It is generated sequentially and is 1-based.
2332 LABEL-STYLE-NAME is a key `org-e-odt-label-styles'.
2334 See `org-e-odt-add-label-definition' and
2335 `org-e-odt-fixup-label-references'.")
2337 (defvar org-e-odt-entity-counts-plist nil
2338 "Plist of running counters of SEQNOs for each of the CATEGORY-NAMEs.
2339 See `org-e-odt-entity-labels-alist' for known CATEGORY-NAMEs.")
2341 (defvar org-e-odt-label-styles
2342 '(("text" "(%n)" "text" "(%n)")
2343 ("category-and-value" "%e %n%c" "category-and-value" "%e %n")
2344 ("value" "%e %n%c" "value" "%n"))
2345 "Specify how labels are applied and referenced.
2346 This is an alist where each element is of the
2347 form (LABEL-STYLE-NAME LABEL-ATTACH-FMT LABEL-REF-MODE
2348 LABEL-REF-FMT).
2350 LABEL-ATTACH-FMT controls how labels and captions are attached to
2351 an entity. It may contain following specifiers - %e, %n and %c.
2352 %e is replaced with the CATEGORY-NAME. %n is replaced with
2353 \"<text:sequence ...> SEQNO </text:sequence>\". %c is replaced
2354 with CAPTION. See `org-e-odt-format-label-definition'.
2356 LABEL-REF-MODE and LABEL-REF-FMT controls how label references
2357 are generated. The following XML is generated for a label
2358 reference - \"<text:sequence-ref
2359 text:reference-format=\"LABEL-REF-MODE\" ...> LABEL-REF-FMT
2360 </text:sequence-ref>\". LABEL-REF-FMT may contain following
2361 specifiers - %e and %n. %e is replaced with the CATEGORY-NAME.
2362 %n is replaced with SEQNO. See
2363 `org-e-odt-format-label-reference'.")
2365 (defvar org-e-odt-category-map-alist
2366 '(("__Table__" "Table" "value")
2367 ("__Figure__" "Figure" "value")
2368 ("__MathFormula__" "Equation" "text")
2369 ("__DvipngImage__" "Equation" "value")
2370 ;; ("__Table__" "Table" "category-and-value")
2371 ;; ("__Figure__" "Figure" "category-and-value")
2372 ;; ("__DvipngImage__" "Equation" "category-and-value")
2374 "Map a CATEGORY-HANDLE to CATEGORY-NAME and LABEL-STYLE.
2375 This is an alist where each element is of the form
2376 \\(CATEGORY-HANDLE CATEGORY-NAME LABEL-STYLE\\). CATEGORY_HANDLE
2377 could either be one of the internal handles (as seen above) or be
2378 derived from the \"#+LABEL:<label-name>\" specification. See
2379 `org-export-e-odt-get-category-from-label'. CATEGORY-NAME and
2380 LABEL-STYLE are used for generating ODT labels. See
2381 `org-e-odt-label-styles'.")
2383 (defvar org-export-e-odt-user-categories
2384 '("Illustration" "Table" "Text" "Drawing" "Equation" "Figure"))
2386 (defvar org-export-e-odt-get-category-from-label nil
2387 "Should category of label be inferred from label itself.
2388 When this option is non-nil, a label is parsed in to two
2389 component parts delimited by a \":\" (colon) as shown here -
2390 #+LABEL:[CATEGORY-HANDLE:]EXTRA. The CATEGORY-HANDLE is mapped
2391 to a CATEGORY-NAME and LABEL-STYLE using
2392 `org-e-odt-category-map-alist'. (If no such map is provided and
2393 CATEGORY-NAME is set to CATEGORY-HANDLE and LABEL-STYLE is set to
2394 \"category-and-value\"). If CATEGORY-NAME so obtained is listed
2395 under `org-export-e-odt-user-categories' then the user specified
2396 styles are used. Otherwise styles as determined by the internal
2397 CATEGORY-HANDLE is used. See
2398 `org-e-odt-get-label-category-and-style' for details.")
2400 (defvar org-e-odt-manifest-file-entries nil)
2401 (defvar hfy-user-sheet-assoc) ; bound during org-do-lparse
2402 (defvar org-lparse-latex-fragment-fallback) ; set by org-do-lparse
2405 ;;;; HTML Internal Variables
2407 (defvar org-e-odt-option-alist
2409 ;; (:agenda-style nil nil org-agenda-export-html-style)
2410 ;; (:convert-org-links nil nil org-e-odt-link-org-files-as-html)
2411 ;; ;; FIXME Use (org-xml-encode-org-text-skip-links s) ??
2412 ;; ;; (:expand-quoted-html nil "@" org-e-odt-expand)
2413 ;; (:inline-images nil nil org-e-odt-inline-images)
2414 ;; ;; (:link-home nil nil org-e-odt-link-home) FIXME
2415 ;; ;; (:link-up nil nil org-e-odt-link-up) FIXME
2416 ;; (:style nil nil org-e-odt-style)
2417 ;; (:style-extra nil nil org-e-odt-style-extra)
2418 ;; (:style-include-default nil nil org-e-odt-style-include-default)
2419 ;; (:style-include-scripts nil nil org-e-odt-style-include-scripts)
2420 ;; ;; (:timestamp nil nil org-e-odt-with-timestamp)
2421 ;; (:html-extension nil nil org-e-odt-extension)
2422 ;; (:html-postamble nil nil org-e-odt-postamble)
2423 ;; (:html-preamble nil nil org-e-odt-preamble)
2424 ;; (:html-table-tag nil nil org-e-odt-table-tag)
2425 ;; (:xml-declaration nil nil org-e-odt-xml-declaration)
2426 (:LaTeX-fragments nil "LaTeX" org-export-with-LaTeX-fragments))
2427 "Alist between export properties and ways to set them.
2429 The car of the alist is the property name, and the cdr is a list
2430 like \(KEYWORD OPTION DEFAULT BEHAVIOUR\) where:
2432 KEYWORD is a string representing a buffer keyword, or nil.
2433 OPTION is a string that could be found in an #+OPTIONS: line.
2434 DEFAULT is the default value for the property.
2435 BEHAVIOUR determine how Org should handle multiple keywords for
2436 the same property. It is a symbol among:
2437 nil Keep old value and discard the new one.
2438 t Replace old value with the new one.
2439 `space' Concatenate the values, separating them with a space.
2440 `newline' Concatenate the values, separating them with
2441 a newline.
2442 `split' Split values at white spaces, and cons them to the
2443 previous list.
2445 KEYWORD and OPTION have precedence over DEFAULT.
2447 All these properties should be back-end agnostic. For back-end
2448 specific properties, define a similar variable named
2449 `org-BACKEND-option-alist', replacing BACKEND with the name of
2450 the appropriate back-end. You can also redefine properties
2451 there, as they have precedence over these.")
2453 (defvar html-table-tag nil) ; dynamically scoped into this.
2455 ;; FIXME: it already exists in org-e-odt.el
2456 (defconst org-e-odt-cvt-link-fn
2458 "Function to convert link URLs to exportable URLs.
2459 Takes two arguments, TYPE and PATH.
2460 Returns exportable url as (TYPE PATH), or nil to signal that it
2461 didn't handle this case.
2462 Intended to be locally bound around a call to `org-export-as-html'." )
2467 (defvar org-e-odt-format-table-no-css)
2468 (defvar htmlize-buffer-places) ; from htmlize.el
2469 (defvar body-only) ; dynamically scoped into this.
2471 (defvar org-e-odt-table-rowgrp-open)
2472 (defvar org-e-odt-table-rownum)
2473 (defvar org-e-odt-table-cur-rowgrp-is-hdr)
2474 (defvar org-lparse-table-is-styled)
2477 (defvar org-e-odt-headline-formatter
2478 (lambda (level snumber todo todo-type priority
2479 title tags target extra-targets extra-class)
2480 (concat snumber " " title)))
2484 ;;; User Configuration Variables
2486 (defgroup org-export-e-odt nil
2487 "Options for exporting Org mode files to HTML."
2488 :tag "Org Export HTML"
2489 :group 'org-export)
2491 (defcustom org-e-odt-protect-char-alist
2492 '(("&" . "&amp;")
2493 ("<" . "&lt;")
2494 (">" . "&gt;"))
2495 "Alist of characters to be converted by `org-e-html-protect'."
2496 :group 'org-export-e-html
2497 :type '(repeat (cons (string :tag "Character")
2498 (string :tag "ODT equivalent"))))
2499 (defcustom org-export-e-odt-schema-dir
2500 (let* ((schema-dir
2501 (catch 'schema-dir
2502 (message "Debug (org-e-odt): Searching for OpenDocument schema files...")
2503 (mapc
2504 (lambda (schema-dir)
2505 (when schema-dir
2506 (message "Debug (org-e-odt): Trying %s..." schema-dir)
2507 (when (and (file-readable-p
2508 (expand-file-name "od-manifest-schema-v1.2-cs01.rnc"
2509 schema-dir))
2510 (file-readable-p
2511 (expand-file-name "od-schema-v1.2-cs01.rnc"
2512 schema-dir))
2513 (file-readable-p
2514 (expand-file-name "schemas.xml" schema-dir)))
2515 (message "Debug (org-e-odt): Using schema files under %s"
2516 schema-dir)
2517 (throw 'schema-dir schema-dir))))
2518 org-e-odt-schema-dir-list)
2519 (message "Debug (org-e-odt): No OpenDocument schema files installed")
2520 nil)))
2521 schema-dir)
2522 "Directory that contains OpenDocument schema files.
2524 This directory contains:
2525 1. rnc files for OpenDocument schema
2526 2. a \"schemas.xml\" file that specifies locating rules needed
2527 for auto validation of OpenDocument XML files.
2529 Use the customize interface to set this variable. This ensures
2530 that `rng-schema-locating-files' is updated and auto-validation
2531 of OpenDocument XML takes place based on the value
2532 `rng-nxml-auto-validate-flag'.
2534 The default value of this variable varies depending on the
2535 version of org in use and is initialized from
2536 `org-e-odt-schema-dir-list'. The OASIS schema files are available
2537 only in the org's private git repository. It is *not* bundled
2538 with GNU ELPA tar or standard Emacs distribution."
2539 :type '(choice
2540 (const :tag "Not set" nil)
2541 (directory :tag "Schema directory"))
2542 :group 'org-export-e-odt
2543 :version "24.1"
2544 :set
2545 (lambda (var value)
2546 "Set `org-export-e-odt-schema-dir'.
2547 Also add it to `rng-schema-locating-files'."
2548 (let ((schema-dir value))
2549 (set var
2550 (if (and
2551 (file-readable-p
2552 (expand-file-name "od-manifest-schema-v1.2-cs01.rnc" schema-dir))
2553 (file-readable-p
2554 (expand-file-name "od-schema-v1.2-cs01.rnc" schema-dir))
2555 (file-readable-p
2556 (expand-file-name "schemas.xml" schema-dir)))
2557 schema-dir
2558 (when value
2559 (message "Error (org-e-odt): %s has no OpenDocument schema files"
2560 value))
2561 nil)))
2562 (when org-export-e-odt-schema-dir
2563 (eval-after-load 'rng-loc
2564 '(add-to-list 'rng-schema-locating-files
2565 (expand-file-name "schemas.xml"
2566 org-export-e-odt-schema-dir))))))
2568 (defcustom org-export-e-odt-content-template-file nil
2569 "Template file for \"content.xml\".
2570 The exporter embeds the exported content just before
2571 \"</office:text>\" element.
2573 If unspecified, the file named \"OrgOdtContentTemplate.xml\"
2574 under `org-e-odt-styles-dir' is used."
2575 :type 'file
2576 :group 'org-export-e-odt
2577 :version "24.1")
2579 (defcustom org-export-e-odt-styles-file nil
2580 "Default styles file for use with ODT export.
2581 Valid values are one of:
2582 1. nil
2583 2. path to a styles.xml file
2584 3. path to a *.odt or a *.ott file
2585 4. list of the form (ODT-OR-OTT-FILE (FILE-MEMBER-1 FILE-MEMBER-2
2586 ...))
2588 In case of option 1, an in-built styles.xml is used. See
2589 `org-e-odt-styles-dir' for more information.
2591 In case of option 3, the specified file is unzipped and the
2592 styles.xml embedded therein is used.
2594 In case of option 4, the specified ODT-OR-OTT-FILE is unzipped
2595 and FILE-MEMBER-1, FILE-MEMBER-2 etc are copied in to the
2596 generated odt file. Use relative path for specifying the
2597 FILE-MEMBERS. styles.xml must be specified as one of the
2598 FILE-MEMBERS.
2600 Use options 1, 2 or 3 only if styles.xml alone suffices for
2601 achieving the desired formatting. Use option 4, if the styles.xml
2602 references additional files like header and footer images for
2603 achieving the desired formatting.
2605 Use \"#+ODT_STYLES_FILE: ...\" directive to set this variable on
2606 a per-file basis. For example,
2608 #+ODT_STYLES_FILE: \"/path/to/styles.xml\" or
2609 #+ODT_STYLES_FILE: (\"/path/to/file.ott\" (\"styles.xml\" \"image/hdr.png\"))."
2610 :group 'org-export-e-odt
2611 :version "24.1"
2612 :type
2613 '(choice
2614 (const :tag "Factory settings" nil)
2615 (file :must-match t :tag "styles.xml")
2616 (file :must-match t :tag "ODT or OTT file")
2617 (list :tag "ODT or OTT file + Members"
2618 (file :must-match t :tag "ODF Text or Text Template file")
2619 (cons :tag "Members"
2620 (file :tag " Member" "styles.xml")
2621 (repeat (file :tag "Member"))))))
2624 (defcustom org-export-e-odt-inline-image-extensions
2625 '("png" "jpeg" "jpg" "gif")
2626 "Extensions of image files that can be inlined into HTML."
2627 :type '(repeat (string :tag "Extension"))
2628 :group 'org-export-e-odt
2629 :version "24.1")
2631 (defcustom org-export-e-odt-pixels-per-inch display-pixels-per-inch
2632 "Scaling factor for converting images pixels to inches.
2633 Use this for sizing of embedded images. See Info node `(org)
2634 Images in ODT export' for more information."
2635 :type 'float
2636 :group 'org-export-e-odt
2637 :version "24.1")
2639 (defcustom org-export-e-odt-create-custom-styles-for-srcblocks t
2640 "Whether custom styles for colorized source blocks be automatically created.
2641 When this option is turned on, the exporter creates custom styles
2642 for source blocks based on the advice of `htmlfontify'. Creation
2643 of custom styles happen as part of `org-e-odt-hfy-face-to-css'.
2645 When this option is turned off exporter does not create such
2646 styles.
2648 Use the latter option if you do not want the custom styles to be
2649 based on your current display settings. It is necessary that the
2650 styles.xml already contains needed styles for colorizing to work.
2652 This variable is effective only if
2653 `org-export-e-odt-fontify-srcblocks' is turned on."
2654 :group 'org-export-e-odt
2655 :version "24.1"
2656 :type 'boolean)
2658 (defcustom org-export-e-odt-preferred-output-format nil
2659 "Automatically post-process to this format after exporting to \"odt\".
2660 Interactive commands `org-export-as-e-odt' and
2661 `org-export-as-e-odt-and-open' export first to \"odt\" format and
2662 then use `org-export-e-odt-convert-process' to convert the
2663 resulting document to this format. During customization of this
2664 variable, the list of valid values are populated based on
2665 `org-export-e-odt-convert-capabilities'."
2666 :group 'org-export-e-odt
2667 :version "24.1"
2668 :type '(choice :convert-widget
2669 (lambda (w)
2670 (apply 'widget-convert (widget-type w)
2671 (eval (car (widget-get w :args)))))
2672 `((const :tag "None" nil)
2673 ,@(mapcar (lambda (c)
2674 `(const :tag ,c ,c))
2675 (org-lparse-reachable-formats "odt")))))
2677 (defcustom org-export-e-odt-table-styles
2678 '(("OrgEquation" "OrgEquation"
2679 ((use-first-column-styles . t)
2680 (use-last-column-styles . t))))
2681 "Specify how Table Styles should be derived from a Table Template.
2682 This is a list where each element is of the
2683 form (TABLE-STYLE-NAME TABLE-TEMPLATE-NAME TABLE-CELL-OPTIONS).
2685 TABLE-STYLE-NAME is the style associated with the table through
2686 `org-e-odt-table-style'.
2688 TABLE-TEMPLATE-NAME is a set of - upto 9 - automatic
2689 TABLE-CELL-STYLE-NAMEs and PARAGRAPH-STYLE-NAMEs (as defined
2690 below) that is included in
2691 `org-export-e-odt-content-template-file'.
2693 TABLE-CELL-STYLE-NAME := TABLE-TEMPLATE-NAME + TABLE-CELL-TYPE +
2694 \"TableCell\"
2695 PARAGRAPH-STYLE-NAME := TABLE-TEMPLATE-NAME + TABLE-CELL-TYPE +
2696 \"TableParagraph\"
2697 TABLE-CELL-TYPE := \"FirstRow\" | \"LastColumn\" |
2698 \"FirstRow\" | \"LastRow\" |
2699 \"EvenRow\" | \"OddRow\" |
2700 \"EvenColumn\" | \"OddColumn\" | \"\"
2701 where \"+\" above denotes string concatenation.
2703 TABLE-CELL-OPTIONS is an alist where each element is of the
2704 form (TABLE-CELL-STYLE-SELECTOR . ON-OR-OFF).
2705 TABLE-CELL-STYLE-SELECTOR := `use-first-row-styles' |
2706 `use-last-row-styles' |
2707 `use-first-column-styles' |
2708 `use-last-column-styles' |
2709 `use-banding-rows-styles' |
2710 `use-banding-columns-styles' |
2711 `use-first-row-styles'
2712 ON-OR-OFF := `t' | `nil'
2714 For example, with the following configuration
2716 \(setq org-export-e-odt-table-styles
2717 '\(\(\"TableWithHeaderRowsAndColumns\" \"Custom\"
2718 \(\(use-first-row-styles . t\)
2719 \(use-first-column-styles . t\)\)\)
2720 \(\"TableWithHeaderColumns\" \"Custom\"
2721 \(\(use-first-column-styles . t\)\)\)\)\)
2723 1. A table associated with \"TableWithHeaderRowsAndColumns\"
2724 style will use the following table-cell styles -
2725 \"CustomFirstRowTableCell\", \"CustomFirstColumnTableCell\",
2726 \"CustomTableCell\" and the following paragraph styles
2727 \"CustomFirstRowTableParagraph\",
2728 \"CustomFirstColumnTableParagraph\", \"CustomTableParagraph\"
2729 as appropriate.
2731 2. A table associated with \"TableWithHeaderColumns\" style will
2732 use the following table-cell styles -
2733 \"CustomFirstColumnTableCell\", \"CustomTableCell\" and the
2734 following paragraph styles
2735 \"CustomFirstColumnTableParagraph\", \"CustomTableParagraph\"
2736 as appropriate..
2738 Note that TABLE-TEMPLATE-NAME corresponds to the
2739 \"<table:table-template>\" elements contained within
2740 \"<office:styles>\". The entries (TABLE-STYLE-NAME
2741 TABLE-TEMPLATE-NAME TABLE-CELL-OPTIONS) correspond to
2742 \"table:template-name\" and \"table:use-first-row-styles\" etc
2743 attributes of \"<table:table>\" element. Refer ODF-1.2
2744 specification for more information. Also consult the
2745 implementation filed under `org-e-odt-get-table-cell-styles'.
2747 The TABLE-STYLE-NAME \"OrgEquation\" is used internally for
2748 formatting of numbered display equations. Do not delete this
2749 style from the list."
2750 :group 'org-export-e-odt
2751 :version "24.1"
2752 :type '(choice
2753 (const :tag "None" nil)
2754 (repeat :tag "Table Styles"
2755 (list :tag "Table Style Specification"
2756 (string :tag "Table Style Name")
2757 (string :tag "Table Template Name")
2758 (alist :options (use-first-row-styles
2759 use-last-row-styles
2760 use-first-column-styles
2761 use-last-column-styles
2762 use-banding-rows-styles
2763 use-banding-columns-styles)
2764 :key-type symbol
2765 :value-type (const :tag "True" t))))))
2766 (defcustom org-export-e-odt-fontify-srcblocks t
2767 "Specify whether or not source blocks need to be fontified.
2768 Turn this option on if you want to colorize the source code
2769 blocks in the exported file. For colorization to work, you need
2770 to make available an enhanced version of `htmlfontify' library."
2771 :type 'boolean
2772 :group 'org-export-e-odt
2773 :version "24.1")
2775 (defcustom org-export-e-odt-prettify-xml t ; FIXME
2776 "Specify whether or not the xml output should be prettified.
2777 When this option is turned on, `indent-region' is run on all
2778 component xml buffers before they are saved. Turn this off for
2779 regular use. Turn this on if you need to examine the xml
2780 visually."
2781 :group 'org-export-e-odt
2782 :version "24.1"
2783 :type 'boolean)
2785 (defcustom org-export-e-odt-convert-processes
2786 '(("LibreOffice"
2787 "soffice --headless --convert-to %f%x --outdir %d %i")
2788 ("unoconv"
2789 "unoconv -f %f -o %d %i"))
2790 "Specify a list of document converters and their usage.
2791 The converters in this list are offered as choices while
2792 customizing `org-export-e-odt-convert-process'.
2794 This variable is a list where each element is of the
2795 form (CONVERTER-NAME CONVERTER-CMD). CONVERTER-NAME is the name
2796 of the converter. CONVERTER-CMD is the shell command for the
2797 converter and can contain format specifiers. These format
2798 specifiers are interpreted as below:
2800 %i input file name in full
2801 %I input file name as a URL
2802 %f format of the output file
2803 %o output file name in full
2804 %O output file name as a URL
2805 %d output dir in full
2806 %D output dir as a URL.
2807 %x extra options as set in `org-export-e-odt-convert-capabilities'."
2808 :group 'org-export-e-odt
2809 :version "24.1"
2810 :type
2811 '(choice
2812 (const :tag "None" nil)
2813 (alist :tag "Converters"
2814 :key-type (string :tag "Converter Name")
2815 :value-type (group (string :tag "Command line")))))
2817 (defcustom org-export-e-odt-convert-process "LibreOffice"
2818 "Use this converter to convert from \"odt\" format to other formats.
2819 During customization, the list of converter names are populated
2820 from `org-export-e-odt-convert-processes'."
2821 :group 'org-export-e-odt
2822 :version "24.1"
2823 :type '(choice :convert-widget
2824 (lambda (w)
2825 (apply 'widget-convert (widget-type w)
2826 (eval (car (widget-get w :args)))))
2827 `((const :tag "None" nil)
2828 ,@(mapcar (lambda (c)
2829 `(const :tag ,(car c) ,(car c)))
2830 org-export-e-odt-convert-processes))))
2832 (defcustom org-export-e-odt-convert-capabilities
2833 '(("Text"
2834 ("odt" "ott" "doc" "rtf" "docx")
2835 (("pdf" "pdf") ("odt" "odt") ("rtf" "rtf") ("ott" "ott")
2836 ("doc" "doc" ":\"MS Word 97\"") ("docx" "docx") ("html" "html")))
2837 ("Web"
2838 ("html")
2839 (("pdf" "pdf") ("odt" "odt") ("html" "html")))
2840 ("Spreadsheet"
2841 ("ods" "ots" "xls" "csv" "xlsx")
2842 (("pdf" "pdf") ("ots" "ots") ("html" "html") ("csv" "csv") ("ods" "ods")
2843 ("xls" "xls") ("xlsx" "xlsx")))
2844 ("Presentation"
2845 ("odp" "otp" "ppt" "pptx")
2846 (("pdf" "pdf") ("swf" "swf") ("odp" "odp") ("otp" "otp") ("ppt" "ppt")
2847 ("pptx" "pptx") ("odg" "odg"))))
2848 "Specify input and output formats of `org-export-e-odt-convert-process'.
2849 More correctly, specify the set of input and output formats that
2850 the user is actually interested in.
2852 This variable is an alist where each element is of the
2853 form (DOCUMENT-CLASS INPUT-FMT-LIST OUTPUT-FMT-ALIST).
2854 INPUT-FMT-LIST is a list of INPUT-FMTs. OUTPUT-FMT-ALIST is an
2855 alist where each element is of the form (OUTPUT-FMT
2856 OUTPUT-FILE-EXTENSION EXTRA-OPTIONS).
2858 The variable is interpreted as follows:
2859 `org-export-e-odt-convert-process' can take any document that is in
2860 INPUT-FMT-LIST and produce any document that is in the
2861 OUTPUT-FMT-LIST. A document converted to OUTPUT-FMT will have
2862 OUTPUT-FILE-EXTENSION as the file name extension. OUTPUT-FMT
2863 serves dual purposes:
2864 - It is used for populating completion candidates during
2865 `org-export-e-odt-convert' commands.
2866 - It is used as the value of \"%f\" specifier in
2867 `org-export-e-odt-convert-process'.
2869 EXTRA-OPTIONS is used as the value of \"%x\" specifier in
2870 `org-export-e-odt-convert-process'.
2872 DOCUMENT-CLASS is used to group a set of file formats in
2873 INPUT-FMT-LIST in to a single class.
2875 Note that this variable inherently captures how LibreOffice based
2876 converters work. LibreOffice maps documents of various formats
2877 to classes like Text, Web, Spreadsheet, Presentation etc and
2878 allow document of a given class (irrespective of it's source
2879 format) to be converted to any of the export formats associated
2880 with that class.
2882 See default setting of this variable for an typical
2883 configuration."
2884 :group 'org-export-e-odt
2885 :version "24.1"
2886 :type
2887 '(choice
2888 (const :tag "None" nil)
2889 (alist :tag "Capabilities"
2890 :key-type (string :tag "Document Class")
2891 :value-type
2892 (group (repeat :tag "Input formats" (string :tag "Input format"))
2893 (alist :tag "Output formats"
2894 :key-type (string :tag "Output format")
2895 :value-type
2896 (group (string :tag "Output file extension")
2897 (choice
2898 (const :tag "None" nil)
2899 (string :tag "Extra options"))))))))
2901 ;;;; Debugging
2904 ;;;; Document
2906 ;;;; Document Header (Styles)
2908 ;;;; Document Header (Scripts)
2910 ;;;; Document Header (Mathjax)
2912 ;;;; Preamble
2914 ;;;; Postamble
2916 ;;;; Emphasis
2918 ;;;; Todos
2920 ;;;; Tags
2922 ;;;; Time-stamps
2923 ;;;; Statistics Cookie
2924 ;;;; Subscript
2925 ;;;; Superscript
2927 ;;;; Inline images
2929 ;;;; Block
2930 ;;;; Comment
2931 ;;;; Comment Block
2932 ;;;; Drawer
2933 ;;;; Dynamic Block
2934 ;;;; Emphasis
2935 ;;;; Entity
2936 ;;;; Example Block
2937 ;;;; Export Snippet
2938 ;;;; Export Block
2939 ;;;; Fixed Width
2940 ;;;; Footnotes
2942 ;;;; Headline
2943 ;;;; Horizontal Rule
2944 ;;;; Inline Babel Call
2945 ;;;; Inline Src Block
2946 ;;;; Inlinetask
2947 ;;;; Item
2948 ;;;; Keyword
2949 ;;;; Latex Environment
2950 ;;;; Latex Fragment
2951 ;;;; Line Break
2952 ;;;; Link
2953 ;;;; Babel Call
2954 ;;;; Macro
2955 ;;;; Paragraph
2956 ;;;; Plain List
2957 ;;;; Plain Text
2958 ;;;; Property Drawer
2959 ;;;; Quote Block
2960 ;;;; Quote Section
2961 ;;;; Section
2962 ;;;; Radio Target
2963 ;;;; Special Block
2964 ;;;; Src Block
2966 ;;;; Table
2968 ;;;; Target
2969 ;;;; Time-stamp
2971 ;;;; Verbatim
2972 ;;;; Verse Block
2973 ;;;; Headline
2975 ;;;; Links
2976 ;;;; Drawers
2977 ;;;; Inlinetasks
2978 ;;;; Publishing
2980 ;;;; Compilation
2984 ;;; User Configurable Variables (MAYBE)
2986 ;;;; Preamble
2988 ;;;; Headline
2990 ;;;; Emphasis
2992 (defcustom org-e-odt-format-headline-function nil
2993 "Function to format headline text.
2995 This function will be called with 5 arguments:
2996 TODO the todo keyword \(string or nil\).
2997 TODO-TYPE the type of todo \(symbol: `todo', `done', nil\)
2998 PRIORITY the priority of the headline \(integer or nil\)
2999 TEXT the main headline text \(string\).
3000 TAGS the tags string, separated with colons \(string or nil\).
3002 The function result will be used in the section format string.
3004 As an example, one could set the variable to the following, in
3005 order to reproduce the default set-up:
3007 \(defun org-e-odt-format-headline \(todo todo-type priority text tags\)
3008 \"Default format function for an headline.\"
3009 \(concat \(when todo
3010 \(format \"\\\\textbf{\\\\textsc{\\\\textsf{%s}}} \" todo\)\)
3011 \(when priority
3012 \(format \"\\\\framebox{\\\\#%c} \" priority\)\)
3013 text
3014 \(when tags \(format \"\\\\hfill{}\\\\textsc{%s}\" tags\)\)\)\)"
3015 :group 'org-export-e-odt
3016 :type 'function)
3018 ;;;; Footnotes
3020 ;;;; Time-stamps
3022 (defcustom org-e-odt-active-timestamp-format "\\textit{%s}"
3023 "A printf format string to be applied to active time-stamps."
3024 :group 'org-export-e-odt
3025 :type 'string)
3027 (defcustom org-e-odt-inactive-timestamp-format "\\textit{%s}"
3028 "A printf format string to be applied to inactive time-stamps."
3029 :group 'org-export-e-odt
3030 :type 'string)
3032 (defcustom org-e-odt-diary-timestamp-format "\\textit{%s}"
3033 "A printf format string to be applied to diary time-stamps."
3034 :group 'org-export-e-odt
3035 :type 'string)
3038 ;;;; Links
3040 (defcustom org-e-odt-image-default-option "width=.9\\linewidth"
3041 "Default option for images."
3042 :group 'org-export-e-odt
3043 :type 'string)
3045 (defcustom org-e-odt-default-figure-position "htb"
3046 "Default position for latex figures."
3047 :group 'org-export-e-odt
3048 :type 'string)
3050 (defcustom org-e-odt-inline-image-rules
3051 '(("file" . "\\.\\(pdf\\|jpeg\\|jpg\\|png\\|ps\\|eps\\)\\'"))
3052 "Rules characterizing image files that can be inlined into HTML.
3054 A rule consists in an association whose key is the type of link
3055 to consider, and value is a regexp that will be matched against
3056 link's path.
3058 Note that, by default, the image extension *actually* allowed
3059 depend on the way the HTML file is processed. When used with
3060 pdflatex, pdf, jpg and png images are OK. When processing
3061 through dvi to Postscript, only ps and eps are allowed. The
3062 default we use here encompasses both."
3063 :group 'org-export-e-odt
3064 :type '(alist :key-type (string :tag "Type")
3065 :value-type (regexp :tag "Path")))
3067 ;;;; Tables
3069 (defcustom org-e-odt-table-caption-above t
3070 "When non-nil, place caption string at the beginning of the table.
3071 Otherwise, place it near the end."
3072 :group 'org-export-e-odt
3073 :type 'boolean)
3075 ;;;; Drawers
3077 (defcustom org-e-odt-format-drawer-function nil
3078 "Function called to format a drawer in HTML code.
3080 The function must accept two parameters:
3081 NAME the drawer name, like \"LOGBOOK\"
3082 CONTENTS the contents of the drawer.
3084 The function should return the string to be exported.
3086 For example, the variable could be set to the following function
3087 in order to mimic default behaviour:
3089 \(defun org-e-odt-format-drawer-default \(name contents\)
3090 \"Format a drawer element for HTML export.\"
3091 contents\)"
3092 :group 'org-export-e-odt
3093 :type 'function)
3096 ;;;; Inlinetasks
3098 (defcustom org-e-odt-format-inlinetask-function nil
3099 "Function called to format an inlinetask in HTML code.
3101 The function must accept six parameters:
3102 TODO the todo keyword, as a string
3103 TODO-TYPE the todo type, a symbol among `todo', `done' and nil.
3104 PRIORITY the inlinetask priority, as a string
3105 NAME the inlinetask name, as a string.
3106 TAGS the inlinetask tags, as a string.
3107 CONTENTS the contents of the inlinetask, as a string.
3109 The function should return the string to be exported.
3111 For example, the variable could be set to the following function
3112 in order to mimic default behaviour:
3114 \(defun org-e-odt-format-inlinetask \(todo type priority name tags contents\)
3115 \"Format an inline task element for HTML export.\"
3116 \(let \(\(full-title
3117 \(concat
3118 \(when todo
3119 \(format \"\\\\textbf{\\\\textsf{\\\\textsc{%s}}} \" todo\)\)
3120 \(when priority \(format \"\\\\framebox{\\\\#%c} \" priority\)\)
3121 title
3122 \(when tags \(format \"\\\\hfill{}\\\\textsc{%s}\" tags\)\)\)\)\)
3123 \(format \(concat \"\\\\begin{center}\\n\"
3124 \"\\\\fbox{\\n\"
3125 \"\\\\begin{minipage}[c]{.6\\\\textwidth}\\n\"
3126 \"%s\\n\\n\"
3127 \"\\\\rule[.8em]{\\\\textwidth}{2pt}\\n\\n\"
3128 \"%s\"
3129 \"\\\\end{minipage}}\"
3130 \"\\\\end{center}\"\)
3131 full-title contents\)\)"
3132 :group 'org-export-e-odt
3133 :type 'function)
3136 ;; Src blocks
3138 ;;;; Plain text
3140 (defcustom org-e-odt-quotes
3141 '(("fr" ("\\(\\s-\\|[[(]\\)\"" . "«~") ("\\(\\S-\\)\"" . "~»") ("\\(\\s-\\|(\\)'" . "'"))
3142 ("en" ("\\(\\s-\\|[[(]\\)\"" . "``") ("\\(\\S-\\)\"" . "''") ("\\(\\s-\\|(\\)'" . "`")))
3143 "Alist for quotes to use when converting english double-quotes.
3145 The CAR of each item in this alist is the language code.
3146 The CDR of each item in this alist is a list of three CONS:
3147 - the first CONS defines the opening quote;
3148 - the second CONS defines the closing quote;
3149 - the last CONS defines single quotes.
3151 For each item in a CONS, the first string is a regexp
3152 for allowed characters before/after the quote, the second
3153 string defines the replacement string for this quote."
3154 :group 'org-export-e-odt
3155 :type '(list
3156 (cons :tag "Opening quote"
3157 (string :tag "Regexp for char before")
3158 (string :tag "Replacement quote "))
3159 (cons :tag "Closing quote"
3160 (string :tag "Regexp for char after ")
3161 (string :tag "Replacement quote "))
3162 (cons :tag "Single quote"
3163 (string :tag "Regexp for char before")
3164 (string :tag "Replacement quote "))))
3167 ;;;; Compilation
3171 ;;; Internal Functions (HTML)
3173 ;; (defun org-e-odt-format-inline-image (path &optional caption label attr)
3174 ;; ;; FIXME: alt text missing here?
3175 ;; (let ((inline-image (format "<img src=\"%s\" alt=\"%s\"/>"
3176 ;; path (file-name-nondirectory path))))
3177 ;; (if (not label) inline-image
3178 ;; (org-e-odt-format-section inline-image "figure" label))))
3180 (defun org-e-odt-format-image (src)
3181 "Create image tag with source and attributes."
3182 (save-match-data
3183 (let* ((caption (org-find-text-property-in-string 'org-caption src))
3184 (attr (org-find-text-property-in-string 'org-attributes src))
3185 (label (org-find-text-property-in-string 'org-label src))
3186 (caption (and caption (org-xml-encode-org-text caption)))
3187 (img-extras (if (string-match "^ltxpng/" src)
3188 (format " alt=\"%s\""
3189 (org-find-text-property-in-string
3190 'org-latex-src src))
3191 (if (string-match "\\<alt=" (or attr ""))
3192 (concat " " attr )
3193 (concat " " attr " alt=\"" src "\""))))
3194 (img (format "<img src=\"%s\"%s />" src img-extras))
3195 (extra (concat
3196 (and label
3197 (format "id=\"%s\" " (org-solidify-link-text label)))
3198 "class=\"figure\"")))
3199 (if caption
3200 (with-temp-buffer
3201 (with-org-lparse-preserve-paragraph-state
3202 (insert
3203 (org-lparse-format
3204 '("<div %s>" . "\n</div>")
3205 (concat
3206 (org-lparse-format '("\n<p>" . "</p>") img)
3207 (org-lparse-format '("\n<p>" . "</p>") caption))
3208 extra)))
3209 (buffer-string))
3210 img))))
3212 ;;;; Bibliography
3214 (defun org-e-odt-bibliography ()
3215 "Find bibliography, cut it out and return it."
3216 (catch 'exit
3217 (let (beg end (cnt 1) bib)
3218 (save-excursion
3219 (goto-char (point-min))
3220 (when (re-search-forward
3221 "^[ \t]*<div \\(id\\|class\\)=\"bibliography\"" nil t)
3222 (setq beg (match-beginning 0))
3223 (while (re-search-forward "</?div\\>" nil t)
3224 (setq cnt (+ cnt (if (string= (match-string 0) "<div") +1 -1)))
3225 (when (= cnt 0)
3226 (and (looking-at ">") (forward-char 1))
3227 (setq bib (buffer-substring beg (point)))
3228 (delete-region beg (point))
3229 (throw 'exit bib))))
3230 nil))))
3232 ;;;; Table
3234 (defun org-e-odt-format-table (lines olines)
3235 (let ((org-e-odt-format-table-no-css nil))
3236 (org-lparse-format-table lines olines)))
3238 (defun org-e-odt-splice-attributes (tag attributes)
3239 "Read attributes in string ATTRIBUTES, add and replace in HTML tag TAG."
3240 (if (not attributes)
3242 (let (oldatt newatt)
3243 (setq oldatt (org-extract-attributes-from-string tag)
3244 tag (pop oldatt)
3245 newatt (cdr (org-extract-attributes-from-string attributes)))
3246 (while newatt
3247 (setq oldatt (plist-put oldatt (pop newatt) (pop newatt))))
3248 (if (string-match ">" tag)
3249 (setq tag
3250 (replace-match (concat (org-attributes-to-string oldatt) ">")
3251 t t tag)))
3252 tag)))
3254 (defun org-export-splice-style (style extra)
3255 "Splice EXTRA into STYLE, just before \"</style>\"."
3256 (if (and (stringp extra)
3257 (string-match "\\S-" extra)
3258 (string-match "</style>" style))
3259 (concat (substring style 0 (match-beginning 0))
3260 "\n" extra "\n"
3261 (substring style (match-beginning 0)))
3262 style))
3264 (defun org-export-e-odtize-region-for-paste (beg end)
3265 "Convert the region to HTML, using htmlize.el.
3266 This is much like `htmlize-region-for-paste', only that it uses
3267 the settings define in the org-... variables."
3268 (let* ((htmlize-output-type org-export-e-odtize-output-type)
3269 (htmlize-css-name-prefix org-export-e-odtize-css-font-prefix)
3270 (htmlbuf (htmlize-region beg end)))
3271 (unwind-protect
3272 (with-current-buffer htmlbuf
3273 (buffer-substring (plist-get htmlize-buffer-places 'content-start)
3274 (plist-get htmlize-buffer-places 'content-end)))
3275 (kill-buffer htmlbuf))))
3277 ;;;###autoload
3278 (defun org-export-e-odtize-generate-css ()
3279 "Create the CSS for all font definitions in the current Emacs session.
3280 Use this to create face definitions in your CSS style file that can then
3281 be used by code snippets transformed by htmlize.
3282 This command just produces a buffer that contains class definitions for all
3283 faces used in the current Emacs session. You can copy and paste the ones you
3284 need into your CSS file.
3286 If you then set `org-export-e-odtize-output-type' to `css', calls to
3287 the function `org-export-e-odtize-region-for-paste' will produce code
3288 that uses these same face definitions."
3289 (interactive)
3290 (require 'htmlize)
3291 (and (get-buffer "*html*") (kill-buffer "*html*"))
3292 (with-temp-buffer
3293 (let ((fl (face-list))
3294 (htmlize-css-name-prefix "org-")
3295 (htmlize-output-type 'css)
3296 f i)
3297 (while (setq f (pop fl)
3298 i (and f (face-attribute f :inherit)))
3299 (when (and (symbolp f) (or (not i) (not (listp i))))
3300 (insert (org-add-props (copy-sequence "1") nil 'face f))))
3301 (htmlize-region (point-min) (point-max))))
3302 (org-pop-to-buffer-same-window "*html*")
3303 (goto-char (point-min))
3304 (if (re-search-forward "<style" nil t)
3305 (delete-region (point-min) (match-beginning 0)))
3306 (if (re-search-forward "</style>" nil t)
3307 (delete-region (1+ (match-end 0)) (point-max)))
3308 (beginning-of-line 1)
3309 (if (looking-at " +") (replace-match ""))
3310 (goto-char (point-min)))
3312 ;; (defun org-e-odt-format-toc-entry (snumber todo headline tags href)
3313 ;; (setq headline (concat
3314 ;; ;; section number
3315 ;; (and org-export-with-section-numbers (concat snumber " "))
3316 ;; ;; headline
3317 ;; headline
3318 ;; ;; tags
3319 ;; (and tags (concat
3320 ;; (org-e-odt-format-spaces 3)
3321 ;; (org-e-odt-format-fontify tags "tag")))))
3322 ;; ;; fontify headline based on TODO keyword
3323 ;; (when todo (setq headline (org-e-odt-format-fontify headline "todo")))
3324 ;; (org-e-odt-format-link headline (concat "#" href)))
3326 (defun org-e-odt-toc-entry-formatter
3327 (level snumber todo todo-type priority
3328 headline tags target extra-targets extra-class)
3329 (org-e-odt-format-toc-entry snumber todo headline tags target))
3331 (defun org-e-odt-make-string (n string)
3332 (let (out) (dotimes (i n out) (setq out (concat string out)))))
3334 (defun org-e-odt-toc-text (toc-entries)
3335 (let* ((prev-level (1- (nth 1 (car toc-entries))))
3336 (start-level prev-level))
3337 (mapconcat
3338 (lambda (entry)
3339 (let ((headline (nth 0 entry))
3340 (level (nth 1 entry)))
3341 (prog1 (org-e-odt-format-toc-item headline level prev-level)
3342 (setq prev-level level))))
3343 toc-entries "")))
3345 (defun org-e-odt-toc (depth info)
3346 (assert (wholenump depth))
3347 (let* ((headlines (org-export-collect-headlines info depth))
3348 (toc-entries
3349 (loop for headline in headlines collect
3350 (list (org-e-odt-headline-text
3351 headline info 'org-e-odt-toc-entry-formatter)
3352 (org-export-get-relative-level headline info)))))
3353 (when toc-entries
3354 (let* ((lang-specific-heading "Table of Contents")) ; FIXME
3355 (concat
3356 (org-e-odt-begin-toc lang-specific-heading depth)
3357 (org-e-odt-toc-text toc-entries)
3358 (org-e-odt-end-toc))))))
3360 (defun org-e-odt-begin-outline (level1 snumber title tags
3361 target extra-targets extra-class)
3362 (let* ((class (format "outline-%d" level1))
3363 (class (if extra-class (concat class " " extra-class) class))
3364 (id (format "outline-container-%s"
3365 (org-lparse-suffix-from-snumber snumber)))
3366 (extra (concat (when id (format " id=\"%s\"" id))
3367 (when class (format " class=\"%s\"" class)))))
3368 (org-lparse-insert-tag "<div%s>" extra)
3369 (insert
3370 (org-lparse-format 'HEADING
3371 (org-lparse-format
3372 'HEADLINE title extra-targets tags snumber level1)
3373 level1 target))))
3375 (defun org-e-odt-end-outline ()
3376 (org-lparse-insert-tag "</div>"))
3379 ;; (defun org-e-odt-format-heading (text level &optional id)
3380 ;; (let* ((extra (concat (when id (format " id=\"%s\"" id)))))
3381 ;; (concat (format "<h%d%s>" level extra) text (format "</h%d>" level))))
3383 (defun org-e-odt-suffix-from-snumber (snumber)
3384 (let* ((snu (replace-regexp-in-string "\\." "-" snumber))
3385 (href (cdr (assoc (concat "sec-" snu)
3386 org-export-preferred-target-alist))))
3387 (org-solidify-link-text (or href snu))))
3389 (defun org-e-odt-format-outline (contents level1 snumber title
3390 tags target extra-targets extra-class)
3391 (concat
3392 (org-e-odt-format-heading
3393 (org-e-odt-format-headline title extra-targets tags snumber level1)
3394 level1 target)
3395 contents))
3397 ;; (defun org-e-odt-begin-outline-text (level1 snumber extra-class)
3398 ;; (let* ((class (format "outline-text-%d" level1))
3399 ;; (class (if extra-class (concat class " " extra-class) class))
3400 ;; (id (format "text-%s" (org-lparse-suffix-from-snumber snumber)))
3401 ;; (extra (concat (when id (format " id=\"%s\"" id))
3402 ;; (when class (format " class=\"%s\"" class)))))
3403 ;; (org-lparse-insert-tag "<div%s>" extra)))
3405 ;; (defun org-e-odt-end-outline-text ()
3406 ;; (org-lparse-insert-tag "</div>"))
3408 ;; (defun org-e-odt-format-spaces (n)
3409 ;; (let (out) (dotimes (i n out) (setq out (concat out "&nbsp;")))))
3411 (defun org-e-odt-format-tabs (&optional n)
3412 (ignore))
3414 ;; (defun org-e-odt-format-line (line)
3415 ;; (case org-lparse-dyn-current-environment
3416 ;; ((quote fixedwidth) (concat (org-e-odt-encode-plain-text line) "\n"))
3417 ;; (t (concat line "\n"))))
3419 (defun org-e-odt-format-comment (fmt &rest args)
3420 (let ((comment (apply 'format fmt args)))
3421 (format "\n<!-- %s -->\n" comment)))
3423 (defun org-e-odt-fix-class-name (kwd) ; audit callers of this function
3424 "Turn todo keyword into a valid class name.
3425 Replaces invalid characters with \"_\"."
3426 (save-match-data
3427 (while (string-match "[^a-zA-Z0-9_]" kwd)
3428 (setq kwd (replace-match "_" t t kwd))))
3429 kwd)
3431 ;; (defun org-e-odt-format-fontify (text style &optional id)
3432 ;; (let (class extra how)
3433 ;; (cond
3434 ;; ((eq style 'underline)
3435 ;; (setq extra " style=\"text-decoration:underline;\"" ))
3436 ;; ((setq how (cdr (assoc style
3437 ;; '((bold . ("<b>" . "</b>"))
3438 ;; (emphasis . ("<i>" . "</i>"))
3439 ;; (code . ("<code>" . "</code>"))
3440 ;; (verbatim . ("<code>" . "</code>"))
3441 ;; (strike . ("<del>" . "</del>"))
3442 ;; (subscript . ("<sub>" . "</sub>"))
3443 ;; (superscript . ("<sup>" . "</sup>")))))))
3444 ;; ((listp style)
3445 ;; (setq class (mapconcat 'identity style " ")))
3446 ;; ((stringp style)
3447 ;; (setq class style))
3448 ;; (t (error "Unknown style %S" style)))
3450 ;; (setq extra (concat (when class (format " class=\"%s\"" class))
3451 ;; (when id (format " id=\"%s\"" id))
3452 ;; extra))
3454 ;; (let ((tags (or how '("<span%s>" . "</span>"))))
3455 ;; (concat (format (car tags) extra) text (cdr tags)))))
3457 ;; (defun org-e-odt-format-link (text href &optional extra)
3458 ;; (let ((extra (concat (format " href=\"%s\"" href)
3459 ;; (and extra (concat " " extra)))))
3460 ;; (format "<a%s>%s</a>" extra text)))
3462 (defun org-e-odt-format-internal-link (text href &optional extra)
3463 (org-e-odt-format-link text (concat "#" href) extra))
3465 ;; (defun org-e-odt-format-heading (text level &optional id)
3466 ;; (let* ((extra (concat (when id (format " id=\"%s\"" id)))))
3467 ;; (concat (format "<h%d%s>" level extra) text (format "</h%d>\n" level))))
3469 ;; (defun org-e-odt-format-anchor (text name &optional class)
3470 ;; (let* ((id name)
3471 ;; (extra (concat
3472 ;; (when name (format " name=\"%s\"" name))
3473 ;; (when id (format " id=\"%s\"" id))
3474 ;; (when class (format " class=\"%s\"" class)))))
3475 ;; (format "<a%s>%s</a>" extra text)))
3477 (defun org-e-odt-format-extra-targets (extra-targets)
3478 (if (not extra-targets) ""
3479 (mapconcat (lambda (x)
3480 (when x
3481 (setq x (org-solidify-link-text
3482 (if (org-uuidgen-p x) (concat "ID-" x) x)))
3483 (org-e-odt-format-anchor "" x))) extra-targets "")))
3485 (defun org-e-odt-format-org-tags (tags)
3486 (if (not tags) ""
3487 (org-e-odt-format-fontify
3488 (mapconcat
3489 (lambda (x)
3490 (org-e-odt-format-fontify
3491 x (concat "" ;; org-e-odt-tag-class-prefix
3492 (org-e-odt-fix-class-name x))))
3493 (org-split-string tags ":")
3494 (org-e-odt-format-spaces 1)) "tag")))
3496 (defun org-e-odt-format-section-number (&optional snumber level)
3497 ;; FIXME
3498 (and nil org-export-with-section-numbers
3499 ;; (not org-lparse-body-only)
3500 snumber level
3501 (org-e-odt-format-fontify snumber (format "section-number-%d" level))))
3503 ;; (defun org-e-odt-format-headline (title extra-targets tags
3504 ;; &optional snumber level)
3505 ;; (concat
3506 ;; (org-e-odt-format-extra-targets extra-targets)
3507 ;; (concat (org-e-odt-format-section-number snumber level) " ")
3508 ;; title
3509 ;; (and tags (concat (org-e-odt-format-spaces 3)
3510 ;; (org-e-odt-format-org-tags tags)))))
3512 ;; (defun org-e-odt-format-footnote-reference (n def refcnt)
3513 ;; (let ((extra (if (= refcnt 1) "" (format ".%d" refcnt))))
3514 ;; (format org-e-odt-footnote-format
3515 ;; (format
3516 ;; "<a class=\"footref\" name=\"fnr.%s%s\" href=\"#fn.%s\">%s</a>"
3517 ;; n extra n n))))
3519 (defun org-e-odt-format-footnotes-section (section-name definitions)
3520 (if (not definitions) ""
3521 (format org-e-odt-footnotes-section section-name definitions)))
3523 ;; (defun org-e-odt-format-footnote-definition (fn)
3524 ;; (let ((n (car fn)) (def (cdr fn)))
3525 ;; (format
3526 ;; "<tr>\n<td>%s</td>\n<td>%s</td>\n</tr>\n"
3527 ;; (format
3528 ;; (format org-e-odt-footnote-format
3529 ;; "<a class=\"footnum\" name=\"fn.%s\" href=\"#fnr.%s\">%s</a>")
3530 ;; n n n) def)))
3532 (defun org-e-odt-get-coding-system-for-write ()
3533 (or org-e-odt-coding-system
3534 (and (boundp 'buffer-file-coding-system) buffer-file-coding-system)))
3536 (defun org-e-odt-get-coding-system-for-save ()
3537 (or org-e-odt-coding-system
3538 (and (boundp 'buffer-file-coding-system) buffer-file-coding-system)))
3540 ;; (defun org-e-odt-format-date (info)
3541 ;; (let ((date (plist-get info :date)))
3542 ;; (cond
3543 ;; ((and date (string-match "%" date))
3544 ;; (format-time-string date))
3545 ;; (date date)
3546 ;; (t (format-time-string "%Y-%m-%d %T %Z")))))
3550 ;;; Internal Functions (Ngz)
3552 (defun org-e-odt--caption/label-string (caption label info)
3553 "Return caption and label HTML string for floats.
3555 CAPTION is a cons cell of secondary strings, the car being the
3556 standard caption and the cdr its short form. LABEL is a string
3557 representing the label. INFO is a plist holding contextual
3558 information.
3560 If there's no caption nor label, return the empty string.
3562 For non-floats, see `org-e-odt--wrap-label'."
3563 (setq label nil) ;; FIXME
3565 (let ((label-str (if label (format "\\label{%s}" label) "")))
3566 (cond
3567 ((and (not caption) (not label)) "")
3568 ((not caption) (format "\\label{%s}\n" label))
3569 ;; Option caption format with short name.
3570 ((cdr caption)
3571 (format "\\caption[%s]{%s%s}\n"
3572 (org-export-secondary-string (cdr caption) 'e-odt info)
3573 label-str
3574 (org-export-secondary-string (car caption) 'e-odt info)))
3575 ;; Standard caption format.
3576 ;; (t (format "\\caption{%s%s}\n"
3577 ;; label-str
3578 ;; (org-export-secondary-string (car caption) 'e-odt info)))
3580 (t (org-export-secondary-string (car caption) 'e-odt info)))))
3582 (defun org-e-odt--find-verb-separator (s)
3583 "Return a character not used in string S.
3584 This is used to choose a separator for constructs like \\verb."
3585 (let ((ll "~,./?;':\"|!@#%^&-_=+abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ<>()[]{}"))
3586 (loop for c across ll
3587 when (not (string-match (regexp-quote (char-to-string c)) s))
3588 return (char-to-string c))))
3590 (defun org-e-odt--make-option-string (options)
3591 "Return a comma separated string of keywords and values.
3592 OPTIONS is an alist where the key is the options keyword as
3593 a string, and the value a list containing the keyword value, or
3594 nil."
3595 (mapconcat (lambda (pair)
3596 (concat (first pair)
3597 (when (> (length (second pair)) 0)
3598 (concat "=" (second pair)))))
3599 options
3600 ","))
3602 (defun org-e-odt--quotation-marks (text info)
3603 "Export quotation marks depending on language conventions.
3604 TEXT is a string containing quotation marks to be replaced. INFO
3605 is a plist used as a communication channel."
3606 (mapc (lambda(l)
3607 (let ((start 0))
3608 (while (setq start (string-match (car l) text start))
3609 (let ((new-quote (concat (match-string 1 text) (cdr l))))
3610 (setq text (replace-match new-quote t t text))))))
3611 (cdr (or (assoc (plist-get info :language) org-e-odt-quotes)
3612 ;; Falls back on English.
3613 (assoc "en" org-e-odt-quotes))))
3614 text)
3616 (defun org-e-odt--wrap-label (element output)
3617 "Wrap label associated to ELEMENT around OUTPUT, if appropriate.
3618 This function shouldn't be used for floats. See
3619 `org-e-odt--caption/label-string'."
3620 ;; (let ((label (org-element-property :name element)))
3621 ;; (if (or (not output) (not label) (string= output "") (string= label ""))
3622 ;; output
3623 ;; (concat (format "\\label{%s}\n" label) output)))
3624 output)
3628 ;;; Template
3630 (defun org-e-odt-template (contents info)
3631 "Return complete document string after HTML conversion.
3632 CONTENTS is the transcoded contents string. RAW-DATA is the
3633 original parsed data. INFO is a plist holding export options."
3636 ;; write meta file
3637 (org-e-odt-update-meta-file info)
3640 (with-temp-buffer
3641 (insert-file-contents
3642 (or org-export-e-odt-content-template-file
3643 (expand-file-name "OrgOdtContentTemplate.xml"
3644 org-e-odt-styles-dir)))
3645 (goto-char (point-min))
3646 (re-search-forward "</office:text>" nil nil)
3647 (goto-char (match-beginning 0))
3649 ;; Title
3650 (insert (org-e-odt-format-preamble info))
3651 ;; Table of Contents
3652 (let ((depth (plist-get info :with-toc)))
3653 (when (wholenump depth) (org-e-odt-toc depth info)))
3655 ;; Contents
3656 (insert contents)
3657 (buffer-substring-no-properties (point-min) (point-max))))
3661 ;;; Transcode Functions
3663 ;;;; Block
3665 (defun org-e-odt-center-block (center-block contents info)
3666 "Transcode a CENTER-BLOCK element from Org to HTML.
3667 CONTENTS holds the contents of the block. INFO is a plist
3668 holding contextual information."
3669 (org-e-odt--wrap-label
3670 center-block
3671 (format "<div style=\"text-align: center\">\n%s</div>" contents)))
3674 ;;;; Comment
3676 ;; Comments are ignored.
3679 ;;;; Comment Block
3681 ;; Comment Blocks are ignored.
3684 ;;;; Drawer
3686 (defun org-e-odt-drawer (drawer contents info)
3687 "Transcode a DRAWER element from Org to HTML.
3688 CONTENTS holds the contents of the block. INFO is a plist
3689 holding contextual information."
3690 (let* ((name (org-element-property :drawer-name drawer))
3691 (output (if (functionp org-e-odt-format-drawer-function)
3692 (funcall org-e-odt-format-drawer-function
3693 name contents)
3694 ;; If there's no user defined function: simply
3695 ;; display contents of the drawer.
3696 contents)))
3697 (org-e-odt--wrap-label drawer output)))
3700 ;;;; Dynamic Block
3702 (defun org-e-odt-dynamic-block (dynamic-block contents info)
3703 "Transcode a DYNAMIC-BLOCK element from Org to HTML.
3704 CONTENTS holds the contents of the block. INFO is a plist
3705 holding contextual information. See
3706 `org-export-data'."
3707 (org-e-odt--wrap-label dynamic-block contents))
3710 ;;;; Emphasis
3712 (defun org-e-odt-emphasis (emphasis contents info)
3713 "Transcode EMPHASIS from Org to HTML.
3714 CONTENTS is the contents of the emphasized text. INFO is a plist
3715 holding contextual information.."
3716 ;; (format (cdr (assoc (org-element-property :marker emphasis)
3717 ;; org-e-odt-emphasis-alist))
3718 ;; contents)
3719 (org-e-odt-format-fontify
3720 contents (cadr (assoc
3721 (org-element-property :marker emphasis)
3722 '(("*" bold)
3723 ("/" emphasis)
3724 ("_" underline)
3725 ("=" code)
3726 ("~" verbatim)
3727 ("+" strike))))))
3730 ;;;; Entity
3732 (defun org-e-odt-entity (entity contents info)
3733 "Transcode an ENTITY object from Org to HTML.
3734 CONTENTS are the definition itself. INFO is a plist holding
3735 contextual information."
3736 ;; (let ((ent (org-element-property :latex entity)))
3737 ;; (if (org-element-property :latex-math-p entity)
3738 ;; (format "$%s$" ent)
3739 ;; ent))
3740 (org-element-property :utf-8 entity))
3743 ;;;; Example Block
3746 ;; (defun org-odt-format-source-code-or-example-colored
3747 ;; (lines lang caption textareap cols rows num cont rpllbl fmt))
3749 ;; (defun org-e-odt-format-source-code-or-example-plain
3750 ;; (lines lang caption textareap cols rows num cont rpllbl fmt)
3751 ;; (setq lines
3752 ;; (concat
3753 ;; "<pre class=\"example\">\n"
3754 ;; (cond
3755 ;; (textareap
3756 ;; (concat
3757 ;; (format "<p>\n<textarea cols=\"%d\" rows=\"%d\">"
3758 ;; cols rows)
3759 ;; lines "</textarea>\n</p>\n"))
3760 ;; (t
3761 ;; (with-temp-buffer
3762 ;; (insert lines)
3763 ;; (goto-char (point-min))
3764 ;; (while (re-search-forward "[<>&]" nil t)
3765 ;; (replace-match (cdr (assq (char-before)
3766 ;; '((?&."&amp;")(?<."&lt;")(?>."&gt;"))))
3767 ;; t t))
3768 ;; (buffer-string))))
3769 ;; "</pre>\n"))
3771 ;; (unless textareap
3772 ;; (setq lines (org-export-number-lines lines 1 1 num cont rpllbl fmt)))
3774 ;; ;; (when (string-match "\\(\\`<[^>]*>\\)\n" lines)
3775 ;; ;; (setq lines (replace-match "\\1" t nil lines)))
3777 ;; lines)
3779 ;; (defun org-e-odt-format-source-code-or-example-colored
3780 ;; (lines lang caption textareap cols rows num cont rpllbl fmt)
3781 ;; (let* ((lang-m (when lang
3782 ;; (or (cdr (assoc lang org-src-lang-modes))
3783 ;; lang)))
3784 ;; (mode (and lang-m (intern
3785 ;; (concat
3786 ;; (if (symbolp lang-m)
3787 ;; (symbol-name lang-m)
3788 ;; lang-m)
3789 ;; "-mode"))))
3790 ;; (org-inhibit-startup t)
3791 ;; (org-startup-folded nil))
3792 ;; (setq lines
3793 ;; (with-temp-buffer
3794 ;; (insert lines)
3795 ;; (if (functionp mode)
3796 ;; (funcall mode)
3797 ;; (fundamental-mode))
3798 ;; (font-lock-fontify-buffer)
3799 ;; ;; markup each line separately
3800 ;; (org-remove-formatting-on-newlines-in-region
3801 ;; (point-min) (point-max))
3802 ;; (org-src-mode)
3803 ;; (set-buffer-modified-p nil)
3804 ;; (org-export-e-odtize-region-for-paste
3805 ;; (point-min) (point-max))))
3807 ;; (when (string-match "<pre\\([^>]*\\)>\n*" lines)
3808 ;; (setq lines (replace-match
3809 ;; (format "<pre class=\"src src-%s\">\n" lang) t t lines)))
3811 ;; (when caption
3812 ;; (setq lines
3813 ;; (concat
3814 ;; "<div class=\"org-src-container\">"
3815 ;; (format "<label class=\"org-src-name\">%s</label>" caption)
3816 ;; lines "</div>")))
3818 ;; (unless textareap
3819 ;; (setq lines (org-export-number-lines lines 1 1 num cont rpllbl fmt)))
3821 ;; ;; (when (string-match "\\(\\`<[^>]*>\\)\n" lines)
3822 ;; ;; (setq lines (replace-match "\\1" t nil lines)))
3823 ;; lines))
3825 ;; (defun org-e-odt-format-source-code-or-example
3826 ;; (lang code &optional opts indent caption)
3827 ;; "Format CODE from language LANG and return it formatted for export.
3828 ;; The CODE is marked up in `org-export-current-backend' format.
3830 ;; Check if a function by name
3831 ;; \"org-<backend>-format-source-code-or-example\" is bound. If yes,
3832 ;; use it as the custom formatter. Otherwise, use the default
3833 ;; formatter. Default formatters are provided for docbook, html,
3834 ;; latex and ascii backends. For example, use
3835 ;; `org-e-odt-format-source-code-or-example' to provide a custom
3836 ;; formatter for export to \"html\".
3838 ;; If LANG is nil, do not add any fontification.
3839 ;; OPTS contains formatting options, like `-n' for triggering numbering lines,
3840 ;; and `+n' for continuing previous numbering.
3841 ;; Code formatting according to language currently only works for HTML.
3842 ;; Numbering lines works for all three major backends (html, latex, and ascii).
3843 ;; INDENT was the original indentation of the block."
3844 ;; (save-match-data
3845 ;; (let* ((backend-formatter 'org-e-odt-format-source-code-or-example-plain)
3846 ;; num cont rtn rpllbl keepp textareap preserve-indentp cols rows fmt)
3847 ;; (setq opts (or opts "")
3848 ;; num (string-match "[-+]n\\>" opts)
3849 ;; cont (string-match "\\+n\\>" opts)
3850 ;; rpllbl (string-match "-r\\>" opts)
3851 ;; keepp (string-match "-k\\>" opts)
3852 ;; textareap (string-match "-t\\>" opts)
3853 ;; preserve-indentp (or org-src-preserve-indentation
3854 ;; (string-match "-i\\>" opts))
3855 ;; cols (if (string-match "-w[ \t]+\\([0-9]+\\)" opts)
3856 ;; (string-to-number (match-string 1 opts))
3857 ;; 80)
3858 ;; rows (if (string-match "-h[ \t]+\\([0-9]+\\)" opts)
3859 ;; (string-to-number (match-string 1 opts))
3860 ;; (org-count-lines code))
3861 ;; fmt (if (string-match "-l[ \t]+\"\\([^\"\n]+\\)\"" opts)
3862 ;; (match-string 1 opts)))
3863 ;; (when (and textareap
3864 ;; ;; (eq org-export-current-backend 'html)
3865 ;; )
3866 ;; ;; we cannot use numbering or highlighting.
3867 ;; (setq num nil cont nil lang nil))
3868 ;; (if keepp (setq rpllbl 'keep))
3869 ;; (setq rtn (if preserve-indentp code (org-remove-indentation code)))
3870 ;; (when (string-match "^," rtn)
3871 ;; (setq rtn (with-temp-buffer
3872 ;; (insert rtn)
3873 ;; ;; Free up the protected lines
3874 ;; (goto-char (point-min))
3875 ;; (while (re-search-forward "^," nil t)
3876 ;; (if (or (equal lang "org")
3877 ;; (save-match-data
3878 ;; (looking-at "\\([*#]\\|[ \t]*#\\+\\)")))
3879 ;; (replace-match ""))
3880 ;; (end-of-line 1))
3881 ;; (buffer-string))))
3882 ;; (when lang
3883 ;; (if (featurep 'xemacs)
3884 ;; (require 'htmlize)
3885 ;; (require 'htmlize nil t)))
3887 ;; (setq backend-formatter
3888 ;; (cond
3889 ;; ((fboundp 'htmlize-region-for-paste)
3890 ;; 'org-e-odt-format-source-code-or-example-colored)
3891 ;; (t
3892 ;; (message
3893 ;; "htmlize.el 1.34 or later is needed for source code formatting")
3894 ;; 'org-e-odt-format-source-code-or-example-plain)))
3895 ;; (funcall backend-formatter rtn lang caption textareap cols rows
3896 ;; num cont rpllbl fmt))))
3898 (defun org-e-odt-example-block (example-block contents info)
3899 "Transcode a EXAMPLE-BLOCK element from Org to HTML.
3900 CONTENTS is nil. INFO is a plist holding contextual information."
3901 (let* ((options (or (org-element-property :options example-block) ""))
3902 (value (org-export-handle-code example-block info)))
3903 ;; (org-e-odt--wrap-label
3904 ;; example-block (format "\\begin{verbatim}\n%s\\end{verbatim}" value))
3905 (org-e-odt--wrap-label
3906 example-block (org-e-odt-format-source-code-or-example value nil))))
3909 ;;;; Export Snippet
3911 (defun org-e-odt-export-snippet (export-snippet contents info)
3912 "Transcode a EXPORT-SNIPPET object from Org to HTML.
3913 CONTENTS is nil. INFO is a plist holding contextual information."
3914 (org-element-property :value export-snippet))
3917 ;;;; Export Block
3919 (defun org-e-odt-export-block (export-block contents info)
3920 "Transcode a EXPORT-BLOCK element from Org to HTML.
3921 CONTENTS is nil. INFO is a plist holding contextual information."
3922 (when (string= (org-element-property :type export-block) "latex")
3923 (org-remove-indentation (org-element-property :value export-block))))
3926 ;;;; Fixed Width
3928 (defun org-e-odt-fixed-width (fixed-width contents info)
3929 "Transcode a FIXED-WIDTH element from Org to HTML.
3930 CONTENTS is nil. INFO is a plist holding contextual information."
3931 (let* ((value (org-element-normalize-string
3932 (replace-regexp-in-string
3933 "^[ \t]*: ?" ""
3934 (org-element-property :value fixed-width)))))
3935 (org-e-odt--wrap-label
3936 fixed-width (org-e-odt-format-source-code-or-example value nil))))
3939 ;;;; Footnote Definition
3941 ;; Footnote Definitions are ignored.
3944 ;;;; Footnote Reference
3946 (defun org-e-odt-footnote-def (raw info) ; FIXME
3947 (if (equal (org-element-type raw) 'org-data)
3948 (org-trim (org-export-data raw 'e-odt info))
3949 (org-odt-format-stylized-paragraph
3950 'footnote (org-trim (org-export-secondary-string raw 'e-odt info)))))
3952 (defvar org-e-odt-footnote-separator
3953 (org-e-odt-format-fontify "," 'superscript))
3955 (defun org-e-odt-footnote-reference (footnote-reference contents info)
3956 "Transcode a FOOTNOTE-REFERENCE element from Org to HTML.
3957 CONTENTS is nil. INFO is a plist holding contextual information."
3958 (concat
3959 ;; Insert separator between two footnotes in a row.
3960 (let ((prev (org-export-get-previous-element footnote-reference info)))
3961 (when (and (listp prev) (eq (car prev) 'footnote-reference))
3962 org-e-odt-footnote-separator))
3963 (cond
3964 ((not (org-export-footnote-first-reference-p footnote-reference info))
3965 (let* ((n (org-export-get-footnote-number footnote-reference info)))
3966 (org-e-odt-format-footnote-reference n "IGNORED" 100)))
3967 ;; Inline definitions are secondary strings.
3968 ((eq (org-element-property :type footnote-reference) 'inline)
3969 (let* ((raw (org-export-get-footnote-definition footnote-reference info))
3970 (n (org-export-get-footnote-number footnote-reference info))
3971 (def (org-e-odt-footnote-def raw info)))
3972 (org-e-odt-format-footnote-reference n def 1)))
3973 ;; Non-inline footnotes definitions are full Org data.
3975 (let* ((raw (org-export-get-footnote-definition footnote-reference info))
3976 (n (org-export-get-footnote-number footnote-reference info))
3977 (def (org-e-odt-footnote-def raw info)))
3978 (org-e-odt-format-footnote-reference n def 1))))))
3981 ;;;; Headline
3983 (defun org-e-odt-todo (todo)
3984 (when todo
3985 (org-e-odt-format-fontify
3986 (concat
3987 "" ; org-e-odt-todo-kwd-class-prefix
3988 (org-e-odt-fix-class-name todo))
3989 (list (if (member todo org-done-keywords) "done" "todo")
3990 todo))))
3992 (defun org-e-odt-headline-text (headline info &optional formatter)
3993 "Transcode an HEADLINE element from Org to HTML.
3994 CONTENTS holds the contents of the headline. INFO is a plist
3995 holding contextual information."
3996 (let* ((numberedp (plist-get info :section-numbers))
3997 (level (org-export-get-relative-level headline info))
3998 (todo (and (plist-get info :with-todo-keywords)
3999 (let ((todo (org-element-property
4000 :todo-keyword headline)))
4001 (and todo
4002 (org-export-secondary-string todo 'e-odt info)))))
4003 (todo-type (and todo (org-element-property :todo-type headline)))
4004 (priority (and (plist-get info :with-priority)
4005 (org-element-property :priority headline)))
4006 (text (org-export-secondary-string
4007 (org-element-property :title headline) 'e-odt info))
4008 (tags (and (plist-get info :with-tags)
4009 (org-element-property :tags headline)))
4011 (headline-no (org-export-get-headline-number headline info))
4012 (headline-label
4013 (format "sec-%s" (mapconcat 'number-to-string headline-no "-")))
4014 (headline-labels (list headline-label))
4015 (headline-no (org-export-get-headline-number headline info))
4016 (section-no (mapconcat 'number-to-string headline-no "."))
4017 (primary-target (car (last headline-labels)))
4018 (secondary-targets (butlast headline-labels))
4019 (extra-class nil)
4020 (formatter (or (and (functionp formatter) formatter)
4021 org-e-odt-headline-formatter)))
4022 (funcall formatter level section-no todo todo-type priority
4023 text tags primary-target secondary-targets extra-class)))
4025 (defun org-e-odt-headline (headline contents info)
4026 "Transcode an HEADLINE element from Org to HTML.
4027 CONTENTS holds the contents of the headline. INFO is a plist
4028 holding contextual information."
4029 (let* ((class (plist-get info :latex-class))
4030 (numberedp (plist-get info :section-numbers))
4031 ;; Get level relative to current parsed data.
4032 (level (org-export-get-relative-level headline info))
4033 ;; (class-sectionning (assoc class org-e-odt-classes))
4034 ;; Section formatting will set two placeholders: one for the
4035 ;; title and the other for the contents.
4036 ;; (section-fmt
4037 ;; (let ((sec (if (and (symbolp (nth 2 class-sectionning))
4038 ;; (fboundp (nth 2 class-sectionning)))
4039 ;; (funcall (nth 2 class-sectionning) level numberedp)
4040 ;; (nth (1+ level) class-sectionning))))
4041 ;; (cond
4042 ;; ;; No section available for that LEVEL.
4043 ;; ((not sec) nil)
4044 ;; ;; Section format directly returned by a function.
4045 ;; ((stringp sec) sec)
4046 ;; ;; (numbered-section . unnumbered-section)
4047 ;; ((not (consp (cdr sec)))
4048 ;; (concat (funcall (if numberedp #'car #'cdr) sec) "\n%s"))
4049 ;; ;; (numbered-open numbered-close)
4050 ;; ((= (length sec) 2)
4051 ;; (when numberedp (concat (car sec) "\n%s" (nth 1 sec))))
4052 ;; ;; (num-in num-out no-num-in no-num-out)
4053 ;; ((= (length sec) 4)
4054 ;; (if numberedp
4055 ;; (concat (car sec) "\n%s" (nth 1 sec))
4056 ;; (concat (nth 2 sec) "\n%s" (nth 3 sec)))))))
4057 (text (org-export-secondary-string
4058 (org-element-property :title headline) 'e-odt info))
4059 (todo (and (plist-get info :with-todo-keywords)
4060 (let ((todo (org-element-property
4061 :todo-keyword headline)))
4062 (and todo
4063 (org-export-secondary-string todo 'e-odt info)))))
4064 (todo-type (and todo (org-element-property :todo-type headline)))
4065 (tags (and (plist-get info :with-tags)
4066 (org-element-property :tags headline)))
4067 (priority (and (plist-get info :with-priority)
4068 (org-element-property :priority headline)))
4069 ;; Create the headline text.
4070 (full-text (if (functionp org-e-odt-format-headline-function)
4071 ;; User-defined formatting function.
4072 (funcall org-e-odt-format-headline-function
4073 todo todo-type priority text tags)
4074 ;; Default formatting.
4075 (concat
4076 ;; (when todo
4077 ;; (format "\\textbf{\\textsf{\\textsc{%s}}} " todo))
4078 (org-e-odt-todo todo) " "
4079 (when priority (format "\\framebox{\\#%c} " priority))
4080 text
4081 ;; (when tags (format "\\hfill{}\\textsc{%s}" tags))
4083 ;; Associate some \label to the headline for internal links.
4084 ;; (headline-label
4085 ;; (format "\\label{sec-%s}\n"
4086 ;; (mapconcat 'number-to-string
4087 ;; (org-export-get-headline-number headline info)
4088 ;; "-")))
4090 ;; FIXME - begin
4091 (headline-no (org-export-get-headline-number headline info))
4092 (headline-label
4093 (format "sec-%s" (mapconcat 'number-to-string headline-no "-")))
4094 (headline-labels (list headline-label))
4095 (headline-no (org-export-get-headline-number headline info))
4096 (section-no (mapconcat 'number-to-string headline-no "."))
4097 ;; FIXME - end
4099 (pre-blanks (make-string
4100 (org-element-property :pre-blank headline) 10)))
4101 (cond
4102 ;; Case 1: This is a footnote section: ignore it.
4103 ((org-element-property :footnote-section-p headline) nil)
4104 ;; Case 2. This is a deep sub-tree: export it as a list item.
4105 ;; Also export as items headlines for which no section
4106 ;; format has been found.
4107 ((org-export-low-level-p headline info) ; FIXME (or (not section-fmt))
4108 ;; Build the real contents of the sub-tree.
4109 (let* ((type (if numberedp 'unordered 'unordered)) ; FIXME
4110 (itemized-body (org-e-odt-format-list-item
4111 contents type nil nil full-text)))
4112 (concat
4113 (and (org-export-first-sibling-p headline info)
4114 (org-e-odt-begin-plain-list type))
4115 itemized-body
4116 (and (org-export-last-sibling-p headline info)
4117 (org-e-odt-end-plain-list type)))))
4118 ;; Case 3. Standard headline. Export it as a section.
4120 ;; (format section-fmt full-text
4121 ;; (concat headline-label pre-blanks contents))
4123 (org-e-odt-format-outline contents level section-no full-text tags
4124 (car (last headline-labels))
4125 (butlast headline-labels) nil)))))
4128 ;;;; Horizontal Rule
4130 (defun org-e-odt-horizontal-rule (horizontal-rule contents info)
4131 "Transcode an HORIZONTAL-RULE object from Org to HTML.
4132 CONTENTS is nil. INFO is a plist holding contextual information."
4133 (let ((attr (mapconcat #'identity
4134 (org-element-property :attr_odt horizontal-rule)
4135 " ")))
4136 (org-e-odt--wrap-label horizontal-rule
4137 (org-e-odt-format-horizontal-line))))
4140 ;;;; Inline Babel Call
4142 ;; Inline Babel Calls are ignored.
4145 ;;;; Inline Src Block
4147 (defun org-e-odt-inline-src-block (inline-src-block contents info)
4148 "Transcode an INLINE-SRC-BLOCK element from Org to HTML.
4149 CONTENTS holds the contents of the item. INFO is a plist holding
4150 contextual information."
4151 (let* ((org-lang (org-element-property :language inline-src-block))
4152 (code (org-element-property :value inline-src-block))
4153 (separator (org-e-odt--find-verb-separator code)))
4154 (error "FIXME")))
4157 ;;;; Inlinetask
4159 (defun org-e-odt-format-section (text class &optional id)
4160 (let ((extra (concat (when id (format " id=\"%s\"" id)))))
4161 (concat (format "<div class=\"%s\"%s>\n" class extra) text "</div>\n")))
4163 (defun org-e-odt-inlinetask (inlinetask contents info)
4164 "Transcode an INLINETASK element from Org to HTML.
4165 CONTENTS holds the contents of the block. INFO is a plist
4166 holding contextual information."
4167 (let ((title (org-export-secondary-string
4168 (org-element-property :title inlinetask) 'e-odt info))
4169 (todo (and (plist-get info :with-todo-keywords)
4170 (let ((todo (org-element-property
4171 :todo-keyword inlinetask)))
4172 (and todo
4173 (org-export-secondary-string todo 'e-odt info)))))
4174 (todo-type (org-element-property :todo-type inlinetask))
4175 (tags (and (plist-get info :with-tags)
4176 (org-element-property :tags inlinetask)))
4177 (priority (and (plist-get info :with-priority)
4178 (org-element-property :priority inlinetask))))
4179 ;; If `org-e-odt-format-inlinetask-function' is provided, call it
4180 ;; with appropriate arguments.
4181 (if (functionp org-e-odt-format-inlinetask-function)
4182 (funcall org-e-odt-format-inlinetask-function
4183 todo todo-type priority title tags contents)
4184 ;; Otherwise, use a default template.
4185 (org-e-odt--wrap-label
4186 inlinetask
4187 (let ((full-title
4188 (concat
4189 (when todo (format "\\textbf{\\textsf{\\textsc{%s}}} " todo))
4190 (when priority (format "\\framebox{\\#%c} " priority))
4191 title
4192 (when tags (format "\\hfill{}\\textsc{%s}" tags)))))
4193 (format (concat "\\begin{center}\n"
4194 "\\fbox{\n"
4195 "\\begin{minipage}[c]{.6\\textwidth}\n"
4196 "%s\n\n"
4197 "\\rule[.8em]{\\textwidth}{2pt}\n\n"
4198 "%s"
4199 "\\end{minipage}\n"
4200 "}\n"
4201 "\\end{center}")
4202 full-title contents))))))
4205 ;;;; Item
4207 (defun org-e-odt-format-list-item (contents type checkbox
4208 &optional term-counter-id
4209 headline)
4210 (when checkbox
4211 (setq checkbox
4212 (org-e-odt-format-fontify (case checkbox
4213 (on "[X]")
4214 (off "[&nbsp;]")
4215 (trans "[-]")) 'code)))
4216 (concat
4217 (org-e-odt-begin-list-item type term-counter-id headline)
4218 ;; FIXME checkbox (and checkbox " ")
4219 contents
4220 (org-e-odt-end-list-item type)))
4222 (defun org-e-odt-item (item contents info)
4223 "Transcode an ITEM element from Org to HTML.
4224 CONTENTS holds the contents of the item. INFO is a plist holding
4225 contextual information."
4226 ;; Grab `:level' from plain-list properties, which is always the
4227 ;; first element above current item.
4228 (let* ((plain-list (org-export-get-parent item info))
4229 (type (org-element-property :type plain-list))
4230 (level (org-element-property :level plain-list))
4231 (counter (org-element-property :counter item))
4232 (checkbox (org-element-property :checkbox item))
4233 (tag (let ((tag (org-element-property :tag item)))
4234 (and tag (org-export-secondary-string tag 'e-odt info)))))
4235 (org-e-odt-format-list-item
4236 contents type checkbox (or tag counter))))
4239 ;;;; Keyword
4241 (defun org-e-odt-keyword (keyword contents info)
4242 "Transcode a KEYWORD element from Org to HTML.
4243 CONTENTS is nil. INFO is a plist holding contextual information."
4244 (let ((key (downcase (org-element-property :key keyword)))
4245 (value (org-element-property :value keyword)))
4246 (cond
4247 ((string= key "latex") value)
4248 ((string= key "index") (format "\\index{%s}" value))
4249 ((string= key "target")
4250 (format "\\label{%s}" (org-export-solidify-link-text value)))
4251 ((string= key "toc")
4252 (let ((value (downcase value)))
4253 (cond
4254 ((string-match "\\<headlines\\>" value)
4255 (let ((depth (or (and (string-match "[0-9]+" value)
4256 (string-to-number (match-string 0 value)))
4257 (plist-get info :with-toc))))
4258 (when (wholenump depth) (org-e-odt-toc depth info))))
4259 ((string= "tables" value) "\\listoftables")
4260 ((string= "figures" value) "\\listoffigures")
4261 ((string= "listings" value)
4262 (cond
4263 ;; At the moment, src blocks with a caption are wrapped
4264 ;; into a figure environment.
4265 (t "\\listoffigures")))))))))
4268 ;;;; Latex Environment
4270 (defun org-e-odt-format-latex (latex-frag processing-type)
4271 (let* ((prefix (case processing-type
4272 (dvipng "ltxpng/")
4273 (mathml "ltxmathml/")))
4274 (cache-relpath
4275 (concat prefix (file-name-sans-extension
4276 (file-name-nondirectory (buffer-file-name)))))
4277 (cache-dir (file-name-directory (buffer-file-name )))
4278 (display-msg (case processing-type
4279 (dvipng "Creating LaTeX Image...")
4280 (mathml "Creating MathML snippet..."))))
4281 (with-temp-buffer
4282 (insert latex-frag)
4283 (org-format-latex cache-relpath cache-dir nil display-msg
4284 nil nil processing-type)
4285 (buffer-string))))
4287 (defun org-e-odt-latex-environment (latex-environment contents info)
4288 "Transcode a LATEX-ENVIRONMENT element from Org to HTML.
4289 CONTENTS is nil. INFO is a plist holding contextual information."
4290 (org-e-odt--wrap-label
4291 latex-environment
4292 (let ((latex-frag
4293 (org-remove-indentation
4294 (org-element-property :value latex-environment)))
4295 (processing-type (plist-get info :LaTeX-fragments)))
4296 (cond
4297 ((member processing-type '(t mathjax))
4298 (org-e-odt-format-latex latex-frag 'mathml))
4299 ((equal processing-type 'dvipng)
4300 (let* ((formula-link (org-e-odt-format-latex
4301 latex-frag processing-type)))
4302 (when (and formula-link
4303 (string-match "file:\\([^]]*\\)" formula-link))
4304 (org-e-odt-format-inline-image (match-string 1 formula-link)))))
4306 latex-frag)))))
4309 ;;;; Latex Fragment
4311 (defun org-e-odt-latex-fragment (latex-fragment contents info)
4312 "Transcode a LATEX-FRAGMENT object from Org to HTML.
4313 CONTENTS is nil. INFO is a plist holding contextual information."
4314 ;; (org-element-property :value latex-fragment)
4315 (let* ((latex-frag (org-element-property :value latex-fragment)))
4316 (cond
4317 ((string-match "\\\\ref{\\([^{}\n]+\\)}" latex-frag)
4318 (let* ((label (match-string 1 latex-frag))
4319 (href (and label (org-export-solidify-link-text label)))
4320 (text (if (string-match "\\`[a-z]\\{1,10\\}:\\(.+\\)" label)
4321 (substring label (match-beginning 1))
4322 label)))
4323 (org-e-odt-format-internal-link text href)))
4324 (t (let ((processing-type (plist-get info :LaTeX-fragments)))
4325 (cond
4326 ((member processing-type '(t mathjax))
4327 (org-e-odt-format-latex latex-frag 'mathjax))
4328 ((equal processing-type 'dvipng)
4329 (let* ((formula-link (org-e-odt-format-latex
4330 latex-frag processing-type)))
4331 (when (and formula-link
4332 (string-match "file:\\([^]]*\\)" formula-link))
4333 (org-e-odt-format-inline-image
4334 (match-string 1 formula-link)))))
4335 (t latex-frag)))))))
4338 ;;;; Line Break
4340 (defun org-e-odt-line-break (line-break contents info)
4341 "Transcode a LINE-BREAK object from Org to HTML.
4342 CONTENTS is nil. INFO is a plist holding contextual information."
4343 "<br/>")
4346 ;;;; Link
4348 (defun org-e-odt-link--inline-image (link info)
4349 "Return HTML code for an inline image.
4350 LINK is the link pointing to the inline image. INFO is a plist
4351 used as a communication channel."
4352 (let* ((parent (org-export-get-parent-paragraph link info))
4353 (path (let ((raw-path (org-element-property :path link)))
4354 (if (not (file-name-absolute-p raw-path)) raw-path
4355 (expand-file-name raw-path))))
4356 (caption (org-e-odt--caption/label-string
4357 (org-element-property :caption parent)
4358 (org-element-property :name parent)
4359 info))
4360 (label (org-element-property :name parent))
4361 ;; Retrieve latex attributes from the element around.
4362 (attr (let ((raw-attr
4363 (mapconcat #'identity
4364 (org-element-property :attr_odt parent)
4365 " ")))
4366 (unless (string= raw-attr "") raw-attr))))
4367 ;; Now clear ATTR from any special keyword and set a default
4368 ;; value if nothing is left.
4369 (setq attr (if (not attr) "" (org-trim attr)))
4370 ;; Return proper string, depending on DISPOSITION.
4371 (let ((href (and label (org-export-solidify-link-text label))))
4372 (org-e-odt-format-inline-image path caption href attr))))
4374 (defun org-e-odt-link (link desc info)
4375 "Transcode a LINK object from Org to HTML.
4377 DESC is the description part of the link, or the empty string.
4378 INFO is a plist holding contextual information. See
4379 `org-export-data'."
4380 (let* ((type (org-element-property :type link))
4381 (raw-path (org-element-property :path link))
4382 ;; Ensure DESC really exists, or set it to nil.
4383 (desc (and (not (string= desc "")) desc))
4384 (imagep (org-export-inline-image-p
4385 link org-e-odt-inline-image-rules))
4386 (path (cond
4387 ((member type '("http" "https" "ftp" "mailto"))
4388 (concat type ":" raw-path))
4389 ((string= type "file")
4390 (when (string-match "\\(.+\\)::.+" raw-path)
4391 (setq raw-path (match-string 1 raw-path)))
4392 (if (file-name-absolute-p raw-path)
4393 (concat "file://" (expand-file-name raw-path))
4394 ;; TODO: Not implemented yet. Concat also:
4395 ;; (org-export-directory :HTML info)
4396 (concat "file://" raw-path)))
4397 (t raw-path)))
4398 protocol)
4399 (cond
4400 ;; Image file.
4401 (imagep (org-e-odt-link--inline-image link info))
4402 ;; Target or radioed target: replace link with the normalized
4403 ;; custom-id/target name.
4404 ((member type '("target" "radio"))
4405 (org-e-odt-format-internal-link
4406 (or desc (org-export-secondary-string path 'e-odt info))
4407 (org-export-solidify-link-text path)))
4408 ;; Links pointing to an headline: Find destination and build
4409 ;; appropriate referencing commanding.
4410 ((member type '("custom-id" "fuzzy" "id"))
4411 (let ((destination (if (string= type "fuzzy")
4412 (org-export-resolve-fuzzy-link link info)
4413 (org-export-resolve-id-link link info))))
4414 ;; Fuzzy link points to a target. Do as above.
4415 (case (org-element-type destination)
4416 (target
4417 (org-e-odt-format-internal-link
4418 (or desc
4419 (org-export-secondary-string
4420 (org-element-property :raw-link link)
4421 'e-odt info))
4422 (org-export-solidify-link-text
4423 (org-element-property :raw-value destination))))
4424 ;; Fuzzy link points to an headline. If headlines are
4425 ;; numbered and the link has no description, display
4426 ;; headline's number. Otherwise, display description or
4427 ;; headline's title.
4428 (headline
4429 (let ((label
4430 (format "sec-%s"
4431 (mapconcat
4432 'number-to-string
4433 (org-export-get-headline-number destination info)
4434 "-"))))
4435 (if (and (plist-get info :section-numbers) (not desc))
4436 (format "\\ref{%s}" label)
4437 (org-e-odt-format-internal-link
4438 (or desc
4439 (org-export-secondary-string
4440 (org-element-property :title destination)
4441 'e-odt info)) label))))
4442 ;; Fuzzy link points nowhere.
4443 (otherwise
4444 (org-e-odt-format-fontify
4445 (or desc
4446 (org-export-secondary-string
4447 (org-element-property :raw-link link)
4448 'e-odt info)) 'emphasis)))))
4449 ;; Coderef: replace link with the reference name or the
4450 ;; equivalent line number.
4451 ((string= type "coderef")
4452 (format (org-export-get-coderef-format path (or desc ""))
4453 (org-export-resolve-coderef path info)))
4454 ;; Link type is handled by a special function.
4455 ((functionp (setq protocol (nth 2 (assoc type org-link-protocols))))
4456 (funcall protocol (org-link-unescape path) desc 'html))
4457 ;; External link with a description part.
4458 ((and path desc) (org-e-odt-format-link desc path))
4459 ;; External link without a description part.
4460 (path (org-e-odt-format-link path path))
4461 ;; No path, only description. Try to do something useful.
4462 (t (org-e-odt-format-fontify desc 'emphasis)))))
4465 ;;;; Babel Call
4467 ;; Babel Calls are ignored.
4470 ;;;; Macro
4472 (defun org-e-odt-macro (macro contents info)
4473 "Transcode a MACRO element from Org to HTML.
4474 CONTENTS is nil. INFO is a plist holding contextual information."
4475 ;; Use available tools.
4476 (org-export-expand-macro macro info))
4479 ;;;; Paragraph
4481 (defun org-e-odt-paragraph (paragraph contents info)
4482 "Transcode a PARAGRAPH element from Org to HTML.
4483 CONTENTS is the contents of the paragraph, as a string. INFO is
4484 the plist used as a communication channel."
4485 (let* ((style nil) ; FIXME
4486 (class (cdr (assoc style '((footnote . "footnote")
4487 (verse . nil)))))
4488 (extra (if class (format " class=\"%s\"" class) ""))
4489 (parent (car (org-export-get-genealogy paragraph info))))
4490 (cond
4491 ;; ((and (equal (car parent) 'item)
4492 ;; (= (org-element-property :begin paragraph)
4493 ;; (org-element-property :contents-begin parent)))
4494 ;; ;; leading paragraph in a list item have no tags
4495 ;; contents)
4496 (t (org-e-odt-format-stylized-paragraph nil contents)))))
4499 ;;;; Plain List
4501 (defun org-e-odt-plain-list (plain-list contents info)
4502 "Transcode a PLAIN-LIST element from Org to HTML.
4503 CONTENTS is the contents of the list. INFO is a plist holding
4504 contextual information."
4505 (let* (arg1 ;; FIXME
4506 (type (org-element-property :type plain-list))
4507 (attr (mapconcat #'identity
4508 (org-element-property :attr_odt plain-list)
4509 " ")))
4510 (org-e-odt--wrap-label
4511 plain-list (format "%s\n%s%s"
4512 (org-e-odt-begin-plain-list type)
4513 contents (org-e-odt-end-plain-list type)))))
4515 ;;;; Plain Text
4517 (defun org-e-odt-convert-special-strings (string)
4518 "Convert special characters in STRING to ODT."
4519 (let ((all org-export-e-odt-special-string-regexps)
4520 e a re rpl start)
4521 (while (setq a (pop all))
4522 (setq re (car a) rpl (cdr a) start 0)
4523 (while (string-match re string start)
4524 (setq string (replace-match rpl t nil string))))
4525 string))
4527 ;; (defun org-e-odt-encode-plain-text (s)
4528 ;; "Convert plain text characters to HTML equivalent.
4529 ;; Possible conversions are set in `org-export-html-protect-char-alist'."
4530 ;; (let ((cl org-e-odt-protect-char-alist) c)
4531 ;; (while (setq c (pop cl))
4532 ;; (let ((start 0))
4533 ;; (while (string-match (car c) s start)
4534 ;; (setq s (replace-match (cdr c) t t s)
4535 ;; start (1+ (match-beginning 0))))))
4536 ;; s))
4538 (defun org-e-odt-plain-text (text info)
4539 "Transcode a TEXT string from Org to HTML.
4540 TEXT is the string to transcode. INFO is a plist holding
4541 contextual information."
4542 (setq text (org-e-odt-encode-plain-text text t))
4543 ;; Protect %, #, &, $, ~, ^, _, { and }.
4544 ;; (while (string-match "\\([^\\]\\|^\\)\\([%$#&{}~^_]\\)" text)
4545 ;; (setq text
4546 ;; (replace-match (format "\\%s" (match-string 2 text)) nil t text 2)))
4547 ;; Protect \
4548 ;; (setq text (replace-regexp-in-string
4549 ;; "\\(?:[^\\]\\|^\\)\\(\\\\\\)\\(?:[^%$#&{}~^_\\]\\|$\\)"
4550 ;; "$\\backslash$" text nil t 1))
4551 ;; HTML into \HTML{} and TeX into \TeX{}.
4552 ;; (let ((case-fold-search nil)
4553 ;; (start 0))
4554 ;; (while (string-match "\\<\\(\\(?:La\\)?TeX\\)\\>" text start)
4555 ;; (setq text (replace-match
4556 ;; (format "\\%s{}" (match-string 1 text)) nil t text)
4557 ;; start (match-end 0))))
4558 ;; Handle quotation marks
4559 ;; (setq text (org-e-odt--quotation-marks text info))
4560 ;; Convert special strings.
4561 ;; (when (plist-get info :with-special-strings)
4562 ;; (while (string-match (regexp-quote "...") text)
4563 ;; (setq text (replace-match "\\ldots{}" nil t text))))
4564 (when (plist-get info :with-special-strings)
4565 (setq text (org-e-odt-convert-special-strings text)))
4566 ;; Handle break preservation if required.
4567 (when (plist-get info :preserve-breaks)
4568 (setq text (replace-regexp-in-string "\\(\\\\\\\\\\)?[ \t]*\n" " \\\\\\\\\n"
4569 text)))
4570 ;; Return value.
4571 text)
4574 ;;;; Property Drawer
4576 (defun org-e-odt-property-drawer (property-drawer contents info)
4577 "Transcode a PROPERTY-DRAWER element from Org to HTML.
4578 CONTENTS is nil. INFO is a plist holding contextual
4579 information."
4580 ;; The property drawer isn't exported but we want separating blank
4581 ;; lines nonetheless.
4585 ;;;; Quote Block
4587 (defun org-e-odt-quote-block (quote-block contents info)
4588 "Transcode a QUOTE-BLOCK element from Org to HTML.
4589 CONTENTS holds the contents of the block. INFO is a plist
4590 holding contextual information."
4591 (org-e-odt--wrap-label
4592 quote-block (format "<blockquote>\n%s</blockquote>" contents)))
4595 ;;;; Quote Section
4597 (defun org-e-odt-quote-section (quote-section contents info)
4598 "Transcode a QUOTE-SECTION element from Org to HTML.
4599 CONTENTS is nil. INFO is a plist holding contextual information."
4600 (let ((value (org-remove-indentation
4601 (org-element-property :value quote-section))))
4602 (when value (format "<pre>\n%s</pre>" value))))
4605 ;;;; Section
4607 (defun org-e-odt-section (section contents info) ; FIXME
4608 "Transcode a SECTION element from Org to HTML.
4609 CONTENTS holds the contents of the section. INFO is a plist
4610 holding contextual information."
4611 contents)
4613 ;;;; Radio Target
4615 (defun org-e-odt-radio-target (radio-target text info)
4616 "Transcode a RADIO-TARGET object from Org to HTML.
4617 TEXT is the text of the target. INFO is a plist holding
4618 contextual information."
4619 (org-e-odt-format-anchor
4620 text (org-export-solidify-link-text
4621 (org-element-property :raw-value radio-target))))
4624 ;;;; Special Block
4626 (defun org-e-odt-special-block (special-block contents info)
4627 "Transcode a SPECIAL-BLOCK element from Org to HTML.
4628 CONTENTS holds the contents of the block. INFO is a plist
4629 holding contextual information."
4630 (let ((type (downcase (org-element-property :type special-block))))
4631 (org-e-odt--wrap-label
4632 special-block
4633 (format "\\begin{%s}\n%s\\end{%s}" type contents type))))
4636 ;;;; Src Block
4638 (defun org-e-odt-src-block (src-block contents info)
4639 "Transcode a SRC-BLOCK element from Org to HTML.
4640 CONTENTS holds the contents of the item. INFO is a plist holding
4641 contextual information."
4642 (let* ((lang (org-element-property :language src-block))
4643 (code (org-export-handle-code src-block info))
4644 (caption (org-element-property :caption src-block))
4645 (label (org-element-property :name src-block)))
4646 ;; FIXME: Handle caption
4648 ;; caption-str (when caption)
4649 ;; (main (org-export-secondary-string (car caption) 'e-odt info))
4650 ;; (secondary (org-export-secondary-string (cdr caption) 'e-odt info))
4651 ;; (caption-str (org-e-odt--caption/label-string caption label info))
4652 (org-e-odt-format-source-code-or-example code lang)))
4655 ;;;; Statistics Cookie
4657 (defun org-e-odt-statistics-cookie (statistics-cookie contents info)
4658 "Transcode a STATISTICS-COOKIE object from Org to HTML.
4659 CONTENTS is nil. INFO is a plist holding contextual information."
4660 (let ((cookie-value (org-element-property :value statistics-cookie)))
4661 (org-e-odt-format-fontify cookie-value 'code)))
4664 ;;;; Subscript
4666 (defun org-e-odt-subscript (subscript contents info)
4667 "Transcode a SUBSCRIPT object from Org to HTML.
4668 CONTENTS is the contents of the object. INFO is a plist holding
4669 contextual information."
4670 ;; (format (if (= (length contents) 1) "$_%s$" "$_{\\mathrm{%s}}$") contents)
4671 (org-e-odt-format-fontify contents 'subscript))
4674 ;;;; Superscript
4676 (defun org-e-odt-superscript (superscript contents info)
4677 "Transcode a SUPERSCRIPT object from Org to HTML.
4678 CONTENTS is the contents of the object. INFO is a plist holding
4679 contextual information."
4680 ;; (format (if (= (length contents) 1) "$^%s$" "$^{\\mathrm{%s}}$") contents)
4681 (org-e-odt-format-fontify contents 'superscript))
4684 ;;;; Table
4686 ;; (defun org-e-odt-begin-table (caption label attributes)
4687 ;; (let* ((html-table-tag (or (plist-get info :html-table-tag) ; FIXME
4688 ;; org-e-odt-table-tag))
4689 ;; (html-table-tag
4690 ;; (org-e-odt-splice-attributes html-table-tag attributes)))
4691 ;; (when label
4692 ;; (setq html-table-tag
4693 ;; (org-e-odt-splice-attributes
4694 ;; html-table-tag
4695 ;; (format "id=\"%s\"" (org-solidify-link-text label)))))
4696 ;; (concat "\n" html-table-tag
4697 ;; (format "\n<caption>%s</caption>" (or caption "")))))
4699 ;; (defun org-e-odt-end-table ()
4700 ;; "</table>\n")
4702 ;; (defun org-e-odt-format-table-cell (text r c horiz-span)
4703 ;; (let ((cell-style-cookie
4704 ;; (if org-e-odt-table-align-individual-fields
4705 ;; (format (if (and (boundp 'org-e-odt-format-table-no-css)
4706 ;; org-e-odt-format-table-no-css)
4707 ;; " align=\"%s\"" " class=\"%s\"")
4708 ;; (or (aref (plist-get table-info :alignment) c) "left")) ""))) ;; FIXME
4709 ;; (cond
4710 ;; (org-e-odt-table-cur-rowgrp-is-hdr
4711 ;; (concat
4712 ;; (format (car org-export-table-header-tags) "col" cell-style-cookie)
4713 ;; text (cdr org-export-table-header-tags)))
4714 ;; ((and (= c 0) org-e-odt-table-use-header-tags-for-first-column)
4715 ;; (concat
4716 ;; (format (car org-export-table-header-tags) "row" cell-style-cookie)
4717 ;; text (cdr org-export-table-header-tags)))
4718 ;; (t
4719 ;; (concat
4720 ;; (format (car org-export-table-data-tags) cell-style-cookie)
4721 ;; text (cdr org-export-table-data-tags))))))
4723 (defun org-e-odt-table-row (fields &optional text-for-empty-fields)
4724 (incf org-e-odt-table-rownum)
4725 (let ((i -1))
4726 (org-e-odt-format-table-row
4727 (mapconcat
4728 (lambda (x)
4729 (when (and (string= x "") text-for-empty-fields)
4730 (setq x text-for-empty-fields))
4731 (incf i)
4732 (let (horiz-span)
4733 (org-e-odt-format-table-cell
4734 x org-e-odt-table-rownum i (or horiz-span 0))))
4735 fields "\n"))))
4737 ;; (defun org-e-odt-end-table-rowgroup ()
4738 ;; (when org-e-odt-table-rowgrp-open
4739 ;; (setq org-e-odt-table-rowgrp-open nil)
4740 ;; (if org-e-odt-table-cur-rowgrp-is-hdr "</thead>" "</tbody>")))
4742 ;; (defun org-e-odt-begin-table-rowgroup (&optional is-header-row)
4743 ;; (concat
4744 ;; (when org-e-odt-table-rowgrp-open
4745 ;; (org-e-odt-end-table-rowgroup))
4746 ;; (progn
4747 ;; (setq org-e-odt-table-rowgrp-open t)
4748 ;; (setq org-e-odt-table-cur-rowgrp-is-hdr is-header-row)
4749 ;; (if is-header-row "<thead>" "<tbody>"))))
4751 (defun org-e-odt-table-preamble ()
4752 (let ((colgroup-vector (plist-get table-info :column-groups)) ;; FIXME
4753 c gr colgropen preamble)
4754 (unless (aref colgroup-vector 0)
4755 (setf (aref colgroup-vector 0) 'start))
4756 (dotimes (c columns-number preamble)
4757 (setq gr (aref colgroup-vector c))
4758 (setq preamble
4759 (concat
4760 preamble
4761 (when (memq gr '(start start-end))
4762 (prog1 (if colgropen "</colgroup>\n<colgroup>" "\n<colgroup>")
4763 (setq colgropen t)))
4764 (let* ((colalign-vector (plist-get table-info :alignment)) ;; FIXME
4765 (align (cdr (assoc (aref colalign-vector c)
4766 '(("l" . "left")
4767 ("r" . "right")
4768 ("c" . "center")))))
4769 (alignspec (if (and (boundp 'org-e-odt-format-table-no-css)
4770 org-e-odt-format-table-no-css)
4771 " align=\"%s\"" " class=\"%s\""))
4772 (extra (format alignspec align)))
4773 (format "<col%s />" extra))
4774 (when (memq gr '(end start-end))
4775 (setq colgropen nil)
4776 "</colgroup>"))))
4777 (concat preamble (if colgropen "</colgroup>"))))
4779 (defun org-e-odt-list-table (lines caption label attributes)
4780 (setq lines (org-e-odt-org-table-to-list-table lines))
4781 (let* ((splice nil) head
4782 (org-e-odt-table-rownum -1)
4783 i (cnt 0)
4784 fields line
4785 org-e-odt-table-cur-rowgrp-is-hdr
4786 org-e-odt-table-rowgrp-open
4788 (org-lparse-table-style 'org-table)
4789 org-lparse-table-is-styled)
4790 (cond
4791 (splice
4792 (setq org-lparse-table-is-styled nil)
4793 (mapconcat 'org-e-odt-table-row lines "\n"))
4795 (setq org-lparse-table-is-styled t)
4797 (concat
4798 (org-e-odt-begin-table caption label attributes)
4799 ;; FIXME (org-e-odt-table-preamble)
4800 (org-e-odt-begin-table-rowgroup head)
4802 (mapconcat
4803 (lambda (line)
4804 (cond
4805 ((equal line 'hline) (org-e-odt-begin-table-rowgroup))
4806 (t (org-e-odt-table-row line))))
4807 lines "\n")
4809 (org-e-odt-end-table-rowgroup)
4810 (org-e-odt-end-table))))))
4812 (defun org-e-odt-transcode-table-row (row)
4813 (if (string-match org-table-hline-regexp row) 'hline
4814 (mapcar
4815 (lambda (cell)
4816 (org-export-secondary-string
4817 (let ((cell (org-element-parse-secondary-string
4818 cell
4819 (cdr (assq 'table org-element-string-restrictions)))))
4820 cell)
4821 'e-odt info))
4822 (org-split-string row "[ \t]*|[ \t]*"))))
4824 (defun org-e-odt-org-table-to-list-table (lines &optional splice)
4825 "Convert org-table to list-table.
4826 LINES is a list of the form (ROW1 ROW2 ROW3 ...) where each
4827 element is a `string' representing a single row of org-table.
4828 Thus each ROW has vertical separators \"|\" separating the table
4829 fields. A ROW could also be a row-group separator of the form
4830 \"|---...|\". Return a list of the form (ROW1 ROW2 ROW3
4831 ...). ROW could either be symbol `'hline' or a list of the
4832 form (FIELD1 FIELD2 FIELD3 ...) as appropriate."
4833 (let (line lines-1)
4834 (cond
4835 (splice
4836 (while (setq line (pop lines))
4837 (unless (string-match "^[ \t]*|-" line)
4838 (push (org-e-odt-transcode-table-row line) lines-1))))
4839 (t (while (setq line (pop lines))
4840 (cond
4841 ((string-match "^[ \t]*|-" line)
4842 (when lines (push 'hline lines-1)))
4843 (t (push (org-e-odt-transcode-table-row line) lines-1))))))
4844 (nreverse lines-1)))
4846 (defun org-e-odt-table-table (raw-table)
4847 (require 'table)
4848 (with-current-buffer (get-buffer-create "*org-export-table*")
4849 (erase-buffer))
4850 (let ((output (with-temp-buffer
4851 (insert raw-table)
4852 (goto-char 1)
4853 (re-search-forward "^[ \t]*|[^|]" nil t)
4854 (table-generate-source 'html "*org-export-table*")
4855 (with-current-buffer "*org-export-table*"
4856 (org-trim (buffer-string))))))
4857 (kill-buffer (get-buffer "*org-export-table*"))
4858 output))
4860 (defun org-e-odt-table (table contents info)
4861 "Transcode a TABLE element from Org to HTML.
4862 CONTENTS is nil. INFO is a plist holding contextual information."
4863 (let* ((label (org-element-property :name table))
4864 (caption (org-e-odt--caption/label-string
4865 (org-element-property :caption table) label info))
4866 (attr (mapconcat #'identity
4867 (org-element-property :attr_odt table)
4868 " "))
4869 (raw-table (org-element-property :raw-table table))
4870 (table-type (org-element-property :type table)))
4871 (case table-type
4872 (table.el
4873 ;; (org-e-odt-table-table raw-table)
4876 (let* ((table-info (org-export-table-format-info raw-table))
4877 (columns-number (length (plist-get table-info :alignment)))
4878 (lines (org-split-string
4879 (org-export-clean-table
4880 raw-table (plist-get table-info :special-column-p)) "\n")))
4881 (org-e-odt-list-table lines caption label attr))))))
4884 ;;;; Target
4886 (defun org-e-odt-target (target text info)
4887 "Transcode a TARGET object from Org to HTML.
4888 TEXT is the text of the target. INFO is a plist holding
4889 contextual information."
4890 (org-e-odt-format-anchor
4891 text (org-export-solidify-link-text
4892 (org-element-property :raw-value target))))
4895 ;;;; Time-stamp
4897 (defun org-e-odt-time-stamp (time-stamp contents info)
4898 "Transcode a TIME-STAMP object from Org to HTML.
4899 CONTENTS is nil. INFO is a plist holding contextual
4900 information."
4901 ;; (let ((value (org-element-property :value time-stamp))
4902 ;; (type (org-element-property :type time-stamp))
4903 ;; (appt-type (org-element-property :appt-type time-stamp)))
4904 ;; (concat (cond ((eq appt-type 'scheduled)
4905 ;; (format "\\textbf{\\textsc{%s}} " org-scheduled-string))
4906 ;; ((eq appt-type 'deadline)
4907 ;; (format "\\textbf{\\textsc{%s}} " org-deadline-string))
4908 ;; ((eq appt-type 'closed)
4909 ;; (format "\\textbf{\\textsc{%s}} " org-closed-string)))
4910 ;; (cond ((memq type '(active active-range))
4911 ;; (format org-e-odt-active-timestamp-format value))
4912 ;; ((memq type '(inactive inactive-range))
4913 ;; (format org-e-odt-inactive-timestamp-format value))
4914 ;; (t
4915 ;; (format org-e-odt-diary-timestamp-format value)))))
4916 (let ((value (org-element-property :value time-stamp))
4917 (type (org-element-property :type time-stamp))
4918 (appt-type (org-element-property :appt-type time-stamp)))
4919 (setq value (org-export-secondary-string value 'e-odt info))
4920 (org-e-odt-format-fontify
4921 (concat
4922 (org-e-odt-format-fontify
4923 (cond ((eq appt-type 'scheduled) org-scheduled-string)
4924 ((eq appt-type 'deadline) org-deadline-string)
4925 ((eq appt-type 'closed) org-closed-string)) "timestamp-kwd")
4926 ;; FIXME: (org-translate-time value)
4927 (org-e-odt-format-fontify value "timestamp"))
4928 "timestamp-wrapper")))
4931 ;;;; Verbatim
4933 (defun org-e-odt-verbatim (verbatim contents info)
4934 "Transcode a VERBATIM object from Org to HTML.
4935 CONTENTS is nil. INFO is a plist used as a communication
4936 channel."
4937 (org-e-odt-emphasis
4938 verbatim (org-element-property :value verbatim) info))
4941 ;;;; Verse Block
4943 (defun org-e-odt-verse-block (verse-block contents info)
4944 "Transcode a VERSE-BLOCK element from Org to HTML.
4945 CONTENTS is nil. INFO is a plist holding contextual information."
4946 ;; Replace each newline character with line break. Also replace
4947 ;; each blank line with a line break.
4948 (setq contents (replace-regexp-in-string
4949 "^ *\\\\\\\\$" "<br/>\n"
4950 (replace-regexp-in-string
4951 "\\(\\\\\\\\\\)?[ \t]*\n" " <br/>\n"
4952 (org-remove-indentation
4953 (org-export-secondary-string
4954 (org-element-property :value verse-block)
4955 'e-odt info)))))
4957 ;; Replace each white space at beginning of a line with a
4958 ;; non-breaking space.
4959 (while (string-match "^[ \t]+" contents)
4960 (let ((new-str (org-e-odt-format-spaces
4961 (length (match-string 0 contents)))))
4962 (setq contents (replace-match new-str nil t contents))))
4964 (org-e-odt--wrap-label
4965 verse-block (format "<p class=\"verse\">\n%s</p>" contents)))
4970 ;;; Filter Functions
4972 ;;;; Filter Settings
4974 (defconst org-e-odt-filters-alist
4975 '((:filter-final-output . org-e-odt-final-function))
4976 "Alist between filters keywords and back-end specific filters.
4977 See `org-export-filters-alist' for more information.")
4980 ;;;; Filters
4982 (defun org-e-odt-final-function (contents backend info)
4983 (if (not org-export-e-odt-prettify-xml) contents
4984 (with-temp-buffer
4985 (nxml-mode)
4986 (insert contents)
4987 (indent-region (point-min) (point-max))
4988 (buffer-substring-no-properties (point-min) (point-max)))))
4991 ;;; Interactive functions
4993 (defun org-e-odt-export-to-odt
4994 (&optional subtreep visible-only body-only ext-plist pub-dir)
4995 "Export current buffer to a HTML file.
4997 If narrowing is active in the current buffer, only export its
4998 narrowed part.
5000 If a region is active, export that region.
5002 When optional argument SUBTREEP is non-nil, export the sub-tree
5003 at point, extracting information from the headline properties
5004 first.
5006 When optional argument VISIBLE-ONLY is non-nil, don't export
5007 contents of hidden elements.
5009 When optional argument BODY-ONLY is non-nil, only write code
5010 between \"\\begin{document}\" and \"\\end{document}\".
5012 EXT-PLIST, when provided, is a property list with external
5013 parameters overriding Org default settings, but still inferior to
5014 file-local settings.
5016 When optional argument PUB-DIR is set, use it as the publishing
5017 directory.
5019 Return output file's name."
5020 (interactive)
5022 ;; FIXME
5023 (with-current-buffer (get-buffer-create "*debug*")
5024 (erase-buffer))
5026 ;; (let* ((outfile (org-export-output-file-name ".html" subtreep pub-dir))
5027 ;; (outfile "content.xml"))
5028 ;; (org-export-to-file
5029 ;; 'e-odt outfile subtreep visible-only body-only ext-plist))
5031 (let* ((outbuf (org-e-odt-init-outfile))
5032 (target (org-export-output-file-name ".odt" subtreep pub-dir))
5033 (outdir (file-name-directory (buffer-file-name outbuf)))
5034 (default-directory outdir))
5036 ;; FIXME: for copying embedded images
5037 (setq org-current-export-file
5038 (file-name-directory
5039 (org-export-output-file-name ".odt" subtreep nil)))
5041 (org-export-to-buffer
5042 'e-odt outbuf
5043 (memq 'subtree optns) (memq 'visible optns) (memq 'body optns))
5045 (setq org-lparse-opt-plist nil) ; FIXME
5046 (org-e-odt-save-as-outfile target ;; info
5050 ;; return outfile
5051 target))
5056 ;;; FIXMES, TODOS, FOR REVIEW etc
5058 ;;;; org-format-table-html
5059 ;;;; org-format-org-table-html
5060 ;;;; org-format-table-table-html
5061 ;;;; org-table-number-fraction
5062 ;;;; org-table-number-regexp
5063 ;;;; org-e-odt-table-caption-above
5065 ;;;; org-whitespace
5066 ;;;; "<span style=\"visibility:hidden;\">%s</span>"
5067 ;;;; Remove display properties
5068 ;;;; org-e-odt-final-hook
5070 ;;;; org-e-odt-with-timestamp
5071 ;;;; org-e-odt-html-helper-timestamp
5073 ;;;; org-export-as-html-and-open
5074 ;;;; org-export-as-html-batch
5075 ;;;; org-export-as-html-to-buffer
5076 ;;;; org-replace-region-by-html
5077 ;;;; org-export-region-as-html
5078 ;;;; org-export-as-html
5080 ;;;; (org-export-directory :html opt-plist)
5081 ;;;; (plist-get opt-plist :html-extension)
5082 ;;;; org-e-odt-toplevel-hlevel
5083 ;;;; org-e-odt-special-string-regexps
5084 ;;;; org-e-odt-coding-system
5085 ;;;; org-e-odt-coding-system
5086 ;;;; org-e-odt-inline-images
5087 ;;;; org-e-odt-inline-image-extensions
5088 ;;;; org-e-odt-protect-char-alist
5089 ;;;; org-e-odt-table-use-header-tags-for-first-column
5090 ;;;; org-e-odt-todo-kwd-class-prefix
5091 ;;;; org-e-odt-tag-class-prefix
5092 ;;;; org-e-odt-footnote-separator
5095 ;;; Library Initializations
5097 (mapc
5098 (lambda (desc)
5099 ;; Let Org open all OpenDocument files using system-registered app
5100 (add-to-list 'org-file-apps
5101 (cons (concat "\\." (car desc) "\\'") 'system))
5102 ;; Let Emacs open all OpenDocument files in archive mode
5103 (add-to-list 'auto-mode-alist
5104 (cons (concat "\\." (car desc) "\\'") 'archive-mode)))
5105 org-e-odt-file-extensions)
5107 ;; register the odt exporter with the pre-processor
5108 (add-to-list 'org-export-backends 'odt)
5110 ;; register the odt exporter with org-lparse library
5111 (org-lparse-register-backend 'odt)
5113 (eval-after-load 'org-exp
5114 '(add-to-list 'org-export-inbuffer-options-extra
5115 '("ODT_STYLES_FILE" :odt-styles-file)))
5117 (provide 'org-e-odt)
5119 ;;; org-e-odt.el ends here