;;; org-odt.el --- OpenDocument Text exporter for Org-mode
-;; Copyright (C) 2010-2012 Free Software Foundation, Inc.
+;; Copyright (C) 2010-2013 Free Software Foundation, Inc.
;; Author: Jambunathan K <kjambunathan at gmail dot com>
;; Keywords: outlines, hypermedia, calendar, wp
(expand-file-name "./schema/" org-odt-data-dir)) ; bail out
(eval-when-compile
(and (boundp 'org-odt-data-dir) org-odt-data-dir ; see make install
- (expand-file-name "./schema/" org-odt-data-dir)))
- (expand-file-name "../contrib/odt/etc/schema/" org-odt-lib-dir) ; git
- )
+ (expand-file-name "./schema/" org-odt-data-dir))))
"List of directories to search for OpenDocument schema files.
Use this list to set the default value of
`org-export-odt-schema-dir'. The entries in this list are
org-odt-styles-dir-list)
nil)))
(unless styles-dir
- (error "Error (org-odt): Cannot find factory styles files. Aborting."))
+ (error "Error (org-odt): Cannot find factory styles files, aborting"))
styles-dir)
"Directory that holds auxiliary XML files used by the ODT exporter.
(mapc
(lambda (desc)
- ;; Let Org open all OpenDocument files using system-registered app
- (add-to-list 'org-file-apps
- (cons (concat "\\." (car desc) "\\'") 'system))
;; Let Emacs open all OpenDocument files in archive mode
(add-to-list 'auto-mode-alist
(cons (concat "\\." (car desc) "\\'") 'archive-mode)))
4. list of the form (ODT-OR-OTT-FILE (FILE-MEMBER-1 FILE-MEMBER-2
...))
-In case of option 1, an in-built styles.xml is used. See
+In case of option 1, an in-built styles.xml is used. See
`org-odt-styles-dir' for more information.
In case of option 3, the specified file is unzipped and the
(defconst org-export-odt-tmpdir-prefix "%s-")
(defconst org-export-odt-bookmark-prefix "OrgXref.")
+(defvar org-odt-zip-dir nil
+ "Temporary directory that holds XML files during export.")
(defvar org-export-odt-embed-images t
"Should the images be copied in to the odt file or just linked?")
(table . "Table")
(definition-term . "Text_20_body_20_bold")
(horizontal-line . "Horizontal_20_Line")))
- (character . ((bold . "Bold")
+ (character . ((default . "Default")
+ (bold . "Bold")
(emphasis . "Emphasis")
(code . "OrgCode")
(verbatim . "OrgCode")
then use `org-export-odt-convert-process' to convert the
resulting document to this format. During customization of this
variable, the list of valid values are populated based on
-`org-export-odt-convert-capabilities'."
+`org-export-odt-convert-capabilities'.
+
+You can set this option on per-file basis using file local
+values. See Info node `(emacs) File Variables'."
:group 'org-export-odt
:version "24.1"
:type '(choice :convert-widget
,@(mapcar (lambda (c)
`(const :tag ,c ,c))
(org-lparse-reachable-formats "odt")))))
+;;;###autoload
+(put 'org-export-odt-preferred-output-format 'safe-local-variable 'stringp)
+
+(defmacro org-odt-cleanup-xml-buffers (&rest body)
+ `(let ((org-odt-zip-dir
+ (make-temp-file
+ (format org-export-odt-tmpdir-prefix "odf") t))
+ (--cleanup-xml-buffers
+ (function
+ (lambda nil
+ (let ((xml-files '("mimetype" "META-INF/manifest.xml" "content.xml"
+ "meta.xml" "styles.xml")))
+ ;; kill all xml buffers
+ (mapc (lambda (file)
+ (with-current-buffer
+ (find-file-noselect
+ (expand-file-name file org-odt-zip-dir) t)
+ (set-buffer-modified-p nil)
+ (kill-buffer)))
+ xml-files))
+ ;; delete temporary directory.
+ (org-delete-directory org-odt-zip-dir t)))))
+ (condition-case err
+ (prog1 (progn ,@body)
+ (funcall --cleanup-xml-buffers))
+ ((quit error)
+ (funcall --cleanup-xml-buffers)
+ (message "OpenDocument export failed: %s"
+ (error-message-string err))))))
;;;###autoload
(defun org-export-as-odt-and-open (arg)
The prefix ARG specifies how many levels of the outline should become
headlines. The default is 3. Lower levels will become bulleted lists."
(interactive "P")
- (org-lparse-and-open
- (or org-export-odt-preferred-output-format "odt") "odt" arg))
+ (org-odt-cleanup-xml-buffers
+ (org-lparse-and-open
+ (or org-export-odt-preferred-output-format "odt") "odt" arg)))
;;;###autoload
(defun org-export-as-odt-batch ()
--load=$HOME/lib/emacs/org.el
--eval \"(setq org-export-headline-levels 2)\"
--visit=MyFile --funcall org-export-as-odt-batch"
- (org-lparse-batch "odt"))
+ (org-odt-cleanup-xml-buffers (org-lparse-batch "odt")))
;;; org-export-as-odt
;;;###autoload
<body>...</body>, without even the body tags themselves. When
PUB-DIR is set, use this as the publishing directory."
(interactive "P")
- (org-lparse (or org-export-odt-preferred-output-format "odt")
- "odt" arg hidden ext-plist to-buffer body-only pub-dir))
+ (org-odt-cleanup-xml-buffers
+ (org-lparse (or org-export-odt-preferred-output-format "odt")
+ "odt" arg hidden ext-plist to-buffer body-only pub-dir)))
(defvar org-odt-entity-control-callbacks-alist
`((EXPORT
(delete-region (match-beginning 0) (point-max)))
;; Following variable is let bound when `org-do-lparse' is in
-;; progress. See org-html.el.
+;; progress. See org-html.el.
(defvar org-lparse-toc)
(defun org-odt-format-toc ()
(if (not org-lparse-toc) "" (concat "\n" org-lparse-toc "\n")))
(org-lparse-begin-list-item list-type)))
;; Following variables are let bound when table emission is in
-;; progress. See org-lparse.el.
+;; progress. See org-lparse.el.
(defvar org-lparse-table-begin-marker)
(defvar org-lparse-table-ncols)
(defvar org-lparse-table-rowgrp-open)
(defvar org-odt-object-counters nil
"Running counters for various OBJECT-TYPEs.
-Use this to generate automatic names and style-names. See
+Use this to generate automatic names and style-names. See
`org-odt-add-automatic-style'.")
(defun org-odt-write-automatic-styles ()
(cons object-name style-name)))
(defvar org-odt-table-indentedp nil)
-(defun org-odt-begin-table (caption label attributes)
+(defun org-odt-begin-table (caption label attributes short-caption)
(setq org-odt-table-indentedp (not (null org-lparse-list-stack)))
(when org-odt-table-indentedp
;; Within the Org file, the table is appearing within a list item.
(insert
(org-odt-format-stylized-paragraph
'table (org-odt-format-entity-caption label caption "__Table__"))))
- (let ((name-and-style (org-odt-add-automatic-style "Table" attributes)))
+ (let ((automatic-name (org-odt-add-automatic-style "Table" attributes)))
(org-lparse-insert-tag
"<table:table table:name=\"%s\" table:style-name=\"%s\">"
- (car name-and-style) (or (nth 1 org-odt-table-style-spec)
- (cdr name-and-style) "OrgTable")))
+ (or short-caption (car automatic-name))
+ (or (nth 1 org-odt-table-style-spec)
+ (cdr automatic-name) "OrgTable")))
(setq org-lparse-table-begin-marker (point)))
(defvar org-lparse-table-colalign-info)
;; Additional Note: LibreOffice's AutoFormat facility for tables -
;; which recognizes as many as 16 different cell types - is much
- ;; richer. Unfortunately it is NOT amenable to easy configuration
+ ;; richer. Unfortunately it is NOT amenable to easy configuration
;; by hand.
(let* ((template-name (nth 1 style-spec))
(+ level (or (org-lparse-get 'TOPLEVEL-HLEVEL) 1) -1))))
(insert "\n" (org-odt-format-stylized-paragraph style toc-entry) "\n")))
-;; Following variable is let bound during 'ORG-LINK callback. See
+;; Following variable is let bound during 'ORG-LINK callback. See
;; org-html.el
(defvar org-lparse-link-description-is-image nil)
(defun org-odt-format-link (desc href &optional attr)
(" " "<text:s/>")
(" " "<text:tab/>")))
(hfy-face-to-css 'org-odt-hfy-face-to-css)
- (hfy-optimisations-1 (copy-seq hfy-optimisations))
+ (hfy-optimisations-1 (copy-sequence hfy-optimisations))
(hfy-optimisations (add-to-list 'hfy-optimisations-1
'body-text-only))
(hfy-begin-span-handler
(defun org-export-odt-format-formula (src href)
(save-match-data
(let* ((caption (org-find-text-property-in-string 'org-caption src))
+ (short-caption
+ (or (org-find-text-property-in-string 'org-caption-shortn src)
+ caption))
(caption (and caption (org-xml-format-desc caption)))
+ (short-caption (and short-caption
+ (org-xml-encode-plain-text short-caption)))
(label (org-find-text-property-in-string 'org-label src))
(latex-frag (org-find-text-property-in-string 'org-latex-src src))
(embed-as (or (and latex-frag
`((,(org-odt-format-entity
(if (not (or caption label)) "DisplayFormula"
"CaptionedDisplayFormula")
- href width height :caption caption :label label)
+ href width height :caption caption :label label
+ :short-caption short-caption)
,(if (not (or caption label)) ""
(let* ((label-props (car org-odt-entity-labels-alist)))
(setcar (last label-props) "math-label")
((and (string= type "")
(or (not thefile) (string= thefile ""))
(plist-get org-lparse-opt-plist :section-numbers)
+ (get-text-property 0 'org-no-description fragment)
(setq sec-frag fragment)
- (org-find-text-property-in-string 'org-no-description fragment)
(or (string-match "\\`sec\\(\\(-[0-9]+\\)+\\)" sec-frag)
(and (setq sec-frag
(loop for alias in org-export-target-aliases do
(when (not (member type '("" "file")))
(setq thefile (concat type ":" thefile)))
- (let ((org-odt-suppress-xref nil))
+ (let ((org-odt-suppress-xref
+ ;; Typeset link to headlines with description, as a
+ ;; regular hyperlink.
+ (and (string= type "")
+ (not (get-text-property 0 'org-no-description fragment)))))
(org-odt-format-link
(org-xml-format-desc desc) thefile attr)))))))
(concat
(org-lparse-format 'EXTRA-TARGETS extra-targets)
- ;; No need to generate section numbers. They are auto-generated by
+ ;; No need to generate section numbers. They are auto-generated by
;; the application
;; (concat (org-lparse-format 'SECTION-NUMBER snumber level) " ")
"Create image tag with source and attributes."
(save-match-data
(let* ((caption (org-find-text-property-in-string 'org-caption src))
+ (short-caption
+ (or (org-find-text-property-in-string 'org-caption-shortn src)
+ caption))
(caption (and caption (org-xml-format-desc caption)))
+ (short-caption (and short-caption
+ (org-xml-encode-plain-text short-caption)))
(attr (org-find-text-property-in-string 'org-attributes src))
(label (org-find-text-property-in-string 'org-label src))
(latex-frag (org-find-text-property-in-string
(org-odt-format-entity
frame-style-handle href width height
:caption caption :label label :category category
+ :short-caption short-caption
:user-frame-params user-frame-params)))))
(defun org-odt-format-object-description (title description)
(defun* org-odt-format-entity (entity href width height
&key caption label category
- user-frame-params)
+ user-frame-params short-caption)
(let* ((entity-style (assoc-string entity org-odt-entity-frame-styles t))
default-frame-params frame-params)
(cond
'illustration
(concat
(apply 'org-odt-format-frame href width height
- (nth 2 entity-style))
+ (let ((entity-style-1 (copy-sequence
+ (nth 2 entity-style))))
+ (setcar (cdr entity-style-1)
+ (concat
+ (cadr entity-style-1)
+ (and short-caption
+ (format " draw:name=\"%s\" "
+ short-caption))))
+
+ entity-style-1))
(org-odt-format-entity-caption
label caption (or category (nth 1 entity-style)))))
width height frame-params)))))
methods.")
;; A4 page size is 21.0 by 29.7 cms
-;; The default page settings has 2cm margin on each of the sides. So
+;; The default page settings has 2cm margin on each of the sides. So
;; the effective text area is 17.0 by 25.7 cm
(defvar org-export-odt-max-image-size '(17.0 . 20.0)
"Limiting dimensions for an embedded image.")
(defun org-odt-do-image-size (probe-method file &optional dpi anchor-type)
- (setq dpi (or dpi org-export-odt-pixels-per-inch))
- (setq anchor-type (or anchor-type "paragraph"))
- (flet ((size-in-cms (size-in-pixels)
- (flet ((pixels-to-cms (pixels)
- (let* ((cms-per-inch 2.54)
- (inches (/ pixels dpi)))
- (* cms-per-inch inches))))
- (and size-in-pixels
- (cons (pixels-to-cms (car size-in-pixels))
- (pixels-to-cms (cdr size-in-pixels)))))))
+ (let* ((dpi (or dpi org-export-odt-pixels-per-inch))
+ (anchor-type (or anchor-type "paragraph"))
+ (--pixels-to-cms
+ (function
+ (lambda (pixels dpi)
+ (let* ((cms-per-inch 2.54)
+ (inches (/ pixels dpi)))
+ (* cms-per-inch inches)))))
+ (--size-in-cms
+ (function
+ (lambda (size-in-pixels dpi)
+ (and size-in-pixels
+ (cons (funcall --pixels-to-cms (car size-in-pixels) dpi)
+ (funcall --pixels-to-cms (cdr size-in-pixels) dpi)))))))
(case probe-method
(emacs
- (size-in-cms (ignore-errors ; Emacs could be in batch mode
- (clear-image-cache)
- (image-size (create-image file) 'pixels))))
+ (let ((size-in-pixels
+ (ignore-errors ; Emacs could be in batch mode
+ (clear-image-cache)
+ (image-size (create-image file) 'pixels))))
+ (funcall --size-in-cms size-in-pixels dpi)))
(imagemagick
- (size-in-cms
- (let ((dim (shell-command-to-string
- (format "identify -format \"%%w:%%h\" \"%s\"" file))))
- (when (string-match "\\([0-9]+\\):\\([0-9]+\\)" dim)
- (cons (string-to-number (match-string 1 dim))
- (string-to-number (match-string 2 dim)))))))
- (t
- (cdr (assoc-string anchor-type
- org-export-odt-default-image-sizes-alist))))))
+ (let ((size-in-pixels
+ (let ((dim (shell-command-to-string
+ (format "identify -format \"%%w:%%h\" \"%s\"" file))))
+ (when (string-match "\\([0-9]+\\):\\([0-9]+\\)" dim)
+ (cons (string-to-number (match-string 1 dim))
+ (string-to-number (match-string 2 dim)))))))
+ (funcall --size-in-cms size-in-pixels dpi)))
+ (t (cdr (assoc-string anchor-type
+ org-export-odt-default-image-sizes-alist))))))
(defun org-odt-image-size-from-file (file &optional user-width
user-height scale dpi embed-as)
until size
do (setq size (org-odt-do-image-size
probe-method file dpi embed-as)))
- (or size (error "Cannot determine Image size. Aborting ..."))
+ (or size (error "Cannot determine image size, aborting"))
(setq width (car size) height (cdr size)))
(cond
(scale
;; Not at all OSes ship with zip by default
(error "Executable \"zip\" needed for creating OpenDocument files"))
- (let* ((outdir (make-temp-file
- (format org-export-odt-tmpdir-prefix org-lparse-backend) t))
- (content-file (expand-file-name "content.xml" outdir)))
-
+ (let* ((content-file (expand-file-name "content.xml" org-odt-zip-dir)))
;; init conten.xml
- (with-current-buffer (find-file-noselect content-file t))
+ (require 'nxml-mode)
+ (let ((nxml-auto-insert-xml-declaration-flag nil))
+ (find-file-noselect content-file t))
;; reset variables
(setq org-odt-manifest-file-entries nil
(org-odt-write-manifest-file)
(let ((xml-files '("mimetype" "META-INF/manifest.xml" "content.xml"
- "meta.xml"))
- (zipdir default-directory))
+ "meta.xml")))
(when (equal org-lparse-backend 'odt)
(push "styles.xml" xml-files))
- (message "Switching to directory %s" (expand-file-name zipdir))
;; save all xml files
(mapc (lambda (file)
cmds))
;; move the file from outdir to target-dir
- (rename-file target-name target-dir)
+ (rename-file target-name target-dir)))
- ;; kill all xml buffers
- (mapc (lambda (file)
- (kill-buffer
- (find-file-noselect (expand-file-name file zipdir) t)))
- xml-files)
-
- (delete-directory zipdir)))
(message "Created %s" target)
(set-buffer (find-file-noselect target t)))
(make-directory "META-INF")
(let ((manifest-file (expand-file-name "META-INF/manifest.xml")))
(with-current-buffer
- (find-file-noselect manifest-file t)
+ (let ((nxml-auto-insert-xml-declaration-flag nil))
+ (find-file-noselect manifest-file t))
(insert
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>
<manifest:manifest xmlns:manifest=\"urn:oasis:names:tc:opendocument:xmlns:manifest:1.0\" manifest:version=\"1.2\">\n")
(org-odt-format-tags '("\n<meta:generator>" . "</meta:generator>")
(when org-export-creator-info
(format "Org-%s/Emacs-%s"
- org-version emacs-version)))
+ (org-version)
+ emacs-version)))
(org-odt-format-tags '("\n<meta:keyword>" . "</meta:keyword>") keywords)
(org-odt-format-tags '("\n<dc:subject>" . "</dc:subject>") description)
(org-odt-format-tags '("\n<dc:title>" . "</dc:title>") title)
;; Update styles.xml - take care of outline numbering
(with-current-buffer
(find-file-noselect (expand-file-name "styles.xml") t)
- ;; Don't make automatic backup of styles.xml file. This setting
+ ;; Don't make automatic backup of styles.xml file. This setting
;; prevents the backed-up styles.xml file from being zipped in to
- ;; odt file. This is more of a hackish fix. Better alternative
+ ;; odt file. This is more of a hackish fix. Better alternative
;; would be to fix the zip command so that the output odt file
;; includes only the needed files and excludes any auto-generated
- ;; extra files like backups and auto-saves etc etc. Note that
+ ;; extra files like backups and auto-saves etc etc. Note that
;; currently the zip command zips up the entire temp directory so
;; that any auto-generated files created under the hood ends up in
;; the resulting odt file.
cache-dir display-msg)
(cond
((eq latex-frag-opt 'dvipng)
- (setq cache-dir "ltxpng/")
+ (setq cache-dir org-latex-preview-ltxpng-directory)
(setq display-msg "Creating LaTeX image %s"))
((member latex-frag-opt '(mathjax t))
(setq latex-frag-opt 'mathml)
"" (org-add-props label '(org-protected t)))) t t)))))
;; process latex fragments as part of
-;; `org-export-preprocess-after-blockquote-hook'. Note that this hook
+;; `org-export-preprocess-after-blockquote-hook'. Note that this hook
;; is the one that is closest and well before the call to
;; `org-export-attach-captions-and-attributes' in
;; `org-export-preprocess-string'. The above arrangement permits
(defun org-export-odt-preprocess (parameters)
(org-export-odt-preprocess-label-references))
-(declare-function archive-zip-extract "arc-mode.el" (archive name))
+(declare-function archive-zip-extract "arc-mode" (archive name))
(defun org-odt-zip-extract-one (archive member &optional target)
(require 'arc-mode)
(let* ((target (or target default-directory))
members))
(defun org-odt-copy-styles-file (&optional styles-file)
- ;; Non-availability of styles.xml is not a critical error. For now
+ ;; Non-availability of styles.xml is not a critical error. For now
;; throw an error purely for aesthetic reasons.
(setq styles-file (or styles-file
org-export-odt-styles-file
non-nil."
(interactive
`(,(let (frag)
- (setq frag (and (setq frag (and (region-active-p)
+ (setq frag (and (setq frag (and (org-region-active-p)
(buffer-substring (region-beginning)
(region-end))))
(loop for e in org-latex-regexps
(file-name-directory buffer-file-name))))
(read-file-name "ODF filename: " nil odf-filename nil
(file-name-nondirectory odf-filename)))))
- (let* ((org-lparse-backend 'odf)
- org-lparse-opt-plist
- (filename (or odf-file
- (expand-file-name
- (concat
- (file-name-sans-extension
- (or (file-name-nondirectory buffer-file-name)))
- "." "odf")
- (file-name-directory buffer-file-name))))
- (buffer (find-file-noselect (org-odt-init-outfile filename)))
- (coding-system-for-write 'utf-8)
- (save-buffer-coding-system 'utf-8))
- (set-buffer buffer)
- (set-buffer-file-coding-system coding-system-for-write)
- (let ((mathml (org-create-math-formula latex-frag)))
- (unless mathml (error "No Math formula created"))
- (insert mathml)
- (or (org-export-push-to-kill-ring
- (upcase (symbol-name org-lparse-backend)))
- (message "Exporting... done")))
- (org-odt-save-as-outfile filename nil)))
+ (org-odt-cleanup-xml-buffers
+ (let* ((org-lparse-backend 'odf)
+ org-lparse-opt-plist
+ (filename (or odf-file
+ (expand-file-name
+ (concat
+ (file-name-sans-extension
+ (or (file-name-nondirectory buffer-file-name)))
+ "." "odf")
+ (file-name-directory buffer-file-name))))
+ (buffer (find-file-noselect (org-odt-init-outfile filename)))
+ (coding-system-for-write 'utf-8)
+ (save-buffer-coding-system 'utf-8))
+ (set-buffer buffer)
+ (set-buffer-file-coding-system coding-system-for-write)
+ (let ((mathml (org-create-math-formula latex-frag)))
+ (unless mathml (error "No Math formula created"))
+ (insert mathml)
+ (or (org-export-push-to-kill-ring
+ (upcase (symbol-name org-lparse-backend)))
+ (message "Exporting... done")))
+ (org-odt-save-as-outfile filename nil))))
;;;###autoload
(defun org-export-as-odf-and-open ()
(provide 'org-odt)
+;; Local variables:
+;; generated-autoload-file: "org-loaddefs.el"
+;; End:
+
;;; org-odt.el ends here